diff options
| author | Markus Tiede | 2012-12-13 15:46:50 +0000 |
|---|---|---|
| committer | Markus Tiede | 2012-12-13 15:46:50 +0000 |
| commit | 87dcf3117f746a5bd16bd3d71fa23827ee508e58 (patch) | |
| tree | ebfe8745ee0d7407b2aad813fea92408b1c70453 | |
| parent | 8130f1b4fd362036b3d54172efc3b26aa1c1874d (diff) | |
| download | org.eclipse.jubula.core-87dcf3117f746a5bd16bd3d71fa23827ee508e58.tar.gz org.eclipse.jubula.core-87dcf3117f746a5bd16bd3d71fa23827ee508e58.tar.xz org.eclipse.jubula.core-87dcf3117f746a5bd16bd3d71fa23827ee508e58.zip | |
Sprint task - patch for enhancement 394179 applied.
78 files changed, 14288 insertions, 24 deletions
diff --git a/org.eclipse.jubula.rc.common/META-INF/MANIFEST.MF b/org.eclipse.jubula.rc.common/META-INF/MANIFEST.MF index 8c481b025..4d88ec21b 100644 --- a/org.eclipse.jubula.rc.common/META-INF/MANIFEST.MF +++ b/org.eclipse.jubula.rc.common/META-INF/MANIFEST.MF @@ -7,6 +7,7 @@ Bundle-Vendor: Eclipse Jubula Export-Package: org.eclipse.jubula.rc.common, org.eclipse.jubula.rc.common.adaptable, org.eclipse.jubula.rc.common.businessprocess, + org.eclipse.jubula.rc.common.caps, org.eclipse.jubula.rc.common.classloader, org.eclipse.jubula.rc.common.commands, org.eclipse.jubula.rc.common.components, @@ -18,6 +19,8 @@ Export-Package: org.eclipse.jubula.rc.common, org.eclipse.jubula.rc.common.listener, org.eclipse.jubula.rc.common.logger, org.eclipse.jubula.rc.common.registration, + org.eclipse.jubula.rc.common.uiadapter.factory, + org.eclipse.jubula.rc.common.uiadapter.interfaces, org.eclipse.jubula.rc.common.util Require-Bundle: org.apache.commons.beanutils;bundle-version="[1.7.0,2.0.0)", org.apache.commons.lang;bundle-version="[2.4.0,3.0.0)", diff --git a/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/caps/AbstractButtonCAPs.java b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/caps/AbstractButtonCAPs.java new file mode 100644 index 000000000..ab3213958 --- /dev/null +++ b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/caps/AbstractButtonCAPs.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * 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.caps; + +import org.eclipse.jubula.rc.common.implclasses.MatchUtil; +import org.eclipse.jubula.rc.common.implclasses.Verifier; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.IButtonAdapter; + + +/** + * Implementation for all Button like classes, it holds the + * general methods for the testing of buttons. + * + * @author BREDEX GmbH + * + */ +public abstract class AbstractButtonCAPs extends AbstractTextVerifiable { + + /** + * + * @return the IButtonAdapter for the component. + */ + private IButtonAdapter getButtonAdapter() { + return (IButtonAdapter)getComponent(); + } + + /** + * Verifies the selected property. + * + * @param selected The selected property value to verify. + */ + public void gdVerifySelected(boolean selected) { + + Verifier.equals(selected, getButtonAdapter().isSelected()); + } + + /** + * Verifies the passed text. + * + * @param text The text to verify + */ + public void gdVerifyText(String text) { + gdVerifyText(text, MatchUtil.DEFAULT_OPERATOR); + } + +} diff --git a/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/caps/AbstractComboBoxCAPs.java b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/caps/AbstractComboBoxCAPs.java new file mode 100644 index 000000000..d8ba160a6 --- /dev/null +++ b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/caps/AbstractComboBoxCAPs.java @@ -0,0 +1,180 @@ +/******************************************************************************* + * 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.caps; + +import org.eclipse.jubula.rc.common.exception.StepExecutionException; +import org.eclipse.jubula.rc.common.implclasses.IndexConverter; +import org.eclipse.jubula.rc.common.implclasses.MatchUtil; +import org.eclipse.jubula.rc.common.implclasses.Verifier; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.IComboBoxAdapter; +import org.eclipse.jubula.tools.constants.TestDataConstants; +import org.eclipse.jubula.tools.utils.StringParsing; + +/** + * General implementation for ComboBoxes and ComboBox like components. + * @author BREDEX GmbH + * + */ +public class AbstractComboBoxCAPs extends AbstractTextInputSupport { + + /** The dafault separator of a list of values */ + public static final char VALUE_SEPARATOR = + TestDataConstants.VALUE_CHAR_DEFAULT; + + /** + * + * @return the <code>IComboBoxAdapter</code> + */ + private IComboBoxAdapter getCBAdapter() { + return (IComboBoxAdapter) getComponent(); + } + + + /** + * {@inheritDoc} + */ + public String[] getTextArrayFromComponent() { + return null; + } + + /** + * Verifies the editable property. + * @param editable The editable property to verify. + */ + public void gdVerifyEditable(boolean editable) { + Verifier.equals(editable, getCBAdapter().isEditable()); + } + + /** + * Checks if the component contains the specified text. + * @param text check if this text is in the combobox + */ + public void gdVerifyContainsValue(final String text) { + Verifier.equals(true, getCBAdapter().containsValue(text)); + } + + /** + * Verifies if the list contains an element that renderes <code>value</code>. + * @param value The text to verify + * @param operator The operator used to verify + * @param exists If the value should exist or not. + */ + public void gdVerifyContainsValue(String value, String operator, + boolean exists) { + final boolean contains = getCBAdapter().containsValue(value, operator); + Verifier.equals(exists, contains); + } + + /** + * @see org.eclipse.jubula.rc.swing.swing.implclasses.AbstractSwingImplClass#getText() + * @return value from ComboBoxHelper + */ + protected String getText() { + return getCBAdapter().getText(); + } + + /** + * {@inheritDoc} + */ + public void gdInputText(String text) { + getCBAdapter().input(text, false); + } + + /** + * {@inheritDoc} + */ + public void gdReplaceText(String text) throws StepExecutionException { + getCBAdapter().input(text, true); + } + + /** + * Selects <code>index</code> in the combobox. + * + * @param index + * The index to select + */ + public void gdSelectIndex(String index) { + int implIdx = IndexConverter.toImplementationIndex( + IndexConverter.intValue(index)); + getCBAdapter().select(implIdx); + + } + + /** + * Selects a value from the list of the combobox + * @param valueList The value or list of values to (not)select + * @param operator if regular expressions are used + * @param searchType Determines where the search begins ("relative" or "absolute") + */ + public void gdSelectValue(String valueList, String operator, + final String searchType) { + gdSelectValue(valueList, String.valueOf(VALUE_SEPARATOR), operator, + searchType); + } + + /** + * Selects a value from the list of the combobox + * + * @param valueList + * the item(s) which should be (not)selected. + * @param separator + * The seperator if <code>text</code> is an enumeration of + * values. Not supported by this implementation class + * @param operator + * if regular expressions are used + * @param searchType + * Determines where the search begins ("relative" or "absolute") + */ + private void gdSelectValue(String valueList, String separator, + String operator, final String searchType) { + String[] values = split(valueList, separator); + getCBAdapter().select(values, operator, searchType); + + } + + /** + * Verifies if the combobox has <code>index</code> selected. + * @param index The index to verify + * @param isSelected If the index should be selected or not. + */ + public void gdVerifySelectedIndex(String index, boolean isSelected) { + int implIdx = IndexConverter.toImplementationIndex( + IndexConverter.intValue(index)); + int actual = getCBAdapter().getSelectedIndex(); + Verifier.equals(implIdx, actual, isSelected); + } + + /** + * Verifies if the passed text is currently selected in the combobox. + * @param text The text to verify. + */ + public void gdVerifyText(String text) { + gdVerifyText(text, MatchUtil.DEFAULT_OPERATOR); + } + + /** + * Splits the enumeration of values. + * + * @param values + * The values to split + * @param separator + * The separator, may be <code>null</code> + * @return The array of values + */ + private String[] split(String values, String separator) { + String[] list = StringParsing.splitToArray(values, ((separator == null) + || (separator.length() == 0) ? INDEX_LIST_SEP_CHAR + : separator.charAt(0)), + TestDataConstants.ESCAPE_CHAR_DEFAULT); + return list; + } + +} diff --git a/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/caps/AbstractListCAPs.java b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/caps/AbstractListCAPs.java new file mode 100644 index 000000000..66f2b8c32 --- /dev/null +++ b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/caps/AbstractListCAPs.java @@ -0,0 +1,476 @@ +/******************************************************************************* + * 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.caps; + +import java.util.Arrays; + +import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.lang.StringUtils; +import org.eclipse.jubula.rc.common.CompSystemConstants; +import org.eclipse.jubula.rc.common.driver.ClickOptions; +import org.eclipse.jubula.rc.common.driver.DragAndDropHelper; +import org.eclipse.jubula.rc.common.exception.StepExecutionException; +import org.eclipse.jubula.rc.common.implclasses.IndexConverter; +import org.eclipse.jubula.rc.common.implclasses.ListSelectionVerifier; +import org.eclipse.jubula.rc.common.implclasses.MatchUtil; +import org.eclipse.jubula.rc.common.implclasses.Verifier; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.IListAdapter; +import org.eclipse.jubula.tools.constants.StringConstants; +import org.eclipse.jubula.tools.constants.TestDataConstants; +import org.eclipse.jubula.tools.objects.event.EventFactory; +import org.eclipse.jubula.tools.objects.event.TestErrorEvent; +import org.eclipse.jubula.tools.utils.StringParsing; + +/** + * + * @author BREDEX GmbH + * + */ +public abstract class AbstractListCAPs extends AbstractTextVerifiable { + + /** The default separator for enumerations of list values. */ + public static final char INDEX_LIST_SEP_CHAR = + TestDataConstants.VALUE_CHAR_DEFAULT; + //FIXME this should be in an upper class or Util + /** The default separator of a list of values */ + public static final char VALUE_SEPARATOR = + TestDataConstants.VALUE_CHAR_DEFAULT; + + /** + * Splits the enumeration of values. + * @param values The values to split + * @param separator The separator, may be <code>null</code> + * @return The array of values + */ + private String[] split(String values, String separator) { + String[] list = StringParsing.splitToArray(values, ((separator == null) + || (separator.length() == 0) ? INDEX_LIST_SEP_CHAR + : separator.charAt(0)), + TestDataConstants.ESCAPE_CHAR_DEFAULT); + list = StringUtils.stripAll(list); + return list; + } + + /** + * @return The array of selected indices + * @throws StepExecutionException If there are no indices selected + */ + private int[] getCheckedSelectedIndices() throws StepExecutionException { + int[] selected = getListAdapter().getSelectedIndices(); + if (selected.length == 0) { + throw new StepExecutionException("No list element selected", //$NON-NLS-1$ + EventFactory.createActionError(TestErrorEvent.NO_SELECTION)); + } + return selected; + } + + /** + * + * @return the List Adapter + */ + private IListAdapter getListAdapter() { + return ((IListAdapter) getComponent()); + } + + /** + * Verifies if the passed index is selected. + * + * @param index The index to verify + * @param expectSelected Whether the index should be selected. + */ + public void gdVerifySelectedIndex(String index, boolean expectSelected) { + int[] selected = getCheckedSelectedIndices(); + int implIndex = IndexConverter.toImplementationIndex( + Integer.parseInt(index)); + + boolean isSelected = ArrayUtils.contains(selected, implIndex); + if (expectSelected != isSelected) { + throw new StepExecutionException( + "Selection check failed for index: " + index, //$NON-NLS-1$ + EventFactory.createVerifyFailed( + String.valueOf(expectSelected), + String.valueOf(isSelected))); + } + } + + /** + * Verifies if the passed value or enumeration of values is selected. By + * default, the enumeration separator is <code>,</code> + * @param valueList The value or list of values to verify + */ + public void gdVerifySelectedValue(String valueList) { + gdVerifySelectedValue(valueList, MatchUtil.DEFAULT_OPERATOR, true); + } + + /** + * Verifies if the passed value is selected. + * + * @param value The value to verify + * @param operator The operator to use when comparing the + * expected and actual values. + * @param isSelected if the value should be selected or not. + */ + public void gdVerifySelectedValue(String value, String operator, + boolean isSelected) { + + final String[] current = getListAdapter().getSelectedValues(); + final ListSelectionVerifier listSelVerifier = + new ListSelectionVerifier(); + for (int i = 0; i < current.length; i++) { + listSelVerifier.addItem(i, current[i], true); + } + listSelVerifier.verifySelection(value, operator, isSelected); + } + + /** + * Verifies if all selected elements of a list match a text. + * @param text The text to verify + * @param operator The operator used to verify + */ + public void gdVerifyText(String text, String operator) { + String[] selected = getListAdapter().getSelectedValues(); + final int selCount = selected.length; + if (selCount < 1) { + throw new StepExecutionException("No selection", //$NON-NLS-1$ + EventFactory.createActionError(TestErrorEvent.NO_SELECTION)); + } + for (int i = 0; i < selCount; i++) { + Verifier.match(selected[i], text, operator); + } + } + + /** + * Selects the passed index or enumeration of indices. The enumeration must + * be separated by <code>,</code>, e.g. <code>1, 3,6</code>. + * @param indexList The index or indices to select + * @param extendSelection Whether this selection extends a previous + * selection. + * @param button what mouse button should be used + */ + public void gdSelectIndex(String indexList, final String extendSelection, + int button) { + final boolean isExtendSelection = extendSelection + .equals(CompSystemConstants.EXTEND_SELECTION_YES); + selectIndices(IndexConverter + .toImplementationIndices(parseIndices(indexList)), ClickOptions + .create().setClickCount(1).setMouseButton(button), + isExtendSelection); + } + + /** + * Selects the passed value or enumeration of values. By default, the + * enumeration separator is <code>,</code>. + * @param valueList The value or list of values to select + * @param operator If regular expressions are used + * @param searchType Determines where the search begins ("relative" or "absolute") + * @param extendSelection Whether this selection extends a previous + * selection. If <code>true</code>, the first + * element will be selected with CONTROL as a + * modifier. + * @param button what mouse button should be used + */ + public void gdSelectValue(String valueList, String operator, + String searchType, final String extendSelection, int button) { + final boolean isExtendSelection = + extendSelection.equals(CompSystemConstants.EXTEND_SELECTION_YES); + selectValue(valueList, String.valueOf(VALUE_SEPARATOR), operator, + searchType, ClickOptions.create() + .setClickCount(1) + .setMouseButton(button), isExtendSelection); + } + + /** + * Selects the passed value or enumeration of values. By default, the + * enumeration separator is <code>,</code>, but may be changed by + * <code>separator</code>. + * @param valueList The value or list of values to select + * @param separator The separator, optional + * @param operator If regular expressions are used + * @param searchType Determines where the search begins ("relative" or "absolute") + * @param clickCount the amount of clicks to use + * @param extendSelection Whether this selection extends a previous + * selection. + */ + public void gdSelectValue(String valueList, String separator, + String operator, final String searchType, int clickCount, + final String extendSelection) { + final boolean isExtendSelection = + extendSelection.equals(CompSystemConstants.EXTEND_SELECTION_YES); + selectValue(valueList, separator, operator, searchType, ClickOptions + .create().setClickCount(clickCount), isExtendSelection); + } + + /** + * Verifies if the list contains an element that renderes <code>value</code>. + * @param value The text to verify + */ + public void gdVerifyContainsValue(String value) { + Verifier.equals(true, containsValue(value)); + } + + /** + * Verifies if the list contains an element that renderes <code>value</code>. + * @param value The text to verify + * @param operator The operator used to verify + * @param exists if the wanted value should exist or not. + */ + public void gdVerifyContainsValue(String value, String operator, + boolean exists) { + + Verifier.equals(exists, containsValue(value, operator)); + } + + /** + * Action to read the value of the current selected item of the JList + * to store it in a variable in the Client + * @param variable the name of the variable + * @return the text value. + */ + public String gdReadValue(String variable) { + String[] selected = getListAdapter().getSelectedValues(); + if (selected.length > 0) { + return selected[0]; + } + throw new StepExecutionException("No list item selected", //$NON-NLS-1$ + EventFactory.createActionError(TestErrorEvent.NO_SELECTION)); + } + + /** + * Drags the passed value. + * + * @param mouseButton the mouseButton. + * @param modifier the modifier. + * @param value The value to drag + * @param operator If regular expressions are used + * @param searchType Determines where the search begins ("relative" or "absolute") + */ + public void gdDragValue(int mouseButton, String modifier, String value, + String operator, final String searchType) { + + DragAndDropHelper dndHelper = DragAndDropHelper.getInstance(); + dndHelper.setModifier(modifier); + dndHelper.setMouseButton(mouseButton); + + Integer [] indices = getListAdapter().findIndicesOfValues( + new String [] {value}, operator, searchType); + selectIndices(ArrayUtils.toPrimitive(indices), + ClickOptions.create().setClickCount(0), false); + + pressOrReleaseModifiers(modifier, true); + getRobot().mousePress(null, null, mouseButton); + } + + /** + * Drops on the passed value. + * + * @param value The value on which to drop + * @param operator If regular expressions are used + * @param searchType Determines where the search begins ("relative" or "absolute") + * @param delayBeforeDrop the amount of time (in milliseconds) to wait + * between moving the mouse to the drop point and + * releasing the mouse button + */ + public void gdDropValue(String value, String operator, + final String searchType, int delayBeforeDrop) { + + DragAndDropHelper dndHelper = DragAndDropHelper.getInstance(); + try { + Integer [] indices = getListAdapter().findIndicesOfValues( + new String [] {value}, operator, searchType); + selectIndices(ArrayUtils.toPrimitive(indices), + ClickOptions.create().setClickCount(0), false); + waitBeforeDrop(delayBeforeDrop); + } finally { + getRobot().mouseRelease(null, null, dndHelper.getMouseButton()); + pressOrReleaseModifiers(dndHelper.getModifier(), false); + } + } + + /** + * Drags the passed index. + * + * @param mouseButton the mouseButton. + * @param modifier the modifier. + * @param index The index to drag + */ + public void gdDragIndex(final int mouseButton, final String modifier, + int index) { + + DragAndDropHelper dndHelper = DragAndDropHelper.getInstance(); + dndHelper.setModifier(modifier); + dndHelper.setMouseButton(mouseButton); + + selectIndices( + new int [] {IndexConverter.toImplementationIndex(index)}, + ClickOptions.create().setClickCount(0), false); + + pressOrReleaseModifiers(modifier, true); + getRobot().mousePress(null, null, mouseButton); + } + + /** + * Drops onto the passed index. + * + * @param index The index on which to drop + * @param delayBeforeDrop the amount of time (in milliseconds) to wait + * between moving the mouse to the drop point and + * releasing the mouse button + */ + public void gdDropIndex(final int index, int delayBeforeDrop) { + + DragAndDropHelper dndHelper = DragAndDropHelper.getInstance(); + + try { + selectIndices( + new int [] {IndexConverter.toImplementationIndex(index)}, + ClickOptions.create().setClickCount(0), false); + waitBeforeDrop(delayBeforeDrop); + } finally { + getRobot().mouseRelease(null, null, dndHelper.getMouseButton()); + pressOrReleaseModifiers(dndHelper.getModifier(), false); + } + } + + /** + * @param value The value + * @return <code>true</code> if the list contains an element that is rendered with <code>value</code> + */ + public boolean containsValue(String value) { + Integer[] indices = getListAdapter().findIndicesOfValues( + new String[] { value }, + MatchUtil.EQUALS, CompSystemConstants.SEARCH_TYPE_ABSOLUTE); + return indices.length > 0; + } + + /** + * @param value The value + * @param operator The operator used to verify + * @return <code>true</code> if the list contains an element that is rendered with <code>value</code> + */ + public boolean containsValue(String value, String operator) { + Integer[] indices = null; + if (operator.equals(MatchUtil.NOT_EQUALS)) { + indices = getListAdapter().findIndicesOfValues( + new String[] { value }, + MatchUtil.EQUALS, CompSystemConstants.SEARCH_TYPE_ABSOLUTE); + return indices.length == 0; + } + indices = getListAdapter().findIndicesOfValues(new String[] { value }, + operator, CompSystemConstants.SEARCH_TYPE_ABSOLUTE); + return indices.length > 0; + } + + /** + * Selects the passed value or enumeration of values. By default, the + * enumeration separator is <code>,</code>, but may be changed by + * <code>separator</code>. + * @param valueList The value or list of values to select + * @param separator The separator, optional + * @param operator If regular expressions are used + * @param searchType Determines where the search begins ("relative" or "absolute") + * @param co the click options to use + * @param isExtendSelection Whether this selection extends a previous + * selection. + */ + private void selectValue(String valueList, String separator, + String operator, final String searchType, ClickOptions co, + final boolean isExtendSelection) { + + String[] values = null; + if (StringConstants.EMPTY.equals(valueList)) { + values = new String[1]; + values[0] = StringConstants.EMPTY; + } else { + values = split(valueList, separator); + } + Integer[] indices = getListAdapter().findIndicesOfValues(values, + operator, searchType); + Arrays.sort(indices); + if (!operator.equals(MatchUtil.NOT_EQUALS) + && (indices.length < values.length)) { + throw new StepExecutionException("One or more values not found of set: " //$NON-NLS-1$ + + Arrays.asList(values).toString(), + EventFactory.createActionError(TestErrorEvent.NOT_FOUND)); + } + selectIndices(ArrayUtils.toPrimitive(indices), co, isExtendSelection); + } + + /** + * Parses the enumeration of indices. + * @param indexList The enumeration of indices + * @return The array of parsed indices + */ + private int[] parseIndices(String indexList) { + String[] list = StringParsing.splitToArray(indexList, + INDEX_LIST_SEP_CHAR, TestDataConstants.ESCAPE_CHAR_DEFAULT); + int[] indices = new int[list.length]; + for (int i = 0; i < list.length; i++) { + indices[i] = IndexConverter.intValue(list[i]); + } + return indices; + } + + /** + * @param indices The indices to select + * @param co the click options to use + * @param isExtendSelection Whether this selection extends a previous + * selection. If <code>true</code>, the first + * element will be selected with CONTROL as a + * modifier. + */ + private void selectIndices(int[] indices, ClickOptions co, + boolean isExtendSelection) { + Object list = getListAdapter().getRealComponent(); + if (indices.length > 0) { + try { + if (isExtendSelection) { + getRobot().keyPress(list, + getSystemDefaultModifier()); + } + + // first selection + getListAdapter().clickOnIndex( + new Integer(indices[0]), co); + } finally { + if (isExtendSelection) { + getRobot().keyRelease(list, + getSystemDefaultModifier()); + } + } + } + try { + getRobot().keyPress(list, + getSystemDefaultModifier()); + // following selections + for (int i = 1; i < indices.length; i++) { + getListAdapter().clickOnIndex( + new Integer(indices[i]), co); + } + } finally { + getRobot().keyRelease(list, + getSystemDefaultModifier()); + } + } + + /** + * {@inheritDoc} + */ + public String[] getTextArrayFromComponent() { + return null; + } + + /** + * + * @return - + */ + protected abstract int getSystemDefaultModifier(); + +} diff --git a/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/caps/AbstractMenuCAPs.java b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/caps/AbstractMenuCAPs.java new file mode 100644 index 000000000..43d9ef04e --- /dev/null +++ b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/caps/AbstractMenuCAPs.java @@ -0,0 +1,584 @@ +/******************************************************************************* + * 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.caps; + +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.implclasses.MatchUtil; +import org.eclipse.jubula.rc.common.implclasses.MenuUtilBase; +import org.eclipse.jubula.rc.common.implclasses.Verifier; +import org.eclipse.jubula.rc.common.logger.AutServerLogger; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.IMenuAdapter; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.IMenuItemAdapter; +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 AbstractMenuCAPs extends AbstractUICAPs { + + /** the logger */ + private static AutServerLogger log = new AutServerLogger( + AbstractMenuCAPs.class); + + /** + * @return the log + */ + public static AutServerLogger getLog() { + return log; + } + + /** + * This method gets the object which should implementet the menu Interface. + * It is saved as Component so it must be casted. + * @return the MenuAdapter + */ + public IMenuAdapter getMenuAdapter() { + return (IMenuAdapter) 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 IMenuItemAdapter item = navigateToMenuItem( + getAndCheckMenu(), menuItem, operator); + checkIsNull(item); + try { + Verifier.equals(enabled, item.isEnabled()); + } finally { + closeMenu(getAndCheckMenu(), menuItem, operator); + } + + } + /** + * Checks if the given MenuItemAdapter is null and thorws an Exception + * + * @param item the MenuItemAdapter which should be checked + */ + private void checkIsNull(final IMenuItemAdapter 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 IMenuItemAdapter item = navigateToMenuItem( + getAndCheckMenu(), menuItem); + checkIsNull(item); + try { + Verifier.equals(enabled, item.isEnabled()); + } finally { + closeMenu(getAndCheckMenu(), menuItem); + } + } + + + + /** + * Verifies if the specified menu item exists + * + * @param menuItem the menu item to verifiy 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 IMenuItemAdapter 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 verifiy 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 IMenuItemAdapter 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 IMenuItemAdapter item = navigateToMenuItem( + getAndCheckMenu(), menuItem, operator); + checkIsNull(item); + try { + 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 IMenuItemAdapter item = navigateToMenuItem( + getAndCheckMenu(), menuItem); + checkIsNull(item); + try { + 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 IMenuItemAdapter 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()); + } + IMenuItemAdapter item = navigateToMenuItem(getAndCheckMenu(), + menuItems, operator); + if (item == 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$ + } + throw new StepExecutionException("no such menu item found", //$NON-NLS-1$ + EventFactory.createActionError(TestErrorEvent.NOT_FOUND)); + } + item.selectMenuItem(); + } + + + /** + * + * @return the IMenuAdapter. + * @throws StepExecutionException + * if the active window has no menu bar. + */ + protected IMenuAdapter 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(IMenuAdapter menuBar, String[] textPath, + String operator) { + IMenuItemAdapter 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(IMenuAdapter menuBar, int[] path) { + IMenuItemAdapter 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(IMenuAdapter menu, String name, + String operator) { + IMenuItemAdapter [] subElements = menu.getItems(); + int downcount = 0; + for (int j = 0; j < subElements.length; j++) { + IMenuItemAdapter tempMenu = (IMenuItemAdapter)subElements[j]; + if (tempMenu.isSeparator()) { + downcount++; + } + if (tempMenu.isShowing() + && MatchUtil.getInstance().match( + tempMenu.getText(), name, operator)) { + return j - downcount; + } + } + 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 IMenuItemAdapter navigateToMenuItem( + IMenuAdapter menuBar, String[] path, String operator) { + checkPathLength(path.length); + IMenuAdapter currentmenu = menuBar; + IMenuItemAdapter 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 IMenuItemAdapter navigateToMenuItem( + IMenuAdapter menubar, int[] path) { + checkPathLength(path.length); + + IMenuAdapter currentmenu = menubar; + IMenuItemAdapter 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 IMenuItemAdapter getNextMenuItem(IMenuAdapter currentmenu, + final int pathIndex) { + IMenuItemAdapter 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 IMenuItemAdapter findMenu(IMenuAdapter menu, int idx) { + List visibleSubMenus = new ArrayList(); + IMenuItemAdapter[] subElements = menu.getItems(); + + for (int i = 0; i < subElements.length; ++i) { + + IMenuItemAdapter menuitem = subElements[i]; + if (menuitem.getRealComponent() != null && !menuitem.isSeparator() + && menuitem.isShowing()) { + visibleSubMenus.add(menuitem); + } + + } + + if (idx >= visibleSubMenus.size() || idx < 0) { + return newMenuItemAdapter(null); + } + + return (IMenuItemAdapter) 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 IMenuItemAdapter newMenuItemAdapter(Object component); + +}
\ No newline at end of file diff --git a/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/caps/AbstractTableCAPs.java b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/caps/AbstractTableCAPs.java new file mode 100644 index 000000000..b6411d943 --- /dev/null +++ b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/caps/AbstractTableCAPs.java @@ -0,0 +1,1094 @@ +/******************************************************************************* + * 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.caps; + +import java.awt.Rectangle; +import org.eclipse.jubula.rc.common.CompSystemConstants; +import org.eclipse.jubula.rc.common.driver.ClickOptions; +import org.eclipse.jubula.rc.common.driver.DragAndDropHelper; +import org.eclipse.jubula.rc.common.exception.StepExecutionException; +import org.eclipse.jubula.rc.common.implclasses.IndexConverter; +import org.eclipse.jubula.rc.common.implclasses.MatchUtil; +import org.eclipse.jubula.rc.common.implclasses.Verifier; +import org.eclipse.jubula.rc.common.implclasses.table.Cell; +import org.eclipse.jubula.rc.common.logger.AutServerLogger; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.ITableAdapter; +import org.eclipse.jubula.tools.constants.InputConstants; +import org.eclipse.jubula.tools.objects.event.EventFactory; +import org.eclipse.jubula.tools.objects.event.TestErrorEvent; + +/** + * General implementation for tables. + * + * @author BREDEX GmbH + */ +public abstract class AbstractTableCAPs extends AbstractTextInputSupport { + + /** the logger */ + private static AutServerLogger log = new AutServerLogger( + AbstractMenuCAPs.class); + + /** + * @return the log + */ + public static AutServerLogger getLog() { + return log; + } + + /** + * This method is mostly needed for clicks + * @return the real table as object + */ + private Object getRealTable() { + return getComponent().getRealComponent(); + } + /** + * + * @return the ITableAdapter of this table + */ + private ITableAdapter getTableAdapter() { + return (ITableAdapter) getComponent(); + } + + /** + * Verifies the rendered text inside the currently selected cell. + * + * @param text The cell text to verify. + * @throws StepExecutionException + * If there is no selected cell, or if the rendered text cannot + * be extracted. + */ + public void gdVerifyText(String text) + throws StepExecutionException { + + gdVerifyText(text, MatchUtil.DEFAULT_OPERATOR); + } + + /** + * Verifies the rendered text inside the currently selected cell. + * @param text The cell text to verify. + * @param operator The operation used to verify + * @throws StepExecutionException If there is no selected cell, or if the rendered text cannot be extracted. + */ + public void gdVerifyText(String text, String operator) + throws StepExecutionException { + ITableAdapter adapter = getTableAdapter(); + Cell cell = adapter.getSelectedCell(); + final int implRow = cell.getRow(); + final int implCol = cell.getCol(); + checkRowColBounds(implRow, implCol); + + adapter.scrollCellToVisible(implRow, implCol); + final String current = getCellText(implRow, implCol); + Verifier.match(current, text, operator); + } + + /** + * Verifies the rendered text inside the passed cell. + * @param row The row of the cell. + * @param rowOperator The row header operator + * @param col The column of the cell. + * @param colOperator The column header operator + * @param text The cell text to verify. + * @param operator The operation used to verify + * @throws StepExecutionException If the row or the column is invalid, or if the rendered text cannot be extracted. + */ + public void gdVerifyText(String text, String operator, final String row, + final String rowOperator, final String col, + final String colOperator) throws StepExecutionException { + ITableAdapter adapter = getTableAdapter(); + final int implRow = adapter.getRowFromString(row, rowOperator); + final int implCol = adapter.getColumnFromString(col, colOperator); + String current; + //if row is header and column is existing + if (implRow == -1 && implCol > -1) { + current = adapter.getColumnName(implCol); + } else { + checkRowColBounds(implRow, implCol); + adapter.scrollCellToVisible(implRow, implCol); + current = getCellText(implRow, implCol); + } + + + + + Verifier.match(current, text, operator); + } + + /** + * Selects the cell of the Table.<br> + * With the xPos, yPos, xunits and yUnits the click position inside the cell can be defined. + * @param row The row of the cell. + * @param rowOperator The row header operator + * @param col The column of the cell. + * @param colOperator The column header operator + * @param clickCount The number of clicks with the right mouse button + * @param xPos what x position + * @param xUnits should x position be pixel or percent values + * @param yPos what y position + * @param yUnits should y position be pixel or percent values + * @param extendSelection Should this selection be part of a multiple selection + * @param button what mouse button should be used + * @throws StepExecutionException If the row or the column is invalid + */ + public void gdSelectCell(final String row, final String rowOperator, + final String col, final String colOperator, + final int clickCount, final int xPos, final String xUnits, + final int yPos, final String yUnits, final String extendSelection, + int button) + throws StepExecutionException { + ITableAdapter adapter = getTableAdapter(); + final int implRow = adapter.getRowFromString(row, rowOperator); + final int implCol = adapter.getColumnFromString(col, colOperator); + final boolean isExtendSelection = extendSelection.equals( + CompSystemConstants.EXTEND_SELECTION_YES); + if (log.isDebugEnabled()) { + log.debug("Selecting row, col: " + row + ", " + col); //$NON-NLS-1$//$NON-NLS-2$ + } + + Rectangle cellBounds; + //if row is header and col is existing + if (implRow == -1 && implCol > -1) { + cellBounds = adapter.getHeaderBounds(implCol); + } else { + cellBounds = adapter.scrollCellToVisible(implRow, implCol); + } + Object o = getSpecificRectangle(cellBounds); + ClickOptions clickOptions = ClickOptions.create(); + clickOptions.setClickCount(clickCount).setScrollToVisible(false); + clickOptions.setMouseButton(button); + try { + if (isExtendSelection) { + getRobot().keyPress(getRealTable(), + getExtendSelectionModifier()); + } + getRobot().click(getRealTable(), o, clickOptions, + xPos, xUnits.equalsIgnoreCase(POS_UNIT_PIXEL), + yPos, yUnits.equalsIgnoreCase(POS_UNIT_PIXEL)); + } finally { + if (isExtendSelection) { + getRobot().keyRelease(getRealTable(), + getExtendSelectionModifier()); + } + } + } + /** + * This is a workaround because the toolkit specific + * Robot implementation are using different rectangle types. + * @param rectangle the java.awt.rectangle which needs to + * casted + * @return the rectangle in the type for the specific robot + */ + protected Object getSpecificRectangle(Rectangle rectangle) { + //FIXME changing the Robots might be useful here + return rectangle; + } + /** + * Verifies, if value exists in column. + * + * @param col The column of the cell. + * @param colOperator the column header operator + * @param value The cell text to verify. + * @param operator The operation used to verify + * @param searchType Determines where the search begins ("relative" or "absolute") + * @param exists true if value exists, false otherwise + * @throws StepExecutionException + * If the row or the column is invalid, or if the rendered text + * cannot be extracted. + */ + public void gdVerifyValueInColumn(final String col, + final String colOperator, final String value, + final String operator, final String searchType, boolean exists) + throws StepExecutionException { + ITableAdapter adapter = getTableAdapter(); + final int implCol = adapter.getColumnFromString(col, colOperator); + + + boolean valueExists = isValueExisting(adapter, implCol, + value, operator, searchType); + + Verifier.equals(exists, valueExists); + } + /** + * Looks if value exists in the Column. + * + * @param adapter the teble adapter working on. + * @param implCol the implementation column of the cell. + * @param value the cellt text to verify. + * @param operator The operation used to verify. + * @param searchType searchType Determines where the search begins ("relative" or "absolute") + * @return <code>true</code> it the value exists in the column + */ + private boolean isValueExisting(ITableAdapter adapter, int implCol, + String value, String operator, final String searchType) { + final int rowCount = adapter.getRowCount(); + for (int i = getStartingRowIndex(searchType); + i < rowCount; ++i) { + if (MatchUtil.getInstance().match(getCellText(i, + implCol), value, operator)) { + return true; + } + } + if (adapter.isHeaderVisible()) { + String header = adapter.getColumnName(implCol); + if (MatchUtil.getInstance().match(header, value, + operator)) { + return true; + } + } + return false; + } + + + + /** + * Verifies, if value exists in row.. + * + * @param row The row of the cell. + * @param rowOperator the row header operator + * @param value The cell text to verify. + * @param operator The operation used to verify + * @param searchType Determines where the search begins ("relative" or "absolute") + * @param exists true if value exists, false otherwise + * @throws StepExecutionException + * If the row or the column is invalid, or if the rendered text + * cannot be extracted. + */ + public void gdVerifyValueInRow(final String row, final String rowOperator, + final String value, final String operator, final String searchType, + boolean exists) + throws StepExecutionException { + final ITableAdapter adapter = getTableAdapter(); + final int implRow = adapter.getRowFromString(row, rowOperator); + boolean valueIsExisting = false; + //if row is header + if (implRow == -1) { + + for (int k = getStartingColIndex(searchType); + k < adapter.getColumnCount(); ++k) { + if (MatchUtil.getInstance().match( + adapter.getColumnName(k), + value, operator)) { + valueIsExisting = true; + break; + } + } + + + } else { + + final int columnCount = adapter.getColumnCount(); + if (columnCount > 0) { + for (int i = getStartingColIndex(searchType); + i < columnCount; ++i) { + if (MatchUtil.getInstance().match( + getCellText(implRow, i), value, operator)) { + valueIsExisting = true; + break; + } + } + } else { + // No columns found. This table is used to present a + // list-like component. + if (MatchUtil.getInstance().match( + adapter.getRowName(implRow), + value, operator)) { + valueIsExisting = true; + + } + } + + } + Verifier.equals(exists, valueIsExisting); + } + + /** + * Verifies the editable property of the given indices. + * + * @param editable + * The editable property to verify. + * @param row the row to select + * @param rowOperator the row header operator + * @param col the column to select + * @param colOperator the column header operator + */ + public void gdVerifyEditable(boolean editable, String row, + String rowOperator, String col, String colOperator) { + //if row is header row + + if (getTableAdapter().getRowFromString(row, rowOperator) == -1) { + throw new StepExecutionException("Unsupported Header Action", //$NON-NLS-1$ + EventFactory.createActionError( + TestErrorEvent.UNSUPPORTED_HEADER_ACTION)); + } + gdSelectCell(row, rowOperator, col, colOperator, ClickOptions.create(), + CompSystemConstants.EXTEND_SELECTION_NO); + gdVerifyEditable(editable); + } + + + /** + * Selects a table cell in the given row and column via click in the midle of the cell. + * @param row The row of the cell. + * @param rowOperator The row header operator + * @param col The column of the cell. + * @param colOperator The column header operator + * @param co the click options to use + * @param extendSelection Should this selection be part of a multiple selection + */ + private void gdSelectCell(final String row, final String rowOperator, + final String col, final String colOperator, + final ClickOptions co, final String extendSelection) { + + gdSelectCell(row, rowOperator, col, colOperator, co.getClickCount(), + 50, POS_UNI_PERCENT, 50, POS_UNI_PERCENT, extendSelection, + co.getMouseButton()); + } + + + /** + * Verifies the rendered text inside cell at the mouse position on screen. + * + * @param text The cell text to verify. + * @param operator The operation used to verify + * @throws StepExecutionException If there is no selected cell, or if the + * rendered text cannot be extracted. + */ + public void gdVerifyTextAtMousePosition(String text, String operator) + throws StepExecutionException { + if (isMouseOnHeader()) { + throw new StepExecutionException("Unsupported Header Action", //$NON-NLS-1$ + EventFactory.createActionError( + TestErrorEvent.UNSUPPORTED_HEADER_ACTION)); + } + Cell cell = getCellAtMousePosition(); + gdVerifyText(text, operator, + Integer.toString(IndexConverter.toUserIndex(cell.getRow())), + MatchUtil.EQUALS, + Integer.toString(IndexConverter.toUserIndex(cell.getCol())), + MatchUtil.EQUALS); + } + + /** + * Verifies the editable property of the selected cell. + * + * @param editable the editable property to verify. + */ + public void gdVerifyEditableSelected(boolean editable) { + gdVerifyEditable(editable); + } + + /** + * Verifies the editable property of the current selected cell. + * + * @param editable The editable property to verify. + */ + public void gdVerifyEditable(boolean editable) { + Cell cell = getTableAdapter().getSelectedCell(); + + Verifier.equals(editable, getTableAdapter() + .isCellEditable(cell.getRow(), cell.getCol())); + } + + /** + * Verifies the editable property of the cell under current mouse position. + * + * @param editable the editable property to verify. + */ + public void gdVerifyEditableMousePosition(boolean editable) { + //if row is header row + if (isMouseOnHeader()) { + throw new StepExecutionException("Unsupported Header Action", //$NON-NLS-1$ + EventFactory.createActionError( + TestErrorEvent.UNSUPPORTED_HEADER_ACTION)); + } + Cell cell = getCellAtMousePosition(); + boolean isEditable = getTableAdapter().isCellEditable( + cell.getRow(), cell.getCol()); + Verifier.equals(editable, isEditable); + } + /** + * Finds the first row which contains the value <code>value</code> + * in column <code>col</code> and selects this row. + * @param col the column + * @param colOperator the column header operator + * @param value the value + * @param clickCount the number of clicks. + * @param regexOp the regex operator + * @param extendSelection Should this selection be part of a multiple selection + * @param searchType Determines where the search begins ("relative" or "absolute") + * @param button what mouse button should be used + */ + public void gdSelectRowByValue(String col, String colOperator, + final String value, final String regexOp, int clickCount, + final String extendSelection, final String searchType, int button) { + gdSelectRowByValue(col, colOperator, value, regexOp, extendSelection, + searchType, ClickOptions.create() + .setClickCount(clickCount) + .setMouseButton(button)); + } + + /** + * Finds the first row which contains the value <code>value</code> + * in column <code>col</code> and selects this row. + * + * @param col the column + * @param colOperator the column header operator + * @param value the value + * @param regexOp the regex operator + * @param extendSelection Should this selection be part of a multiple selection + * @param searchType Determines where the search begins ("relative" or "absolute") + * @param co the clickOptions to use + */ + protected void gdSelectRowByValue(String col, String colOperator, + final String value, final String regexOp, final String extendSelection, + final String searchType, ClickOptions co) { + ITableAdapter adapter = getTableAdapter(); + final int implCol = adapter.getColumnFromString(col, colOperator); + Integer implRow = null; + final int rowCount = adapter.getRowCount(); + + for (int i = getStartingRowIndex(searchType); i < rowCount; ++i) { + if (MatchUtil.getInstance().match(getCellText(i, implCol), + value, regexOp)) { + + implRow = new Integer(i); + break; + } + } + if (implRow == null) { + String header = adapter.getColumnName(implCol); + if (MatchUtil.getInstance().match(header, value, regexOp)) { + implRow = new Integer(-1); + } + } + + if (implRow == null) { + throw new StepExecutionException("no such row found", //$NON-NLS-1$ + EventFactory.createActionError(TestErrorEvent.NOT_FOUND)); + } + + String userIdxRow = new Integer(IndexConverter.toUserIndex( + implRow.intValue())).toString(); + String userIdxCol = new Integer(IndexConverter.toUserIndex( + implCol)).toString(); + + gdSelectCell(userIdxRow, MatchUtil.EQUALS, userIdxCol, colOperator, co, + extendSelection); + } + + /** + * Finds the first column which contains the value <code>value</code> + * in the given row and selects the cell. + * + * @param row the row to select + * @param rowOperator the row header operator + * @param value the value + * @param clickCount the number of clicks + * @param regex search using regex + * @param extendSelection Should this selection be part of a multiple selection + * @param searchType Determines where the search begins ("relative" or "absolute") + * @param button what mouse button should be used + */ + public void gdSelectCellByColValue(String row, String rowOperator, + final String value, final String regex, int clickCount, + final String extendSelection, final String searchType, int button) { + gdSelectCellByColValue(row, rowOperator, value, regex, extendSelection, + searchType, ClickOptions.create() + .setClickCount(clickCount) + .setMouseButton(button)); + } + + /** + * Finds the first column which contains the value <code>value</code> + * in the given row and selects the cell. + * + * @param row the row + * @param rowOperator the row header operator + * @param value the value + * @param regex search using regex + * @param extendSelection Should this selection be part of a multiple selection + * @param searchType Determines where the search begins ("relative" or "absolute") + * @param co the click options to use + */ + protected void gdSelectCellByColValue(String row, String rowOperator, + final String value, final String regex, final String extendSelection, + final String searchType, ClickOptions co) { + ITableAdapter adapter = getTableAdapter(); + final int implRow = adapter.getRowFromString(row, rowOperator); + int colCount = adapter.getColumnCount(); + Integer implCol = null; + if (implRow == -1) { + + for (int i = getStartingColIndex(searchType); i < colCount; ++i) { + if (MatchUtil.getInstance().match(adapter.getColumnName(i), + value, regex)) { + implCol = new Integer(i); + break; + } + } + } else { + for (int i = getStartingColIndex(searchType); i < colCount; ++i) { + if (MatchUtil.getInstance().match(getCellText(implRow, i), + value, regex)) { + + implCol = new Integer(i); + break; + } + } + } + if (implCol == null) { + throw new StepExecutionException("no such cell found", EventFactory //$NON-NLS-1$ + .createActionError(TestErrorEvent.NOT_FOUND)); + } + + String usrIdxRowStr = new Integer(IndexConverter.toUserIndex( + implRow)).toString(); + String usrIdxColStr = new Integer(IndexConverter.toUserIndex( + implCol.intValue())).toString(); + + gdSelectCell(usrIdxRowStr, rowOperator, usrIdxColStr, MatchUtil.EQUALS, + co, extendSelection); + + } +//FIXME +// /** +// * Action to read the value of the current selected cell of the JTable +// * to store it in a variable in the Client +// * @param variable the name of the variable +// * @return the text value. +// */ +// public String gdReadValue(String variable) { +// final Cell selectedCell = getTableAdapter().getSelectedCell(); +// return getCellText(selectedCell.getRow(), selectedCell.getCol()); +// } + + /** + * Action to read the value of the passed cell of the JTable + * to store it in a variable in the Client + * @param variable the name of the variable + * @param row the row to select + * @param rowOperator the row header operator + * @param col the column to select + * @param colOperator the column header operator + * @return the text value. + */ + public String gdReadValue(String variable, String row, String rowOperator, + String col, String colOperator) { + ITableAdapter adapter = getTableAdapter(); + final int implRow = adapter.getRowFromString(row, rowOperator); + final int implCol = adapter.getColumnFromString(col, colOperator); + + //if row is header and column is existing + if (implRow == -1 && implCol > -1) { + return adapter.getColumnName(implCol); + } + + checkRowColBounds(implRow, implCol); + + adapter.scrollCellToVisible(implRow, implCol); + return getCellText(implRow, implCol); + } + + /** + * {@inheritDoc} + */ + public String gdReadValueAtMousePosition(String variable) { + Cell cellAtMousePosition = getTableAdapter().getSelectedCell(); + return getCellText(cellAtMousePosition.getRow(), + cellAtMousePosition.getCol()); + } + + /** + * Tries to click in the cell under the mouse position. If the mouse is not + * over a cell, the current selected cell will be clicked on. If there is no + * selected cell, the middle of the table is used to click on. + * @param count Number of clicks + * @param button The mouse button + */ + public void gdClick(int count, int button) { + ITableAdapter adapter = getTableAdapter(); + Cell cell = null; + if (isMouseOverCell()) { + cell = getCellAtMousePosition(); + } else if (adapter.hasCellSelection()) { + cell = adapter.getSelectedCell(); + } + if (cell != null) { + Rectangle cellRect = + adapter.scrollCellToVisible(cell.getRow(), cell.getCol()); + getRobot().click(getRealTable(), cellRect, ClickOptions.create() + .setClickCount(count).setMouseButton(button)); + } else { + super.gdClick(count, button); + } + } + + /** + * Selects a cell relative to the cell at the current mouse position. + * If the mouse is not at any cell, the current selected cell is used. + * @param direction the direction to move. + * @param cellCount the amount of cells to move + * @param clickCount the click count to select the new cell. + * @param xPos what x position + * @param xUnits should x position be pixel or percent values + * @param yPos what y position + * @param yUnits should y position be pixel or percent values + * @param extendSelection Should this selection be part of a multiple selection + * @throws StepExecutionException if any error occurs + */ + public void gdMove(String direction, int cellCount, int clickCount, + final int xPos, final String xUnits, + final int yPos, final String yUnits, final String extendSelection) + throws StepExecutionException { + if (isMouseOnHeader()) { + throw new StepExecutionException("Unsupported Header Action", //$NON-NLS-1$ + EventFactory.createActionError( + TestErrorEvent.UNSUPPORTED_HEADER_ACTION)); + } + Cell currCell = null; + try { + currCell = getCellAtMousePosition(); + } catch (StepExecutionException e) { + currCell = getTableAdapter().getSelectedCell(); + } + int newCol = currCell.getCol(); + int newRow = currCell.getRow(); + if (CompSystemConstants.TABLE_MOVE_UP + .equalsIgnoreCase(direction)) { + newRow -= cellCount; + } else if (CompSystemConstants.TABLE_MOVE_DOWN + .equalsIgnoreCase(direction)) { + newRow += cellCount; + } else if (CompSystemConstants.TABLE_MOVE_LEFT + .equalsIgnoreCase(direction)) { + newCol -= cellCount; + } else if (CompSystemConstants.TABLE_MOVE_RIGHT + .equalsIgnoreCase(direction)) { + newCol += cellCount; + } + newRow = IndexConverter.toUserIndex(newRow); + newCol = IndexConverter.toUserIndex(newCol); + String row = Integer.toString(newRow); + String col = Integer.toString(newCol); + gdSelectCell(row, MatchUtil.DEFAULT_OPERATOR , col, + MatchUtil.DEFAULT_OPERATOR, clickCount, xPos, + xUnits, yPos, yUnits, extendSelection, + InputConstants.MOUSE_BUTTON_LEFT); +// gdSelectCell(newRow, newCol, clickCount, +// xPos, xUnits, yPos, yUnits, extendSelection); + } + + /** + * Writes the passed text into the currently selected cell. + * + * @param text + * The text. + * @throws StepExecutionException + * If there is no selected cell, or if the cell is not editable, + * or if the table cell editor permits the text to be written. + */ + public void gdInputText(final String text) throws StepExecutionException { + inputText(text, false); + } + + /** + * Types the text in the specified cell. + * @param text The text + * @param row The row of the cell. + * @param rowOperator The row operator + * @param col The column of the cell. + * @param colOperator The column operator + * @throws StepExecutionException If the text input fails + */ + public void gdInputText(String text, String row, String rowOperator, + String col, String colOperator) + throws StepExecutionException { + //if row is header row + if (getTableAdapter().getRowFromString(row, rowOperator) == -1) { + throw new StepExecutionException("Unsupported Header Action", //$NON-NLS-1$ + EventFactory.createActionError( + TestErrorEvent.UNSUPPORTED_HEADER_ACTION)); + } + gdSelectCell(row, rowOperator, col, colOperator, + ClickOptions.create().setClickCount(1), + CompSystemConstants.EXTEND_SELECTION_NO); + gdInputText(text); + } + + /** + * Types <code>text</code> into the component. This replaces the shown + * content in the current selected cell. + * + * @param text the text to type in + * @throws StepExecutionException + * If there is no selected cell, or if the cell is not editable, + * or if the table cell editor permits the text to be written. + */ + public void gdReplaceText(String text) throws StepExecutionException { + inputText(text, true); + } + + /** + * Replaces the given text in the given cell coordinates + * @param text the text to replace + * @param row The row of the cell. + * @param rowOperator The row operator + * @param col The column of the cell. + * @param colOperator The column operator + */ + public void gdReplaceText(String text, String row, String rowOperator, + String col, String colOperator) { + //if row is header row + if (getTableAdapter().getRowFromString(row, rowOperator) == -1) { + throw new StepExecutionException("Unsupported Header Action", //$NON-NLS-1$ + EventFactory.createActionError( + TestErrorEvent.UNSUPPORTED_HEADER_ACTION)); + } + gdSelectCell(row, rowOperator, col, colOperator, + ClickOptions.create().setClickCount(1), + CompSystemConstants.EXTEND_SELECTION_NO); + inputText(text, true); + } + + /** + * Drags the cell of the Table.<br> + * With the xPos, yPos, xunits and yUnits the click position inside the + * cell can be defined. + * + * @param mouseButton the mouseButton. + * @param modifier the modifier. + * @param row the row to select + * @param rowOperator the row header operator + * @param col the column to select + * @param colOperator the column header operator + * @param xPos what x position + * @param xUnits should x position be pixel or percent values + * @param yPos what y position + * @param yUnits should y position be pixel or percent values + * @throws StepExecutionException + * If the row or the column is invalid + */ + public void gdDragCell(final int mouseButton, final String modifier, + final String row, final String rowOperator, + final String col, final String colOperator, final int xPos, + final String xUnits, final int yPos, final String yUnits) + throws StepExecutionException { + + final DragAndDropHelper dndHelper = DragAndDropHelper.getInstance(); + dndHelper.setModifier(modifier); + dndHelper.setMouseButton(mouseButton); + dndHelper.setDragComponent(null); + gdSelectCell(row, rowOperator, col, colOperator, 0, xPos, xUnits, yPos, + yUnits, CompSystemConstants.EXTEND_SELECTION_NO, 1); + pressOrReleaseModifiers(modifier, true); + getRobot().mousePress(null, null, mouseButton); + } + + /** + * Drops on the cell of the JTable.<br> + * With the xPos, yPos, xunits and yUnits the click position inside the + * cell can be defined. + * + * @param row the row to select + * @param rowOperator the row header operator + * @param col the column to select + * @param colOperator the column header operator + * @param xPos what x position + * @param xUnits should x position be pixel or percent values + * @param yPos what y position + * @param yUnits should y position be pixel or percent values + * @param delayBeforeDrop the amount of time (in milliseconds) to wait + * between moving the mouse to the drop point and + * releasing the mouse button + * @throws StepExecutionException + * If the row or the column is invalid + */ + public void gdDropCell(final String row, final String rowOperator, + final String col, final String colOperator, final int xPos, + final String xUnits, final int yPos, final String yUnits, + int delayBeforeDrop) throws StepExecutionException { + + final DragAndDropHelper dndHelper = DragAndDropHelper.getInstance(); + try { + gdSelectCell(row, rowOperator, col, colOperator, 0, xPos, xUnits, + yPos, yUnits, CompSystemConstants.EXTEND_SELECTION_NO, 1); + waitBeforeDrop(delayBeforeDrop); + } finally { + getRobot().mouseRelease(null, null, dndHelper.getMouseButton()); + pressOrReleaseModifiers(dndHelper.getModifier(), false); + } + } + + /** + * Finds the first row which contains the value <code>value</code> + * in column <code>col</code> and drags this row. + * + * @param mouseButton the mouse button + * @param modifier the modifier + * @param col the column + * @param colOperator the column header operator + * @param value the value + * @param regexOp the regex operator + * @param searchType Determines where the search begins ("relative" or "absolute") + */ + public void gdDragRowByValue(int mouseButton, String modifier, String col, + String colOperator, final String value, final String regexOp, + final String searchType) { + + final DragAndDropHelper dndHelper = DragAndDropHelper.getInstance(); + dndHelper.setModifier(modifier); + dndHelper.setMouseButton(mouseButton); + gdSelectRowByValue(col, colOperator, value, regexOp, 1, + CompSystemConstants.EXTEND_SELECTION_NO, searchType, 1); + pressOrReleaseModifiers(modifier, true); + getRobot().mousePress(null, null, mouseButton); + } + + /** + * Finds the first row which contains the value <code>value</code> + * in column <code>col</code> and drops on this row. + * + * @param col the column to select + * @param colOperator the column header operator + * @param value the value + * @param regexOp the regex operator + * @param searchType Determines where the search begins ("relative" or "absolute") + * @param delayBeforeDrop the amount of time (in milliseconds) to wait + * between moving the mouse to the drop point and + * releasing the mouse button + */ + public void gdDropRowByValue(String col, String colOperator, + final String value, final String regexOp, final String searchType, + int delayBeforeDrop) { + + final DragAndDropHelper dndHelper = DragAndDropHelper.getInstance(); + try { + gdSelectRowByValue(col, colOperator, value, regexOp, + CompSystemConstants.EXTEND_SELECTION_NO, + searchType, ClickOptions + .create().setClickCount(0)); + waitBeforeDrop(delayBeforeDrop); + } finally { + getRobot().mouseRelease(null, null, dndHelper.getMouseButton()); + pressOrReleaseModifiers(dndHelper.getModifier(), false); + } + } + + /** + * Finds the first column which contains the value <code>value</code> + * in the given row and drags the cell. + * + * @param mouseButton the mouse button + * @param modifier the modifiers + * @param row the row to select + * @param rowOperator the row header operator + * @param value the value + * @param regex search using regex + * @param searchType Determines where the search begins ("relative" or "absolute") + */ + public void gdDragCellByColValue(int mouseButton, String modifier, + String row, String rowOperator, final String value, + final String regex, final String searchType) { + + final DragAndDropHelper dndHelper = DragAndDropHelper.getInstance(); + dndHelper.setModifier(modifier); + dndHelper.setMouseButton(mouseButton); + + gdSelectCellByColValue(row, rowOperator, value, regex, + CompSystemConstants.EXTEND_SELECTION_NO, searchType, + ClickOptions.create().setClickCount(0)); + pressOrReleaseModifiers(modifier, true); + getRobot().mousePress(null, null, mouseButton); + } + + /** + * Finds the first column which contains the value <code>value</code> + * in the given row and drops on the cell. + * + * @param row the row to select + * @param rowOperator the row header operator + * @param value the value + * @param regex search using regex + * @param searchType Determines where the search begins ("relative" or "absolute") + * @param delayBeforeDrop the amount of time (in milliseconds) to wait + * between moving the mouse to the drop point and + * releasing the mouse button + */ + public void gdDropCellByColValue(String row, String rowOperator, + final String value, final String regex, final String searchType, + int delayBeforeDrop) { + + final DragAndDropHelper dndHelper = DragAndDropHelper.getInstance(); + try { + gdSelectCellByColValue(row, rowOperator, value, regex, + CompSystemConstants.EXTEND_SELECTION_NO, searchType, + ClickOptions.create().setClickCount(0)); + waitBeforeDrop(delayBeforeDrop); + } finally { + getRobot().mouseRelease(null, null, dndHelper.getMouseButton()); + pressOrReleaseModifiers(dndHelper.getModifier(), false); + } + } + + + /** + * Gets the text from the specific cell which is given + * by the row and the column. + * @param row the zero based index of the row + * @param column the zero based index of the column + * @return the text of the cell of the given coordinates + */ + private String getCellText(final int row, final int column) { + return getTableAdapter().getCellText(row, column); + + } + + /** + * Checks whether <code>0 <= value < count</code>. + * @param value The value to check. + * @param count The upper bound. + */ + private void checkBounds(int value, int count) { + if (value < 0 || value >= count) { + throw new StepExecutionException("Invalid row/column: " + value, //$NON-NLS-1$ + EventFactory.createActionError( + TestErrorEvent.INVALID_INDEX_OR_HEADER)); + } + } + + /** + * Checks if the passed row and column are inside the bounds of the Table. + * @param row The row + * @param column The column + * @throws StepExecutionException If the row or the column is outside of the Table's bounds. + */ + protected void checkRowColBounds(int row, int column) + throws StepExecutionException { + ITableAdapter adapter = getTableAdapter(); + checkBounds(row, adapter.getRowCount()); + + // Corner case: Only check the bounds if the table is not being + // used as a list or anything other than the first column + // is being checked. + int colCount = adapter.getColumnCount(); + if (colCount > 0 || column > 0) { + checkBounds(column, colCount); + } + } + + /** + * @param searchType Determines column where the search begins ("relative" or "absolute") + * @return The index from which to begin a search, based on the search type + * and (if appropriate) the currently selected cell. + */ + private int getStartingColIndex(String searchType) { + int startingIndex = 0; + if (searchType.equalsIgnoreCase( + CompSystemConstants.SEARCH_TYPE_RELATIVE)) { + startingIndex = getTableAdapter().getSelectedCell().getCol() + 1; + } + return startingIndex; + } + + /** + * @param searchType Determines the row where the search begins ("relative" or "absolute") + * @return The index from which to begin a search, based on the search type + * and (if appropriate) the currently selected cell. + */ + private int getStartingRowIndex(String searchType) { + int startingIndex = 0; + if (searchType.equalsIgnoreCase( + CompSystemConstants.SEARCH_TYPE_RELATIVE)) { + startingIndex = getTableAdapter().getSelectedCell().getRow() + 1; + } + return startingIndex; + } + + /** + * inputs/replaces the given text + * @param text the text to input + * @param replace wheter to replace or not + * @throws StepExecutionException If there is no selected cell, + * or if the cell is not editable, or if the table cell editor permits + * the text to be written. + */ + private void inputText(final String text, boolean replace) + throws StepExecutionException { + ITableAdapter adapter = getTableAdapter(); + + final Cell cell = adapter.getSelectedCell(); + // Ensure that the cell is visible. + Rectangle rectangle = + adapter.scrollCellToVisible(cell.getRow(), cell.getCol()); + + Object editor = activateEditor(cell, rectangle); + editor = setEditorToReplaceMode(editor, replace); + + getRobot().type(editor, text); + } + + /** + * @return true if the mouse pointer is over any cell, false otherwise. + */ + private boolean isMouseOverCell() { + try { + getCellAtMousePosition(); + } catch (StepExecutionException se) { + return false; + } + return true; + } + + + + /** + * Sets the specific editor to an replace mode. Means that the next key + * input will override the complete text of the editor. + * @param editor + * @param replace if <code>true</code> than the editor has to override + * the complete text with the next key input. Else the next + * key input will append to the end. + * @return the editor if it changed + */ + protected abstract Object setEditorToReplaceMode(Object editor, + boolean replace); + + /** + * Activates the editor of the specific cell. + * @param cell + * @param rectangle + * @return the editor of the cell + */ + protected abstract Object activateEditor(Cell cell, Rectangle rectangle); + + + /** + * Gets The modifier for an extended selection (more than one item) + * @return the modifier + */ + protected abstract int getExtendSelectionModifier(); + + /** + * @return the cell under the current mouse position. + * @throws StepExecutionException If no cell is found. + */ + protected abstract Cell getCellAtMousePosition() + throws StepExecutionException; + + /** + * Verifies if mouse is on header. + * @return true if mouse is on header + */ + protected abstract boolean isMouseOnHeader(); + + +}
\ No newline at end of file diff --git a/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/caps/AbstractTextComponent.java b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/caps/AbstractTextComponent.java new file mode 100644 index 000000000..3a67632f1 --- /dev/null +++ b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/caps/AbstractTextComponent.java @@ -0,0 +1,205 @@ +/******************************************************************************* + * 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.caps; + +import org.apache.commons.lang.StringUtils; +import org.eclipse.jubula.rc.common.exception.StepExecutionException; +import org.eclipse.jubula.rc.common.implclasses.MatchUtil; +import org.eclipse.jubula.rc.common.implclasses.Verifier; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.ITextComponentAdapter; +import org.eclipse.jubula.tools.objects.event.EventFactory; +import org.eclipse.jubula.tools.objects.event.TestErrorEvent; +import org.eclipse.jubula.tools.utils.TimeUtil; +/** + * Implementation of the CAPs from all Text like components. + * @author BREDEX GmbH + * + */ +public class AbstractTextComponent extends AbstractTextInputSupport { + + /** + * Gets the specific adapter + * @return the specific adapter + */ + private ITextComponentAdapter getTextCompAdapter() { + return (ITextComponentAdapter) getComponent(); + } + + /** + * Sets the caret at the position <code>index</code>. + * @param index The caret position + */ + private void setCaretPosition(final int index) { + if (index < 0) { + throw new StepExecutionException("Invalid position: " + index, //$NON-NLS-1$ + EventFactory.createActionError(TestErrorEvent.INPUT_FAILED)); + } + int index2 = 0; + String text = getTextCompAdapter().getText(); + if (text != null) { + index2 = index > text.length() ? text.length() : index; + } + getTextCompAdapter().setSelection(index2); + } + + /** + * @param text The text to insert at the current caret position + */ + protected void insertText(final String text) { + // Scroll it to visible first to ensure that the typing + // performs correctly. + getRobot().scrollToVisible(getComponent().getRealComponent(), null); + getRobot().type(getComponent().getRealComponent(), text); + } + + /** + * Types <code>text</code> into the component. This replaces the shown + * content. + * + * @param text the text to type in + */ + public void gdReplaceText(String text) { + gdSelect(); + if (StringUtils.EMPTY.equals(text)) { + getRobot().keyStroke("DELETE"); //$NON-NLS-1$ + } + insertText(text); + } + + /** + * Types <code>text</code> into the component. + * + * @param text the text to type in + */ + public void gdInputText(String text) { + if (!getTextCompAdapter().hasFocus()) { + TimeUtil.delay(100); + gdClick(1, 1); + } + insertText(text); + } + + /** + * Inserts <code>text</code> at the position <code>index</code>. + * + * @param text The text to insert + * @param index The position for insertion + */ + public void gdInsertText(String text, int index) { + gdClick(1, 1); + setCaretPosition(index); + insertText(text); + } + + /** + * Inserts <code>text</code> before or after the first appearance of + * <code>pattern</code>. + * @param text The text to insert + * @param pattern The pattern to find the position for insertion + * @param operator Operator to select Matching Algorithm + * @param after If <code>true</code>, the text will be inserted after the + * pattern, otherwise before the pattern. + * @throws StepExecutionException If the pattern is invalid or cannot be found + */ + public void gdInsertText(String text, String pattern, String operator, + boolean after) + throws StepExecutionException { + + if (text == null) { + throw new StepExecutionException( + "The text to be inserted must not be null", EventFactory //$NON-NLS-1$ + .createActionError()); + } + final MatchUtil.FindResult matchedText = MatchUtil.getInstance(). + find(getTextCompAdapter().getText(), pattern, operator); + + if ((matchedText == null) || (matchedText.getStr() == null)) { + throw new StepExecutionException("The pattern '" + pattern //$NON-NLS-1$ + + "' could not be found", //$NON-NLS-1$ + EventFactory.createActionError(TestErrorEvent.NOT_FOUND)); + } + + int index = matchedText.getPos(); + + int insertPos = after ? index + matchedText.getStr().length() : index; + gdInsertText(text, insertPos); + } + + + + /** + * select the whole text of the textfield by calling "selectAll()". + */ + public void gdSelect() { + gdClick(1, 1); + // Wait a while. Without this, we got no selectAll sometimes! + TimeUtil.delay(100); + getTextCompAdapter().selectAll(); + } + + /** + * Verifies the editable property. + * @param editable The editable property to verify. + */ + public void gdVerifyEditable(boolean editable) { + Verifier.equals(editable, getTextCompAdapter().isEditable()); + } + + /** + * Selects the first (not)appearance of <code>pattern</code> in the text + * component's content. + * + * @param pattern The pattern to select + * @param operator operator + * @throws StepExecutionException + * If the pattern is invalid or cannot be found + */ + public void gdSelect(final String pattern, String operator) + throws StepExecutionException { + gdClick(1, 1); + final MatchUtil.FindResult matchedText = MatchUtil.getInstance(). + find(getTextCompAdapter().getText(), pattern, operator); + if ((matchedText == null) || (matchedText.getStr().length() == 0)) { + throw new StepExecutionException("Invalid pattern for insertion", //$NON-NLS-1$ + EventFactory.createActionError()); + } + final int index = matchedText.getPos(); + if (operator.startsWith("not")) { //$NON-NLS-1$ + if (pattern.equals(getTextCompAdapter().getText())) { + String msg = "The pattern '" + pattern //$NON-NLS-1$ + + "' is equal to current text"; //$NON-NLS-1$ + throw new StepExecutionException(msg, EventFactory + .createActionError(TestErrorEvent + .EXECUTION_ERROR, new String[] {msg})); + } else if (index > 0) { + // select part before pattern + getTextCompAdapter().setSelection(0, index); + } else { + // select part after pattern + getTextCompAdapter().setSelection( + matchedText.getStr().length(), + getTextCompAdapter().getText().length()); + } + } else { + getTextCompAdapter().setSelection(index, + index + matchedText.getStr().length()); + } + } + + /** + * {@inheritDoc} + */ + public String[] getTextArrayFromComponent() { + return null; + } + + +} diff --git a/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/caps/AbstractTextInputSupport.java b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/caps/AbstractTextInputSupport.java new file mode 100644 index 000000000..ba91ed623 --- /dev/null +++ b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/caps/AbstractTextInputSupport.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * 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.caps; + +import org.eclipse.jubula.rc.common.exception.StepExecutionException; + +/** + * This class represents the general implmentation for components, + * which have text input support. + * + * @author BREDEX GmbH + */ +public abstract class AbstractTextInputSupport extends AbstractTextVerifiable { + + /** + * Verifies the editable property of the current component.<br> + * If it is a complex component, it is always the selected object. + * @param editable The editable property to verify. + */ + public abstract void gdVerifyEditable(boolean editable); + // FIXME this is only a pattern because only Tables uses this at the moment + /** + * Types <code>text</code> into the component. This replaces the shown + * content.<br> + * If it is a complex component, it is always the selected object. + * @param text the text to type in + * @throws StepExecutionException + * If there is no selected cell, or if the cell is not editable, + * or if the table cell editor permits the text to be written. + */ + public abstract void gdReplaceText(String text) + throws StepExecutionException; + // FIXME this is only a pattern because only Tables uses this at the moment + /** + * Writes the passed text into the currently component.<br> + * If it is a complex component, it is always the selected object. + * @param text The text. + * @throws StepExecutionException + * If there is no selected cell, or if the cell is not editable, + * or if the table cell editor permits the text to be written. + */ + public abstract void gdInputText(final String text) + throws StepExecutionException; + // FIXME this is only a pattern because only Tables uses this at the moment +} diff --git a/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/caps/AbstractTextVerifiable.java b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/caps/AbstractTextVerifiable.java new file mode 100644 index 000000000..ac23efbf5 --- /dev/null +++ b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/caps/AbstractTextVerifiable.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * 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.caps; + +import org.eclipse.jubula.rc.common.exception.StepExecutionException; +import org.eclipse.jubula.rc.common.implclasses.Verifier; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.ITextVerifiable; + +/** + * This class represents the general implementation for components + * which have readable text. + * + * @author BREDEX GmbH + */ +public abstract class AbstractTextVerifiable extends AbstractWidgetCAPs { + + /** + * Action to read the value of the current component + * to store it in a variable in the Client.<br> + * If it is a complex component, it is always the selected object. + * @param variable the name of the variable + * @return the text value. + */ + public String gdReadValue(String variable) { + return ((ITextVerifiable)getComponent()).getText(); + } + + /** + * Verifies the rendered text inside the currently component.<br> + * If it is a complex component, it is always the selected object. + * @param text The text to verify. + * @param operator The operation used to verify + * @throws StepExecutionException If the rendered text cannot be extracted. + */ + public void gdVerifyText(String text, String operator) + throws StepExecutionException { + Verifier.match(((ITextVerifiable)getComponent()).getText(), text, + operator); + } + +} diff --git a/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/caps/AbstractTreeCAPs.java b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/caps/AbstractTreeCAPs.java new file mode 100644 index 000000000..b1e153b5a --- /dev/null +++ b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/caps/AbstractTreeCAPs.java @@ -0,0 +1,754 @@ +/******************************************************************************* + * 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.caps; + +import java.util.Collection; +import java.util.Iterator; + +import org.apache.commons.lang.Validate; +import org.eclipse.jubula.rc.common.CompSystemConstants; +import org.eclipse.jubula.rc.common.driver.ClickOptions; +import org.eclipse.jubula.rc.common.exception.StepExecutionException; +import org.eclipse.jubula.rc.common.exception.StepVerifyFailedException; +import org.eclipse.jubula.rc.common.implclasses.IndexConverter; +import org.eclipse.jubula.rc.common.implclasses.MatchUtil; +import org.eclipse.jubula.rc.common.implclasses.Verifier; +import org.eclipse.jubula.rc.common.implclasses.tree.AbstractTreeNodeTraverser; +import org.eclipse.jubula.rc.common.implclasses.tree.AbstractTreeOperationContext; +import org.eclipse.jubula.rc.common.implclasses.tree.ChildTraverser; +import org.eclipse.jubula.rc.common.implclasses.tree.ExpandCollapseTreeNodeOperation; +import org.eclipse.jubula.rc.common.implclasses.tree.INodePath; +import org.eclipse.jubula.rc.common.implclasses.tree.IndexNodePath; +import org.eclipse.jubula.rc.common.implclasses.tree.ParentTraverser; +import org.eclipse.jubula.rc.common.implclasses.tree.PathBasedTraverser; +import org.eclipse.jubula.rc.common.implclasses.tree.SelectTreeNodeOperation; +import org.eclipse.jubula.rc.common.implclasses.tree.SiblingTraverser; +import org.eclipse.jubula.rc.common.implclasses.tree.StringNodePath; +import org.eclipse.jubula.rc.common.implclasses.tree.TreeNodeOperation; +import org.eclipse.jubula.rc.common.implclasses.tree.TreeNodeOperationConstraint; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.ITreeAdapter; +import org.eclipse.jubula.tools.constants.StringConstants; +import org.eclipse.jubula.tools.constants.TestDataConstants; +import org.eclipse.jubula.tools.objects.event.EventFactory; +import org.eclipse.jubula.tools.objects.event.TestErrorEvent; +import org.eclipse.jubula.tools.utils.StringParsing; + + +/** + * General implementation for Trees. + * + * @author BREDEX GmbH + */ +public abstract class AbstractTreeCAPs extends AbstractWidgetCAPs { + + /** + * {@inheritDoc} + */ + public String[] getTextArrayFromComponent() { + //FIXME is here an TextArray? + return null; + } + + /** + * This method is only casting the IComponentAdapter to the wanted ITreeAdapter + * @return The ITreeAdapter out of the stored IComponentAdapter + */ + private ITreeAdapter getTreeAdapter() { + return (ITreeAdapter)getComponent(); + + } + + /** + * Verifies the text of the Node at mousePosition + * @param text the text to check + * @param operator the operator for the verification + */ + public abstract void gdVerifyTextAtMousePosition( + String text, + String operator); + /** + * Splits the <code>treepath</code> string into an array, one entry for each level in the path + * + * @param treePath The tree path + * @return An array of string representing the tree path + */ + protected String[] splitTextTreePath(String treePath) { + return StringParsing.splitToArray(treePath, + TestDataConstants.PATH_CHAR_DEFAULT, + TestDataConstants.ESCAPE_CHAR_DEFAULT, + true); + } + + /** + * Splits the <code>treepath</code> string into an array, one entry for each level in the path + * + * @param treePath The tree path + * @return An array of indices (type <code>Integer</code>) representing + * the tree path + * @throws StepExecutionException + * If the values of the passed path cannot be parsed + */ + protected Integer[] splitIndexTreePath(String treePath) + throws StepExecutionException { + Integer[] indexPath = null; + String[] path = splitTextTreePath(treePath); + if (path != null) { + indexPath = new Integer[path.length]; + for (int i = 0; i < path.length; i++) { + indexPath[i] = new Integer(IndexConverter.intValue(path[i])); + } + } + return IndexConverter.toImplementationIndices(indexPath); + } + + /** + * Splits the <code>treepath</code> string into an array, one entry for each level in the path + * + * @param treePath The tree path + * @param operator The operator + * @return An array of string representing the tree path + */ + protected INodePath createStringNodePath(String [] treePath, + String operator) { + return new StringNodePath(treePath, operator); + } + + /** + * Splits the <code>treepath</code> string into an array, one entry for each level in the path + * + * @param treePath The tree path + * @return An array of string representing the tree path + */ + protected INodePath createIndexNodePath(Integer [] treePath) { + return new IndexNodePath(treePath); + } + + + /** + * Traverses the tree by searching for the nodes in the tree + * path entry and calling the given operation on each matching node. + * + * @param treePath The tree path. + * @param pathType For example, "relative" or "absolute". + * @param preAscend Relative traversals will start this many parent nodes + * above the current node. Absolute traversals ignore this + * parameter. + * @param operation The tree node operation. + * @throws StepExecutionException If the path traversion fails. + */ + protected void traverseTreeByPath(INodePath treePath, String pathType, + int preAscend, TreeNodeOperation operation) + throws StepExecutionException { + + Validate.notNull(treePath); + Validate.notNull(operation); + + ITreeAdapter adapter = getTreeAdapter(); + AbstractTreeOperationContext context = adapter.getContext(); + + AbstractTreeNodeTraverser traverser = + new PathBasedTraverser(context, treePath); + + traverser.traversePath(operation, + getStartNode(pathType, preAscend, context)); + + } + + /** + * Traverses the tree by searching for the nodes in the tree + * path entry and calling the given operation on the last element in the path. + * @param treePath The tree path. + * @param pathType For example, "relative" or "absolute". + * @param preAscend + * Relative traversals will start this many parent nodes + * above the current node. Absolute traversals ignore this + * parameter. + * @param operation The tree node operation. + * @throws StepExecutionException If the path traversion fails. + */ + protected void traverseLastElementByPath(INodePath treePath, + String pathType, int preAscend, TreeNodeOperation operation) + throws StepExecutionException { + + Validate.notNull(treePath); + Validate.notNull(operation); + + AbstractTreeOperationContext context = getTreeAdapter().getContext(); + Object startNode = getStartNode(pathType, preAscend, context); + + AbstractTreeNodeTraverser traverser = new PathBasedTraverser( + context, treePath, new TreeNodeOperationConstraint()); + + traverser.traversePath(operation, startNode); + } + + /** + * @param pathType pathType + * @param preAscend + * Relative traversals will start this many parent nodes + * above the current node. Absolute traversals ignore this + * parameter. + * @param objectPath objectPath + * @param co the click options to use + */ + private void selectByPath(String pathType, int preAscend, + INodePath objectPath, ClickOptions co) { + + TreeNodeOperation expOp = new ExpandCollapseTreeNodeOperation(false); + TreeNodeOperation selectOp = new SelectTreeNodeOperation(co); + INodePath subPath = objectPath.subPath(0, objectPath.getLength() - 1); + + traverseTreeByPath(subPath, pathType, preAscend, expOp); + traverseLastElementByPath(objectPath, pathType, preAscend, selectOp); + } + + /** + * Returns the selected node + * @param context context + * @return node + */ + protected Object getSelectedNode(AbstractTreeOperationContext context) { + return context.getSelectedNode(); + } + + /** + * Clicks the tree. + * If the mouse pointer is in the tree no mouse move will be perfomed. + * Otherwise, the mouse is first moved to the center of the tree. + * + * @param count Number of mouse clicks + * @param button Pressed button + */ + public void gdClick(int count, int button) { + if (getRobot().isMouseInComponent( + getTreeAdapter().getRealComponent())) { + getRobot().clickAtCurrentPosition( + getTreeAdapter().getRealComponent(), count, button); + } else { + getRobot().click(getTreeAdapter().getRealComponent(), null, + ClickOptions.create().setClickCount(count) + .setMouseButton(button)); + } + } + + /** + * Collapses the JTree. The passed tree path is a slash-seperated list of + * nodes that specifies a valid top-down path in the JTree. The last node of + * the tree path is collapsed if it is currently expanded. Otherwise, the JTree is + * left unchanged. + * + * @param pathType whether the path is relative or absolute + * @param preAscend Relative traversals will start this many parent nodes + * above the current node. Absolute traversals ignore this + * parameter. + * @param treePath The tree path. + * @param operator + * Whether regular expressions are used to determine the tree path. + * <code>"matches"</code> for regex, <code>"equals"</code> for simple matching. + * @throws StepExecutionException + * If the tree path is invalid or the double click to collapse + * the node fails. + */ + public void gdCollapse(String pathType, int preAscend, + String treePath, String operator) throws StepExecutionException { + traverseLastElementByPath( + createStringNodePath(splitTextTreePath(treePath), operator), + pathType, preAscend, + new ExpandCollapseTreeNodeOperation(true)); + } + + /** + * Collapses the tree. This method works like {@link #gdCollapse(String, int, String, String)}, + * but expects an enumeration of indices representing the top-down tree + * path. Any index is the node's position at the current tree level. + * + * @param pathType whether the path is relative or absolute + * @param preAscend Relative traversals will start this many parent nodes + * above the current node. Absolute traversals ignore this + * parameter. + * @param indexPath The index path + * @throws StepExecutionException + * If the tree path is invalid or the double-click to collapse + * the node fails. + */ + public void gdCollapseByIndices(String pathType, int preAscend, + String indexPath) throws StepExecutionException { + + try { + traverseLastElementByPath( + createIndexNodePath(splitIndexTreePath(indexPath)), + pathType, preAscend, + new ExpandCollapseTreeNodeOperation(true)); + } catch (NumberFormatException e) { + throw new StepExecutionException(e.getMessage(), EventFactory + .createActionError(TestErrorEvent.INVALID_INDEX)); + } + } + + /** + * <p> + * Expands the Tree. Any node defined by the passed tree path is expanded, + * if it is collapsed. The node is expanded by performing a double click + * onto the node. If the node is already expanded, the JTree is left + * unchanged. The tree path is a slash-seperated list of nodes that specifies + * a valid top-down path in the JTree. + * </p> + * + * An example: Say the passed tree path is <code>animals/birds/kakadu</code>. + * To get a valid expansion, the JTree has to look as follows: + * + * <pre> + * animals + * | + * - -- birds + * | + * - -- kakadu + * </pre> + * + * <code>animals</code> is the Tree's root node, if the root node has + * been set to visible, + * or it is one of the root node's children, if the root node has been set + * to invisible. + * + * <p> + * It is important to know that the tree path entries have to match the + * rendered node texts, but not the underlying user object data etc. + * </p> + * + * @param pathType whether the path is relative or absolute + * @param preAscend + * Relative traversals will start this many parent nodes + * above the current node. Absolute traversals ignore this + * parameter. + * @param treePath + * The tree path. + * @param operator + * If regular expressions are used to determine the tree path + * @throws StepExecutionException + * If the tree path is invalid or the double click fails. + */ + public void gdExpand(String pathType, int preAscend, + String treePath, String operator) throws StepExecutionException { + traverseTreeByPath( + createStringNodePath(splitTextTreePath(treePath), operator), + pathType, preAscend, + new ExpandCollapseTreeNodeOperation(false)); + } + + /** + * Expands the tree. This method works like {@link #gdExpand(String, int, String, String)}, but + * expects an enumeration of indices representing the top-down tree path. + * Any index is the node's position at the current tree level. + * + * @param pathType whether the path is relative or absolute + * @param preAscend + * Relative traversals will start this many parent nodes + * above the current node. Absolute traversals ignore this + * parameter. + * @param indexPath The index path + * @throws StepExecutionException + * If the tree path is invalid or the double-click fails. + */ + public void gdExpandByIndices(String pathType, int preAscend, + String indexPath) throws StepExecutionException { + + try { + traverseTreeByPath( + createIndexNodePath(splitIndexTreePath(indexPath)), + pathType, preAscend, + new ExpandCollapseTreeNodeOperation(false)); + } catch (NumberFormatException e) { + throw new StepExecutionException(e.getMessage(), EventFactory + .createActionError(TestErrorEvent.INVALID_INDEX)); + } + } + + + + /** + * Selects a node relative to the currently selected node. + * @param direction the direction to move. + * directions: + * UP - Navigates through parents + * DOWN - Navigates through children + * NEXT - Navigates to next sibling + * PREVIOUS - Navigates to previous sibling + * @param distance the distance to move + * @param clickCount the click count to select the new cell. + * @throws StepExecutionException if any error occurs + */ + public void gdMove(String direction, int distance, int clickCount) + throws StepExecutionException { + + AbstractTreeOperationContext context = getTreeAdapter().getContext(); + + Object selectedNode = getSelectedNode(context); + + TreeNodeOperation selectOp = + new SelectTreeNodeOperation( + ClickOptions.create().setClickCount(clickCount)); + TreeNodeOperationConstraint constraint = + new TreeNodeOperationConstraint(); + + if (CompSystemConstants.TREE_MOVE_UP.equalsIgnoreCase(direction)) { + AbstractTreeNodeTraverser traverser = + new ParentTraverser(context, distance, constraint); + traverser.traversePath(selectOp, selectedNode); + } else if (CompSystemConstants + .TREE_MOVE_DOWN.equalsIgnoreCase(direction)) { + TreeNodeOperation expandOp = + new ExpandCollapseTreeNodeOperation(false); + AbstractTreeNodeTraverser expandTraverser = + new ChildTraverser(context, distance - 1); + expandTraverser.traversePath(expandOp, selectedNode); + + AbstractTreeNodeTraverser selectTraverser = + new ChildTraverser(context, distance, constraint); + selectTraverser.traversePath(selectOp, selectedNode); + + } else if (CompSystemConstants + .TREE_MOVE_NEXT.equalsIgnoreCase(direction)) { + // Look through siblings + AbstractTreeNodeTraverser traverser = + new SiblingTraverser(context, distance, true, constraint); + traverser.traversePath(selectOp, selectedNode); + + } else if (CompSystemConstants + .TREE_MOVE_PREVIOUS.equalsIgnoreCase(direction)) { + // Look through siblings + AbstractTreeNodeTraverser traverser = + new SiblingTraverser(context, distance, false, constraint); + traverser.traversePath(selectOp, selectedNode); + } + + } + + /** + * Selects the node at the end of the <code>treepath</code>. + * + * @param pathType whether the path is relative or absolute + * @param preAscend + * Relative traversals will start this many parent nodes + * above the current node. Absolute traversals ignore this + * parameter. + * @param treePath The tree path. + * @param operator If regular expressions are used to match the tree path + * @param clickCount the click count + * @param button what mouse button should be used + * @param extendSelection Whether this selection extends a previous + * selection. + * @throws StepExecutionException If the tree path is invalid, if the + * double-click to expand the node fails, or if the selection is invalid. + */ + public void gdSelect(String pathType, int preAscend, String treePath, + String operator, int clickCount, int button, + final String extendSelection) + throws StepExecutionException { + selectByPath(pathType, preAscend, + createStringNodePath(splitTextTreePath(treePath), operator), + ClickOptions.create() + .setClickCount(clickCount) + .setMouseButton(button) + .setClickModifier(getClickModifier(extendSelection))); + } + /** + * Selects the last node of the path given by <code>indexPath</code> + * @param pathType whether the path is relative or absolute + * @param preAscend + * Relative traversals will start this many parent nodes + * above the current node. Absolute traversals ignore this + * parameter. + * @param indexPath the index path + * @param clickCount the number of times to click + * @param button what mouse button should be used + * @param extendSelection Whether this selection extends a previous + * selection. + * @throws StepExecutionException if <code>indexPath</code> is not a valid + * path + */ + public void gdSelectByIndices(String pathType, int preAscend, + String indexPath, int clickCount, int button, + final String extendSelection) + throws StepExecutionException { + + selectByPath(pathType, preAscend, + createIndexNodePath(splitIndexTreePath(indexPath)), + ClickOptions.create() + .setClickCount(clickCount) + .setMouseButton(button) + .setClickModifier(getClickModifier(extendSelection))); + } + + /** + * Tests whether the given treePath exists or not + * @param pathType whether the path is relative or absolute + * @param preAscend + * Relative traversals will start this many parent nodes + * above the current node. Absolute traversals ignore this + * parameter. + * @param treePath the path to check + * @param operator the RegEx operator + * @param exists if true, the verify succeeds if the path DOES exist. + * If false, the verify succeeds if the path DOES NOT exist. + */ + public void gdVerifyPath(String pathType, int preAscend, + String treePath, String operator, boolean exists) { + try { + gdExpand(pathType, preAscend, treePath, operator); + } catch (StepExecutionException e) { + if (exists) { + throw new StepVerifyFailedException( + "Verify failed on tree-path: " //$NON-NLS-1$ + + treePath, EventFactory.createVerifyFailed( + treePath, StringConstants.EMPTY)); + } + return; + } + if (!exists) { + throw new StepVerifyFailedException("Verify failed on tree-path: ", //$NON-NLS-1$ + EventFactory.createVerifyFailed( + StringConstants.EMPTY, treePath)); + } + } + + /** + * Tests whether the given treePath exists or not + * @param pathType whether the path is relative or absolute + * @param preAscend + * Relative traversals will start this many parent nodes + * above the current node. Absolute traversals ignore this + * parameter. + * @param treePath the path to check + * @param exists if true, the verify succeeds if the path DOES exist. + * If false, the verify succeeds if the path DOES NOT exist. + */ + public void gdVerifyPathByIndices(String pathType, int preAscend, + String treePath, boolean exists) { + try { + gdExpandByIndices(pathType, preAscend, treePath); + } catch (StepExecutionException e) { + if (exists) { + throw new StepVerifyFailedException("Verify failed on tree-path: " //$NON-NLS-1$ + + treePath, + EventFactory.createVerifyFailed(treePath, + StringConstants.EMPTY)); + } + return; + } + if (!exists) { + throw new StepVerifyFailedException("Verify failed on tree-path: ", //$NON-NLS-1$ + EventFactory.createVerifyFailed( + StringConstants.EMPTY, treePath)); + } + } + + /** + * {@inheritDoc} + */ + public String gdStoreSelectedNodeValue(String variable) { + AbstractTreeOperationContext context = getTreeAdapter().getContext(); + Object selectedNode = + getSelectedNode(context); + if (selectedNode == null) { + throw new StepExecutionException("No tree item selected", //$NON-NLS-1$ + EventFactory.createActionError(TestErrorEvent.NO_SELECTION)); + } + + return context.getRenderedText(selectedNode); + } + + /** + * Returns the text from the mouse position. + * @param variable - + * @return the text from the node at mouse position + */ + public String gdStoreValueAtMousePosition(String variable) { + AbstractTreeOperationContext context = getTreeAdapter().getContext(); + + return context.getRenderedText(getNodeAtMousePosition()); + } + /** + * + * @return the tree node at the current mouse position. + * @throws StepExecutionException If no tree node can be found at the + * current mouse position. + */ + protected abstract Object getNodeAtMousePosition() + throws StepExecutionException; + + /** + * Verifies whether the first selection in the tree has a rendered text that is + * equal to <code>selection</code>. + * + * @param selection + * The selection to verify + * @throws StepExecutionException + * If no node is selected or the verification fails. + */ + public void gdVerifySelectedValue(String selection) + throws StepExecutionException { + gdVerifySelectedValue(selection, MatchUtil.DEFAULT_OPERATOR); + } + + /** + * Verifies whether the first selection in the tree has a rendered text that is + * equal to <code>pattern</code>. + * + * @param pattern + * The expected text + * @param operator + * The operator to use when comparing the expected and + * actual values. + * @throws StepExecutionException + * If no node is selected or the verification fails. + */ + public void gdVerifySelectedValue(String pattern, String operator) + throws StepExecutionException { + + AbstractTreeOperationContext context = getTreeAdapter().getContext(); + checkNodeText(getSelectedNode(context), pattern, operator); + } + + + + /** + * Checks the text for the given node against the given pattern and + * operator. + * + * @param node The node containing the text to check. + * @param pattern The expected text. + * @param operator The operator to use when comparing the expected and + * actual values. + * @throws StepVerifyFailedException If the verification fails. + */ + protected void checkNodeText(Object node, String pattern, String operator) + throws StepVerifyFailedException { + + AbstractTreeOperationContext context = getTreeAdapter().getContext(); + Collection nodeTextList = context.getNodeTextList(node); + Iterator it = nodeTextList.iterator(); + boolean isMatched = false; + while (it.hasNext() && !isMatched) { + try { + Verifier.match((String)it.next(), pattern, operator); + isMatched = true; + } catch (StepVerifyFailedException svfe) { + if (!it.hasNext()) { + throw svfe; + } + // Otherwise just try the next element + } + } + } + + /** + * @param pathType For example, "relative" or "absolute". + * @param preAscend Relative traversals will start this many parent nodes + * above the current node. Absolute traversals ignore this + * parameter. + * @param context The context of the traversal. + * @return The node at which to begin the traversal or <code>null</code> + * if the traversal should begin at the root of the node. + */ + protected Object getStartNode(String pathType, int preAscend, + AbstractTreeOperationContext context) { + Object startNode; + ITreeAdapter tree = getTreeAdapter(); + if (pathType.equals( + CompSystemConstants.TREE_PATH_TYPE_RELATIVE)) { + startNode = getSelectedNode(context); + Object child = startNode; + for (int i = 0; i < preAscend; ++i) { + if ((startNode == null) || ((tree.isRootVisible()) + && (tree.getRootNode() == null))) { + TestErrorEvent event = EventFactory + .createActionError(TestErrorEvent.TREE_NODE_NOT_FOUND); + throw new StepExecutionException( + "Tree node not found: Parent of " //$NON-NLS-1$ + + child.toString(), event); + } + child = startNode; + startNode = context.getParent(startNode); + + } + // Extra handling for tree without visible root node + if ((startNode == null) || ((tree.isRootVisible()) + && (tree.getRootNode() == null))) { + startNode = null; + } + } else if (pathType.equals( + CompSystemConstants.TREE_PATH_TYPE_ABSOLUTE)) { + startNode = null; + } else { + throw new StepExecutionException( + pathType + " is not a valid Path Type", EventFactory //$NON-NLS-1$ + .createActionError(TestErrorEvent.INVALID_PARAM_VALUE)); + + } + + return startNode; + } + + /** + * @param mouseButton mouseButton + * @param modifierSpecification modifierSpecification + * @param pathType pathType + * @param preAscend preAscend + * @param treeTextPath treeTextPath + * @param operator operator */ + public abstract void gdDragByTextPath( + int mouseButton, + String modifierSpecification, + String pathType, + int preAscend, + String treeTextPath, + String operator); + + /** + * @param pathType pathType + * @param preAscend preAscend + * @param treeTextPath treeTextPath + * @param operator operator + * @param delayBeforeDrop delayBeforeDrop */ + public abstract void gdDropByTextPath( + String pathType, + int preAscend, + String treeTextPath, + String operator, + int delayBeforeDrop); + + /** + * @param mouseButton mouseButton + * @param modifierSpecification modifierSpecification + * @param pathType pathType + * @param preAscend preAscend + * @param treeIndexPath treeIndexPath */ + public abstract void gdDragByIndexPath( + int mouseButton, + String modifierSpecification, + String pathType, + int preAscend, + String treeIndexPath); + + /** + * @param pathType pathType + * @param preAscend preAscend + * @param treeIndexPath treeIndexPath + * @param delayBeforeDrop delayBeforeDrop */ + public abstract void gdDropByIndexPath( + String pathType, + int preAscend, + String treeIndexPath, + int delayBeforeDrop); + + + +}
\ No newline at end of file diff --git a/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/caps/AbstractUICAPs.java b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/caps/AbstractUICAPs.java new file mode 100644 index 000000000..ddf4ebecc --- /dev/null +++ b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/caps/AbstractUICAPs.java @@ -0,0 +1,88 @@ +/******************************************************************************* + * 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.caps; + + +import org.eclipse.jubula.rc.common.AUTServer; +import org.eclipse.jubula.rc.common.driver.IRobot; +import org.eclipse.jubula.rc.common.driver.IRobotFactory; +import org.eclipse.jubula.rc.common.exception.RobotException; +import org.eclipse.jubula.rc.common.implclasses.IBaseImplementationClass; +import org.eclipse.jubula.rc.common.uiadapter.factory.GUIAdapterFactoryRegistry; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.IComponentAdapter; +import org.eclipse.jubula.tools.constants.TestDataConstants; +/** + * Implementation of basic functions for all tester classes. This class + * gives the basic functions which are needed for testing. + * + * + * @author BREDEX GmbH + */ +public abstract class AbstractUICAPs implements IBaseImplementationClass { + + /** constants for communication */ + protected static final String POS_UNIT_PIXEL = "Pixel"; //$NON-NLS-1$ + + /** constants for communication */ + protected static final String POS_UNI_PERCENT = "Percent"; //$NON-NLS-1$ + + /** The default separator for enumerations of list values. */ + protected static final char INDEX_LIST_SEP_CHAR = + TestDataConstants.VALUE_CHAR_DEFAULT; + + /** */ + private IRobotFactory m_robotFactory; + + /** */ + private IComponentAdapter m_component; + + + /** + * Gets the Robot. + * @return The Robot + * @throws RobotException If the Robot cannot be created. + */ + protected IRobot getRobot() throws RobotException { + return AUTServer.getInstance().getRobot(); + } + /** + * Gets the Robot factory. The factory is created once per instance. + * @return The Robot factory. + */ + protected IRobotFactory getRobotFactory() { + m_robotFactory = m_component.getRobotFactory(); + return m_robotFactory; + } + + /** + * {@inheritDoc} + */ + public void setComponent(Object graphicsComponent) { + GUIAdapterFactoryRegistry afr = GUIAdapterFactoryRegistry.getInstance(); + m_component = null; + IComponentAdapter adapter = + (IComponentAdapter)afr.getAdapter(graphicsComponent); + m_component = adapter; + } + /** + * Getter for the stored GraphicalComponent + * @return gets the stored IComponentAdapter + */ + public IComponentAdapter getComponent() { + return m_component; + } + + + + + + +}
\ No newline at end of file diff --git a/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/caps/AbstractWidgetCAPs.java b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/caps/AbstractWidgetCAPs.java new file mode 100644 index 000000000..4f0fb1b9f --- /dev/null +++ b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/caps/AbstractWidgetCAPs.java @@ -0,0 +1,539 @@ +/******************************************************************************* + * 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.caps; + +import java.util.StringTokenizer; + +import org.eclipse.jubula.rc.common.CompSystemConstants; +import org.eclipse.jubula.rc.common.driver.ClickOptions; +import org.eclipse.jubula.rc.common.driver.IRobot; +import org.eclipse.jubula.rc.common.driver.ClickOptions.ClickModifier; +import org.eclipse.jubula.rc.common.exception.StepExecutionException; +import org.eclipse.jubula.rc.common.implclasses.Verifier; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.IWidgetAdapter; +import org.eclipse.jubula.rc.common.util.KeyStrokeUtil; +import org.eclipse.jubula.tools.utils.TimeUtil; +/** + * Implementation of basic functions for a lot of graphics components + * except for context menus and menus. + * + * @author BREDEX GmbH + */ +public abstract class AbstractWidgetCAPs extends AbstractUICAPs { + + + /** + * Casts the IComponentAdapter to an IWidgetAdapter for better access + * @return The widgetAdapter + */ + private IWidgetAdapter getWidgetAdapter() { + return (IWidgetAdapter) getComponent(); + } + + /** + * Verifies that the component exists and is visible. + * + * @param exists <code>True</code> if the component is expected to exist + * and be visible, otherwise <code>false</code>. + */ + public void gdVerifyExists(boolean exists) { + Verifier.equals(exists, getWidgetAdapter().isShowing()); + } + + + /** + * Verifies if the component has the focus. + * @param hasFocus <code>True</code> if the component is expected to has + * the focus, otherwise <code>false</code> + */ + public void gdVerifyFocus(boolean hasFocus) { + Verifier.equals(hasFocus, getWidgetAdapter().hasFocus()); + } + /** + * Verifies if the component is enabled + * @param enabled <code>True</code> if the component is expected to be + * enabled, otherwise <code>false</code> + */ + public void gdVerifyEnabled(boolean enabled) { + Verifier.equals(enabled, getWidgetAdapter().isEnabled()); + } + + /** + * Verifies the value of the property with the name <code>name</code>. + * The name of the property has be specified according to the JavaBean + * specification. The value returned by the property is converted into a + * string by calling <code>toString()</code> and is compared to the passed + * <code>value</code>. + * + * @param name The name of the property + * @param value The value of the property as a string + * @param operator The operator used to verify + */ + public void gdVerifyProperty(final String name, String value, + String operator) { + + final IWidgetAdapter bean = (IWidgetAdapter) getComponent(); + bean.getPropteryValue(name); + + final String propToStr = bean.getPropteryValue(name); + Verifier.match(propToStr, value, operator); + } + + + /** + * Clicks the center of the component. + * @param count Number of mouse clicks + * @param button Pressed button + */ + public void gdClick(int count, int button) { + getRobot().click(getComponent().getRealComponent(), null, + ClickOptions.create() + .setClickCount(count) + .setMouseButton(button)); + } + + /** + * Clicks the center of the component with the MouseButton 1 + * @param count Number of mouse clicks + */ + public void gdclick(int count) { + gdClick(count, 1); + } + /** + * clicks into a component. + * + * @param count amount of clicks + * @param button what mouse button should be used + * @param xPos what x position + * @param xUnits should x position be pixel or percent values + * @param yPos what y position + * @param yUnits should y position be pixel or percent values + * @throws StepExecutionException error + */ + public void gdClickDirect(int count, int button, int xPos, String xUnits, + int yPos, String yUnits) throws StepExecutionException { + + getRobot().click(getComponent().getRealComponent(), null, + ClickOptions.create() + .setClickCount(count) + .setMouseButton(button), + xPos, xUnits.equalsIgnoreCase(POS_UNIT_PIXEL), + yPos, yUnits.equalsIgnoreCase(POS_UNIT_PIXEL)); + } + + /** + * Performs a Drag. Moves into the middle of the Component and presses and + * holds the given modifier and the given mouse button. + * @param mouseButton the mouse button. + * @param modifier the modifier, e.g. shift, ctrl, etc. + * @param xPos what x position + * @param xUnits should x position be pixel or percent values + * @param yPos what y position + * @param yUnits should y position be pixel or percent values + */ + public void gdDrag(int mouseButton, String modifier, int xPos, + String xUnits, int yPos, String yUnits) { + getWidgetAdapter().gdDrag(mouseButton, modifier, xPos, xUnits, + yPos, yUnits); + } + + + /** + * Performs a Drop. Moves into the middle of the Component and releases + * the modifier and mouse button pressed by gdDrag. + * @param xPos what x position + * @param xUnits should x position be pixel or percent values + * @param yPos what y position + * @param yUnits should y position be pixel or percent values + * @param delayBeforeDrop the amount of time (in milliseconds) to wait + * between moving the mouse to the drop point and + * releasing the mouse button + */ + public void gdDrop(int xPos, String xUnits, int yPos, String yUnits, + int delayBeforeDrop) { + + getWidgetAdapter().gdDrop(xPos, xUnits, yPos, yUnits, + delayBeforeDrop); + } + + /** + * dummy method 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 + * {@inheritDoc} + */ + public void gdWaitForComponent (int timeout, int delay) { + // do NOT delete this method! + // do nothing, implementation is in class CAPTestCommand.getImplClass + // because this action needs a special implementation! + } + + /** + * Stores the value of the property with the name <code>name</code>. + * The name of the property has be specified according to the JavaBean + * specification. The value returned by the property is converted into a + * string by calling <code>toString()</code> and is stored to the passed + * variable. + * + * @param variableName The name of the variable to store the property value in + * @param propertyName The name of the property + * @return the property value. + */ + public String gdStorePropertyValue(String variableName, + final String propertyName) { + IWidgetAdapter bean = (IWidgetAdapter) getComponent(); + + return bean.getPropteryValue(propertyName); + } + + /** + * Select an item in the popup menu + * @param indexPath path of item indices + * @param button MouseButton + * @throws StepExecutionException error + */ + public void gdPopupSelectByIndexPath(String indexPath, int button) + throws StepExecutionException { + + AbstractMenuCAPs popup = getWidgetAdapter().showPopup(button); + popup.selectMenuItemByIndexpath(indexPath); + } + /** + * Selects an item in the popup menu + * @param textPath path of item texts + * @param operator operator used for matching + * @param button MouseButton + * @throws StepExecutionException error + */ + public void gdPopupSelectByTextPath(String textPath, String operator, + int button) + throws StepExecutionException { + AbstractMenuCAPs popup = getWidgetAdapter().showPopup(button); + popup.selectMenuItem(textPath, operator); + } + /** + * Selects an item in the popup menu + * + * @param xPos what x position + * @param xUnits should x position be pixel or percent values + * @param yPos what y position + * @param yUnits should y position be pixel or percent values + * @param textPath path of item texts + * @param operator operator used for matching + * @param button MouseButton + * @throws StepExecutionException error + */ + public void gdPopupSelectByTextPath(final int xPos, final String xUnits, + final int yPos, final String yUnits, + String textPath, String operator, int button) + throws StepExecutionException { + AbstractMenuCAPs popup = getWidgetAdapter() + .showPopup(xPos, xUnits, yPos, yUnits, button); + popup.selectMenuItem(textPath, operator); + } + + /** + * Opens the popup menu at the given position relative the current component + * and selects an item at the given position in the popup menu + * + * @param xPos what x position + * @param xUnits should x position be pixel or percent values + * @param yPos what y position + * @param yUnits should y position be pixel or percent values + * @param indexPath path of item indices + * @param button MouseButton + * @throws StepExecutionException error + */ + public void gdPopupSelectByIndexPath( + int xPos, String xUnits, int yPos, String yUnits, + String indexPath, int button) throws StepExecutionException { + AbstractMenuCAPs popup = getWidgetAdapter().showPopup(button); + popup.selectMenuItemByIndexpath(indexPath); + } + + /** + * Checks if the specified context menu entry is enabled. + * @param indexPath the menu item to verify + * @param enabled for checking enabled or disabled + * @param button MouseButton + */ + public void gdPopupVerifyEnabledByIndexPath(String indexPath, + boolean enabled, int button) + throws StepExecutionException { + AbstractMenuCAPs popup = getWidgetAdapter().showPopup(button); + popup.verifyEnabledByIndexpath(indexPath, enabled); + } + + + /** + * Opens the popup menu at the given position relative the current component + * and checks if the specified context menu entry is enabled. + * @param xPos what x position + * @param xUnits should x position be pixel or percent values + * @param yPos what y position + * @param yUnits should y position be pixel or percent values + * @param indexPath the menu item to verify + * @param enabled for checking enabled or disabled + * @param button MouseButton + */ + public void gdPopupVerifyEnabledByIndexPath(int xPos, String xUnits, + int yPos, String yUnits, String indexPath, + boolean enabled, int button) throws StepExecutionException { + AbstractMenuCAPs popup = getWidgetAdapter() + .showPopup(xPos, xUnits, yPos, yUnits, button); + popup.verifyEnabledByIndexpath(indexPath, enabled); + } + + /** + * Checks if the specified context menu entry is enabled. + * @param textPath the menu item to verify + * @param operator operator used for matching + * @param enabled for checking enabled or disabled + * @param button MouseButton + */ + public void gdPopupVerifyEnabledByTextPath(String textPath, + String operator, boolean enabled, int button) + throws StepExecutionException { + AbstractMenuCAPs popup = getWidgetAdapter().showPopup(button); + popup.verifyEnabled(textPath, operator, enabled); + } + + /** + * Opens the popup menu at the given position relative the current component + * and checks if the specified context menu entry is enabled. + * @param xPos what x position + * @param xUnits should x position be pixel or percent values + * @param yPos what y position + * @param yUnits should y position be pixel or percent values + * @param textPath the menu item to verify + * @param operator operator used for matching + * @param enabled for checking enabled or disabled + * @param button MouseButton + */ + public void gdPopupVerifyEnabledByTextPath(final int xPos, + final String xUnits, final int yPos, + final String yUnits, String textPath, String operator, + boolean enabled, int button) + throws StepExecutionException { + AbstractMenuCAPs popup = getWidgetAdapter() + .showPopup(xPos, xUnits, yPos, yUnits, button); + popup.verifyEnabled(textPath, operator, enabled); + } + + /** + * Checks if the specified context menu entry is selected. + * @param indexPath the menu item to verify + * @param selected for checking if entry is selected + * @param button MouseButton + */ + public void gdPopupVerifySelectedByIndexPath(String indexPath, + boolean selected, int button) + throws StepExecutionException { + AbstractMenuCAPs popup = getWidgetAdapter().showPopup(button); + popup.verifySelectedByIndexpath(indexPath, selected); + } + + /** + * Opens the popup menu at the given position relative the current component + * and checks if the specified context menu entry is selected. + * @param xPos what x position + * @param xUnits should x position be pixel or percent values + * @param yPos what y position + * @param yUnits should y position be pixel or percent values + * @param indexPath the menu item to verify + * @param selected for checking if entry is selected + * @param button MouseButton + */ + public void gdPopupVerifySelectedByIndexPath(int xPos, String xUnits, + int yPos, String yUnits, String indexPath, boolean selected, + int button) throws StepExecutionException { + AbstractMenuCAPs popup = getWidgetAdapter() + .showPopup(xPos, xUnits, yPos, yUnits, button); + popup.verifySelectedByIndexpath(indexPath, selected); + } + + /** + * Checks if the specified context menu entry is selected. + * @param textPath the menu item to verify + * @param operator operator used for matching + * @param selected for checking if entry is selected + * @param button MouseButton + */ + public void gdPopupVerifySelectedByTextPath(String textPath, + String operator, boolean selected, int button) + throws StepExecutionException { + AbstractMenuCAPs popup = getWidgetAdapter().showPopup(button); + popup.verifySelected(textPath, operator, selected); + } + + /** + * Opens the popup menu at the given position relative the current component + * and checks if the specified context menu entry is selected. + * @param xPos what x position + * @param xUnits should x position be pixel or percent values + * @param yPos what y position + * @param yUnits should y position be pixel or percent values + * @param textPath the menu item to verify + * @param operator operator used for matching + * @param selected for checking if entry is selected + * @param button MouseButton + */ + public void gdPopupVerifySelectedByTextPath(final int xPos, + final String xUnits, final int yPos, + final String yUnits, String textPath, String operator, + boolean selected, int button) + throws StepExecutionException { + AbstractMenuCAPs popup = getWidgetAdapter() + .showPopup(xPos, xUnits, yPos, yUnits, button); + popup.verifySelected(textPath, operator, selected); + } + + /** + * Checks if the specified context menu entry exists. + * @param indexPath the menu item to verify + * @param exists for checking if entry exists + * @param button MouseButton + */ + public void gdPopupVerifyExistsByIndexPath(String indexPath, + boolean exists, int button) + throws StepExecutionException { + AbstractMenuCAPs popup = getWidgetAdapter().showPopup(button); + popup.verifyExistsByIndexpath(indexPath, exists); + } + + /** + * Opens the popup menu at the given position relative the current component + * and checks if the specified context menu entry exists. + * @param xPos what x position + * @param xUnits should x position be pixel or percent values + * @param yPos what y position + * @param yUnits should y position be pixel or percent values + * @param indexPath the menu item to verify + * @param exists for checking if entry exists + * @param button MouseButton + */ + public void gdPopupVerifyExistsByIndexPath(int xPos, String xUnits, + int yPos, String yUnits, String indexPath, + boolean exists, int button) throws StepExecutionException { + AbstractMenuCAPs popup = getWidgetAdapter() + .showPopup(xPos, xUnits, yPos, yUnits, button); + popup.verifyExistsByIndexpath(indexPath, exists); + } + + /** + * Checks if the specified context menu entry exists. + * @param textPath the menu item to verify + * @param operator operator used for matching + * @param exists for checking if entry exists + * @param button MouseButton + */ + public void gdPopupVerifyExistsByTextPath(String textPath, + String operator, boolean exists, int button) + throws StepExecutionException { + AbstractMenuCAPs popup = getWidgetAdapter().showPopup(button); + popup.verifyExists(textPath, operator, exists); + } + + /** + * Opens the popup menu at the given position relative the current component + * and checks if the specified context menu entry exists. + * @param xPos what x position + * @param xUnits should x position be pixel or percent values + * @param yPos what y position + * @param yUnits should y position be pixel or percent values + * @param textPath the menu item to verify + * @param operator operator used for matching + * @param exists for checking if entry exists + * @param button MouseButton + */ + public void gdPopupVerifyExistsByTextPath(final int xPos, + final String xUnits, final int yPos, + final String yUnits, String textPath, String operator, + boolean exists, int button) + throws StepExecutionException { + AbstractMenuCAPs popup = getWidgetAdapter() + .showPopup(xPos, xUnits, yPos, yUnits, button); + popup.verifyExists(textPath, operator, exists); + } + /** + * + * @param extendSelection + * the string to indicate that the selection should be extended + * @return a ClickModifier for the given extend selection + */ + protected ClickModifier getClickModifier(String extendSelection) { + // FIXME This is a method which belongs in an upper class + + ClickModifier cm = ClickModifier.create(); + if (CompSystemConstants.EXTEND_SELECTION_YES + .equalsIgnoreCase(extendSelection)) { + cm.add(ClickModifier.M1); + } + return cm; + } + + /** + * Simulates a tooltip for demonstration purposes. + * + * @param text The text to show in the tooltip + * @param textSize The size of the text in points + * @param timePerWord The amount of time, in milliseconds, used to display a + * single word. A word is defined as a string surrounded + * by whitespace. + * @param windowWidth The width of the tooltip window in pixels. + */ + public void gdShowText(final String text, final int textSize, + final int timePerWord, final int windowWidth) { + getWidgetAdapter().showToolTip(text, textSize, + timePerWord, windowWidth); + } + + /** + * Presses or releases the given modifier. + * @param modifier the modifier. + * @param press if true, the modifier will be pressed. + * if false, the modifier will be released. + */ + protected void pressOrReleaseModifiers(String modifier, boolean press) { + final IRobot robot = getRobot(); + final StringTokenizer modTok = new StringTokenizer( + KeyStrokeUtil.getModifierString(modifier), " "); //$NON-NLS-1$ + while (modTok.hasMoreTokens()) { + final String mod = modTok.nextToken(); + final int keyCode = getKeyCode(mod); + if (press) { + robot.keyPress(null, keyCode); + } else { + robot.keyRelease(null, keyCode); + } + } + } + + /** + * Gets the key code for a specific modifier + * @param mod the modifier + * @return the integer key code value + */ + protected int getKeyCode(String mod) { + return getWidgetAdapter().getKeyCode(mod); + } + + /** + * Waits the given amount of time. Logs a drop-related error if interrupted. + * + * @param delayBeforeDrop the amount of time (in milliseconds) to wait + * between moving the mouse to the drop point and + * releasing the mouse button + */ + public static void waitBeforeDrop(int delayBeforeDrop) { + TimeUtil.delay(delayBeforeDrop); + } +} diff --git a/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/caps/LabelCAPs.java b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/caps/LabelCAPs.java new file mode 100644 index 000000000..c2f806ca8 --- /dev/null +++ b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/caps/LabelCAPs.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * 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.caps; + +import org.eclipse.jubula.rc.common.uiadapter.interfaces.ITextVerifiable; + +/** + * + * @author BREDEX GmbH + * + */ +public class LabelCAPs extends AbstractTextVerifiable { + + /** + * {@inheritDoc} + */ + public String[] getTextArrayFromComponent() { + ITextVerifiable label = (ITextVerifiable) getComponent(); + return new String[] {label.getText()}; + } + +} diff --git a/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/caps/TabbedPaneCAPs.java b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/caps/TabbedPaneCAPs.java new file mode 100644 index 000000000..9244d5e72 --- /dev/null +++ b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/caps/TabbedPaneCAPs.java @@ -0,0 +1,307 @@ +/******************************************************************************* + * 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.caps; + +import org.eclipse.jubula.rc.common.driver.ClickOptions; +import org.eclipse.jubula.rc.common.exception.StepExecutionException; +import org.eclipse.jubula.rc.common.implclasses.IndexConverter; +import org.eclipse.jubula.rc.common.implclasses.MatchUtil; +import org.eclipse.jubula.rc.common.implclasses.Verifier; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.ITabPaneAdapter; +import org.eclipse.jubula.tools.i18n.I18n; +import org.eclipse.jubula.tools.objects.event.EventFactory; +import org.eclipse.jubula.tools.objects.event.TestErrorEvent; + +/** + * Implementation of the general actions for TabPanes + * @author BREDEX GmbH + * + */ +public class TabbedPaneCAPs extends AbstractWidgetCAPs { + + /** + * + * @return the <code>ITabPane</code> + */ + public ITabPaneAdapter getTabPane() { + return (ITabPaneAdapter)getComponent(); + } + + /** + * @param title The tab title + * @param operator The matching operator + * @return The tab index + */ + private int getIndexOfTab(final String title, final String operator) { + int index = -1; + int tabs = getTabPane().getTabCount(); + for (int a = 0; a < tabs; a++) { + if (MatchUtil.getInstance().match( + getTabPane().getTitleofTab(a), + title, + operator)) { + + index = a; + break; + } + } + + if (index == -1) { + throw new StepExecutionException( + "Can not find tab: '" + title + "' using operator: '" //$NON-NLS-1$ //$NON-NLS-2$ + + operator + "'", EventFactory //$NON-NLS-1$ + .createActionError(TestErrorEvent.NOT_FOUND)); + } + return index; + + } + + /** + * {@inheritDoc} + */ + protected void verifyIndexExists(final int index) { + boolean exists = (index >= 0) && (index < getTabPane().getTabCount()); + + if (!exists) { + throw new StepExecutionException( + "The tab index doesn't exist: " + index, EventFactory //$NON-NLS-1$ + .createActionError(TestErrorEvent.INVALID_INDEX)); + } + } + + + + /** + * {@inheritDoc} + */ + public String[] getTextArrayFromComponent() { + final String[] componentTextArray; + componentTextArray = new String[getTabPane().getTabCount()]; + for (int i = 0; i < componentTextArray.length; i++) { + componentTextArray[i] = getTabPane().getTitleofTab(i); + } + return componentTextArray; + } + + /** + * Selects the tab with the passed index. The method doesn't care if the tab is enabled or not. + * @param index The tab index + */ + private void selectTabByImplIndex(int index) { + verifyIndexExists(index); + + // FIXME zeb: We currently ignore the possibility of needing to scroll + // or use a pulldown menu to find the tab item. This means + // that the user must know when this type of action is + // necessary and specify their tests accordingly. We may wish + // to change this later so that it is "smarter" (i.e. can + // scroll or use a pulldown menu to find tab items in a crowded + // tab folder). + + // Some tab items have a close button embedded in them. + // In order to reduce the chance of clicking this close button, we click + // at x-coordinate 25% rather than 50%. + getRobot().click(getTabPane().getRealComponent(), + getTabPane().getBoundsAt(index), + ClickOptions.create().left(), 25, false, 50, false); + + } + + /** + * Selects the tab with the passed index. + * The method doesn't care if the tab is enabled or not. + * + * @param index + * The tab index + * @throws StepExecutionException + * If the tab index is invalid. + */ + public void gdSelectTabByIndex(int index) + throws StepExecutionException { + int implIdx = IndexConverter.toImplementationIndex(index); + + selectTabByImplIndex(implIdx); + } + /** + * Selects the tab with the passed title. The method doesn't care if the tab + * is enabled or not. + * + * @param title + * The tab title + * @param operator + * using regex + * @throws StepExecutionException + * If the tab title is invalid. + */ + public void gdSelectTab(final String title, String operator) + throws StepExecutionException { + + selectTabByImplIndex(getIndexOfTab(title, operator)); + + } + + /** + * Verifies the text of the tab by index + * + * @param index index of tab + * @param text The tab title + * @param operator Operator to be executed + * @throws StepExecutionException + * If the tab title is invalid. + */ + public void gdVerifyTextOfTabByIndex(final int index, final String text, + final String operator) + throws StepExecutionException { + final int tabIndex = IndexConverter.toImplementationIndex(index); + String tabTitle = getTabPane().getTitleofTab(tabIndex); + Verifier.match(tabTitle, text, operator); + } + + /** + * Verifies existence of tab by index/value + * + * @param tab index/value of tab + * @param operator Operator to be executed + * @param exists boolean, tab exists + * @throws StepExecutionException if tab does not exist. + */ + public void gdVerifyExistenceOfTab(String tab, String operator, + boolean exists) + throws StepExecutionException { + final int tabIdx = getTabIndexFromString(tab, operator); + boolean tabExists = true; + try { + verifyIndexExists(tabIdx); + } catch (StepExecutionException e) { + tabExists = false; + } + + Verifier.equals(exists, tabExists); + } + + /** + * @param tab index or title of tab + * @param operator Operator to be executed + * @return returns index of tab if exists, -1 otherwise + */ + private int getTabIndexFromString(String tab, String operator) { + int tabIndex = -1; + try { + tabIndex = IndexConverter.toImplementationIndex( + Integer.parseInt(tab)); + } catch (NumberFormatException nfe) { + for (int i = 0; i < getTabPane().getTabCount(); i++) { + String text = getTabPane().getTitleofTab(i); + if (MatchUtil.getInstance().match(text, tab, operator)) { + return i; + } + } + + } + return tabIndex; + } + + /** + * Verifies if the tab with the passed title is enabled. + * + * @param title The tab title + * @param operator operation to be executed + * @param isEnabled wether to test if the tab is enabled or not + * @throws StepExecutionException + * If the tab title is invalid. + */ + public void gdVerifyEnabled(String title, String operator, + boolean isEnabled) + + throws StepExecutionException { + final int tabIndex = getIndexOfTab(title, operator); + + Verifier.equals(isEnabled, getTabPane().isEnabledAt(tabIndex)); + } + + /** + * Verifies if the tab with the passed index is enabled. + * + * @param index + * The tab index + * @param enabled + * Should the tab be enabled? + * @throws StepExecutionException + * If the tab index is invalid. + */ + public void gdVerifyEnabledByIndex(int index, boolean enabled) + throws StepExecutionException { + final int implIdx = IndexConverter.toImplementationIndex(index); + verifyIndexExists(implIdx); + Verifier.equals(enabled, getTabPane().isEnabledAt(implIdx)); + } + + /** + * Verifies the selection of the tab with the passed index. + * + * @param index + * The tab index + * @param selected + * Should the tab be selected? + * @throws StepExecutionException + * If the tab index is invalid. + */ + public void gdVerifySelectedTabByIndex(int index, boolean selected) + throws StepExecutionException { + int implIdx = IndexConverter.toImplementationIndex(index); + int selIndex = getTabPane().getSelectedIndex(); + + if (selIndex == -1) { + if (!selected) { + return; + } + throw new StepExecutionException( + I18n.getString(TestErrorEvent.NO_SELECTION), + EventFactory.createActionError(TestErrorEvent.NO_SELECTION)); + } + + Verifier.equals(selected, selIndex == implIdx); + } + + /** + * Verifies the selection of the tab with the passed title. + * + * @param tabTitlePattern + * The tab title pattern to use for checking + * @param operator + * Operator to be executed + * @param selected + * Should the tab be selected? + * @throws StepExecutionException + * If the tab title is invalid. + */ + public void gdVerifySelectedTab(String tabTitlePattern, String operator, + boolean selected) + throws StepExecutionException { + String selectedTabTitle = null; // for no Selection + int selectedIndex = getTabPane().getSelectedIndex(); + if (selectedIndex >= 0) { + selectedTabTitle = getTabPane().getTitleofTab(selectedIndex); + } + + if (selectedTabTitle == null) { + if (!selected) { + return; + } + throw new StepExecutionException( + I18n.getString(TestErrorEvent.NO_SELECTION), + EventFactory.createActionError(TestErrorEvent.NO_SELECTION)); + } + Verifier.match(selectedTabTitle, tabTitlePattern, operator, selected); + } + + +} diff --git a/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/driver/DragAndDropHelper.java b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/driver/DragAndDropHelper.java index 4b4105fe9..c36b01304 100644 --- a/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/driver/DragAndDropHelper.java +++ b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/driver/DragAndDropHelper.java @@ -30,6 +30,10 @@ public class DragAndDropHelper { /** Flag if the Mouse is in drag mode (pressed key) */ private boolean m_isDragMode = false; + /** The Component to drag */ + private Object m_dragComponent = null; + + /** * hidden singleton constructor. */ @@ -92,4 +96,18 @@ public class DragAndDropHelper { m_isDragMode = drag; } + /** + * @return the dragComponent + */ + public Object getDragComponent() { + return m_dragComponent; + } + + /** + * @param dragComponent the dragComponent to set + */ + public void setDragComponent(Object dragComponent) { + m_dragComponent = dragComponent; + } + } diff --git a/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/factory/GUIAdapterFactoryRegistry.java b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/factory/GUIAdapterFactoryRegistry.java new file mode 100644 index 000000000..d89cbd6a4 --- /dev/null +++ b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/factory/GUIAdapterFactoryRegistry.java @@ -0,0 +1,101 @@ +/******************************************************************************* + * 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.uiadapter.factory; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.jubula.rc.common.adaptable.IAdapterFactory; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.IComponentAdapter; +/** + * This factory registry holds all the toolkit specific factory's. + * These factory's holding the classes which are implementing the component + * specific interface. It could be an adapter or the specific component + * implementing the interface. + * + * You must register a factory before a test is started. + * @author BREDEX GmbH + * + */ +public class GUIAdapterFactoryRegistry { + + /** + * Singleton instance of this class + */ + private static GUIAdapterFactoryRegistry instance = + new GUIAdapterFactoryRegistry(); + + /** + * Map that manages the registration. Key is always a class Value is a + * collection of IAdapterFactory + */ + private Map m_registrationMap = new HashMap(); + + /** + * Call Constructor only by using getInstance + */ + private GUIAdapterFactoryRegistry() { + } + + /** + * Return the singleton of this class + * + * @return singleton + */ + public static GUIAdapterFactoryRegistry getInstance() { + return instance; + } + + /** + * Register adapter factory with all its supported classes + * + * @param factory + * adapter factory that should be registered + */ + public void registerFactory(IUIAdapterFactory factory) { + Class[] supportedClasses = factory.getSupportedClasses(); + for (int i = 0; i < supportedClasses.length; i++) { + m_registrationMap.put(supportedClasses[i], factory); + } + } + + /** + * Sign off adapter factory from all its supported classes + * + * @param factory + * adapter factory that should be signed off + */ + public void signOffFactory(IAdapterFactory factory) { + Class[] supportedClasses = factory.getSupportedClasses(); + for (int i = 0; i < supportedClasses.length; i++) { + m_registrationMap.remove(supportedClasses[i]); + } + } + /** + * + * @param objectToAdapt + * @return - + */ + public IComponentAdapter getAdapter(Object objectToAdapt) { + Class adapteeclass = objectToAdapt.getClass(); + IUIAdapterFactory factory = (IUIAdapterFactory) m_registrationMap. + get(adapteeclass); + Class superclass = adapteeclass; + while (factory == null && superclass != Object.class) { + factory = (IUIAdapterFactory) m_registrationMap. + get(superclass); + superclass = superclass.getSuperclass(); + } + // FIXME Here is missing the right Exception!!! + return factory.getAdapter(objectToAdapt); + + } +} diff --git a/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/factory/IUIAdapterFactory.java b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/factory/IUIAdapterFactory.java new file mode 100644 index 000000000..4d16650bf --- /dev/null +++ b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/factory/IUIAdapterFactory.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * 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.uiadapter.factory; + +import org.eclipse.jubula.rc.common.uiadapter.interfaces.IComponentAdapter; + +/** + * This is the interface for the factory which is used by the + * <code>AbstractUI</code> to get the specific Object which implements the + * corresponding interface for the tester class. + * + * @author BREDEX GmbH + */ +public interface IUIAdapterFactory { + /** + * @return all classes that will be supported by this adapter factory + */ + Class[] getSupportedClasses(); + + /** + * Adapts object to adapt to a new object of type targetAdapterClass + * + * @param objectToAdapt + * object that should be adapted + * @return the adapter for the object to adapt of type targetAdapterClass + */ + IComponentAdapter getAdapter(Object objectToAdapt); +} diff --git a/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/interfaces/IButtonAdapter.java b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/interfaces/IButtonAdapter.java new file mode 100644 index 000000000..cd4bfe67e --- /dev/null +++ b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/interfaces/IButtonAdapter.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * 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.uiadapter.interfaces; + +/** + * Interface for all necessary methods to test buttons. + * It extends the <code>IWidgetAdapter</code> to add button specific methods. + * + * + * @author BREDEX GmbH + */ + +public interface IButtonAdapter extends ITextVerifiable { + /** + * Gets the text from the button + * @return the text which is saved in the component + */ + public String getText(); + + /** + * isSelected is mostly for RadioButtons and CheckBoxes + * @return <code>true</code> if the component is selected + */ + public boolean isSelected(); + +}
\ No newline at end of file diff --git a/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/interfaces/IComboBoxAdapter.java b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/interfaces/IComboBoxAdapter.java new file mode 100644 index 000000000..0b0270474 --- /dev/null +++ b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/interfaces/IComboBoxAdapter.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * 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.uiadapter.interfaces; + +import org.eclipse.jubula.rc.common.exception.StepExecutionException; + +/** + * This interface holds all methods which are needed to test + * ComboBox like components. + * @author BREDEX GmbH + * + */ +public interface IComboBoxAdapter extends ITextVerifiable { + + /** + * + * @return the value if the Text Component is editable + */ + boolean isEditable(); + /** + * @param value The value to check + * @param operator The operator used to verify + * @return <code>true</code> if the combobox contains an element rendered with the passed value + */ + public boolean containsValue(String value, String operator); + /** + * @param value The value to check + * @return <code>true</code> if the combobox contains an element rendered with the passed value + */ + public boolean containsValue(String value); + + /** + * select the whole text of the textfield by clicking three times. + */ + void selectAll(); + + + /** + * @return The currently selected index for the combo box, or -1 if no + * index is currently selected. + */ + public int getSelectedIndex(); + + /** + * Selects the combobox element with the passed index. + * @param index The index to select + */ + public void select(int index); + + /** + * Selects the specified item in the combobox. + * @param values the values which should be (not) selected + * @param operator if regular expressions are used + * @param searchType Determines where the search begins ("relative" or "absolute") + * @throws StepExecutionException if an error occurs during selecting the item + * @throws IllegalArgumentException if <code>component</code> or <code>text</code> are null + */ + public void select(final String[] values, String operator, + String searchType) + throws StepExecutionException, IllegalArgumentException; + + /** + * Inputs <code>text</code> to <code>component</code>.<br> + * @param text the text to type + * @param replace whether to replace the text or not + * @throws StepExecutionException if an error occurs during typing <code>text</code> + * @throws IllegalArgumentException if <code>component</code> or <code>text</code> are null + */ + public void input(String text, boolean replace) + throws StepExecutionException, IllegalArgumentException; +} diff --git a/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/interfaces/IComponentAdapter.java b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/interfaces/IComponentAdapter.java new file mode 100644 index 000000000..b55809944 --- /dev/null +++ b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/interfaces/IComponentAdapter.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * 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.uiadapter.interfaces; + +import org.eclipse.jubula.rc.common.driver.IRobotFactory; + +/** + * This is the main interface for classes which will hold or be the + * component that implement the methods we need for this + * specific component to test . + * + * @author BREDEX GmbH + */ +public interface IComponentAdapter { + /** + * Gets the toolkit specific component + * @return toolkit specific component + */ + public Object getRealComponent(); + + /** + * Gets the toolkit specific RobotFactory + * @return the RobotFactory + */ + public IRobotFactory getRobotFactory(); + +}
\ No newline at end of file diff --git a/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/interfaces/IListAdapter.java b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/interfaces/IListAdapter.java new file mode 100644 index 000000000..97d30cac3 --- /dev/null +++ b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/interfaces/IListAdapter.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * 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.uiadapter.interfaces; + +import org.eclipse.jubula.rc.common.driver.ClickOptions; + +/** + * + * @author BREDEX GmbH + * + */ +public interface IListAdapter extends ITextVerifiable { + /** + * + * @return The array of selected indices + */ + public int[] getSelectedIndices(); + + /** + * Clicks on the index of the passed list. + * @param i The index to click + * @param co the click options to use for selecting an index item + */ + public void clickOnIndex(Integer i, ClickOptions co); + + /** + * @return The array of selected values as the renderer shows them + */ + public String[] getSelectedValues(); + + /** + * Finds the indices of the list elements that are rendered with the passed values. + * @param values The values + * @param operator operator to use + * @param searchType + * Determines where the search begins ("relative" or "absolute") + * @return The array of indices. It's length is equal to the length of the + * values array, but may contains <code>null</code> elements for + * all values that are not found in the list + */ + public Integer[] findIndicesOfValues(final String[] values, + final String operator, final String searchType); + +} diff --git a/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/interfaces/IMenuAdapter.java b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/interfaces/IMenuAdapter.java new file mode 100644 index 000000000..26d159765 --- /dev/null +++ b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/interfaces/IMenuAdapter.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * 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.uiadapter.interfaces; + + +/** + * This interface is for the functionality of menus. This is only for the + * not visible part of menus which only contains the next menuitems in the + * Hierarchy of the menu. + * + * @author BREDEX GmbH + */ +public interface IMenuAdapter extends IComponentAdapter { + + /** + * + * @return the items of the menu + */ + public IMenuItemAdapter[] getItems(); + + /** + * Gets the amount of items in the menu + * + * @return the amount of Items in the menu (with Seperator) + */ + public int getItemCount(); +} diff --git a/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/interfaces/IMenuItemAdapter.java b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/interfaces/IMenuItemAdapter.java new file mode 100644 index 000000000..b79ad7330 --- /dev/null +++ b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/interfaces/IMenuItemAdapter.java @@ -0,0 +1,80 @@ +/******************************************************************************* + * 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.uiadapter.interfaces; + +/** + * Interface for all necessary methods for testing menuitems. + * + * @author BREDEX GmbH + */ +public interface IMenuItemAdapter extends IComponentAdapter { + + /** + * + * @return the text which is saved in the item + */ + public String getText(); + /** + * + * @return <code>true</code> if the component is visible + */ + public boolean isEnabled(); + /** + * + * @return <code>true</code> if the component exists + * that means there is an item in this wrapper + */ + public boolean isExisting(); + /** + * + * @return <code>true</code> if the component is selected + * + */ + public boolean isSelected(); + /** + * + * @return <code>true</code> if the component is Showing + */ + public boolean isShowing(); + + /** Gets the menu of the menuitem + * @return the menu which is attached to the item + */ + public IMenuAdapter getMenu(); + + /** + * + * @return <code>true</code> if the menuitem has a menu + */ + public boolean hasSubMenu(); + /** + * Checks whether the given menu item is a separator. + * This method runs in the GUI thread. + * @return <code>true</code> if <code>menuItem</code> is a separator item. + * Otherwise <code>false</code>. + */ + public boolean isSeparator(); + + /** + * This Methods selects the specific menuItem with an click + * or in another toolkit specitif way + */ + public void selectMenuItem(); + + /** + * This method trys to open the the next Menu in the cascade + * + * @return the next SubMenu in the Menu + */ + public IMenuAdapter openSubMenu(); + + +} diff --git a/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/interfaces/ITabPaneAdapter.java b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/interfaces/ITabPaneAdapter.java new file mode 100644 index 000000000..90712aff6 --- /dev/null +++ b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/interfaces/ITabPaneAdapter.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * 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.uiadapter.interfaces; + +/** + * Interface for all necessary methods to test TabbedPanes. + * It extends the <code>IWidgetAdapter</code> to add Tab Pane specific methods. + * @author BREDEX GmbH + * + */ +public interface ITabPaneAdapter extends IWidgetAdapter { + /** + * + * @return the number of the tabs + */ + public int getTabCount(); + + /** + * + * @param index of the tab + * @return the title of the wanted tab. + */ + public String getTitleofTab(int index); + + /** + * + * @param index of the tab + * @return the bounds of the tabs. + */ + public Object getBoundsAt(int index); + + /** + * + * @param index index of the tab + * @return the enablement of the specific tab. + */ + public boolean isEnabledAt(int index); + + /** + * + * @return the index of the selected tab. + */ + public int getSelectedIndex(); +} diff --git a/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/interfaces/ITableAdapter.java b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/interfaces/ITableAdapter.java new file mode 100644 index 000000000..ab0e65792 --- /dev/null +++ b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/interfaces/ITableAdapter.java @@ -0,0 +1,128 @@ +/******************************************************************************* + * 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.uiadapter.interfaces; + +import java.awt.Rectangle; + +import org.eclipse.jubula.rc.common.exception.StepExecutionException; +import org.eclipse.jubula.rc.common.implclasses.table.Cell; + +/** + * Interface for all necessary methods for testing tables. + * + * @author BREDEX GmbH + */ +public interface ITableAdapter extends ITextVerifiable { + + + /** + * Gets the number of columns + * + * @return the number of columns + */ + public int getColumnCount(); + + /** + * Gets the number of rows + * + * @return the number of rows + */ + public int getRowCount(); + + /** + * @param row the zero based index of the row + * @param column the zero based index of the column + * @return the text of the cell of the given coordinates + */ + public String getCellText(int row, int column); + + /** + * Returns the name of the column appearing in the view at + * column position <code>column</code>. + * + * @param column the column in the view being queried + * @return the name of the column at position <code>column</code> + in the view where the first column is column 0 + */ + public String getColumnName(int column); + + /** + * Gets column index from string with header name or index + * + * @param col Headername or index of column + * @param operator The operation used to verify + * @return column index + */ + public int getColumnFromString(String col, String operator); + + /** + * This is only for a specific case where tables could act + * like lists. And the getText is not working. + * If this is not the case for the component return <code>null</code> + * @param row the row + * @return the text of the row + */ + public String getRowName(int row); + + /** + * Gets row index from string with index or text of first row + * + * @param row index or value in first col + * @param operator The operation used to verify + * @return integer of String of row + */ + public int getRowFromString(String row, String operator); + + /** + * gets header bounds for column + * @param col The column. + * @return The rectangle of the header + */ + public Rectangle getHeaderBounds(int col); + + /** + * @return The currently selected cell of the Table. + * @throws StepExecutionException If no cell is selected. + */ + public Cell getSelectedCell() throws StepExecutionException; + + /** + * + * @return <code>true</code> if the Header is visible, <code>false</code> otherwise + */ + public boolean isHeaderVisible(); + + /** + * + * @param row the row + * @param col the column + * @return <code>true</code> if the Cell is editable, <code>false</code> otherwise + */ + public boolean isCellEditable(int row, int col); + + /** + * @return true, if there is any cell selection in the table, false otherwise. + */ + public boolean hasCellSelection(); + + /** + * Scrolls the passed cell (as row and column) to visible.<br> + * This method must return null if there is no scrolling. + * @param row The row. + * @param col The column. + * @return The rectangle of the cell. + * @throws StepExecutionException If getting the cell rectangle or the scrolling fails. + */ + public Rectangle scrollCellToVisible (int row , int col) + throws StepExecutionException; + + +} diff --git a/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/interfaces/ITextComponentAdapter.java b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/interfaces/ITextComponentAdapter.java new file mode 100644 index 000000000..4e989c670 --- /dev/null +++ b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/interfaces/ITextComponentAdapter.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * 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.uiadapter.interfaces; +/** + * Interface for all needed methods which are needed from TextComponents + * @author BREDEX GmbH + * + */ +public interface ITextComponentAdapter extends ITextVerifiable { + + /** + * Sets the caret to a specific position. + * + * @param start The index at which the selection begins. + */ + void setSelection(int start); + /** + * Selects text in the component. + * + * @param start The index at which the selection begins. + * @param end The index at which the selection ends. + */ + void setSelection(int start, int end); + + + /** + * + * @return the selectes text + */ + String getSelectionText(); + + /** + * Selects all text in the component. + */ + void selectAll(); + + /** + * + * @return the value if the Text Component is editable + */ + boolean isEditable(); + + +} diff --git a/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/interfaces/ITextVerifiable.java b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/interfaces/ITextVerifiable.java new file mode 100644 index 000000000..84d98dcd7 --- /dev/null +++ b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/interfaces/ITextVerifiable.java @@ -0,0 +1,15 @@ +package org.eclipse.jubula.rc.common.uiadapter.interfaces; +/** + * + * @author BREDEX GmbH + * + */ +public interface ITextVerifiable extends IWidgetAdapter { + + /** + * Gets the value of the component, or if there are more + * than the first selected. + * @return the value of the component + */ + public String getText(); +} diff --git a/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/interfaces/ITreeAdapter.java b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/interfaces/ITreeAdapter.java new file mode 100644 index 000000000..a7f06687d --- /dev/null +++ b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/interfaces/ITreeAdapter.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * 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.uiadapter.interfaces; + +import org.eclipse.jubula.rc.common.implclasses.tree.AbstractTreeOperationContext; + +/** + * Interface for all necessary methods for testing trees. + * + * @author BREDEX GmbH + */ +public interface ITreeAdapter extends IWidgetAdapter { + + /** + * Gets the root node(s) of the tree. + * This could be either a single node or multiple nodes + * @return The root node(s). + */ + public Object getRootNode(); + + /** + * Gets the TreeOperationContext which is created through an + * toolkit specific implementation. + * @return the TreeOperationContext for the tree + */ + public AbstractTreeOperationContext getContext(); + + /** + * + * @return The visibility of the Root Node + */ + public boolean isRootVisible(); +} diff --git a/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/interfaces/IWidgetAdapter.java b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/interfaces/IWidgetAdapter.java new file mode 100644 index 000000000..04b360569 --- /dev/null +++ b/org.eclipse.jubula.rc.common/src/org/eclipse/jubula/rc/common/uiadapter/interfaces/IWidgetAdapter.java @@ -0,0 +1,117 @@ +/******************************************************************************* + * 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.uiadapter.interfaces; + +import org.eclipse.jubula.rc.common.caps.AbstractMenuCAPs; +import org.eclipse.jubula.rc.common.exception.StepExecutionException; + +/** + * This interface defines basic functionality for nearly all UI components. + * + * @author BREDEX GmbH + */ +public interface IWidgetAdapter extends IComponentAdapter { + + /** + * + * @return <code>true</code> if the component is visible + */ + public boolean isShowing(); + /** + * + * @return <code>true</code> if the component is enabled + */ + public boolean isEnabled(); + /** + * + * @return <code>true</code> if the component has focus + */ + public boolean hasFocus(); + /** + * @param propertyname the name of the property value to return + * @return the property value + */ + public String getPropteryValue(String propertyname); + + + /** + * Shows and returns the popup menu + * + * @param xPos what x position + * @param xUnits should x position be pixel or percent values + * @param yPos what y position + * @param yUnits should y position be pixel or percent values + * @param button MouseButton + * @return the popup menu + * @throws StepExecutionException error + */ + public AbstractMenuCAPs showPopup(final int xPos, + final String xUnits, final int yPos, + final String yUnits, final int button) + throws StepExecutionException; + + /** + * Shows and returns the popup menu + * @param button MouseButton + * @return the popup menu + */ + public AbstractMenuCAPs showPopup(int button); + + + + /** + * Simulates a tooltip for demonstration purposes. + * + * @param text The text to show in the tooltip + * @param textSize The size of the text in points + * @param timePerWord The amount of time, in milliseconds, used to display a + * single word. A word is defined as a string surrounded + * by whitespace. + * @param windowWidth The width of the tooltip window in pixels. + */ + public void showToolTip(final String text, final int textSize, + final int timePerWord, final int windowWidth); + + /** + * Performs a Drag. Moves into the middle of the Component and presses and + * holds the given modifier and the given mouse button. + * @param mouseButton the mouse button. + * @param modifier the modifier, e.g. shift, ctrl, etc. + * @param xPos what x position + * @param xUnits should x position be pixel or percent values + * @param yPos what y position + * @param yUnits should y position be pixel or percent values + */ + public void gdDrag(int mouseButton, String modifier, int xPos, + String xUnits, int yPos, String yUnits); + + /** + * Performs a Drop. Moves into the middle of the Component and releases + * the modifier and mouse button pressed by gdDrag. + * @param xPos what x position + * @param xUnits should x position be pixel or percent values + * @param yPos what y position + * @param yUnits should y position be pixel or percent values + * @param delayBeforeDrop the amount of time (in milliseconds) to wait + * between moving the mouse to the drop point and + * releasing the mouse button + */ + public void gdDrop(int xPos, String xUnits, int yPos, String yUnits, + int delayBeforeDrop); + + /** + * Gets the key code for a specific modifier + * @param mod the modifier + * @return the integer key code value + */ + public int getKeyCode(String mod); + +}
\ No newline at end of file diff --git a/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/SwingAUTServer.java b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/SwingAUTServer.java index f438c6299..053781710 100644 --- a/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/SwingAUTServer.java +++ b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/SwingAUTServer.java @@ -22,12 +22,14 @@ import org.eclipse.jubula.rc.common.AUTServer; import org.eclipse.jubula.rc.common.driver.IRobot; import org.eclipse.jubula.rc.common.driver.IRobotFactory; import org.eclipse.jubula.rc.common.listener.BaseAUTListener; +import org.eclipse.jubula.rc.common.uiadapter.factory.GUIAdapterFactoryRegistry; import org.eclipse.jubula.rc.swing.driver.RobotFactoryConfig; import org.eclipse.jubula.rc.swing.listener.CheckListener; import org.eclipse.jubula.rc.swing.listener.ComponentHandler; import org.eclipse.jubula.rc.swing.listener.FocusTracker; import org.eclipse.jubula.rc.swing.listener.MappingListener; import org.eclipse.jubula.rc.swing.listener.RecordListener; +import org.eclipse.jubula.rc.swing.swing.uiadapter.factory.SwingAdapterFactory; import org.eclipse.jubula.tools.constants.AUTServerExitConstants; import org.eclipse.jubula.tools.utils.EnvironmentUtils; import org.slf4j.Logger; @@ -219,6 +221,10 @@ public class SwingAUTServer extends AUTServer { } AUTServer.getInstance().invokeAUT(); + + // FIXME don't know where to put + GUIAdapterFactoryRegistry.getInstance(). + registerFactory(new SwingAdapterFactory()); } /** diff --git a/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/caps/AbstractButtonCAPs.java b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/caps/AbstractButtonCAPs.java new file mode 100644 index 000000000..1ff29f7f3 --- /dev/null +++ b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/caps/AbstractButtonCAPs.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * 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.swing.swing.caps; + + +import org.eclipse.jubula.rc.common.uiadapter.interfaces.IButtonAdapter; + +/** + * The implementation class for <code>AbstractButton</code> and subclasses. Note + * the "Abstract" in the class name implies only that this class can test + * <code>AbstractButton</code> components. The class itself should <em>NOT</em> + * be designated <code>abstract</code>, as this class is instantiated using + * reflection. + * + * @author BREDEX GmbH + */ +public class AbstractButtonCAPs + extends org.eclipse.jubula.rc.common.caps.AbstractButtonCAPs { + + /** + * Clicks the button <code>count</code> times. + * + * @param count The number of clicks + */ + public void gdClick(int count) { + gdClick(count, 1); + } + + /** + * {@inheritDoc} + */ + public String[] getTextArrayFromComponent() { + IButtonAdapter returnvalue = ((IButtonAdapter)getComponent()); + return new String[] { returnvalue.getText() }; + } + +}
\ No newline at end of file diff --git a/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/caps/CapUtil.java b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/caps/CapUtil.java new file mode 100644 index 000000000..e46fde641 --- /dev/null +++ b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/caps/CapUtil.java @@ -0,0 +1,301 @@ +/******************************************************************************* + * 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.swing.swing.caps; + +import java.awt.AWTEvent; +import java.awt.Component; +import java.awt.Container; +import java.awt.event.ContainerEvent; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.StringTokenizer; + +import javax.swing.AbstractButton; +import javax.swing.JLabel; +import javax.swing.JPopupMenu; +import javax.swing.JToggleButton; +import javax.swing.text.JTextComponent; + +import org.eclipse.jubula.rc.common.AUTServer; +import org.eclipse.jubula.rc.common.adaptable.AdapterFactoryRegistry; +import org.eclipse.jubula.rc.common.adaptable.ITextRendererAdapter; +import org.eclipse.jubula.rc.common.driver.IEventThreadQueuer; +import org.eclipse.jubula.rc.common.driver.IRobot; +import org.eclipse.jubula.rc.common.driver.IRobotFactory; +import org.eclipse.jubula.rc.common.driver.IRunnable; +import org.eclipse.jubula.rc.common.exception.StepExecutionException; +import org.eclipse.jubula.rc.common.util.KeyStrokeUtil; +import org.eclipse.jubula.rc.swing.driver.RobotFactoryConfig; +import org.eclipse.jubula.rc.swing.swing.driver.KeyCodeConverter; +import org.eclipse.jubula.rc.swing.swing.implclasses.EventListener; +import org.eclipse.jubula.tools.objects.event.EventFactory; +import org.eclipse.jubula.tools.objects.event.TestErrorEvent; + +/** + * Util class for Swing specific aspects. + * + * @author BREDEX GmbH + */ +public class CapUtil { + + /** + * <code>RENDERER_FALLBACK_TEXT_GETTER_METHOD_1</code> + */ + public static final String RENDERER_FALLBACK_TEXT_GETTER_METHOD_1 = "getTestableText"; //$NON-NLS-1$ + + /** + * <code>RENDERER_FALLBACK_TEXT_GETTER_METHOD_2</code> + */ + public static final String RENDERER_FALLBACK_TEXT_GETTER_METHOD_2 = "getText"; //$NON-NLS-1$ + + + /** + * Is true, if a popup menu is shown + */ + public static class PopupShownCondition implements + EventListener.Condition { + + /** + * the popup menu + */ + private JPopupMenu m_popup = null; + + /** + * + * @return the popup menu + */ + public JPopupMenu getPopup() { + return m_popup; + } + + /** + * {@inheritDoc} + * @param event event + * @return result of the condition + */ + public boolean isTrue(AWTEvent event) { + if (event.getID() != ContainerEvent.COMPONENT_ADDED) { + return false; + } + ContainerEvent ce = (ContainerEvent)event; + if (ce.getChild() instanceof JPopupMenu) { + m_popup = (JPopupMenu)ce.getChild(); + return true; + } else if (ce.getChild() instanceof Container) { + Container popupContainer = (Container)ce.getChild(); + final int length = popupContainer.getComponents().length; + for (int i = 0; i < length; i++) { + if (popupContainer.getComponents()[i] + instanceof JPopupMenu) { + + m_popup = (JPopupMenu)popupContainer.getComponents()[i]; + return true; + } + } + } + return false; + } + } + + /** + * The robot factory. + */ + private static IRobotFactory robotFactory; + + /** + * + */ + private CapUtil() { } + + /** + * + * @return the Robot + */ + public static IRobot getRobot() { + return AUTServer.getInstance().getRobot(); + } + + /** + * Gets the Robot factory. The factory is created once per instance. + * + * @return The Robot factory. + */ + protected static IRobotFactory getRobotFactory() { + if (robotFactory == null) { + robotFactory = new RobotFactoryConfig().getRobotFactory(); + } + return robotFactory; + } + /** + * @return The event thread queuer. + */ + protected static IEventThreadQueuer getEventThreadQueuer() { + return getRobotFactory().getEventThreadQueuer(); + } + + /** + * Presses or releases the given modifier. + * @param modifier the modifier. + * @param press if true, the modifier will be pressed. + * if false, the modifier will be released. + */ + public static void pressOrReleaseModifiers(String modifier, boolean press) { + final IRobot robot = getRobot(); + final StringTokenizer modTok = new StringTokenizer( + KeyStrokeUtil.getModifierString(modifier), " "); //$NON-NLS-1$ + while (modTok.hasMoreTokens()) { + final String mod = modTok.nextToken(); + final int keyCode = KeyCodeConverter.getKeyCode(mod); + if (press) { + robot.keyPress(null, keyCode); + } else { + robot.keyRelease(null, keyCode); + } + } + } + + /** + * Casts the passed renderer component to a known type and extracts the + * rendered text. + * + * @param renderer + * The renderer. + * @param queueInEventThread + * If <code>true</code>, the text extraction is executed in + * the event queue thread. + * @return The rendered text. + * @throws StepExecutionException + * If the passed renderer is not supported. Supported types are + * <code>JLabel</code>, <code>JToggleButton</code>, + * <code>AbstractButton</code> and <code>JTextComponent</code> + * + */ + public static String getRenderedText(final Component renderer, + boolean queueInEventThread) throws StepExecutionException { + + if (queueInEventThread) { + return (String)getEventThreadQueuer().invokeAndWait( + "getRenderedText", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return getRenderedText(renderer); + } + }); + } + + return getRenderedText(renderer); + } + + /** + * @param renderer + * The component which is used as the renderer + * @return The string that the renderer displays. + * @throws StepExecutionException + * If the renderer component is not of type <code>JLabel</code>, + * <code>JToggleButton</code>, <code>AbstractButton</code>, + * <code>JTextComponent</code> or supports one of the fallback + * methods + */ + public static String getRenderedText(Component renderer) + throws StepExecutionException { + String renderedText = resolveRenderedText(renderer); + if (renderedText != null) { + return renderedText; + } + throw new StepExecutionException( + "Renderer not supported: " + renderer.getClass(), //$NON-NLS-1$ + EventFactory.createActionError( + TestErrorEvent.RENDERER_NOT_SUPPORTED)); + } + + /** + * @param renderer + * The component which is used as the renderer + * @return The string that the renderer displays or <code>null</code> if it + * could not be resolved. + */ + private static String resolveRenderedText(Component renderer) { + if (renderer instanceof JLabel) { + return ((JLabel)renderer).getText(); + } else if (renderer instanceof JToggleButton) { + return ((JToggleButton)renderer).isSelected() ? Boolean.TRUE + .toString() : Boolean.FALSE.toString(); + } else if (renderer instanceof AbstractButton) { + return ((AbstractButton)renderer).getText(); + } else if (renderer instanceof JTextComponent) { + return ((JTextComponent)renderer).getText(); + } + // Check if an adapter exists + ITextRendererAdapter textRendererAdapter = + ((ITextRendererAdapter) AdapterFactoryRegistry + .getInstance().getAdapter( + ITextRendererAdapter.class, renderer)); + if (textRendererAdapter != null) { + return textRendererAdapter.getText(); + } else if (renderer != null) { + String[] methodNames = new String[] { + RENDERER_FALLBACK_TEXT_GETTER_METHOD_1, + RENDERER_FALLBACK_TEXT_GETTER_METHOD_2 }; + for (int i = 0; i < methodNames.length; i++) { + String text = getTextFromComponent(renderer, methodNames[i]); + if (text != null) { + return text; + } + } + } + return null; + } + + /** + * @param obj + * the object to invoke the method for + * @param getterName + * the name of the getter Method for string retrival + * @return the return value of the given method name or <code>null</code> if + * something went wrong during method invocation + */ + private static String getTextFromComponent(Object obj, String getterName) { + String text = null; + try { + Method getter = null; + Class objClass = obj.getClass(); + try { + getter = objClass.getDeclaredMethod(getterName, null); + } catch (NoSuchMethodException e) { + // ignore + } catch (SecurityException e) { + // ignore + } + if (getter == null) { + try { + getter = objClass.getMethod(getterName, null); + } catch (NoSuchMethodException e) { + return text; + } catch (SecurityException e) { + return text; + } + } + getter.setAccessible(true); + Object returnValue = getter.invoke(obj, null); + if (returnValue instanceof String) { + text = (String) returnValue; + } + return text; + } catch (SecurityException e) { + return text; + } catch (IllegalArgumentException e) { + return text; + } catch (IllegalAccessException e) { + return text; + } catch (InvocationTargetException e) { + return text; + } + } +} diff --git a/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/caps/JListCAPs.java b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/caps/JListCAPs.java new file mode 100644 index 000000000..c8453eb3a --- /dev/null +++ b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/caps/JListCAPs.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * 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.swing.swing.caps; + +import org.eclipse.jubula.rc.common.caps.AbstractListCAPs; +import org.eclipse.jubula.rc.swing.utils.SwingUtils; +/** + * + * @author BREDEX GmbH + * + */ +public class JListCAPs extends AbstractListCAPs { + + /** + * {@inheritDoc} + */ + protected int getSystemDefaultModifier() { + return SwingUtils.getSystemDefaultModifier(); + } + +} diff --git a/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/caps/JMenuBarCAPs.java b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/caps/JMenuBarCAPs.java new file mode 100644 index 000000000..aa1d92138 --- /dev/null +++ b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/caps/JMenuBarCAPs.java @@ -0,0 +1,191 @@ +/******************************************************************************* + * 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.swing.swing.caps; + +import java.awt.Component; +import java.awt.Container; +import java.awt.Window; +import java.awt.event.KeyEvent; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JPopupMenu; +import javax.swing.MenuElement; + +import org.eclipse.jubula.rc.common.caps.AbstractMenuCAPs; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.IComponentAdapter; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.IMenuAdapter; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.IMenuItemAdapter; +import org.eclipse.jubula.rc.swing.swing.implclasses.WindowHelper; +import org.eclipse.jubula.rc.swing.swing.uiadapter.JMenuItemAdapter; + +/** + * Toolkit specific commands for the <code>JMenuBar</code>. + * + * @author BREDEX GmbH + */ +public class JMenuBarCAPs extends AbstractMenuCAPs { + + /** + * {@inheritDoc} + */ + public String[] getTextArrayFromComponent() { + + return null; + } + + /** + * Workaround to get the menu bar existing somewhere in the given + * container's hierarchy. This method should <b>only</b> be used if + * {@link JFrame#getJMenuBar()} / {@link JDialog#getJMenuBar()} return + * <code>null</code>, which is a very rare case. + * + * This method also performs some unorthodox visibility testing in order + * to avoid retrieving the wrong menu. + * + * @param rootPane The root container from which to start the search for + * the menu bar. + * @return the first menu bar found in the hierarchy that: <ul> + * <li>is showing</li> + * <li>contains at least one visible menu</li> + */ + private JMenuBar getMenuBarWorkaround(Container rootPane) { + JMenuBar menuBar = null; + List menuList = new ArrayList(); + collectMenuBarsWorkaround(rootPane, menuList); + Iterator menuIter = menuList.iterator(); + while (menuIter.hasNext() && menuBar == null) { + JMenuBar menu = (JMenuBar)menuIter.next(); + boolean hasAtLeastOneItem = false; + MenuElement [] subElements = menu.getSubElements(); + for (int i = 0; + i < subElements.length && !hasAtLeastOneItem; + i++) { + if (subElements[i] instanceof JMenu) { + JMenu subMenu = (JMenu)subElements[i]; + hasAtLeastOneItem = + subMenu != null && subMenu.isShowing(); + } + } + if (hasAtLeastOneItem) { + menuBar = menu; + } + } + return menuBar; + } + + /** + * Adds all menu bars found in the hierarchy <code>container</code> to + * <code>menuBarList</code>. This is part of a workaround for finding menus + * in AUTs that don't make proper use of + * {@link JFrame#setJMenuBar()} / {@link JDialog#setJMenuBar()}. + * + * @see #getMenuBarWorkaround(Container) + * + * @param container The root container from which to start the search for + * the menu bars. + * @param menuBarList The list to which each menu bar found will be added. + * Only objects of type {@link JMenuBar} will be added + * to this list. + */ + private void collectMenuBarsWorkaround( + Container container, List menuBarList) { + Component [] children = container.getComponents(); + for (int i = 0; i < children.length; i++) { + if (children[i] instanceof JMenuBar + && children[i].isShowing()) { + menuBarList.add(children[i]); + } + } + + for (int i = 0; i < children.length; i++) { + if (children[i] instanceof Container + && children[i].isVisible()) { + collectMenuBarsWorkaround((Container)children[i], menuBarList); + } + } + + } + /** + * @return the component + */ + public IComponentAdapter getComponent() { + if (super.getComponent().getRealComponent() instanceof JPopupMenu) { + return super.getComponent(); + } + Window activeWindow = WindowHelper.getActiveWindow(); + if (activeWindow == null) { + getLog().warn("JMenuBarImplClass.getComponent(): No active window."); //$NON-NLS-1$ + } else { + JMenuBar menuBar = null; + Container rootPane = null; + if (activeWindow instanceof JDialog) { + JDialog dialog = (JDialog)activeWindow; + menuBar = dialog.getJMenuBar(); + rootPane = dialog.getRootPane(); + } else if (activeWindow instanceof JFrame) { + JFrame frame = (JFrame)activeWindow; + menuBar = frame.getJMenuBar(); + rootPane = frame.getRootPane(); + } + + if (menuBar == null) { + menuBar = getMenuBarWorkaround(rootPane); + } + + setComponent(menuBar); + } + return super.getComponent(); + } + + /** + *{@inheritDoc} + */ + protected void closeMenu(IMenuAdapter menuBar, String[] textPath, + String operator) { + if (menuBar.getRealComponent() instanceof JPopupMenu) { + for (int i = 0; i < textPath.length; i++) { + getRobot().keyType(menuBar.getRealComponent(), + KeyEvent.VK_ESCAPE); + } + return; + } + super.closeMenu(menuBar, textPath, operator); + + } + + /** + *{@inheritDoc} + */ + protected void closeMenu(IMenuAdapter menuBar, int[] path) { + if (menuBar.getRealComponent() instanceof JPopupMenu) { + for (int i = 0; i < path.length; i++) { + getRobot().keyType(menuBar.getRealComponent(), + KeyEvent.VK_ESCAPE); + } + return; + } + super.closeMenu(menuBar, path); + } + + /** + * {@inheritDoc} + */ + protected IMenuItemAdapter newMenuItemAdapter(Object component) { + return new JMenuItemAdapter(component); + } + +} diff --git a/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/caps/JTableCAPs.java b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/caps/JTableCAPs.java new file mode 100644 index 000000000..a20d36e71 --- /dev/null +++ b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/caps/JTableCAPs.java @@ -0,0 +1,190 @@ +/******************************************************************************* + * 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.swing.swing.caps; + +import java.awt.Component; +import java.awt.IllegalComponentStateException; +import java.awt.Point; +import java.awt.Rectangle; + +import javax.swing.JTable; +import javax.swing.table.JTableHeader; +import javax.swing.table.TableColumn; +import javax.swing.table.TableColumnModel; + +import org.eclipse.jubula.rc.common.caps.AbstractTableCAPs; +import org.eclipse.jubula.rc.common.driver.ClickOptions; +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.implclasses.table.Cell; +import org.eclipse.jubula.rc.common.logger.AutServerLogger; +import org.eclipse.jubula.rc.swing.utils.SwingUtils; +/** + * Toolkit specific commands for the <code>JTable</code> + * + * @author BREDEX GmbH + */ +public class JTableCAPs extends AbstractTableCAPs { + + /** the logger */ + private static AutServerLogger log = new AutServerLogger( + JTableCAPs.class); + + /** + * @return the log + */ + public static AutServerLogger getLog() { + return log; + } + + + /** + * + * @return the real AUT JTable + */ + private JTable getTable() { + return (JTable) getComponent().getRealComponent(); + } + + /** + * @return The event thread queuer. + */ + public IEventThreadQueuer getEventThreadQueuer() { + return getRobotFactory().getEventThreadQueuer(); + } + + + /** + * {@inheritDoc} + */ + public String[] getTextArrayFromComponent() { + final String[] componentTextArray; + TableColumnModel columnModel = getTable().getColumnModel(); + if (columnModel == null) { + componentTextArray = null; + } else { + componentTextArray = new String[columnModel.getColumnCount()]; + for (int i = 0; i < componentTextArray.length; i++) { + TableColumn tableColumn = columnModel.getColumn(i); + if (tableColumn == null) { + componentTextArray[i] = null; + } else { + Object headerValue = tableColumn.getHeaderValue(); + if (headerValue == null) { + componentTextArray[i] = null; + } else { + componentTextArray[i] = headerValue.toString(); + } + } + } + } + return componentTextArray; + } + /** + * {@inheritDoc} + */ + protected int getExtendSelectionModifier() { + return SwingUtils.getSystemDefaultModifier(); + } + + /** + * {@inheritDoc} + */ + protected Cell getCellAtMousePosition() throws StepExecutionException { + JTable table = getTable(); + Point mousePos = getRobot().getCurrentMousePosition(); + Point tablePos = table.getLocationOnScreen(); + Point relativePos = new Point(mousePos.x - tablePos.x, + mousePos.y - tablePos.y); + final int column = table.columnAtPoint(relativePos); + final int row = table.rowAtPoint(relativePos); + if (log.isDebugEnabled()) { + log.debug("Selected row, col: " + row + ", " + column); //$NON-NLS-1$ //$NON-NLS-2$ + } + checkRowColBounds(row, column); + return new Cell(row, column); + } + + /** + * {@inheritDoc} + */ + protected boolean isMouseOnHeader() { + JTable table = getTable(); + if (table.getTableHeader() == null + || !(table.getTableHeader().isShowing())) { + return false; + } + + JTableHeader header = table.getTableHeader(); + Point mousePos = getRobot().getCurrentMousePosition(); + try { + Point headerPos = header.getLocationOnScreen(); + Point relativePos = new Point(mousePos.x - headerPos.x, + mousePos.y - headerPos.y); + return header.getBounds().contains(relativePos); + } catch (IllegalComponentStateException icse) { + return false; + } + } + + /** + * {@inheritDoc} + */ + protected Object setEditorToReplaceMode(Object editor, boolean replace) { + Object returnvalue = editor; + if (replace) { + getRobot().clickAtCurrentPosition(editor, 3, 1); + } else { + returnvalue = getComponent().getRealComponent(); + } + return returnvalue; + } + + /** + * {@inheritDoc} + */ + protected Object activateEditor(Cell cell, Rectangle rectangle) { + Object table = getComponent().getRealComponent(); + getRobot().click(table, rectangle); + Component editor = getTableCellEditor(cell); + // sometimes the editor only appears after doubleclick! + if (editor == null) { + ClickOptions co = ClickOptions.create().setClickCount(2); + getRobot().click(table, rectangle, co); + editor = getTableCellEditor(cell); + } + return editor; + } + + /** + * Gets the TableCellEditor of the given cell + * @param cell the cell. + * @return the TableCellEditor + */ + private Component getTableCellEditor(final Cell cell) { + final JTable table = (JTable) getComponent().getRealComponent(); + return (Component) getEventThreadQueuer() + .invokeAndWait("getCellEditor", //$NON-NLS-1$ + new IRunnable() { + public Object run() { + Object value = table.getValueAt( + cell.getRow(), cell.getCol()); + boolean selected = table.isCellSelected( + cell.getRow(), cell.getCol()); + return table.getCellEditor(cell.getRow(), + cell.getCol()).getTableCellEditorComponent(table, + value, selected, cell.getRow(), cell.getCol()); + } + }); + } + +} diff --git a/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/caps/JTreeCAPs.java b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/caps/JTreeCAPs.java new file mode 100644 index 000000000..2c7cd0a5b --- /dev/null +++ b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/caps/JTreeCAPs.java @@ -0,0 +1,157 @@ +/******************************************************************************* + * 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.swing.swing.caps; + +import java.awt.Point; +import javax.swing.JTree; +import javax.swing.tree.TreePath; + +import org.eclipse.jubula.rc.common.CompSystemConstants; +import org.eclipse.jubula.rc.common.caps.AbstractTreeCAPs; +import org.eclipse.jubula.rc.common.driver.DragAndDropHelper; +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.tools.objects.event.EventFactory; +import org.eclipse.jubula.tools.objects.event.TestErrorEvent; +/** + * Toolkit specific commands for the <code>JTree</code> + * + * @author BREDEX GmbH + */ +public class JTreeCAPs extends AbstractTreeCAPs { + + + /** + * {@inheritDoc} + */ + public void gdDragByTextPath(int mouseButton, + String modifier, String pathType, int preAscend, + String treeTextPath, String operator) { + final DragAndDropHelper dndHelper = DragAndDropHelper.getInstance(); + dndHelper.setModifier(modifier); + dndHelper.setMouseButton(mouseButton); + gdSelect(pathType, preAscend, treeTextPath, operator, 0, 1, + CompSystemConstants.EXTEND_SELECTION_NO); + pressOrReleaseModifiers(modifier, true); + getRobot().mousePress(null, null, mouseButton); + + } + + /** + * {@inheritDoc} + */ + public void gdDropByTextPath(String pathType, int preAscend, + String treeTextPath, String operator, int delayBeforeDrop) { + try { + gdSelect(pathType, preAscend, treeTextPath, operator, 0, 1, + CompSystemConstants.EXTEND_SELECTION_NO); + waitBeforeDrop(delayBeforeDrop); + } finally { + final DragAndDropHelper dndHelper = DragAndDropHelper.getInstance(); + getRobot().mouseRelease(null, null, dndHelper.getMouseButton()); + pressOrReleaseModifiers(dndHelper.getModifier(), false); + } + + } + + /** + * {@inheritDoc} + */ + public void gdDragByIndexPath(int mouseButton, + String modifier, String pathType, int preAscend, + String treeIndexPath) { + final DragAndDropHelper dndHelper = DragAndDropHelper.getInstance(); + dndHelper.setModifier(modifier); + dndHelper.setMouseButton(mouseButton); + gdSelectByIndices(pathType, preAscend, treeIndexPath, 0, 1, + CompSystemConstants.EXTEND_SELECTION_NO); + pressOrReleaseModifiers(modifier, true); + getRobot().mousePress(null, null, mouseButton); + + } + + /** + * {@inheritDoc} + */ + public void gdDropByIndexPath(String pathType, int preAscend, + String treeIndexPath, int delayBeforeDrop) { + try { + gdSelectByIndices(pathType, preAscend, treeIndexPath, 0, 1, + CompSystemConstants.EXTEND_SELECTION_NO); + waitBeforeDrop(delayBeforeDrop); + } finally { + final DragAndDropHelper dndHelper = DragAndDropHelper.getInstance(); + getRobot().mouseRelease(null, null, dndHelper.getMouseButton()); + pressOrReleaseModifiers(dndHelper.getModifier(), false); + } + + } + /** + * {@inheritDoc} + */ + public void gdVerifyTextAtMousePosition(String text, String operator) { + checkNodeText(getNodeAtMousePosition(), text, operator); + } + /** + * + * @return the tree node at the current mouse position. + * @throws StepExecutionException If no tree node can be found at the + * current mouse position. + */ + protected Object getNodeAtMousePosition() throws StepExecutionException { + return getEventThreadQueuer().invokeAndWait("getNodeAtMousePosition", new IRunnable() { //$NON-NLS-1$ + + public Object run() throws StepExecutionException { + Point mousePosition = getRobot().getCurrentMousePosition(); + Point treeLocation = getTreeComponent().getLocationOnScreen(); + Point relativePos = new Point( + mousePosition.x - treeLocation.x, + mousePosition.y - treeLocation.y); + + int rowAtMousePosition = + getTreeComponent(). + getRowForLocation(relativePos.x, relativePos.y); + + if (rowAtMousePosition != -1) { + TreePath treePath = + getTreeComponent(). + getPathForLocation(relativePos.x, relativePos.y); + + if (treePath != null + && treePath.getLastPathComponent() != null) { + return treePath.getLastPathComponent(); + } + + } + + throw new StepExecutionException("No tree node found at mouse position.", //$NON-NLS-1$ + EventFactory.createActionError(TestErrorEvent.NOT_FOUND)); + } + + }); + + } + /** + * + * @return The JTree + */ + private JTree getTreeComponent() { + return (JTree) getComponent().getRealComponent(); + } + + /** + * @return The event thread queuer. + */ + protected IEventThreadQueuer getEventThreadQueuer() { + return getRobotFactory().getEventThreadQueuer(); + } +} diff --git a/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/AbstractButtonAdapter.java b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/AbstractButtonAdapter.java new file mode 100644 index 000000000..843d91d59 --- /dev/null +++ b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/AbstractButtonAdapter.java @@ -0,0 +1,103 @@ +/******************************************************************************* + * 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.swing.swing.uiadapter; + +import javax.swing.AbstractButton; + +import org.eclipse.jubula.rc.common.driver.IEventThreadQueuer; +import org.eclipse.jubula.rc.common.driver.IRunnable; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.IButtonAdapter; +/** + * Implementation of the button interface as an adapter which holds + * the <code>javax.swing.AbstractButton</code>. + * + * @author BREDEX GmbH + */ +public class AbstractButtonAdapter extends WidgetAdapter + implements IButtonAdapter { + + /** + * Creates an object with the adapted JMenu. + * @param objectToAdapt this must be an object of the Type + * <code>AbstractButton</code> + */ + public AbstractButtonAdapter(Object objectToAdapt) { + super(objectToAdapt); + } + + /** + * + * @return the casted Object + */ + private AbstractButton getAbstractButton() { + return (AbstractButton) getRealComponent(); + } + /** + * @return The event thread queuer. + */ + public IEventThreadQueuer getEventThreadQueuer() { + return getRobotFactory().getEventThreadQueuer(); + } + + /** + * {@inheritDoc} + */ + public String getText() { + return (String) getEventThreadQueuer().invokeAndWait( + "getText", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return getAbstractButton().getText(); + } + }); + } + + /** + * {@inheritDoc} + */ + public boolean isEnabled() { + Boolean returnvalue = (Boolean) getEventThreadQueuer().invokeAndWait( + "isEnabled", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return getAbstractButton().getModel().isEnabled() + ? Boolean.TRUE : Boolean.FALSE; + } + }); + return (boolean) returnvalue.booleanValue(); + } + + /** + * {@inheritDoc} + */ + public boolean isSelected() { + Boolean returnvalue = (Boolean) getEventThreadQueuer().invokeAndWait( + "isSelected", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return getAbstractButton().getModel().isSelected() + ? Boolean.TRUE : Boolean.FALSE; + } + }); + return (boolean) returnvalue.booleanValue(); + } + + /** + * {@inheritDoc} + */ + public String readValue(String variable) { + + return (String) getEventThreadQueuer().invokeAndWait( + "isShowing", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return getAbstractButton().getText(); + } + }); + } + +} diff --git a/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/AbstractComponentAdapter.java b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/AbstractComponentAdapter.java new file mode 100644 index 000000000..eb4aff71e --- /dev/null +++ b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/AbstractComponentAdapter.java @@ -0,0 +1,28 @@ +package org.eclipse.jubula.rc.swing.swing.uiadapter; + +import org.eclipse.jubula.rc.common.driver.IRobotFactory; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.IComponentAdapter; +import org.eclipse.jubula.rc.swing.driver.RobotFactoryConfig; +/** + * + * @author BREDEX GmbH + * + */ +public abstract class AbstractComponentAdapter implements IComponentAdapter { + + /** the RobotFactory from the AUT */ + private IRobotFactory m_robotFactory; + + /** + * Gets the Robot factory. The factory is created once per instance. + * + * @return The Robot factory. + */ + public IRobotFactory getRobotFactory() { + if (m_robotFactory == null) { + m_robotFactory = new RobotFactoryConfig().getRobotFactory(); + } + return m_robotFactory; + } + +} diff --git a/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/JComboBoxAdapter.java b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/JComboBoxAdapter.java new file mode 100644 index 000000000..3619c9733 --- /dev/null +++ b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/JComboBoxAdapter.java @@ -0,0 +1,405 @@ +/******************************************************************************* + * 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.swing.swing.uiadapter; + +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Rectangle; +import java.util.Arrays; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.swing.ComboBoxEditor; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JList; +import javax.swing.JPopupMenu; +import javax.swing.SwingUtilities; + +import org.apache.commons.lang.Validate; +import org.eclipse.jubula.rc.common.driver.ClickOptions; +import org.eclipse.jubula.rc.common.driver.IRunnable; +import org.eclipse.jubula.rc.common.exception.StepExecutionException; +import org.eclipse.jubula.rc.common.implclasses.MatchUtil; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.IComboBoxAdapter; +import org.eclipse.jubula.rc.swing.swing.caps.CapUtil; +import org.eclipse.jubula.rc.swing.swing.implclasses.JComboBoxHelper; +import org.eclipse.jubula.rc.swing.swing.implclasses.JComboBoxImplClass; +import org.eclipse.jubula.tools.objects.event.EventFactory; +import org.eclipse.jubula.tools.objects.event.TestErrorEvent; +/** + * Implementation of the Interface <code>IComboBoxAdapter</code> as a + * adapter for the <code>JComboBox</code> component. + * @author BREDEX GmbH + * + */ +public class JComboBoxAdapter extends WidgetAdapter implements + IComboBoxAdapter { + /** + * <code>INVALID_MAX_WIDTH</code> + */ + public static final int NO_MAX_WIDTH = -1; + + /** */ + private JComboBox m_comboBox; + /** + * + * @param objectToAdapt + */ + public JComboBoxAdapter(Object objectToAdapt) { + super(objectToAdapt); + m_comboBox = (JComboBox) objectToAdapt; + } + + /** + * {@inheritDoc} + */ + public String getText() { + String comboBoxText; + if (m_comboBox.isEditable()) { + comboBoxText = CapUtil.getRenderedText( + getComboBoxEditorComponent(m_comboBox), true); + } else { + final int selIndex = m_comboBox.getSelectedIndex(); + if (selIndex == -1) { + comboBoxText = String.valueOf( + m_comboBox.getSelectedItem()); + } else { + final JList jlist = new JList(m_comboBox.getModel()); + Object o = getEventThreadQueuer().invokeAndWait( + "getText", new IRunnable() { //$NON-NLS-1$ + public Object run() { + Component disp = m_comboBox.getRenderer() + .getListCellRendererComponent(jlist, + jlist.getModel().getElementAt(selIndex), + selIndex, true, m_comboBox.hasFocus()); + return CapUtil.getRenderedText(disp, false); + } + }); + comboBoxText = String.valueOf(o); + } + } + return comboBoxText; + + } + + /** + * {@inheritDoc} + */ + public boolean isEditable() { + Boolean editable = (Boolean)getEventThreadQueuer().invokeAndWait("isEditable", //$NON-NLS-1$ + new IRunnable() { + public Object run() { + // see findBugs + return m_comboBox.isEditable() + ? Boolean.TRUE : Boolean.FALSE; + } + }); + return editable.booleanValue(); + } + + /** + * {@inheritDoc} + */ + public boolean containsValue(String value, String operator) { + JListAdapter list = new JListAdapter(findJList()); + return list.containsValue(value, operator); + } + + /** + * {@inheritDoc} + */ + public boolean containsValue(String value) { + return containsValue(value, MatchUtil.EQUALS); + } + + /** + * select the whole text of the textfield by clicking three times. + */ + public void selectAll() { + click(new Integer(1)); + getRobot().keyStroke(getRobot().getSystemModifierSpec() + " A"); //$NON-NLS-1$ + } + + /** + * {@inheritDoc} + */ + public int getSelectedIndex() { + Integer actual = (Integer)getEventThreadQueuer() + .invokeAndWait( + JComboBoxImplClass.class.getName() + ".getSelectedIndex", //$NON-NLS-1$ + new IRunnable() { + public Object run() { + return new Integer(m_comboBox.getSelectedIndex()); + } + }); + return actual.intValue(); + } + + /** + * {@inheritDoc} + */ + public void select(int index) { + JListAdapter list = new JListAdapter(findJList()); + list.clickOnIndex(new Integer(index), ClickOptions + .create().setClickCount(1), getMaxWidth()); + } + + /** + * Selects the specified item in the combobox. + * @param values the values which should be (not) selected + * @param operator if regular expressions are used + * @param searchType Determines where the search begins ("relative" or "absolute") + * @throws StepExecutionException if an error occurs during selecting the item + * @throws IllegalArgumentException if <code>component</code> or <code>text</code> are null + */ + public void select(final String[] values, String operator, + String searchType) + throws StepExecutionException, IllegalArgumentException { + try { + for (int i = 0; i < values.length; i++) { + String text = values[i]; + Validate.notNull(text, "text must not be null"); //$NON-NLS-1$ + } + JListAdapter list = new JListAdapter(findJList()); + Integer[] indices = list.findIndicesOfValues(values, + operator, searchType); + Arrays.sort(indices); + if (indices.length == 0) { + throw new StepExecutionException("Text '" + Arrays.asList(values).toString() //$NON-NLS-1$ + + "' not found", //$NON-NLS-1$ + EventFactory.createActionError(TestErrorEvent.NOT_FOUND)); + } + list.clickOnIndex(indices[0], ClickOptions + .create().setClickCount(1), getMaxWidth()); + } catch (StepExecutionException e) { + m_comboBox.hidePopup(); + throw e; + } catch (IllegalArgumentException e) { + m_comboBox.hidePopup(); + throw e; + } + } + + /** + * Inputs <code>text</code> to <code>component</code>.<br> + * @param text the text to type in + * @param replace whether to rplace the text or not + * @throws StepExecutionException if an error occurs during typing <code>text</code> + * @throws IllegalArgumentException if <code>component</code> or <code>text</code> are null + */ + public void input(String text, boolean replace) + throws StepExecutionException, IllegalArgumentException { + + Validate.notNull(text, "text must not be null"); //$NON-NLS-1$ + Component editor = getComboBoxEditorComponent(m_comboBox); + if (editor == null) { + throw new StepExecutionException("could not find editor", //$NON-NLS-1$ + EventFactory.createActionError(TestErrorEvent.COMP_NOT_FOUND)); + } + if (replace) { + selectAll(); + } + getRobot().type(editor, text); + } + + /** + * performs a <code>count</code> -click on the textfield. + * @param count the number of clicks + */ + public void click(Integer count) { + Component editor = getComboBoxEditorComponent(m_comboBox); + if (editor == null) { + throw new StepExecutionException("no editor found", //$NON-NLS-1$ + EventFactory.createActionError(TestErrorEvent.COMP_NOT_FOUND)); + } + getRobot().click(editor, null, ClickOptions.create().setClickCount( + count.intValue())); + } + + /** + * @param component + * the combobox + * @return the editor used to render and edit the selected item in the + * JComboBox field. + * @throws StepExecutionException + * if the editor comonent could not be found + */ + private Component getComboBoxEditorComponent(JComboBox component) + throws StepExecutionException { + + ComboBoxEditor cbe = component.getEditor(); + if (cbe == null) { + throw new StepExecutionException("no ComboBoxEditor found", //$NON-NLS-1$ + EventFactory.createActionError(TestErrorEvent.COMP_NOT_FOUND)); + } + Component c = cbe.getEditorComponent(); + if (c == null) { + throw new StepExecutionException("no EditorComponent found", //$NON-NLS-1$ + EventFactory.createActionError(TestErrorEvent.COMP_NOT_FOUND)); + } + return c; + } + + /** + * Finds the <code>JList</code> of the combobox. + * @return The list + */ + private JList findJList() { + JList list = (JList)getComponentViaHierarchy(openPopupMenu(), + JList.class); + if (list == null) { + throw new StepExecutionException("list component not found", //$NON-NLS-1$ + EventFactory.createActionError(TestErrorEvent.COMP_NOT_FOUND)); + } + return list; + } + + /** + * Opens the combobox popup menu and returns the popup instance. May also be + * called if the popup is already visible + * @return The popup menu + */ + private JPopupMenu openPopupMenu() { + if (!isPopupVisible()) { + Component c = getComponentViaHierarchy(m_comboBox, JButton.class); + Rectangle r = null; + if ((c == null) && (!m_comboBox.isEditable())) { + c = m_comboBox; + } else if ((c == null) && (m_comboBox.isEditable())) { + c = m_comboBox; + r = findArrowIconArea(); + } +// if (log.isDebugEnabled()) { +// log.debug("Opening popup by clicking on: " + c); //$NON-NLS-1$ +// } + getRobot().click(c, r); + } + if (!isPopupVisible()) { +// log.debug("Dropdown list still not visible, must be an error"); //$NON-NLS-1$ + throw new StepExecutionException("dropdown list not visible", //$NON-NLS-1$ + EventFactory.createActionError( + TestErrorEvent.DROPDOWN_LIST_NOT_FOUND)); + } + return getPopupMenu(m_comboBox); + } + + /** + * Tries to find the popup menu from the combobox + * @param component the combobox + * @return the popup of the combobox + * @throws StepExecutionException if the popup could not be found + */ + private JPopupMenu getPopupMenu(JComboBox component) + throws StepExecutionException { + + AccessibleContext ac = component.getAccessibleContext(); + for (int i = 0; i < ac.getAccessibleChildrenCount(); i++) { + Accessible a = ac.getAccessibleChild(i); + if (a instanceof JPopupMenu) { + return (JPopupMenu)a; + } + } + throw new StepExecutionException("cannot find dropdown list", //$NON-NLS-1$ + EventFactory.createActionError( + TestErrorEvent.DROPDOWN_LIST_NOT_FOUND)); + } + /** + * Tries to find the component in the component hierarchy + * @param component where to search + * @param c type of the component which should be found + * @return the desired component + */ + private Component getComponentViaHierarchy(Container component, Class c) { + Component[] comps = component.getComponents(); + for (int i = 0; i < comps.length; i++) { + if (c.isInstance(comps[i])) { + return comps[i]; + } + } + for (int i = 0; i < comps.length; i++) { + if (comps[i] instanceof Container) { + Component ct = getComponentViaHierarchy((Container)comps[i], c); + if (ct != null) { + return ct; + } + } + } + return null; + } + + /** + * @return true, if the popup of the combobox is visible + */ + private boolean isPopupVisible() { + Boolean visible = (Boolean)getEventThreadQueuer().invokeAndWait( + JComboBoxHelper.class.getName() + + "isPopupVisible", new IRunnable() { //$NON-NLS-1$ + public Object run() throws StepExecutionException { + return m_comboBox.isPopupVisible() + ? Boolean.TRUE : Boolean.FALSE; + } + }); + return visible.booleanValue(); + } + + /** + * @return a rectangle, where the arrow icon is expected. + */ + private Rectangle findArrowIconArea() { + JComboBox comboBox = m_comboBox; + Component editor = getComboBoxEditorComponent(comboBox); + Rectangle r = null; + if (editor == null) { + throw new StepExecutionException("could not find editor", //$NON-NLS-1$ + EventFactory.createActionError(TestErrorEvent.COMP_NOT_FOUND)); + } + Rectangle ra[] = + SwingUtilities.computeDifference(comboBox.getBounds(), + editor.getBounds()); + if ((ra == null) || (ra.length < 1)) { + throw new StepExecutionException("could not arrow icon", //$NON-NLS-1$ + EventFactory.createActionError(TestErrorEvent.COMP_NOT_FOUND)); + } + r = ra[0]; + // find the largest area of the returned rectangles. + double bestAreaIndex = Double.MAX_VALUE; + for (int i = 0; i < ra.length; i++) { + if ((ra[i].height > 0) && (ra[i].width > 0)) { + double areaIndex = ((double)ra[i].width) / ra[i].height - 1.0; + if (areaIndex < 0) { + areaIndex *= (-1); + } + if (areaIndex < bestAreaIndex) { + bestAreaIndex = areaIndex; + r = ra[i]; + } + } + } + return r; + } + + /** + * @return the maximal width for the selection; -1 if none available + * e.g. the preferred width of the combo box itself is 100 pixel although + * the preferred size of the embedded items is more than two times bigger + * --> click outside of component (JList) #3013 + */ + private double getMaxWidth() { + double maxWidth = NO_MAX_WIDTH; + Dimension d = m_comboBox.getPreferredSize(); + if (d != null) { + maxWidth = d.getWidth(); + } + return maxWidth; + } +} diff --git a/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/JLabelAdapter.java b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/JLabelAdapter.java new file mode 100644 index 000000000..405607366 --- /dev/null +++ b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/JLabelAdapter.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * 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.swing.swing.uiadapter; + +import javax.swing.JLabel; + +import org.eclipse.jubula.rc.common.uiadapter.interfaces.ITextVerifiable; +/** + * + * @author BREDEX GmbH + * + */ +public class JLabelAdapter extends WidgetAdapter implements ITextVerifiable { + + /** + * + * @param objectToAdapt the component + */ + public JLabelAdapter(Object objectToAdapt) { + super(objectToAdapt); + + } + + /** + * {@inheritDoc} + */ + public String getText() { + return ((JLabel) getRealComponent()).getText(); + } + +} diff --git a/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/JListAdapter.java b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/JListAdapter.java new file mode 100644 index 000000000..48a66c8ed --- /dev/null +++ b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/JListAdapter.java @@ -0,0 +1,243 @@ +/******************************************************************************* + * 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.swing.swing.uiadapter; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Rectangle; +import java.util.HashSet; +import java.util.Set; + +import javax.swing.JList; +import javax.swing.ListCellRenderer; +import javax.swing.ListModel; + +import org.eclipse.jubula.rc.common.CompSystemConstants; +import org.eclipse.jubula.rc.common.driver.ClickOptions; +import org.eclipse.jubula.rc.common.driver.IRunnable; +import org.eclipse.jubula.rc.common.exception.StepExecutionException; +import org.eclipse.jubula.rc.common.implclasses.MatchUtil; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.IListAdapter; +import org.eclipse.jubula.rc.swing.swing.caps.CapUtil; +import org.eclipse.jubula.rc.swing.swing.implclasses.JComboBoxImplClass; +import org.eclipse.jubula.tools.objects.event.EventFactory; +import org.eclipse.jubula.tools.objects.event.TestErrorEvent; +/** + * + * @author BREDEX GmbH + * + */ +public class JListAdapter extends WidgetAdapter implements IListAdapter { + /** */ + private JList m_list; + + /** + * + * @param objectToAdapt + */ + public JListAdapter(Object objectToAdapt) { + super(objectToAdapt); + m_list = (JList) objectToAdapt; + } + + /** + * {@inheritDoc} + */ + public String getText() { + String[] selected = getSelectedValues(); + if (selected.length > 0) { + return selected[0]; + } + throw new StepExecutionException("No list item selected", //$NON-NLS-1$ + EventFactory.createActionError(TestErrorEvent.NO_SELECTION)); + } + + /** + * {@inheritDoc} + */ + public int[] getSelectedIndices() { + return (int[])getEventThreadQueuer().invokeAndWait( + "getSelectedIndices", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return m_list.getSelectedIndices(); + } + }); + } + + /** + * Clicks on the index of the passed list. + * + * @param i The index to click + * @param co the click options to use + * @param maxWidth the maximal width which is used to select the item + */ + public void clickOnIndex(final Integer i, + ClickOptions co, double maxWidth) { + final int index = i.intValue(); + ListModel model = m_list.getModel(); + if ((model == null) || (index >= model.getSize()) + || (index < 0)) { + throw new StepExecutionException("List index '" + i //$NON-NLS-1$ + + "' is out of range", //$NON-NLS-1$ + EventFactory.createActionError(TestErrorEvent.INVALID_INDEX)); + } + // Call of JList.ensureIndexIsVisible() is not required, + // because the Robot scrolls the click rectangle to visible. + Rectangle r = (Rectangle) getRobotFactory().getEventThreadQueuer() + .invokeAndWait("getCellBounds", new IRunnable() { //$NON-NLS-1$ + + public Object run() throws StepExecutionException { + return m_list.getCellBounds(index, index); + } + }); + + if (r == null) { + throw new StepExecutionException( + "List index '" + i + "' is not visible", //$NON-NLS-1$ //$NON-NLS-2$ + EventFactory.createActionError(TestErrorEvent.NOT_VISIBLE)); + } + + // if possible adjust height and width for items + ListCellRenderer lcr = m_list.getCellRenderer(); + if (lcr != null) { + Component listItem = lcr.getListCellRendererComponent(m_list, model + .getElementAt(index), index, false, false); + Dimension preferredSize = listItem.getPreferredSize(); + r.setSize(preferredSize); + } + + if (maxWidth != JComboBoxImplClass.NO_MAX_WIDTH + && r.getWidth() > maxWidth) { + Dimension d = new Dimension(); + d.setSize(maxWidth, r.getHeight()); + r.setSize(d); + } + + getRobot().click(m_list, r, + co.setClickType(ClickOptions.ClickType.RELEASED)); + } + + /** + * {@inheritDoc} + */ + public String[] getSelectedValues() { + final int[] indices = getSelectedIndices(); + + return (String[])getEventThreadQueuer().invokeAndWait( + "getSelectedValues", new IRunnable() { //$NON-NLS-1$ + public Object run() { + Object[] values = m_list.getSelectedValues(); + String[] selected = new String[values.length]; + ListCellRenderer renderer = m_list.getCellRenderer(); + for (int i = 0; i < values.length; i++) { + Object value = values[i]; + Component c = renderer.getListCellRendererComponent( + m_list, value, indices[i], true, false); + selected[i] = CapUtil.getRenderedText(c); + } + return selected; + } + }); + } + /** + * {@inheritDoc} + */ + public Integer[] findIndicesOfValues( + final String[] values, final String operator, + final String searchType) { + + final Set indexSet = new HashSet(); + getEventThreadQueuer().invokeAndWait("findIndices", //$NON-NLS-1$ + new IRunnable() { + public Object run() { + ListCellRenderer renderer = m_list.getCellRenderer(); + ListModel model = m_list.getModel(); + for (int i = getStartingIndex(searchType); + i < model.getSize(); ++i) { + Object obj = model.getElementAt(i); + m_list.ensureIndexIsVisible(i); + Component comp = renderer + .getListCellRendererComponent( + m_list, obj, i, false, false); + String str = CapUtil.getRenderedText(comp); + if (MatchUtil.getInstance(). + match(str, values, operator)) { + indexSet.add(new Integer(i)); + } + } + return null; // return value is not used + } + }); + + Integer[] indices = new Integer[indexSet.size()]; + indexSet.toArray(indices); + return indices; + } + + /** + * Finds the indices of the list elements that are rendered with the passed + * values. + * + * @param values The values + * @param operator operator to use + * @return The array of indices. It's length is equal to the length of the + * values array, but may contains <code>null</code> elements for + * all values that are not found in the list + */ + public Integer[] findIndicesOfValues( + final String[] values, final String operator) { + + return findIndicesOfValues(values, operator, + CompSystemConstants.SEARCH_TYPE_ABSOLUTE); + } + + /** + * {@inheritDoc} + */ + public boolean containsValue(String value, String operator) { + Integer[] indices = null; + if (operator.equals(MatchUtil.NOT_EQUALS)) { + indices = findIndicesOfValues(new String[] { value }, + MatchUtil.EQUALS); + return indices.length == 0; + } + indices = findIndicesOfValues(new String[] { value }, + operator); + return indices.length > 0; + } + + /** + * Clicks on the index of the passed list. + * + * @param i + * The index to click + * @param co the click options to use + */ + public void clickOnIndex(final Integer i, ClickOptions co) { + clickOnIndex(i, co, JComboBoxImplClass.NO_MAX_WIDTH); + } + + /** + * @param searchType Determines where the search begins ("relative" or "absolute") + * @return The index from which to begin a search, based on the search type + * and (if appropriate) the currently selected cell. + */ + private int getStartingIndex(final String searchType) { + int startingIndex = 0; + if (searchType.equalsIgnoreCase( + CompSystemConstants.SEARCH_TYPE_RELATIVE)) { + int [] selectedIndices = getSelectedIndices(); + // Start from the last selected item + startingIndex = selectedIndices[selectedIndices.length - 1] + 1; + } + return startingIndex; + } +} diff --git a/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/JMenuAdapter.java b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/JMenuAdapter.java new file mode 100644 index 000000000..1cb35e507 --- /dev/null +++ b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/JMenuAdapter.java @@ -0,0 +1,91 @@ +/******************************************************************************* + * 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.swing.swing.uiadapter; + +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +import javax.swing.JMenu; +import javax.swing.JMenuItem; + +import org.eclipse.jubula.rc.common.uiadapter.interfaces.IMenuAdapter; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.IMenuItemAdapter; +/** + * Implementation of the menu interface for adapting the <code>JMenu</code>. + * In Swing we have three implementations of the menu interface because + * the Interface is used for the <code>JMenubar</code>, the <code>JPopupMenu</code> and the <code>JMenu</code>. + * All these behave same in the implementation. + * + * @author BREDEX GmbH + * + */ +public class JMenuAdapter extends AbstractComponentAdapter + implements IMenuAdapter { + /** The JMenu from the AUT */ + private JMenu m_menu; + + /** + * Creates an object with the adapted JMenu. + * @param toAdapt graphics component which will be adapted + */ + public JMenuAdapter(Object toAdapt) { + m_menu = (JMenu) toAdapt; + } + + /** + * {@inheritDoc} + */ + public Object getRealComponent() { + return m_menu; + } + + /** + * {@inheritDoc} + */ + public IMenuItemAdapter[] getItems() { + List adapters = new LinkedList(); + + for (int i = 0; i < m_menu.getItemCount(); i++) { + JMenuItem getted = m_menu.getItem(i); + if (getted instanceof JMenuItem) { + adapters.add(new JMenuItemAdapter(getted)); + } + + } + + + IMenuItemAdapter[] allitems = null; + if (adapters.size() > 0) { + allitems = new IMenuItemAdapter[adapters.size()]; + int i = 0; + for (Iterator iterator = adapters.iterator(); iterator.hasNext();) { + Object object = (Object) iterator.next(); + + allitems[i] = (IMenuItemAdapter) object; + i++; + } + + } + + + return allitems; + } + /** + * {@inheritDoc} + */ + public int getItemCount() { + return m_menu.getItemCount(); + } + + + +} diff --git a/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/JMenuBarAdapter.java b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/JMenuBarAdapter.java new file mode 100644 index 000000000..ba1d33fdc --- /dev/null +++ b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/JMenuBarAdapter.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * 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.swing.swing.uiadapter; + +import java.util.LinkedList; +import java.util.List; + +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; + +import org.eclipse.jubula.rc.common.uiadapter.interfaces.IMenuAdapter; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.IMenuItemAdapter; + +/** + * Implementation of the menu interface for adapting the <code>JMenuBar</code>. + * In Swing we have three implementations of the menu interface because + * the Interface is used for the <code>JMenubar</code>, the <code>JPopupMenu</code> and the <code>JMenu</code>. + * All these behave same in the implementation. + * + * @author BREDEX GmbH + * + */ +public class JMenuBarAdapter extends AbstractComponentAdapter + implements IMenuAdapter { + /** The JMenuBar */ + private JMenuBar m_menuBar; + + /** + * @param objectToAdapt + */ + public JMenuBarAdapter(Object objectToAdapt) { + m_menuBar = (JMenuBar) objectToAdapt; + } + + /** + * {@inheritDoc} + */ + public Object getRealComponent() { + + return m_menuBar; + } + /** + * {@inheritDoc} + */ + + public IMenuItemAdapter[] getItems() { + Object[] menus = m_menuBar.getSubElements(); + List adapters = new LinkedList(); + for (int i = 0; i < menus.length; i++) { + if (menus[i] instanceof JMenuItem) { + adapters.add(new JMenuItemAdapter(menus[i])); + } + } + IMenuItemAdapter[] allitems = new IMenuItemAdapter[adapters.size()]; + adapters.toArray(allitems); + return allitems; + } + + /** + * {@inheritDoc} + */ + public int getItemCount() { + return m_menuBar.getMenuCount(); + } + +} diff --git a/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/JMenuItemAdapter.java b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/JMenuItemAdapter.java new file mode 100644 index 000000000..dc1ec7943 --- /dev/null +++ b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/JMenuItemAdapter.java @@ -0,0 +1,225 @@ +/******************************************************************************* + * 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.swing.swing.uiadapter; + +import javax.swing.JMenu; +import javax.swing.JMenuItem; + +import org.eclipse.jubula.rc.common.driver.ClickOptions; +import org.eclipse.jubula.rc.common.driver.IEventThreadQueuer; +import org.eclipse.jubula.rc.common.driver.IRobot; +import org.eclipse.jubula.rc.common.driver.IRunnable; +import org.eclipse.jubula.rc.common.driver.RobotTiming; +import org.eclipse.jubula.rc.common.exception.RobotException; +import org.eclipse.jubula.rc.common.exception.StepExecutionException; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.IMenuAdapter; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.IMenuItemAdapter; +import org.eclipse.jubula.tools.objects.event.EventFactory; +import org.eclipse.jubula.tools.objects.event.TestErrorEvent; + +/** + * Implementation of the MenuItem interface for adapting <code>JMenuItem</code>. + * @author BREDEX GmbH + * + */ +public class JMenuItemAdapter extends AbstractComponentAdapter + implements IMenuItemAdapter { + + /** the JMenuItem from the AUT */ + private JMenuItem m_menuItem; + + /** + * + * @param objectToAdapt + */ + public JMenuItemAdapter(Object objectToAdapt) { + m_menuItem = (JMenuItem) objectToAdapt; + } + + /** + * Gets the IEventThreadQueuer. + * + * @return The Robot + * @throws RobotException + * If the Robot cannot be created. + */ + protected IRobot getRobot() throws RobotException { + return getRobotFactory().getRobot(); + } + /** + * @return The event thread queuer. + */ + public IEventThreadQueuer getEventThreadQueuer() { + return getRobotFactory().getEventThreadQueuer(); + } + + + /** + * {@inheritDoc} + */ + public Object getRealComponent() { + + return m_menuItem; + } + + /** + * {@inheritDoc} + */ + public void setComponent(Object element) { + m_menuItem = (JMenuItem) element; + + } + + /** + * {@inheritDoc} + */ + public boolean isEnabled() { + Boolean actual = (Boolean) getEventThreadQueuer().invokeAndWait( + "isEnabled", new IRunnable() { //$NON-NLS-1$ + public Object run() { + // see findBugs + return ((m_menuItem != null) + && (m_menuItem instanceof JMenuItem) + && m_menuItem.isEnabled()) + ? Boolean.TRUE : Boolean.FALSE; + } + }); + + return actual.booleanValue(); + } + /** + * {@inheritDoc} + */ + public String getText() { + return (String) getEventThreadQueuer().invokeAndWait( + "getText", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return m_menuItem.getText(); + } + }); + } + /** + * {@inheritDoc} + */ + public boolean isShowing() { + Boolean actual = (Boolean) getEventThreadQueuer().invokeAndWait( + "isShowing", new IRunnable() { //$NON-NLS-1$ + public Object run() { + // see findBugs + return ((m_menuItem != null) + && (m_menuItem instanceof JMenuItem) + && m_menuItem.isShowing()) + ? Boolean.TRUE : Boolean.FALSE; + } + }); + + return actual.booleanValue(); + } + + /** + * {@inheritDoc} + */ + public boolean isExisting() { + if (m_menuItem != null) { + return true; + } + return false; + } + /** + * {@inheritDoc} + */ + public boolean isSelected() { + Boolean actual = (Boolean) getEventThreadQueuer().invokeAndWait( + "isSelected", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return ((m_menuItem != null) + && (m_menuItem instanceof JMenuItem) + && m_menuItem.isSelected()) + ? Boolean.TRUE : Boolean.FALSE; + } + }); + + return actual.booleanValue(); + } + + /** + * {@inheritDoc} + */ + public IMenuAdapter getMenu() { + if (m_menuItem instanceof JMenu) { + return new JMenuAdapter(m_menuItem); + } + return null; + } + + /** + * {@inheritDoc} + */ + public boolean hasSubMenu() { + if (m_menuItem.getSubElements().length > 0) { + return true; + } + return false; + } + /** + * {@inheritDoc} + */ + public boolean isSeparator() { + if (m_menuItem == null) { + return true; + } + return false; + } + + /** + * {@inheritDoc} + */ + public void selectMenuItem() { + clickMenuItem(getRobot(), m_menuItem); + + } + + /** + * {@inheritDoc} + */ + public IMenuAdapter openSubMenu() { + if (!m_menuItem.isEnabled()) { + throw new StepExecutionException("menu item not enabled", //$NON-NLS-1$ + EventFactory.createActionError( + TestErrorEvent.MENU_ITEM_NOT_ENABLED)); + } + if (!(m_menuItem instanceof JMenu)) { + throw new StepExecutionException("unexpected item found", //$NON-NLS-1$ + EventFactory.createActionError(TestErrorEvent.NOT_FOUND)); + } + JMenu menu = (JMenu) m_menuItem; + getRobot().click(m_menuItem, null, ClickOptions.create().setClickType( + ClickOptions.ClickType.RELEASED)); + RobotTiming.sleepPostShowSubMenuItem(menu.getDelay()); + return getMenu(); + } + + /** + * Clicks on a menu item + * + * @param robot the robot + * @param item the menu item + */ + private void clickMenuItem(IRobot robot, JMenuItem item) { + if (!item.isEnabled()) { + throw new StepExecutionException("menu item not enabled", //$NON-NLS-1$ + EventFactory.createActionError( + TestErrorEvent.MENU_ITEM_NOT_ENABLED)); + } + robot.click(item, null, ClickOptions.create().setClickType( + ClickOptions.ClickType.RELEASED)); + } +} diff --git a/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/JPopupMenuAdapter.java b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/JPopupMenuAdapter.java new file mode 100644 index 000000000..5a5075c3c --- /dev/null +++ b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/JPopupMenuAdapter.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * 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.swing.swing.uiadapter; + +import java.util.LinkedList; +import java.util.List; + +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; + +import org.eclipse.jubula.rc.common.uiadapter.interfaces.IMenuAdapter; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.IMenuItemAdapter; +/** + * Implementation of the menu interface for adapting the <code>JPopupMenu</code>. + * In Swing we have three implementations of the menu interface because + * the Interface is used for the <code>JMenubar</code>, the <code>JPopupMenu</code> and the <code>JMenu</code>. + * All these behave same in the implementation. + * + * @author BREDEX GmbH + * + */ +public class JPopupMenuAdapter extends AbstractComponentAdapter + implements IMenuAdapter { + /** */ + private JPopupMenu m_contextMenu; + + /** + * + * @param adaptee + */ + public JPopupMenuAdapter(Object adaptee) { + m_contextMenu = (JPopupMenu) adaptee; + } + + /** {@inheritDoc} */ + public Object getRealComponent() { + return m_contextMenu; + } + + /** {@inheritDoc} */ + public IMenuItemAdapter[] getItems() { + Object[] menuItems = m_contextMenu.getSubElements(); + List adapters = new LinkedList(); + for (int i = 0; i < menuItems.length; i++) { + if (menuItems[i] instanceof JMenuItem) { + adapters.add(new JMenuItemAdapter(menuItems[i])); + } + } + IMenuItemAdapter[] allitems = new IMenuItemAdapter[adapters.size()]; + adapters.toArray(allitems); + return allitems; + } + + /** {@inheritDoc} */ + public int getItemCount() { + return m_contextMenu.getSubElements().length; + } + + +} diff --git a/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/JTabbedPaneAdapter.java b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/JTabbedPaneAdapter.java new file mode 100644 index 000000000..f4fc06205 --- /dev/null +++ b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/JTabbedPaneAdapter.java @@ -0,0 +1,98 @@ +/******************************************************************************* + * 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.swing.swing.uiadapter; + +import javax.swing.JTabbedPane; + +import org.eclipse.jubula.rc.common.driver.IRunnable; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.ITabPaneAdapter; +/** + * Implementation of the Interface <code>ITabPaneAdapter</code> as a + * adapter for the <code>JTabbedPane</code> component. + * @author BREDEX GmbH + * + */ +public class JTabbedPaneAdapter extends WidgetAdapter + implements ITabPaneAdapter { + + /** The JTabbedPane on which the actions are performed. */ + private JTabbedPane m_pane; + /** + * + * @param objectToAdapt + */ + public JTabbedPaneAdapter(Object objectToAdapt) { + super(objectToAdapt); + m_pane = (JTabbedPane) objectToAdapt; + } + + /** + * {@inheritDoc} + */ + public int getTabCount() { + return ((Integer) getEventThreadQueuer().invokeAndWait( + "getTabCount", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return new Integer(m_pane.getTabCount()); + } + })).intValue(); + } + + /** + * {@inheritDoc} + */ + public String getTitleofTab(final int index) { + return (String) getEventThreadQueuer().invokeAndWait( + "getTitleOfTab", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return m_pane.getTitleAt(index); + } + }); + } + + /** + * {@inheritDoc} + */ + public Object getBoundsAt(final int index) { + + return getEventThreadQueuer().invokeAndWait( + "getBoundsAt", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return m_pane.getBoundsAt(index); + } + }); + } + + /** + * {@inheritDoc} + */ + public boolean isEnabledAt(final int index) { + return ((Boolean) getEventThreadQueuer().invokeAndWait( + "isEnabledAt", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return Boolean.valueOf(m_pane.isEnabledAt(index)); + } + })).booleanValue(); + } + + /** + * {@inheritDoc} + */ + public int getSelectedIndex() { + return ((Integer) getEventThreadQueuer().invokeAndWait( + "getSelectedIndex", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return new Integer(m_pane.getSelectedIndex()); + } + })).intValue(); + } + +} diff --git a/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/JTableAdapter.java b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/JTableAdapter.java new file mode 100644 index 000000000..50b5461e6 --- /dev/null +++ b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/JTableAdapter.java @@ -0,0 +1,385 @@ +/******************************************************************************* + * 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.swing.swing.uiadapter; + +import java.awt.Component; +import java.awt.Rectangle; + +import javax.swing.JTable; +import javax.swing.table.TableCellRenderer; + +import org.eclipse.jubula.rc.common.caps.AbstractMenuCAPs; +import org.eclipse.jubula.rc.common.driver.IRunnable; +import org.eclipse.jubula.rc.common.exception.StepExecutionException; +import org.eclipse.jubula.rc.common.implclasses.IndexConverter; +import org.eclipse.jubula.rc.common.implclasses.MatchUtil; +import org.eclipse.jubula.rc.common.implclasses.table.Cell; +import org.eclipse.jubula.rc.common.logger.AutServerLogger; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.ITableAdapter; +import org.eclipse.jubula.rc.swing.swing.caps.CapUtil; +import org.eclipse.jubula.tools.objects.event.EventFactory; +import org.eclipse.jubula.tools.objects.event.TestErrorEvent; +/** + * Implements the table interface as an adapter for the <code>JTable</code>. + * + * @author BREDEX GmbH + */ +public class JTableAdapter extends WidgetAdapter implements ITableAdapter { + + /** the logger */ + private static AutServerLogger log = new AutServerLogger( + AbstractMenuCAPs.class); + + /** The JTable from the AUT */ + private JTable m_table; + + /** + * Creates an object with the adapted JMenu. + * @param objectToAdapt the object which needed to be adapted + */ + public JTableAdapter(Object objectToAdapt) { + super(objectToAdapt); + m_table = (JTable) objectToAdapt; + } + + /** + * {@inheritDoc} + */ + public void setComponent(Object element) { + m_table = (JTable) element; + + } + + /** + * {@inheritDoc} + */ + public int getColumnCount() { + Integer returnvalue = (Integer) getEventThreadQueuer().invokeAndWait( + "getColumnCount", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return new Integer(m_table.getColumnCount()); + } + }); + return returnvalue.intValue(); + } + + /** + * {@inheritDoc} + */ + public int getRowCount() { + Integer returnvalue = (Integer) getEventThreadQueuer().invokeAndWait( + "getRowCount", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return new Integer(m_table.getRowCount()); + } + }); + return returnvalue.intValue(); + } + + /** + * {@inheritDoc} + */ + public String getCellText(final int row, final int column) { + Object o = getEventThreadQueuer().invokeAndWait("getCellText", //$NON-NLS-1$ + new IRunnable() { + public Object run() { + Object value = m_table.getValueAt(row, column); + boolean selected = m_table.isCellSelected(row, + column); + if (log.isDebugEnabled()) { + log.debug("Getting cell text:"); //$NON-NLS-1$ + log.debug("Row, col: " + row + ", " + column); //$NON-NLS-1$ //$NON-NLS-2$ + log.debug("Value: " + value); //$NON-NLS-1$ + } + TableCellRenderer renderer = m_table.getCellRenderer( + row, column); + Component c = renderer.getTableCellRendererComponent( + m_table, value, selected, true, row, + column); + + return CapUtil.getRenderedText(c); + } + }); + + String current = String.valueOf(o); + return current; + } + + /** + * {@inheritDoc} + */ + public String getColumnName(final int column) { + String returnvalue = (String)getEventThreadQueuer().invokeAndWait( + "getColumnName", //$NON-NLS-1$ + new IRunnable() { + public Object run() { + return m_table.getColumnName(column); + } + }); + return returnvalue; + } + + /** + * {@inheritDoc} + */ + public int getColumnFromString(final String col, final String operator) { + Integer returnvalue = (Integer) getEventThreadQueuer().invokeAndWait( + "getColumnFromString", new IRunnable() { //$NON-NLS-1$ + public Object run() { + int column = -2; + try { + int usrIdxCol = Integer.parseInt(col); + if (usrIdxCol == 0) { + usrIdxCol = usrIdxCol + 1; + } + column = IndexConverter.toImplementationIndex( + usrIdxCol); + } catch (NumberFormatException nfe) { + try { + if (m_table.getTableHeader() == null + || !(m_table.getTableHeader() + .isShowing())) { + throw new StepExecutionException("No Header", //$NON-NLS-1$ + EventFactory.createActionError( + TestErrorEvent.NO_HEADER)); + } + for (int i = 0; i < m_table.getColumnCount(); + i++) { + String header = m_table.getColumnName(i); + if (MatchUtil.getInstance().match( + header, col, operator)) { + column = i; + } + } + } catch (IllegalArgumentException iae) { + //do nothing here + } + } + + return new Integer(column); + } + }); + return returnvalue.intValue(); + } + + /** + * {@inheritDoc} + */ + public String getRowName(final int row) { + // JTable does not act like lists + return null; + } + + /** + * {@inheritDoc} + */ + public int getRowFromString(final String row, final String operator) { + Integer returnvalue = (Integer) getEventThreadQueuer().invokeAndWait( + "getRowFromString", new IRunnable() { //$NON-NLS-1$ + public Object run() { + int rowInt = -2; + try { + rowInt = IndexConverter.toImplementationIndex( + Integer.parseInt(row)); + if (rowInt == -1) { + if (m_table.getTableHeader() == null + || !(m_table.getTableHeader() + .isShowing())) { + throw new StepExecutionException("No Header", //$NON-NLS-1$ + EventFactory.createActionError( + TestErrorEvent.NO_HEADER)); + } + } + } catch (NumberFormatException nfe) { + for (int i = 0; i < m_table.getRowCount(); i++) { + String cellTxt = getCellText(i, 0); + if (MatchUtil.getInstance().match(cellTxt, row, + operator)) { + return new Integer(i); + } + } + } + return new Integer(rowInt); + } + }); + return returnvalue.intValue(); + } + + /** + * {@inheritDoc} + */ + public Rectangle getBounds() { + Rectangle returnvalue = (Rectangle) getEventThreadQueuer() + .invokeAndWait("getBounds", //$NON-NLS-1$ + new IRunnable() { + public Object run() throws StepExecutionException { + return m_table.getBounds(); + } + }); + + return returnvalue; + } + + /** + * {@inheritDoc} + */ + public Rectangle getHeaderBounds(int col) { + Rectangle returnvalue = (Rectangle) getEventThreadQueuer() + .invokeAndWait("getHeaderBounds", //$NON-NLS-1$ + new IRunnable() { + public Object run() throws StepExecutionException { + return m_table.getTableHeader().getBounds(); + } + }); + + return returnvalue; + } + + /** + * {@inheritDoc} + */ + public Cell getSelectedCell() throws StepExecutionException { + + Cell returnvalue = (Cell) getEventThreadQueuer().invokeAndWait( + "getSelectedCell", new IRunnable() { //$NON-NLS-1$ + public Object run() { + + int row = m_table.getSelectedRow(); + int col = m_table.getSelectedColumn(); + if (log.isDebugEnabled()) { + log.debug("Selected row, col: " + row + ", " + col); //$NON-NLS-1$ //$NON-NLS-2$ + } + try { + checkRowColBounds(row, col); + } catch (StepExecutionException e) { + if ((e.getEvent() != null) + && (TestErrorEvent.INVALID_INDEX.equals( + e.getEvent() + .getProps().get(TestErrorEvent + .Property + .DESCRIPTION_KEY)))) { + // set "invalid index" to "no selection" -> better description! + throw new StepExecutionException("No selection", //$NON-NLS-1$ + EventFactory.createActionError( + TestErrorEvent.NO_SELECTION)); + } + throw e; + } + return new Cell(row, col); + } + }); + return returnvalue; + } + + /** + * {@inheritDoc} + */ + public boolean isHeaderVisible() { + Boolean returnvalue = (Boolean) getEventThreadQueuer().invokeAndWait( + "isHeaderVisible", new IRunnable() { //$NON-NLS-1$ + public Object run() { + if (m_table.getTableHeader() != null) { + return m_table.getTableHeader().isVisible() + ? Boolean.TRUE : Boolean.FALSE; + } + return Boolean.FALSE; + } + }); + return (boolean) returnvalue.booleanValue(); + } + + /** + * {@inheritDoc} + */ + public boolean isCellEditable(int row, int col) { + Boolean editable = (Boolean) getEventThreadQueuer().invokeAndWait( + "isCellEditable", //$NON-NLS-1$ + new IRunnable() { + public Object run() { + Cell cell = getSelectedCell(); + // see findBugs + return (m_table.isCellEditable(cell.getRow(), + cell.getCol())) ? Boolean.TRUE : Boolean.FALSE; + } + }); + return editable.booleanValue(); + } + + /** + * Checks wether <code>0 <= value < count</code>. + * + * @param value + * The value to check. + * @param count + * The upper bound. + */ + private void checkBounds(int value, int count) { + if ((value < 0) || (value >= count)) { + throw new StepExecutionException("Invalid row/column: " + value, //$NON-NLS-1$ + EventFactory.createActionError( + TestErrorEvent.INVALID_INDEX_OR_HEADER)); + } + } + + /** + * Checks if the passed row and column are inside the bounds of the JTable. + * + * @param row + * The row + * @param column + * The column + * @throws StepExecutionException + * If the row or the column is outside of the JTable's bounds. + */ + private void checkRowColBounds(int row, int column) + throws StepExecutionException { + checkBounds(row, m_table.getRowCount()); + checkBounds(column, m_table.getColumnCount()); + } + + /** + * {@inheritDoc} + */ + public boolean hasCellSelection() { + try { + getSelectedCell(); + } catch (StepExecutionException e) { + return false; + } + return true; + } + + /** + * {@inheritDoc} + */ + public Rectangle scrollCellToVisible(final int row, final int col) + throws StepExecutionException { + Rectangle bounds = (Rectangle) getEventThreadQueuer().invokeAndWait( + "getCellRect", //$NON-NLS-1$ + new IRunnable() { + public Object run() { + return m_table + .getCellRect(row, col, true); + } + }); + + getRobot().scrollToVisible(m_table, bounds); + return bounds; + } + + /** + * {@inheritDoc} + */ + public String getText() { + final Cell selectedCell = getSelectedCell(); + return getCellText(selectedCell.getRow(), selectedCell.getCol()); + } +} diff --git a/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/JTextComponentAdapter.java b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/JTextComponentAdapter.java new file mode 100644 index 000000000..75ed7a5d1 --- /dev/null +++ b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/JTextComponentAdapter.java @@ -0,0 +1,119 @@ +/******************************************************************************* + * 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.swing.swing.uiadapter; + +import javax.swing.text.JTextComponent; + +import org.eclipse.jubula.rc.common.driver.IRunnable; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.ITextComponentAdapter; +/** + * Implementation of the Interface <code>ITextComponentAdapter</code> as a + * adapter for the <code>JTextComponent</code> component. + * @author BREDEX GmbH + * + */ +public class JTextComponentAdapter extends WidgetAdapter + implements ITextComponentAdapter { + + /** */ + private JTextComponent m_textComponent; + + /** + * Creates an object with the adapted JTextComponent. + * @param objectToAdapt + */ + public JTextComponentAdapter(Object objectToAdapt) { + super(objectToAdapt); + m_textComponent = (JTextComponent) objectToAdapt; + } + + /** + * {@inheritDoc} + */ + public String getText() { + return m_textComponent.getText(); + } + + /** + * {@inheritDoc} + */ + public void setSelection(final int position) { + getEventThreadQueuer().invokeAndWait("setSelection", //$NON-NLS-1$ + new IRunnable() { + public Object run() { + m_textComponent.setCaretPosition(position); + return null; + } + }); + } + + /** + * {@inheritDoc} + */ + public void setSelection(final int start, final int end) { + getEventThreadQueuer().invokeAndWait("setSelection", //$NON-NLS-1$ + new IRunnable() { + public Object run() { + m_textComponent.setSelectionStart(start); + m_textComponent.setSelectionEnd(end); + return null; + } + }); + } + + /** + * {@inheritDoc} + */ + public String getSelectionText() { + String actual = (String)getEventThreadQueuer().invokeAndWait( + "getSelectionText", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return m_textComponent.getSelectedText(); + } + }); + return actual; + } + + /** + * {@inheritDoc} + */ + public void selectAll() { + getRobot().keyStroke(getRobot().getSystemModifierSpec() + " A"); //$NON-NLS-1$ + + if (!getText().equals(getSelectionText())) { + getEventThreadQueuer().invokeAndWait( + "selectAll", new IRunnable() { //$NON-NLS-1$ + public Object run() { + m_textComponent.selectAll(); + return null; + } + }); + } + + } + + + /** + * {@inheritDoc} + */ + public boolean isEditable() { + return ((Boolean) getEventThreadQueuer(). + invokeAndWait("isEditable", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return m_textComponent.isEditable() + && m_textComponent.isEnabled() + ? Boolean.TRUE : Boolean.FALSE; // see findBugs + } + })).booleanValue(); + } + + +} diff --git a/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/JTreeAdapter.java b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/JTreeAdapter.java new file mode 100644 index 000000000..cd0f716a5 --- /dev/null +++ b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/JTreeAdapter.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * 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.swing.swing.uiadapter; + +import javax.swing.JTree; + +//import org.eclipse.jubula.rc.common.driver.IRunnable; +import org.eclipse.jubula.rc.common.implclasses.tree.AbstractTreeOperationContext; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.ITreeAdapter; +import org.eclipse.jubula.rc.swing.swing.implclasses.TreeOperationContext; +/** + * Implementation of the Tree interface as an adapter for <code>JTree</code>. + * + * @author BREDEX GmbH + * + */ +public class JTreeAdapter extends WidgetAdapter implements ITreeAdapter { + + + /** + * Creates an object with the adapted JTree. + * @param objectToAdapt + */ + public JTreeAdapter(Object objectToAdapt) { + super(objectToAdapt); + } + + /** + * @return the casted Object + */ + private JTree getTable() { + return (JTree) getRealComponent(); + } + + /** + * {@inheritDoc} + */ + public AbstractTreeOperationContext getContext() { + TreeOperationContext context = new TreeOperationContext( + getEventThreadQueuer(), getRobot(), getTable()); + return context; + } + /** + * {@inheritDoc} + */ + public Object getRootNode() { + + return getTable().getModel().getRoot(); + } + /** + * {@inheritDoc} + */ + public boolean isRootVisible() { + return getTable().isRootVisible(); + } + +} diff --git a/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/WidgetAdapter.java b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/WidgetAdapter.java new file mode 100644 index 000000000..c91b5dc24 --- /dev/null +++ b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/WidgetAdapter.java @@ -0,0 +1,329 @@ +/******************************************************************************* + * 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.swing.swing.uiadapter; + + +import java.awt.AWTEvent; +import java.awt.Toolkit; + +import javax.swing.JComponent; + +import org.eclipse.jubula.rc.common.caps.AbstractMenuCAPs; +import org.eclipse.jubula.rc.common.driver.ClickOptions; +import org.eclipse.jubula.rc.common.driver.DragAndDropHelper; +import org.eclipse.jubula.rc.common.driver.IEventThreadQueuer; +import org.eclipse.jubula.rc.common.driver.IRobot; +import org.eclipse.jubula.rc.common.driver.IRunnable; +import org.eclipse.jubula.rc.common.driver.RobotTiming; +import org.eclipse.jubula.rc.common.exception.RobotException; +import org.eclipse.jubula.rc.common.exception.StepExecutionException; +import org.eclipse.jubula.rc.common.listener.EventLock; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.IWidgetAdapter; +import org.eclipse.jubula.rc.swing.swing.caps.CapUtil; +import org.eclipse.jubula.rc.swing.swing.caps.JMenuBarCAPs; +import org.eclipse.jubula.rc.swing.swing.caps.CapUtil.PopupShownCondition; +import org.eclipse.jubula.rc.swing.swing.driver.KeyCodeConverter; +import org.eclipse.jubula.rc.swing.swing.implclasses.EventListener; +import org.eclipse.jubula.tools.constants.TimeoutConstants; +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; +/** + * Implements the interface for widgets and supports basic methods + * which are needed for nearly all Swing ui components. + * This is a basic adaption for <code>JComponent</code>. + * + * @author BREDEX GmbH + */ +public abstract class WidgetAdapter extends AbstractComponentAdapter + implements IWidgetAdapter { + + /** constants for communication */ + protected static final String POS_UNIT_PIXEL = "Pixel"; //$NON-NLS-1$ + /** constants for communication */ + protected static final String POS_UNI_PERCENT = "Percent"; //$NON-NLS-1$ + + + + + + /** */ + private JComponent m_component; + + /** + * Used to store the component into the adapter. + * @param objectToAdapt + */ + protected WidgetAdapter(Object objectToAdapt) { + m_component = (JComponent) objectToAdapt; + } + + /** + * {@inheritDoc} + */ + public Object getRealComponent() { + return m_component; + } + + /** + * Gets the IEventThreadQueuer. + * + * @return The Robot + * @throws RobotException + * If the Robot cannot be created. + */ + protected IRobot getRobot() throws RobotException { + return getRobotFactory().getRobot(); + } + /** + * @return The event thread queuer. + */ + public IEventThreadQueuer getEventThreadQueuer() { + return getRobotFactory().getEventThreadQueuer(); + } + + /** + * {@inheritDoc} + */ + public String getPropteryValue(final String propertyname) { + Object prop = getEventThreadQueuer().invokeAndWait("getProperty", //$NON-NLS-1$ + new IRunnable() { + public Object run() throws StepExecutionException { + try { + return getRobot().getPropertyValue( + getRealComponent(), propertyname); + } catch (RobotException e) { + throw new StepExecutionException( + e.getMessage(), + EventFactory.createActionError( + TestErrorEvent.PROPERTY_NOT_ACCESSABLE)); + } + } + }); + return String.valueOf(prop); + } + + /** + * {@inheritDoc} + */ + public boolean isShowing() { + Boolean returnvalue = (Boolean) getEventThreadQueuer().invokeAndWait( + "isShowing", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return m_component.isShowing() + ? Boolean.TRUE : Boolean.FALSE; + } + }); + return (boolean) returnvalue.booleanValue(); + } + + /** + * {@inheritDoc} + */ + public boolean hasFocus() { + Boolean returnvalue = (Boolean) getEventThreadQueuer().invokeAndWait( + "hasFocus", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return m_component.hasFocus() + ? Boolean.TRUE : Boolean.FALSE; + } + }); + return (boolean) returnvalue.booleanValue(); + } + + /** + * {@inheritDoc} + */ + public boolean isEnabled() { + Boolean returnvalue = (Boolean) getEventThreadQueuer().invokeAndWait( + "isEnabled", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return m_component.isEnabled() + ? Boolean.TRUE : Boolean.FALSE; + } + }); + return (boolean) returnvalue.booleanValue(); + } + + /** + * {@inheritDoc} + */ + public AbstractMenuCAPs showPopup(final int button) { + final Object component = m_component; + Runnable showPopup = new Runnable() { + public void run() { + RobotTiming.sleepPreShowPopupDelay(); + ClassLoader oldCl = Thread.currentThread() + .getContextClassLoader(); + Thread.currentThread().setContextClassLoader(component + .getClass().getClassLoader()); + if ((getRobot()).isMouseInComponent(component)) { + getRobot().clickAtCurrentPosition( + component, 1, button); + } else { + getRobot().click(component, null, + ClickOptions.create() + .setClickCount(1) + .setMouseButton(button)); + } + Thread.currentThread().setContextClassLoader(oldCl); + } + }; + + return showPopup(showPopup); + } + + /** + * {@inheritDoc} + */ + public AbstractMenuCAPs showPopup( + final int xPos, final String xUnits, + final int yPos, final String yUnits, final int button) + throws StepExecutionException { + final Object component = m_component; + Runnable showPopup = new Runnable() { + public void run() { + RobotTiming.sleepPreShowPopupDelay(); + boolean isAbsoluteCoordinatesX = + xUnits.equalsIgnoreCase(POS_UNIT_PIXEL); + boolean isAbsoluteCoordinatesY = + yUnits.equalsIgnoreCase(POS_UNIT_PIXEL); + getRobot().click(component, null, + ClickOptions.create().setMouseButton(button), + xPos, isAbsoluteCoordinatesX, + yPos, isAbsoluteCoordinatesY); + } + }; + return showPopup(showPopup); + } + + /** + * Shows a popup menu using the given runnable and waits for the popup + * menu to appear. + * + * @param showPopupOperation The implementation to use for opening the + * popup menu. + * @return the popup menu. + */ + public AbstractMenuCAPs showPopup(Runnable showPopupOperation) { + PopupShownCondition cond = new PopupShownCondition(); + EventLock lock = new EventLock(); + EventListener listener = new EventListener(lock, cond); + Toolkit.getDefaultToolkit().addAWTEventListener(listener, + AWTEvent.CONTAINER_EVENT_MASK); + + // showPopupOperation must run in the current thread in order to + // avoid a race condition. + showPopupOperation.run(); + + synchronized (lock) { + try { + long timeout = TimeoutConstants.SERVER_TIMEOUT_WAIT_FOR_POPUP; + long done = System.currentTimeMillis() + timeout; + long now; + while ((!lock.isReleased() || (cond.getPopup() == null) + || !cond.getPopup().isShowing()) + && (timeout > 0)) { + lock.wait(timeout); + now = System.currentTimeMillis(); + timeout = done - now; + } + } catch (InterruptedException e) { + // ignore + } finally { + Toolkit.getDefaultToolkit().removeAWTEventListener(listener); + } + } + if (!lock.isReleased() || (cond.getPopup() == null) + || !cond.getPopup().isShowing()) { + throw new StepExecutionException("popup not shown", //$NON-NLS-1$ + EventFactory.createActionError( + TestErrorEvent.POPUP_NOT_FOUND)); + } + AbstractMenuCAPs menuCAPs = new JMenuBarCAPs(); + menuCAPs.setComponent(cond.getPopup()); + return menuCAPs; + } + + /** + * {@inheritDoc} + */ + public void showToolTip(final String text, final int textSize, + final int timePerWord, final int windowWidth) { + throw new StepExecutionException( + I18n.getString(TestErrorEvent.UNSUPPORTED_OPERATION_ERROR), + EventFactory.createActionError( + TestErrorEvent.UNSUPPORTED_OPERATION_ERROR)); + } + + /** + * {@inheritDoc} + */ + public void gdDrag(int mouseButton, String modifier, int xPos, + String xUnits, int yPos, String yUnits) { + final DragAndDropHelper dndHelper = DragAndDropHelper.getInstance(); + dndHelper.setMouseButton(mouseButton); + dndHelper.setModifier(modifier); + final IRobot robot = getRobot(); + clickDirect(0, mouseButton, xPos, xUnits, yPos, yUnits); + CapUtil.pressOrReleaseModifiers(modifier, true); + robot.mousePress(null, null, mouseButton); + } + + + /** + * {@inheritDoc} + */ + public void gdDrop(int xPos, String xUnits, int yPos, String yUnits, + int delayBeforeDrop) { + + final DragAndDropHelper dndHelper = DragAndDropHelper.getInstance(); + final String modifier = dndHelper.getModifier(); + final int mouseButton = dndHelper.getMouseButton(); + try { + clickDirect(0, mouseButton, xPos, xUnits, yPos, yUnits); + TimeUtil.delay(delayBeforeDrop); + } finally { + getRobot().mouseRelease(null, null, mouseButton); + CapUtil.pressOrReleaseModifiers(modifier, false); + } + } + + /** + * clicks into the component. + * + * @param count amount of clicks + * @param button what mouse button should be used + * @param xPos what x position + * @param xUnits should x position be pixel or percent values + * @param yPos what y position + * @param yUnits should y position be pixel or percent values + * @throws StepExecutionException error + */ + private void clickDirect(int count, int button, int xPos, String xUnits, + int yPos, String yUnits) throws StepExecutionException { + + getRobot().click(m_component, null, + ClickOptions.create() + .setClickCount(count) + .setMouseButton(button), + xPos, xUnits.equalsIgnoreCase(POS_UNIT_PIXEL), + yPos, yUnits.equalsIgnoreCase(POS_UNIT_PIXEL)); + } + + /** + * {@inheritDoc} + */ + public int getKeyCode(String mod) { + return KeyCodeConverter.getKeyCode(mod); + } +} diff --git a/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/factory/SwingAdapterFactory.java b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/factory/SwingAdapterFactory.java new file mode 100644 index 000000000..68c690766 --- /dev/null +++ b/org.eclipse.jubula.rc.swing/src/org/eclipse/jubula/rc/swing/swing/uiadapter/factory/SwingAdapterFactory.java @@ -0,0 +1,119 @@ +/******************************************************************************* + * 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.swing.swing.uiadapter.factory; + + +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; +import javax.swing.JRadioButton; +import javax.swing.JTabbedPane; +import javax.swing.JTable; +import javax.swing.JTree; +import javax.swing.text.JTextComponent; + +import org.eclipse.jubula.rc.common.uiadapter.factory.IUIAdapterFactory; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.IComponentAdapter; +import org.eclipse.jubula.rc.swing.swing.uiadapter.AbstractButtonAdapter; +import org.eclipse.jubula.rc.swing.swing.uiadapter.JComboBoxAdapter; +import org.eclipse.jubula.rc.swing.swing.uiadapter.JLabelAdapter; +import org.eclipse.jubula.rc.swing.swing.uiadapter.JListAdapter; +import org.eclipse.jubula.rc.swing.swing.uiadapter.JMenuBarAdapter; +import org.eclipse.jubula.rc.swing.swing.uiadapter.JMenuItemAdapter; +import org.eclipse.jubula.rc.swing.swing.uiadapter.JPopupMenuAdapter; +import org.eclipse.jubula.rc.swing.swing.uiadapter.JTabbedPaneAdapter; +import org.eclipse.jubula.rc.swing.swing.uiadapter.JTableAdapter; +import org.eclipse.jubula.rc.swing.swing.uiadapter.JTextComponentAdapter; +import org.eclipse.jubula.rc.swing.swing.uiadapter.JTreeAdapter; +/** + * This is the adapter factory for all swing components. It is + * creating the specific adapter for a swing component. + * + * Since we are using adapter here, it is a adapter factory. But this must not + * be the case. It is only relevant that the object is implementing the + * specific interface. + * @author BREDEX GmbH + * + */ +public class SwingAdapterFactory implements IUIAdapterFactory { + /** + * + */ + private static final Class[] SUPPORTEDCLASSES = new Class[] { + JButton.class, JCheckBox.class, JRadioButton.class, + JMenuBar.class, JMenuItem.class, JTree.class , + JCheckBox.class, JRadioButton.class, JTable.class, JPopupMenu.class, + JList.class, JTextComponent.class, JComboBox.class, + JLabel.class , JTabbedPane.class}; + + /** + * {@inheritDoc} + */ + public Class[] getSupportedClasses() { + + return SUPPORTEDCLASSES; + } + /** + * {@inheritDoc} + */ + public IComponentAdapter getAdapter(Object objectToAdapt) { + IComponentAdapter returnvalue = null; + if (objectToAdapt instanceof JButton) { + returnvalue = new AbstractButtonAdapter(objectToAdapt); + + } else if (objectToAdapt instanceof JRadioButton) { + returnvalue = new AbstractButtonAdapter(objectToAdapt); + + } else if (objectToAdapt instanceof JCheckBox) { + returnvalue = new AbstractButtonAdapter(objectToAdapt); + + } else if (objectToAdapt instanceof JMenuBar) { + + returnvalue = new JMenuBarAdapter(objectToAdapt); + + } else if (objectToAdapt instanceof JMenuItem) { + returnvalue = new JMenuItemAdapter(objectToAdapt); + + } else if (objectToAdapt instanceof JTree) { + returnvalue = new JTreeAdapter(objectToAdapt); + + } else if (objectToAdapt instanceof JTable) { + returnvalue = new JTableAdapter(objectToAdapt); + + } else if (objectToAdapt instanceof JList) { + returnvalue = new JListAdapter(objectToAdapt); + + } else if (objectToAdapt instanceof JPopupMenu) { + returnvalue = new JPopupMenuAdapter(objectToAdapt); + + } else if (objectToAdapt instanceof JTextComponent) { + returnvalue = new JTextComponentAdapter(objectToAdapt); + + } else if (objectToAdapt instanceof JComboBox) { + returnvalue = new JComboBoxAdapter(objectToAdapt); + + } else if (objectToAdapt instanceof JLabel) { + returnvalue = new JLabelAdapter(objectToAdapt); + + } else if (objectToAdapt instanceof JTabbedPane) { + returnvalue = new JTabbedPaneAdapter(objectToAdapt); + + } + + return returnvalue; + } + +} diff --git a/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/SwtAUTServer.java b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/SwtAUTServer.java index 23c55e44b..cd040450a 100644 --- a/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/SwtAUTServer.java +++ b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/SwtAUTServer.java @@ -15,6 +15,7 @@ import java.lang.reflect.InvocationTargetException; import org.eclipse.jubula.rc.common.AUTServer; import org.eclipse.jubula.rc.common.driver.IRobot; import org.eclipse.jubula.rc.common.listener.BaseAUTListener; +import org.eclipse.jubula.rc.common.uiadapter.factory.GUIAdapterFactoryRegistry; import org.eclipse.jubula.rc.swt.driver.RobotFactoryConfig; import org.eclipse.jubula.rc.swt.driver.RobotFactorySwtImpl; import org.eclipse.jubula.rc.swt.driver.RobotSwtImpl; @@ -25,6 +26,7 @@ import org.eclipse.jubula.rc.swt.listener.FocusTracker; import org.eclipse.jubula.rc.swt.listener.MappingListener; import org.eclipse.jubula.rc.swt.listener.RecordListener; import org.eclipse.jubula.rc.swt.listener.TableSelectionTracker; +import org.eclipse.jubula.rc.swt.uiadapter.factory.SWTAdapterFactory; import org.eclipse.jubula.tools.constants.AUTServerExitConstants; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Listener; @@ -214,7 +216,11 @@ public class SwtAUTServer extends AUTServer { */ protected void startTasks() throws ExceptionInInitializerError, InvocationTargetException, NoSuchMethodException { - + + // FIXME Better place to put the registration of the factory + GUIAdapterFactoryRegistry.getInstance(). + registerFactory(new SWTAdapterFactory()); + super.invokeAUT(); if (getCommunicator() != null) { getCommunicator().close(); diff --git a/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/caps/ButtonCAPs.java b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/caps/ButtonCAPs.java new file mode 100644 index 000000000..d7ffdbde4 --- /dev/null +++ b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/caps/ButtonCAPs.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * 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.caps; + + +import org.eclipse.jubula.rc.common.caps.AbstractButtonCAPs; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.IButtonAdapter; +import org.eclipse.jubula.rc.swt.utils.SwtUtils; + + +/** + * The Toolkit specific implementation for <code>SWTButton</code> and subclasses. + * + * @author BREDEX GmbH + */ +public class ButtonCAPs extends AbstractButtonCAPs { + + /** + * {@inheritDoc} + */ + public String[] getTextArrayFromComponent() { + return new String[] { + SwtUtils.removeMnemonics( + ((IButtonAdapter)getComponent()).getText())}; + } + +}
\ No newline at end of file diff --git a/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/caps/CAPUtil.java b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/caps/CAPUtil.java new file mode 100644 index 000000000..c8d1f619d --- /dev/null +++ b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/caps/CAPUtil.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * 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.caps; + +import java.awt.Point; +import java.util.StringTokenizer; + +import org.eclipse.jubula.rc.common.AUTServer; +import org.eclipse.jubula.rc.common.driver.IRobot; +import org.eclipse.jubula.rc.common.exception.RobotException; +import org.eclipse.jubula.rc.common.util.KeyStrokeUtil; +import org.eclipse.jubula.rc.swt.driver.KeyCodeConverter; +import org.eclipse.jubula.rc.swt.driver.SwtRobot; +import org.eclipse.jubula.tools.utils.EnvironmentUtils; +import org.eclipse.swt.widgets.Display; +/** + * Util class for some swt specific commands. + * + * @author BREDEX GmbH + */ +public class CAPUtil { + + + /** + * + */ + private CAPUtil() { } + + + /** + * Gets the Robot. + * @return The Robot + * @throws RobotException If the Robot cannot be created. + */ + public static IRobot getRobot() throws RobotException { + return AUTServer.getInstance().getRobot(); + } + + /** + * Move the mouse pointer from its current position to a few points in + * its proximity. This is used to initiate a drag operation. + * + */ + public static void shakeMouse() { + /** number of pixels by which a "mouse shake" offsets the mouse cursor */ + final int mouseShakeOffset = 10; + + Point origin = getRobot().getCurrentMousePosition(); + SwtRobot lowLevelRobot = new SwtRobot(Display.getDefault()); + lowLevelRobot.mouseMove( + origin.x + mouseShakeOffset, + origin.y + mouseShakeOffset); + lowLevelRobot.mouseMove( + origin.x - mouseShakeOffset, + origin.y - mouseShakeOffset); + lowLevelRobot.mouseMove(origin.x, origin.y); + if (!EnvironmentUtils.isWindowsOS() + && !EnvironmentUtils.isMacOS()) { + boolean moreEvents = true; + while (moreEvents) { + moreEvents = Display.getDefault().readAndDispatch(); + } + } + } + + /** + * Presses or releases the given modifier. + * @param modifier the modifier. + * @param press if true, the modifier will be pressed. + * if false, the modifier will be released. + */ + public static void pressOrReleaseModifiers(String modifier, boolean press) { + final IRobot robot = getRobot(); + final StringTokenizer modTok = new StringTokenizer( + KeyStrokeUtil.getModifierString(modifier), " "); //$NON-NLS-1$ + while (modTok.hasMoreTokens()) { + final String mod = modTok.nextToken(); + final int keyCode = KeyCodeConverter.getKeyCode(mod); + if (press) { + robot.keyPress(null, keyCode); + } else { + robot.keyRelease(null, keyCode); + } + } + } + + +} diff --git a/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/caps/ListCAPs.java b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/caps/ListCAPs.java new file mode 100644 index 000000000..c6075b560 --- /dev/null +++ b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/caps/ListCAPs.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * 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.caps; + +import org.eclipse.jubula.rc.common.caps.AbstractListCAPs; +import org.eclipse.jubula.rc.swt.utils.SwtUtils; +/** + * + * @author BREDEX GmbH + * + */ +public class ListCAPs extends AbstractListCAPs { + + + /** + * {@inheritDoc} + */ + protected int getSystemDefaultModifier() { + return SwtUtils.getSystemDefaultModifier(); + } + +} diff --git a/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/caps/MenuCAPs.java b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/caps/MenuCAPs.java new file mode 100644 index 000000000..32e82c836 --- /dev/null +++ b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/caps/MenuCAPs.java @@ -0,0 +1,305 @@ +/******************************************************************************* + * 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.caps; + +import org.apache.commons.lang.Validate; +import org.eclipse.jubula.rc.common.caps.AbstractMenuCAPs; +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.implclasses.IBaseImplementationClass; +import org.eclipse.jubula.rc.common.implclasses.MenuUtilBase; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.IComponentAdapter; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.IMenuAdapter; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.IMenuItemAdapter; +import org.eclipse.jubula.rc.swt.driver.EventThreadQueuerSwtImpl; +import org.eclipse.jubula.rc.swt.driver.RobotSwtImpl; +import org.eclipse.jubula.rc.swt.uiadapter.MenuItemAdapter; +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.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 MenuCAPs extends AbstractMenuCAPs + implements IBaseImplementationClass { + + + /** Test variable for contextMenus*/ + private boolean m_isCM = false; + + + /** + * @return The event thread queuer. + */ + public IEventThreadQueuer getEventThreadQueuer() { + return getRobotFactory().getEventThreadQueuer(); + } + + /** + * {@inheritDoc} + */ + public IComponentAdapter 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() { //$NON-NLS-1$ + public Object 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 IMenuAdapter 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 IMenuItemAdapter newMenuItemAdapter(Object component) { + return new MenuItemAdapter(component); + } + + /** + * {@inheritDoc} + */ + protected void closeMenu(IMenuAdapter menuBar, int[] path) { + Validate.notNull(getMenu(menuBar)); + closeMenu(menuBar, path.length); + + } + + /** + * {@inheritDoc} + */ + protected void closeMenu(IMenuAdapter 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 IMenuAdapter 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 IMenuAdapter 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; + } + } + +} diff --git a/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/caps/TableCAPs.java b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/caps/TableCAPs.java new file mode 100644 index 000000000..23d8876e3 --- /dev/null +++ b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/caps/TableCAPs.java @@ -0,0 +1,714 @@ +/******************************************************************************* + * 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.caps; + +import java.awt.Point; +import java.awt.Rectangle; + +import org.eclipse.jubula.rc.common.CompSystemConstants; +import org.eclipse.jubula.rc.common.caps.AbstractTableCAPs; +import org.eclipse.jubula.rc.common.driver.ClickOptions; +import org.eclipse.jubula.rc.common.driver.IEventThreadQueuer; +import org.eclipse.jubula.rc.common.driver.IRobot; +import org.eclipse.jubula.rc.common.driver.IRunnable; +import org.eclipse.jubula.rc.common.exception.StepExecutionException; +import org.eclipse.jubula.rc.common.implclasses.table.Cell; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.ITableAdapter; +import org.eclipse.jubula.rc.swt.driver.DragAndDropHelperSwt; +import org.eclipse.jubula.rc.swt.uiadapter.TableAdapter; +import org.eclipse.jubula.rc.swt.utils.SwtUtils; +import org.eclipse.jubula.tools.constants.InputConstants; +import org.eclipse.jubula.tools.objects.event.EventFactory; +import org.eclipse.jubula.tools.objects.event.TestErrorEvent; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.FontMetrics; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Item; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.swt.widgets.TableItem; +import org.eclipse.swt.widgets.Widget; +/** + * Toolkit specific commands for the <code>Table</code> + * + * @author BREDEX GmbH + */ +public class TableCAPs extends AbstractTableCAPs { + + + /** + * Gets the real table component + * @return the table + */ + private Table getTable() { + return (Table)getComponent().getRealComponent(); + } + + /** + * @return The event thread queuer. + */ + public IEventThreadQueuer getEventThreadQueuer() { + return getRobotFactory().getEventThreadQueuer(); + } + + /** + * {@inheritDoc} + */ + public String[] getTextArrayFromComponent() { + final String[] componentTextArray; + Item[] itemArray = getTable().getColumns(); + componentTextArray = getTextArrayFromItemArray(itemArray); + return componentTextArray; + } + + /** + * {@inheritDoc} + */ + protected Object setEditorToReplaceMode(Object editor, boolean replace) { + if (replace) { + getRobot().clickAtCurrentPosition(editor, 3, + InputConstants.MOUSE_BUTTON_LEFT); + } else { + getRobot().clickAtCurrentPosition(editor, 1, + InputConstants.MOUSE_BUTTON_LEFT); + } + return editor; + } + + /** + * {@inheritDoc} + */ + protected Object activateEditor(Cell cell, Rectangle rectangle) { + TableAdapter table = (TableAdapter) getComponent(); + return table.activateEditor(cell); + } + + /** + * {@inheritDoc} + */ + protected Rectangle scrollCellToVisible(final int row, final int col) + throws StepExecutionException { + final Table table = getTable(); + getEventThreadQueuer().invokeAndWait("scrollCellToVisible", //$NON-NLS-1$ + new IRunnable() { + public Object run() { + if (table.getColumnCount() > 0 || col > 0) { + table.showColumn(table.getColumn(col)); + } + table.showItem(table.getItem(row)); + return null; + } + }); + + final Rectangle cellBoundsRelativeToParent = getCellBounds(row, col); + + getEventThreadQueuer().invokeAndWait("getCellBoundsRelativeToParent", //$NON-NLS-1$ + new IRunnable() { + public Object run() { + org.eclipse.swt.graphics.Point cellOriginRelativeToParent = + table.getDisplay().map( + table, table.getParent(), + new org.eclipse.swt.graphics.Point( + cellBoundsRelativeToParent.x, + cellBoundsRelativeToParent.y)); + cellBoundsRelativeToParent.x = + cellOriginRelativeToParent.x; + cellBoundsRelativeToParent.y = + cellOriginRelativeToParent.y; + return null; + } + }); + + Control parent = (Control)getEventThreadQueuer().invokeAndWait("getParent", //$NON-NLS-1$ + new IRunnable() { + public Object run() { + table.getParent(); + return null; + } + }); + + + getRobot().scrollToVisible( + parent, cellBoundsRelativeToParent); + + return getVisibleBounds(getCellBounds(row, col)); + } + + /** + * {@inheritDoc} + */ + protected int getExtendSelectionModifier() { + return SWT.MOD1; + } + + /** + * {@inheritDoc} + */ + protected Cell getCellAtMousePosition() throws StepExecutionException { + + final Table table = getTable(); + final Point awtMousePos = getRobot().getCurrentMousePosition(); + Cell returnvalue = (Cell) getEventThreadQueuer().invokeAndWait( + "getCellAtMousePosition", //$NON-NLS-1$ + new IRunnable() { + public Object run() throws StepExecutionException { + Cell cell = null; + final int itemCount = table.getItemCount(); + for (int rowCount = table.getTopIndex(); + rowCount < itemCount; rowCount++) { + if (cell != null) { + break; + } + final int columnCount = table.getColumnCount(); + if (columnCount > 0) { + for (int col = 0; col < columnCount; col++) { + final Rectangle itemBounds = getCellBounds( + rowCount, col); + final org.eclipse.swt.graphics.Point + absItemBounds = table + .toDisplay(itemBounds.x, + itemBounds.y); + final Rectangle absRect = new Rectangle( + absItemBounds.x, absItemBounds.y, + itemBounds.width, + itemBounds.height); + if (absRect.contains(awtMousePos)) { + cell = new Cell(rowCount, col); + break; + } + } + } else { + final Rectangle itemBounds = getCellBounds( + rowCount, 0); + final org.eclipse.swt.graphics.Point + absItemBounds = table + .toDisplay(itemBounds.x, itemBounds.y); + final Rectangle absRect = new Rectangle( + absItemBounds.x, absItemBounds.y, + itemBounds.width, itemBounds.height); + if (absRect.contains(awtMousePos)) { + cell = new Cell(rowCount, 0); + } + } + } + if (cell == null) { + throw new StepExecutionException( + "No cell under mouse position found!", //$NON-NLS-1$ + EventFactory + .createActionError( + TestErrorEvent.NOT_FOUND)); + } + return cell; + } + }); + return returnvalue; + } + + /** + * {@inheritDoc} + */ + protected boolean isMouseOnHeader() { + final Table table = getTable(); + final ITableAdapter adapter = (ITableAdapter)getComponent(); + Boolean isVisible; + isVisible = (Boolean)getEventThreadQueuer().invokeAndWait( + "isMouseOnHeader", //$NON-NLS-1$ + new IRunnable() { + public Object run() { + return new Boolean(table.getHeaderVisible()); + } + }); + + if (!(isVisible.booleanValue())) { + return false; + } + + Boolean isOnHeader = new Boolean(false); + isOnHeader = (Boolean)getEventThreadQueuer().invokeAndWait( + "isMouseOnHeader", //$NON-NLS-1$ + new IRunnable() { + public Object run() { + final Point awtMousePos = getRobot() + .getCurrentMousePosition(); + org.eclipse.swt.graphics.Point mousePos = + new org.eclipse.swt.graphics.Point( + awtMousePos.x, awtMousePos.y); + + for (int j = 0; j < table.getColumnCount(); j++) { + final Rectangle constraints = + adapter.getHeaderBounds(j); + + org.eclipse.swt.graphics.Rectangle bounds = + SwtUtils.getWidgetBounds( + table); + + if (constraints != null) { + // Use SWT's mapping function, if possible, as it is more + // multi-platform than simply adding the x and y values. + org.eclipse.swt.graphics.Point + convertedLocation = getConvertedLocation( + constraints); + bounds.x = convertedLocation.x; + bounds.y = convertedLocation.y; + + bounds.height = constraints.height; + bounds.width = constraints.width; + } + + if (bounds.contains(mousePos)) { + return new Boolean(true); + } + } + return new Boolean(false); + } + }); + + return isOnHeader.booleanValue(); + } + + /** + * Returns an array of representation strings that corresponds to the given + * array of items or null if the given array is null; + * @param itemArray the item array whose item texts have to be read + * @return array of item texts corresponding to the given item array + */ + protected final String[] getTextArrayFromItemArray(Item[] itemArray) { + final String[] itemTextArray; + if (itemArray == null) { + itemTextArray = null; + } else { + itemTextArray = new String[itemArray.length]; + for (int i = 0; i < itemArray.length; i++) { + Item item = itemArray[i]; + if (item == null) { + itemTextArray[i] = null; + } else { + itemTextArray[i] = SwtUtils.removeMnemonics(item.getText()); + } + } + } + + return itemTextArray; + } + + /** + * Computes the visible cellBounds inside the visible bounds of the table.<br> + * The result is the intersection of the visible bounds of the table and the + * bounds of the cell. + * @param cellBounds the bounds of the cell to click in. These bounds must + * be relative to the table's location. + * @return the visible cell bounds, relative to the table's location. + */ + private Rectangle getVisibleBounds(Rectangle cellBounds) { + org.eclipse.swt.graphics.Rectangle r = + (org.eclipse.swt.graphics.Rectangle) + getEventThreadQueuer().invokeAndWait("getVisibleCellBounds: " + cellBounds, //$NON-NLS-1$ + new IRunnable() { + + public Object run() { + return getTable().getClientArea(); + } + }); + + Rectangle visibleTableBounds = new Rectangle( + r.x, r.y, r.width, r.height); + Rectangle visibleCellBounds = + visibleTableBounds.intersection(cellBounds); + return visibleCellBounds; + } + + /** + * @param constraints Rectangle + * @return converted Location of table + */ + private org.eclipse.swt.graphics.Point getConvertedLocation( + final Rectangle constraints) { + org.eclipse.swt.graphics.Point convertedLocation = + (org.eclipse.swt.graphics.Point)getEventThreadQueuer() + .invokeAndWait("toDisplay", new IRunnable() { //$NON-NLS-1$ + public Object run() throws StepExecutionException { + return getTable().toDisplay( + constraints.x, constraints.y); + } + }); + return convertedLocation; + } + + /** + * + * @param row The row of the cell + * @param col The column of the cell + * @return The bounding rectangle for the cell, relative to the table's + * location. + */ + private Rectangle getCellBounds(final int row, final int col) { + final Table table = getTable(); + Rectangle cellBounds = (Rectangle)getEventThreadQueuer().invokeAndWait( + "evaluateCellBounds", //$NON-NLS-1$ + new IRunnable() { + public Object run() { + checkRowColBounds(row, col); + TableItem ti = table.getItem(row); + int column = (table.getColumnCount() > 0 || col > 0) + ? col : 0; + org.eclipse.swt.graphics.Rectangle r = + ti.getBounds(column); + String text = ti.getText(column); + Image image = ti.getImage(column); + if (text != null && text.length() != 0) { + GC gc = new GC(table); + int charWidth = 0; + try { + FontMetrics fm = gc.getFontMetrics(); + charWidth = fm.getAverageCharWidth(); + } finally { + gc.dispose(); + } + r.width = text.length() * charWidth; + if (image != null) { + r.width += image.getBounds().width; + } + } else if (image != null) { + r.width = image.getBounds().width; + } + if (column > 0) { + TableColumn tc = table.getColumn(column); + int alignment = tc.getAlignment(); + if (alignment == SWT.CENTER) { + r.x += ((double)tc.getWidth() / 2) + - ((double)r.width / 2); + } + if (alignment == SWT.RIGHT) { + r.x += tc.getWidth() - r.width; + } + } + + return new Rectangle(r.x, r.y, r.width, r.height); + } + }); + return cellBounds; + } + /** + * {@inheritDoc} + */ + protected Object getSpecificRectangle(Rectangle rectangle) { + return new org.eclipse.swt.graphics.Rectangle(rectangle.x, rectangle.y, + rectangle.width, rectangle.height); + } + + /** + * {@inheritDoc} + */ + public void gdClickDirect(int count, int button, int xPos, String xUnits, + int yPos, String yUnits) throws StepExecutionException { + + int correctedYPos = correctYPos(yPos, yUnits); + super.gdClickDirect(count, button, xPos, xUnits, correctedYPos, yUnits); + } + + /** + * Corrects the given Y position based on the height of the table's header. + * This ensures, for example, that test steps don't try to click within the + * table header (where we receive no confirmation events). + * + * @param pos The Y position to correct. + * @param units The units used for the Y position. + * @return The corrected Y position. + */ + private int correctYPos(int pos, String units) { + int correctedPos = pos; + int headerHeight = ((Integer)getEventThreadQueuer().invokeAndWait( + "getHeaderHeight", new IRunnable() { //$NON-NLS-1$ + + public Object run() throws StepExecutionException { + return new Integer( + ((Table)getComponent().getRealComponent()) + .getHeaderHeight()); + } + + })).intValue(); + + if (POS_UNIT_PIXEL.equalsIgnoreCase(units)) { + // Pixel units + correctedPos += headerHeight; + } else { + // Percentage units + int totalHeight = ((Integer)getEventThreadQueuer().invokeAndWait( + "getWidgetBounds", new IRunnable() { //$NON-NLS-1$ + + public Object run() throws StepExecutionException { + return new Integer( + SwtUtils.getWidgetBounds( + (Widget) getComponent(). + getRealComponent()).height); + } + + })).intValue(); + long targetHeight = totalHeight - headerHeight; + long targetPos = Math.round((double)targetHeight * (double)pos + / 100.0); + targetPos += headerHeight; + double heightPercentage = + (double)targetPos / (double)totalHeight * 100.0; + correctedPos = (int)Math.round(heightPercentage); + if (correctedPos > 100) { // rounding error + correctedPos = 100; + } + } + return correctedPos; + } + + /** + * Drags the cell of the Table.<br> + * With the xPos, yPos, xunits and yUnits the click position inside the + * cell can be defined. + * + * @param mouseButton the mouseButton. + * @param modifier the modifier. + * @param row The row of the cell. + * @param rowOperator the row header operator + * @param col The column of the cell. + * @param colOperator the column header operator + * @param xPos what x position + * @param xUnits should x position be pixel or percent values + * @param yPos what y position + * @param yUnits should y position be pixel or percent values + * @throws StepExecutionException + * If the row or the column is invalid + */ + public void gdDragCell(final int mouseButton, final String modifier, + final String row, String rowOperator, final String col, + final String colOperator, final int xPos, final String xUnits, + final int yPos, final String yUnits) + throws StepExecutionException { + + final DragAndDropHelperSwt dndHelper = DragAndDropHelperSwt + .getInstance(); + dndHelper.setMouseButton(mouseButton); + dndHelper.setModifier(modifier); + dndHelper.setDragComponent(null); + + gdSelectCell(row, rowOperator, col, colOperator, 0, xPos, + xUnits, yPos, yUnits, + CompSystemConstants.EXTEND_SELECTION_NO, 1); + } + + /** + * Drops on the cell of the JTable.<br> + * With the xPos, yPos, xunits and yUnits the click position inside the + * cell can be defined. + * + * @param row The row of the cell. + * @param rowOperator The row operator + * @param col The column of the cell. + * @param colOperator The column operator + * @param xPos what x position + * @param xUnits should x position be pixel or percent values + * @param yPos what y position + * @param yUnits should y position be pixel or percent values + * @param delayBeforeDrop the amount of time (in milliseconds) to wait + * between moving the mouse to the drop point and + * releasing the mouse button + * @throws StepExecutionException + * If the row or the column is invalid + */ + public void gdDropCell(final String row, final String rowOperator, + final String col, final String colOperator, final int xPos, + final String xUnits, final int yPos, final String yUnits, + int delayBeforeDrop) throws StepExecutionException { + + final DragAndDropHelperSwt dndHelper = DragAndDropHelperSwt + .getInstance(); + final IRobot robot = getRobot(); + + pressOrReleaseModifiers(dndHelper.getModifier(), true); + try { + getEventThreadQueuer().invokeAndWait("gdDropCell", new IRunnable() { //$NON-NLS-1$ + + public Object run() throws StepExecutionException { + // drag + robot.mousePress(dndHelper.getDragComponent(), null, + dndHelper.getMouseButton()); + + CAPUtil.shakeMouse(); + + // drop + gdSelectCell(row, rowOperator, col, colOperator, 0, xPos, + xUnits, yPos, yUnits, + CompSystemConstants.EXTEND_SELECTION_NO, 1); + return null; + } + }); + + waitBeforeDrop(delayBeforeDrop); + + } finally { + robot.mouseRelease(dndHelper.getDragComponent(), null, + dndHelper.getMouseButton()); + pressOrReleaseModifiers(dndHelper.getModifier(), false); + } + } + + /** + * Finds the first row which contains the value <code>value</code> + * in column <code>col</code> and drags this row. + * + * @param mouseButton the mouse button + * @param modifier the modifier + * @param col the column + * @param colOperator the column header operator + * @param value the value + * @param regexOp the regex operator + * @param searchType Determines where the search begins ("relative" or "absolute") + */ + public void gdDragRowByValue(int mouseButton, String modifier, String col, + String colOperator, final String value, final String regexOp, + final String searchType) { + + final DragAndDropHelperSwt dndHelper = DragAndDropHelperSwt + .getInstance(); + dndHelper.setMouseButton(mouseButton); + dndHelper.setModifier(modifier); + dndHelper.setDragComponent(null); + + gdSelectRowByValue(col, colOperator, value, regexOp, 1, + CompSystemConstants.EXTEND_SELECTION_NO, + searchType, 1); + } + + /** + * Finds the first row which contains the value <code>value</code> + * in column <code>col</code> and drops on this row. + * + * @param col the column + * @param colOperator the column operator + * @param value the value + * @param regexOp the regex operator + * @param searchType Determines where the search begins ("relative" or "absolute") + * @param delayBeforeDrop the amount of time (in milliseconds) to wait + * between moving the mouse to the drop point and + * releasing the mouse button + */ + public void gdDropRowByValue(final String col, final String colOperator, + final String value, final String regexOp, final String searchType, + int delayBeforeDrop) { + + final DragAndDropHelperSwt dndHelper = DragAndDropHelperSwt + .getInstance(); + final IRobot robot = getRobot(); + pressOrReleaseModifiers(dndHelper.getModifier(), true); + + try { + getEventThreadQueuer().invokeAndWait("gdDropRowByValue", new IRunnable() { //$NON-NLS-1$ + + public Object run() throws StepExecutionException { + // drag + robot.mousePress(dndHelper.getDragComponent(), null, + dndHelper.getMouseButton()); + + CAPUtil.shakeMouse(); + + // drop + gdSelectRowByValue(col, colOperator, value, regexOp, + CompSystemConstants.EXTEND_SELECTION_NO, + searchType, + ClickOptions.create().setClickCount(0)); + return null; + } + }); + + waitBeforeDrop(delayBeforeDrop); + + } finally { + robot.mouseRelease(dndHelper.getDragComponent(), null, + dndHelper.getMouseButton()); + pressOrReleaseModifiers(dndHelper.getModifier(), false); + } + } + + /** + * Finds the first column which contains the value <code>value</code> + * in the given row and drags the cell. + * + * @param mouseButton the mouse button + * @param modifier the modifiers + * @param row the row + * @param rowOperator the row header operator + * @param value the value + * @param regex search using regex + * @param searchType Determines where the search begins ("relative" or "absolute") + */ + public void gdDragCellByColValue(int mouseButton, String modifier, + String row, String rowOperator, final String value, + final String regex, final String searchType) { + + final DragAndDropHelperSwt dndHelper = DragAndDropHelperSwt + .getInstance(); + dndHelper.setMouseButton(mouseButton); + dndHelper.setModifier(modifier); + dndHelper.setDragComponent(null); + gdSelectCellByColValue(row, rowOperator, value, regex, + CompSystemConstants.EXTEND_SELECTION_NO, + searchType, ClickOptions.create().setClickCount(0)); + } + + /** + * Finds the first column which contains the value <code>value</code> + * in the given row and drops on the cell. + * + * @param row the row + * @param rowOperator the row header operator + * @param value the value + * @param regex search using regex + * @param searchType Determines where the search begins ("relative" or "absolute") + * @param delayBeforeDrop the amount of time (in milliseconds) to wait + * between moving the mouse to the drop point and + * releasing the mouse button + */ + public void gdDropCellByColValue(final String row, final String rowOperator, + final String value, final String regex, final String searchType, + int delayBeforeDrop) { + + final DragAndDropHelperSwt dndHelper = DragAndDropHelperSwt + .getInstance(); + final IRobot robot = getRobot(); + pressOrReleaseModifiers(dndHelper.getModifier(), true); + + try { + getEventThreadQueuer().invokeAndWait("gdDropCellByColValue", new IRunnable() { //$NON-NLS-1$ + + public Object run() throws StepExecutionException { + // drag + robot.mousePress(dndHelper.getDragComponent(), null, + dndHelper.getMouseButton()); + + CAPUtil.shakeMouse(); + + // drop + gdSelectCellByColValue(row, rowOperator, value, regex, + CompSystemConstants.EXTEND_SELECTION_NO, + searchType, + ClickOptions.create().setClickCount(0)); + return null; + } + }); + + waitBeforeDrop(delayBeforeDrop); + + } finally { + robot.mouseRelease(dndHelper.getDragComponent(), null, + dndHelper.getMouseButton()); + pressOrReleaseModifiers(dndHelper.getModifier(), false); + } + } +} diff --git a/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/caps/TreeCAPs.java b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/caps/TreeCAPs.java new file mode 100644 index 000000000..c9c535edc --- /dev/null +++ b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/caps/TreeCAPs.java @@ -0,0 +1,901 @@ +/******************************************************************************* + * 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.caps; + +import java.util.StringTokenizer; + +import org.apache.commons.lang.Validate; +import org.eclipse.jubula.rc.common.CompSystemConstants; +import org.eclipse.jubula.rc.common.caps.AbstractTreeCAPs; +import org.eclipse.jubula.rc.common.driver.ClickOptions; +import org.eclipse.jubula.rc.common.driver.IEventThreadQueuer; +import org.eclipse.jubula.rc.common.driver.IRobot; +import org.eclipse.jubula.rc.common.driver.IRunnable; +import org.eclipse.jubula.rc.common.exception.StepExecutionException; +import org.eclipse.jubula.rc.common.implclasses.IndexConverter; +import org.eclipse.jubula.rc.common.implclasses.MatchUtil; +import org.eclipse.jubula.rc.common.implclasses.Verifier; +import org.eclipse.jubula.rc.common.implclasses.tree.AbstractTreeNodeOperation; +import org.eclipse.jubula.rc.common.implclasses.tree.AbstractTreeNodeTraverser; +import org.eclipse.jubula.rc.common.implclasses.tree.AbstractTreeOperationContext; +import org.eclipse.jubula.rc.common.implclasses.tree.ChildTraverser; +import org.eclipse.jubula.rc.common.implclasses.tree.ExpandCollapseTreeNodeOperation; +import org.eclipse.jubula.rc.common.implclasses.tree.INodePath; +import org.eclipse.jubula.rc.common.implclasses.tree.ParentTraverser; +import org.eclipse.jubula.rc.common.implclasses.tree.PathBasedTraverser; +import org.eclipse.jubula.rc.common.implclasses.tree.SelectTreeNodeOperation; +import org.eclipse.jubula.rc.common.implclasses.tree.SiblingTraverser; +import org.eclipse.jubula.rc.common.implclasses.tree.StandardDepthFirstTraverser; +import org.eclipse.jubula.rc.common.implclasses.tree.TreeNodeOperation; +import org.eclipse.jubula.rc.common.implclasses.tree.TreeNodeOperationConstraint; +import org.eclipse.jubula.rc.common.util.KeyStrokeUtil; +import org.eclipse.jubula.rc.swt.driver.DragAndDropHelperSwt; +import org.eclipse.jubula.rc.swt.driver.KeyCodeConverter; +import org.eclipse.jubula.rc.swt.implclasses.TableTreeOperationContext; +import org.eclipse.jubula.rc.swt.implclasses.TreeOperationContext; +import org.eclipse.jubula.rc.swt.implclasses.tree.ToggleCheckboxOperation; +import org.eclipse.jubula.rc.swt.implclasses.tree.VerifyCheckboxOperation; +import org.eclipse.jubula.rc.swt.utils.SwtUtils; +import org.eclipse.jubula.tools.objects.event.EventFactory; +import org.eclipse.jubula.tools.objects.event.TestErrorEvent; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.ScrollBar; +import org.eclipse.swt.widgets.TreeItem; +import org.eclipse.swt.widgets.Tree; +/** + * Toolkit specific commands for the <code>Tree</code> + * + * @author BREDEX GmbH + */ +public class TreeCAPs extends AbstractTreeCAPs { + + + /** + * Finds the item at a given position in the tree. + * + * @author BREDEX GmbH + * @created Jul 28, 2010 + */ + private static final class ItemAtPointTreeNodeOperation + extends AbstractTreeNodeOperation { + + /** the item that was found at the given position */ + private TreeItem m_itemAtPoint; + + /** the position (in absolute coordinates) at which to find the item */ + private Point m_absPoint; + + /** + * the bounds (in absolute coordinates) of the tree in which the + * search should take place + */ + private Rectangle m_absTreeBounds; + + + /** + * Constructor + * + * @param absPoint The position (in absolute coordinates) at which to + * find the item. + * @param absTreeBounds The bounds (in absolute coordinates) of the + * tree in which the search should take place. + */ + public ItemAtPointTreeNodeOperation(Point absPoint, + Rectangle absTreeBounds) { + m_absPoint = absPoint; + m_absTreeBounds = absTreeBounds; + } + + /** + * {@inheritDoc} + */ + public boolean operate(Object node) throws StepExecutionException { + if (getContext().isVisible(node) && node instanceof TreeItem) { + TreeItem currentItem = (TreeItem)node; + final Rectangle absItemBounds = + SwtUtils.getBounds(currentItem); + absItemBounds.x = m_absTreeBounds.x; + absItemBounds.width = m_absTreeBounds.width; + if (SwtUtils.containsInclusive( + absItemBounds, m_absPoint)) { + m_itemAtPoint = currentItem; + return false; + } + } + + return true; + } + + /** + * + * @return the item found at the given position, or <code>null</code> if + * no item was found. Note that this method will always return + * <code>null</code> if called before or during execution of + * {@link #operate(Object)}. + */ + public TreeItem getItemAtPoint() { + return m_itemAtPoint; + } + } + + /** + * @return The event thread queuer. + */ + protected IEventThreadQueuer getEventThreadQueuer() { + return getRobotFactory().getEventThreadQueuer(); + } + /** + * + * @return the Tree + */ + private Tree getTree() { + return (Tree) getComponent().getRealComponent(); + } + + /** + * {@inheritDoc} + */ + public void gdVerifyTextAtMousePosition(String pattern, String operator) { + TreeItem itemAtMousePosition = (TreeItem) getNodeAtMousePosition(); + int column = getMouseColumn(); + AbstractTreeOperationContext context; + + if (column != -1) { + context = + new TableTreeOperationContext( + getEventThreadQueuer(), getRobot(), + getTree(), column); + } else { + context = + new TableTreeOperationContext( + getEventThreadQueuer(), getRobot(), + getTree()); + } + + Verifier.match(context.getRenderedText(itemAtMousePosition), + pattern, operator); + + } + + + + + /** + * {@inheritDoc} + */ + public void gdDragByTextPath(int mouseButton, String modifier, + String pathType, int preAscend, String treePath, String operator) { + + final DragAndDropHelperSwt dndHelper = DragAndDropHelperSwt + .getInstance(); + + dndHelper.setMouseButton(mouseButton); + dndHelper.setModifier(modifier); + dndHelper.setDragComponent(null); + + SwtUtils.waitForDisplayIdle(getTree().getDisplay()); + + gdSelect(pathType, preAscend, treePath, operator, 0, 1, + CompSystemConstants.EXTEND_SELECTION_NO); + + SwtUtils.waitForDisplayIdle(getTree().getDisplay()); + } + + /** + * {@inheritDoc} + */ + public void gdDropByTextPath(final String pathType, final int preAscend, + final String treePath, final String operator, int delayBeforeDrop) { + + final DragAndDropHelperSwt dndHelper = DragAndDropHelperSwt + .getInstance(); + final IRobot robot = getRobot(); + + try { + pressOrReleaseModifiers(dndHelper.getModifier(), true); + getEventThreadQueuer().invokeAndWait("gdDropByTextPath - perform drag", new IRunnable() { //$NON-NLS-1$ + + public Object run() throws StepExecutionException { + // drag + robot.mousePress(dndHelper.getDragComponent(), null, + dndHelper.getMouseButton()); + + CAPUtil.shakeMouse(); + + return null; + } + }); + + // Post a MouseMove event in order to break the Display out of its + // post-drag "freeze". It appears as though the mouse position + // change needs to be extreme in order to nudge the Display back + // into action (i.e. (<mouse-location> + 1) was insufficient), + // so the default Event values (x, y = 0) are used. + Event wakeEvent = new Event(); + wakeEvent.type = SWT.MouseMove; + getTree().getDisplay().post(wakeEvent); + + waitForDisplayUpdate(); + + // drop + gdSelect(pathType, preAscend, treePath, operator, 0, 1, + CompSystemConstants.EXTEND_SELECTION_NO); + + SwtUtils.waitForDisplayIdle(getTree().getDisplay()); + waitBeforeDrop(delayBeforeDrop); + + } finally { + robot.mouseRelease(null, null, dndHelper.getMouseButton()); + pressOrReleaseModifiers( + dndHelper.getModifier(), false); + SwtUtils.waitForDisplayIdle(getTree().getDisplay()); + } + } + + /** + * {@inheritDoc} + */ + public void gdDragByIndexPath(int mouseButton, String modifier, + String pathType, int preAscend, String indexPath) { + + final DragAndDropHelperSwt dndHelper = DragAndDropHelperSwt + .getInstance(); + + dndHelper.setMouseButton(mouseButton); + dndHelper.setModifier(modifier); + dndHelper.setDragComponent(null); + + SwtUtils.waitForDisplayIdle(getTree().getDisplay()); + + gdSelectByIndices(pathType, preAscend, indexPath, 0, 1, + CompSystemConstants.EXTEND_SELECTION_NO); + + SwtUtils.waitForDisplayIdle(getTree().getDisplay()); + } + + /** + * {@inheritDoc} + */ + public void gdDropByIndexPath(final String pathType, final int preAscend, + final String indexPath, int delayBeforeDrop) { + + final DragAndDropHelperSwt dndHelper = DragAndDropHelperSwt + .getInstance(); + final IRobot robot = getRobot(); + try { + pressOrReleaseModifiers(dndHelper.getModifier(), true); + getEventThreadQueuer().invokeAndWait("gdDropByIndexPath - perform drag", new IRunnable() { //$NON-NLS-1$ + + public Object run() throws StepExecutionException { + // drag + robot.mousePress(dndHelper.getDragComponent(), null, + dndHelper.getMouseButton()); + + CAPUtil.shakeMouse(); + + return null; + } + }); + + // Post a MouseMove event in order to break the Display out of its + // post-drag "freeze". It appears as though the mouse position + // change needs to be extreme in order to nudge the Display back + // into action (i.e. (<mouse-location> + 1) was insufficient), + // so the default Event values (x, y = 0) are used. + Event wakeEvent = new Event(); + wakeEvent.type = SWT.MouseMove; + getTree().getDisplay().post(wakeEvent); + + waitForDisplayUpdate(); + + // drop + gdSelectByIndices(pathType, preAscend, indexPath, 0, 1, + CompSystemConstants.EXTEND_SELECTION_NO); + + SwtUtils.waitForDisplayIdle(getTree().getDisplay()); + waitBeforeDrop(delayBeforeDrop); + } finally { + robot.mouseRelease(null, null, dndHelper.getMouseButton()); + pressOrReleaseModifiers(dndHelper.getModifier(), + false); + SwtUtils.waitForDisplayIdle(getTree().getDisplay()); + } + } + /** + * {@inheritDoc} + */ + protected Object getNodeAtMousePosition() throws StepExecutionException { + return (TreeItem)getEventThreadQueuer().invokeAndWait("getItemAtMousePosition", new IRunnable() { //$NON-NLS-1$ + + public Object run() throws StepExecutionException { + Point mousePos = SwtUtils.convertToSwtPoint( + getRobot().getCurrentMousePosition()); + ItemAtPointTreeNodeOperation op = + new ItemAtPointTreeNodeOperation( + mousePos, SwtUtils.getWidgetBounds(getTree())); + + TreeItem topItem = getTree().getTopItem(); + if (topItem != null) { + + // FIXME zeb This may be slow for very large trees, as the + // search may continue long past the + // visible client area of the tree. + // It may also cause problems with regard to + // lazy/virtual nodes. + StandardDepthFirstTraverser traverser = + new StandardDepthFirstTraverser( + new TreeOperationContext( + getEventThreadQueuer(), getRobot(), getTree())); + traverser.traversePath(op, topItem); + if (op.getItemAtPoint() != null) { + return op.getItemAtPoint(); + } + + } + + throw new StepExecutionException("No tree node found at mouse position.", //$NON-NLS-1$ + EventFactory.createActionError( + TestErrorEvent.NOT_FOUND)); + } + }); + } + + /** + * @return the column where the mouse pointer currently rests. Returns -1 if + * the mouse pointer is currently outside of the TableTree or if the + * TableTree has no columns. + */ + private int getMouseColumn() { + final Tree treeTable = getTree(); + int column = ((Integer)getEventThreadQueuer().invokeAndWait( + "getMouseColumn", new IRunnable() { //$NON-NLS-1$ + + public Object run() throws StepExecutionException { + Rectangle treeTableBounds = + SwtUtils.getWidgetBounds(getTree()); + Point cursorPosition = + treeTable.getDisplay().getCursorLocation(); + boolean isCursorInBounds = + treeTableBounds.contains(cursorPosition); + if (isCursorInBounds) { + int horizontalScrollOffset = 0; + ScrollBar horizontalBar = + getTree().getHorizontalBar(); + if (horizontalBar != null + && !horizontalBar.isDisposed()) { + horizontalScrollOffset = + horizontalBar.getSelection(); + } + Rectangle columnBounds = new Rectangle( + treeTableBounds.x - horizontalScrollOffset, + treeTableBounds.y, 0, treeTableBounds.height); + for (int i = 0; + i < treeTable.getColumnCount(); i++) { + + columnBounds.x += columnBounds.width; + columnBounds.width = + treeTable.getColumn(i).getWidth(); + if (columnBounds.contains(cursorPosition)) { + return new Integer(i); + } + } + } + + return new Integer(-1); + } + + })).intValue(); + + return column; + } + // + // Methods for Table Trees following + // + + /** + * Selects a node relative to the currently selected node. + * @param direction the direction to move. + * directions: + * UP - Navigates through parents + * DOWN - Navigates through children + * NEXT - Navigates to next sibling + * PREVIOUS - Navigates to previous sibling + * @param distance the distance to move + * @param clickCount the click count to select the new cell. + * @throws StepExecutionException if any error occurs + */ + public void gdMove(String direction, int distance, int clickCount) + throws StepExecutionException { + + if (getColumnCount() > 0) { + TreeOperationContext context; + int mouseColumn = getMouseColumn(); + + if (mouseColumn == -1) { + context = + new TableTreeOperationContext( + getEventThreadQueuer(), getRobot(), getTree()); + } else { + context = + new TableTreeOperationContext( + getEventThreadQueuer(), getRobot(), getTree(), + mouseColumn); + } + + TreeItem selectedNode = (TreeItem) getSelectedNode(context); + + TreeNodeOperation selectOp = + new SelectTreeNodeOperation( + ClickOptions.create().setClickCount(clickCount)); + TreeNodeOperationConstraint constraint = + new TreeNodeOperationConstraint(); + + if (CompSystemConstants + .TREE_MOVE_UP.equalsIgnoreCase(direction)) { + AbstractTreeNodeTraverser traverser = + new ParentTraverser(context, distance, constraint); + traverser.traversePath(selectOp, selectedNode); + } else if (CompSystemConstants + .TREE_MOVE_DOWN.equalsIgnoreCase(direction)) { + TreeNodeOperation expandOp = + new ExpandCollapseTreeNodeOperation(false); + AbstractTreeNodeTraverser expandTraverser = + new ChildTraverser(context, distance - 1); + expandTraverser.traversePath(expandOp, selectedNode); + + AbstractTreeNodeTraverser selectTraverser = + new ChildTraverser(context, distance, constraint); + selectTraverser.traversePath(selectOp, selectedNode); + + } else if (CompSystemConstants + .TREE_MOVE_NEXT.equalsIgnoreCase(direction)) { + // Look through siblings + AbstractTreeNodeTraverser traverser = + new SiblingTraverser(context, distance, true, constraint); + traverser.traversePath(selectOp, selectedNode); + + } else if (CompSystemConstants + .TREE_MOVE_PREVIOUS.equalsIgnoreCase(direction)) { + // Look through siblings + AbstractTreeNodeTraverser traverser = + new SiblingTraverser(context, distance, false, constraint); + traverser.traversePath(selectOp, selectedNode); + } + } else { + super.gdMove(direction, distance, clickCount); + } + } + + /** + * Runs in the GUI thread. + * @return the number of columns in the receivers component. + */ + private int getColumnCount() { + return ((Integer)getEventThreadQueuer().invokeAndWait( + "getColumnCount", new IRunnable() { //$NON-NLS-1$ + + public Object run() throws StepExecutionException { + return new Integer(getTree().getColumnCount()); + } + + })).intValue(); + } + + /** + * Selects the item at the end of the <code>treepath</code> at column + * <code>column</code>. + * + * @param pathType whether the path is relative or absolute + * @param preAscend + * Relative traversals will start this many parent nodes + * above the current node. Absolute traversals ignore this + * parameter. + * @param treePath The tree path. + * @param operator + * If regular expressions are used to match the tree path + * @param clickCount the click count + * @param column the column of the item to select + * @param button what mouse button should be used + * @throws StepExecutionException If the tree path is invalid, if the + * double-click to expand the node fails, or if the selection is invalid. + */ + public void gdSelect(String pathType, int preAscend, String treePath, + String operator, int clickCount, int column, + int button) + throws StepExecutionException { + final int implCol = IndexConverter.toImplementationIndex(column); + checkColumnIndex(implCol); + + selectByPath(pathType, preAscend, + createStringNodePath(splitTextTreePath(treePath), operator), + ClickOptions.create() + .setClickCount(clickCount) + .setMouseButton(button), implCol); + + } + /** + * Selects the last node of the path given by <code>indexPath</code> + * at column <code>column</code>. + * + * @param pathType whether the path is relative or absolute + * @param preAscend + * Relative traversals will start this many parent nodes + * above the current node. Absolute traversals ignore this + * parameter. + * @param indexPath the index path + * @param clickCount the number of times to click + * @param column the column of the item to select + * @param button what mouse button should be used + * @throws StepExecutionException if <code>indexPath</code> is not a valid + * path + */ + public void gdSelectByIndices(String pathType, int preAscend, + String indexPath, int clickCount, int column, + int button) + throws StepExecutionException { + final int implCol = IndexConverter.toImplementationIndex(column); + checkColumnIndex(implCol); + + selectByPath(pathType, preAscend, + createIndexNodePath(splitIndexTreePath(indexPath)), + ClickOptions.create() + .setClickCount(clickCount) + .setMouseButton(button), implCol); + } + + /** + * Verifies whether the first selection in the tree has a rendered text at + * column <code>column</code> that is equal to <code>pattern</code>. + * + * @param pattern The pattern + * @param column + * The column containing the text to verify + * @throws StepExecutionException If no node is selected or the verification fails. + */ + public void gdVerifySelectedValue(String pattern, int column) + throws StepExecutionException { + + gdVerifySelectedValue(pattern, MatchUtil.DEFAULT_OPERATOR, column); + } + /** + * Verifies if the selected node underneath <code>treePath</code> at column + * <code>column</code> has a rendered text which is equal to + * <code>selection</code>. + * + * @param pattern the pattern + * @param operator + * The operator to use when comparing the expected and + * actual values. + * @param column + * The column containing the text to verify + * @throws StepExecutionException If there is no tree node selected, the tree path contains no + * selection or the verification fails + */ + public void gdVerifySelectedValue(String pattern, String operator, + int column) throws StepExecutionException { + + final int implCol = IndexConverter.toImplementationIndex(column); + checkColumnIndex(implCol); + + TableTreeOperationContext context = new TableTreeOperationContext( + getEventThreadQueuer(), getRobot(), getTree(), implCol); + + String text = context.getNodeTextAtColumn(context.getSelectedNode()); + + Verifier.match(text, pattern, operator); + + } + + /** + * + * @param index The 0-based column index to check. + * @throws StepExecutionException if the column index is invalid. + */ + private void checkColumnIndex(final int index) + throws StepExecutionException { + + int numColumns = ((Integer)getEventThreadQueuer().invokeAndWait( + "checkColumnIndex", //$NON-NLS-1$ + new IRunnable() { + + public Object run() { + return new Integer(getTree().getColumnCount()); + } + + })).intValue(); + + if ((index < 0 || index >= numColumns) && index != 0) { + throw new StepExecutionException("Invalid column: " //$NON-NLS-1$ + + IndexConverter.toUserIndex(index), + EventFactory.createActionError( + TestErrorEvent.INVALID_INDEX)); + } + } + + /** + * @param pathType pathType + * @param preAscend + * Relative traversals will start this many parent nodes + * above the current node. Absolute traversals ignore this + * parameter. + * @param objectPath objectPath + * @param co the click options to use + * @param column the column + */ + private void selectByPath(String pathType, int preAscend, + INodePath objectPath, ClickOptions co, int column) { + + TreeNodeOperation expOp = + new ExpandCollapseTreeNodeOperation(false); + TreeNodeOperation selectOp = + new SelectTreeNodeOperation(co); + INodePath subPath = objectPath.subPath(0, objectPath.getLength() - 1); + + traverseTreeByPath(subPath, pathType, preAscend, expOp); + traverseLastElementByPath( + objectPath, pathType, preAscend, selectOp, column); + + } + + /** + * Traverses the tree by searching for the nodes in the tree + * path entry and calling the given operation on the last element in the path. + * @param treePath The tree path. + * @param pathType For example, "relative" or "absolute". + * @param preAscend + * Relative traversals will start this many parent nodes + * above the current node. Absolute traversals ignore this + * parameter. + * @param operation The tree node operation. + * @param column The target column for the operation. + * @throws StepExecutionException If the path traversion fails. + */ + private void traverseLastElementByPath(INodePath treePath, + String pathType, int preAscend, TreeNodeOperation operation, + int column) + throws StepExecutionException { + + Validate.notNull(treePath); + Validate.notNull(operation); + + TableTreeOperationContext context = new TableTreeOperationContext( + getEventThreadQueuer(), getRobot(), getTree(), column); + TreeItem startNode = (TreeItem) getStartNode(pathType, + preAscend, context); + + AbstractTreeNodeTraverser traverser = new PathBasedTraverser( + context, treePath, new TreeNodeOperationConstraint()); + traverser.traversePath(operation, startNode); + } + + /** + * {@inheritDoc} + */ + public String gdStoreValueAtMousePosition(String variable) { + TreeItem itemAtMousePosition = (TreeItem) getNodeAtMousePosition(); + int column = getMouseColumn(); + AbstractTreeOperationContext context; + + if (column != -1) { + context = + new TableTreeOperationContext( + getEventThreadQueuer(), getRobot(), getTree(), column); + } else { + context = + new TableTreeOperationContext( + getEventThreadQueuer(), getRobot(), getTree()); + } + + return context.getRenderedText(itemAtMousePosition); + } + + /** + * Selects Checkbox of last node of the path given by <code>treepath</code>. + * + * @param pathType whether the path is relative or absolute + * @param preAscend + * Relative traversals will start this many parent nodes + * above the current node. Absolute traversals ignore this + * parameter. + * @param treePath The tree path. + * @param operator + * If regular expressions are used to match the tree path + * @throws StepExecutionException If the tree path is invalid, if the + * double-click to expand the node fails, or if the selection is invalid. + */ + public void gdToggleCheckbox(String pathType, int preAscend, String + treePath, String operator) + throws StepExecutionException { + toggleCheckBoxByPath(pathType, preAscend, + createStringNodePath(splitTextTreePath(treePath), operator)); + } + + /** + * Selects Checkbox of last node of the path given by <code>indexPath</code> + * @param pathType whether the path is relative or absolute + * @param preAscend + * Relative traversals will start this many parent nodes + * above the current node. Absolute traversals ignore this + * parameter. + * @param indexPath the index path + * @throws StepExecutionException if <code>indexPath</code> is not a valid + * path + */ + public void gdToggleCheckboxByIndices(String pathType, int preAscend, + String indexPath) + throws StepExecutionException { + + toggleCheckBoxByPath(pathType, preAscend, + createIndexNodePath(splitIndexTreePath(indexPath))); + } + + /** + * Verify Selection of checkbox of the node at the end of the <code>treepath</code>. + * + * @param pathType whether the path is relative or absolute + * @param preAscend + * Relative traversals will start this many parent nodes + * above the current node. Absolute traversals ignore this + * parameter. + * @param treePath The tree path. + * @param operator + * If regular expressions are used to match the tree path + * @param checked true if checkbox of tree node is selected, false otherwise + * @throws StepExecutionException If the tree path is invalid, if the + * double-click to expand the node fails, or if the selection is invalid. + */ + public void gdVerifyCheckbox(String pathType, int preAscend, String + treePath, String operator, boolean checked) + throws StepExecutionException { + verifyCheckBoxByPath(pathType, preAscend, + createStringNodePath(splitTextTreePath(treePath), operator), + checked); + } + + /** + * Verify Selection of checkbox of last node of the path given by <code>indexPath</code> + * @param pathType whether the path is relative or absolute + * @param preAscend + * Relative traversals will start this many parent nodes + * above the current node. Absolute traversals ignore this + * parameter. + * @param indexPath the index path + * @param checked true if checkbox of tree node is selected, false otherwise + * @throws StepExecutionException if <code>indexPath</code> is not a valid + * path + */ + public void gdVerifyCheckboxByIndices(String pathType, int preAscend, + String indexPath, boolean checked) + throws StepExecutionException { + + verifyCheckBoxByPath(pathType, preAscend, + createIndexNodePath(splitIndexTreePath(indexPath)), + checked); + } + + /** + * Verifies whether the checkbox of the first selection in the tree is checked + * + * @param checked true if checkbox of node is selected, false otherwise + * @throws StepExecutionException If no node is selected or the verification fails. + */ + public void gdVerifySelectedCheckbox(boolean checked) + throws StepExecutionException { + Boolean checkSelected = ((Boolean)getEventThreadQueuer().invokeAndWait( + "gdVerifyTreeCheckbox", new IRunnable() { //$NON-NLS-1$ + public Object run() { + TreeItem node = getTree().getSelection()[0]; + return new Boolean(node.getChecked()); + } + })); + + Verifier.equals(checked, checkSelected.booleanValue()); + } + + /** + * @param pathType pathType + * @param preAscend + * Relative traversals will start this many parent nodes + * above the current node. Absolute traversals ignore this + * parameter. + * @param objectPath objectPath + * @param checked true if Checkbox should be enabled, false otherwise + */ + private void verifyCheckBoxByPath(String pathType, int preAscend, + INodePath objectPath, final boolean checked) { + + TreeNodeOperation expOp = + new ExpandCollapseTreeNodeOperation(false); + TreeOperationContext context = new TreeOperationContext( + getEventThreadQueuer(), getRobot(), getTree()); + TreeNodeOperation checkboxOp = new VerifyCheckboxOperation( + checked, context); + INodePath subPath = objectPath.subPath(0, objectPath.getLength() - 1); + + traverseTreeByPath(subPath, pathType, preAscend, expOp); + traverseLastElementByPath(objectPath, pathType, preAscend, checkboxOp); + } + + /** + * @param pathType pathType + * @param preAscend + * Relative traversals will start this many parent nodes + * above the current node. Absolute traversals ignore this + * parameter. + * @param objectPath objectPath + */ + private void toggleCheckBoxByPath(String pathType, int preAscend, + INodePath objectPath) { + + TreeNodeOperation expOp = + new ExpandCollapseTreeNodeOperation(false); + TreeOperationContext context = new TreeOperationContext( + getEventThreadQueuer(), getRobot(), getTree()); + TreeNodeOperation selCheckboxOp = new ToggleCheckboxOperation(context); + INodePath subPath = objectPath.subPath(0, objectPath.getLength() - 1); + + traverseTreeByPath(subPath, pathType, preAscend, expOp); + traverseLastElementByPath(objectPath, pathType, preAscend, + selCheckboxOp); + } + + /** + * {@inheritDoc} + */ + public void gdClick(int count, int button) { + super.gdClick(count, button); + + } + + + + /** + * Forces all outstanding paint requests for the receiver's component's + * display to be processed before this method returns. + * + * @see Display#update() + */ + protected void waitForDisplayUpdate() { + ((Control)getComponent().getRealComponent()) + .getDisplay().syncExec(new Runnable() { + public void run() { + ((Control)getComponent() + .getRealComponent()).getDisplay().update(); + } + }); + } + + /** + * Presses or releases the given modifier. + * @param modifier the modifier. + * @param press if true, the modifier will be pressed. + * if false, the modifier will be released. + */ + public void pressOrReleaseModifiers(String modifier, boolean press) { + final IRobot robot = getRobot(); + final StringTokenizer modTok = new StringTokenizer( + KeyStrokeUtil.getModifierString(modifier), " "); //$NON-NLS-1$ + while (modTok.hasMoreTokens()) { + final String mod = modTok.nextToken(); + final int keyCode = KeyCodeConverter.getKeyCode(mod); + if (press) { + robot.keyPress(null, keyCode); + } else { + robot.keyRelease(null, keyCode); + } + } + } + +} diff --git a/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/AbstractComboBoxAdapter.java b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/AbstractComboBoxAdapter.java new file mode 100644 index 000000000..9ca0e579b --- /dev/null +++ b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/AbstractComboBoxAdapter.java @@ -0,0 +1,318 @@ +/******************************************************************************* + * 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.uiadapter; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import org.apache.commons.lang.Validate; +import org.eclipse.jubula.rc.common.CompSystemConstants; +import org.eclipse.jubula.rc.common.driver.ClickOptions; +import org.eclipse.jubula.rc.common.driver.IRunnable; +import org.eclipse.jubula.rc.common.exception.StepExecutionException; +import org.eclipse.jubula.rc.common.implclasses.MatchUtil; +import org.eclipse.jubula.rc.common.logger.AutServerLogger; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.IComboBoxAdapter; +import org.eclipse.jubula.rc.swt.utils.SwtUtils; +import org.eclipse.jubula.tools.objects.event.EventFactory; +import org.eclipse.jubula.tools.objects.event.TestErrorEvent; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Widget; +/** + * Implementation of the Interface <code>IComboBoxAdapter</code> as a abstract + * adapter for the swt comboboxes. + * This class needs specific methods of its subclasses therefore it is abstract. + * + * @author BREDEX GmbH + * + */ +public abstract class AbstractComboBoxAdapter extends WidgetAdapter + implements IComboBoxAdapter { + + /** number of clicks to give focus without selecting any text */ + public static final int CLICK_COUNT_FOR_SELECTING_NONE = 3; + + /** the logger */ + private static AutServerLogger log = new AutServerLogger( + AbstractComboBoxAdapter.class); + + /** + * + * @param objectToAdapt + */ + protected AbstractComboBoxAdapter(Object objectToAdapt) { + super(objectToAdapt); + } + + /** + * {@inheritDoc} + */ + public void select(final String[] values, String operator, + final String searchType) + throws StepExecutionException, IllegalArgumentException { + + for (int i = 0; i < values.length; i++) { + String text = values[i]; + Validate.notNull(text, "text must not be null"); //$NON-NLS-1$ + } + + Integer[] indices = findIndicesOfValues(values, + operator, searchType); + Arrays.sort(indices); + if (indices.length == 0) { + throw new StepExecutionException("Text '" + Arrays.asList(values).toString() //$NON-NLS-1$ + + "' not found", //$NON-NLS-1$ + EventFactory.createActionError(TestErrorEvent.NOT_FOUND)); + } + select(indices[0].intValue()); + } + + /** + * {@inheritDoc} + */ + public void select(int index) { + + int comboItemCount = getItemCount(); + + if (index >= comboItemCount + || index < 0) { + throw new StepExecutionException("Combo Box index '" + index //$NON-NLS-1$ + + "' is out of range", //$NON-NLS-1$ + EventFactory.createActionError(TestErrorEvent.INVALID_INDEX)); + } + + if (isComboEnabled()) { + // FIXME zeb: Needs special handling if style is not DROP_DOWN + openDropdownList(); + selectImpl(index); + } + } + + /** + * @return <code>true</code> if the combo box is currently enabled. + */ + protected abstract boolean isComboEnabled(); + + /** + * + * @param index idx + */ + protected abstract void selectImpl(int index); + + /** + * Opens the combobox dropdown list. May also be + * called if the list is already visible. + */ + protected abstract void openDropdownList(); + + /** + * Finds the indices of the list elements that are rendered with the passed + * values. + * + * @param values + * The values + * @param operator + * operator to use + * @param searchType + * Determines where the search begins ("relative" or "absolute") + * @return The array of indices. It's length is equal to the length of the + * values array, but may contains <code>null</code> elements for + * all values that are not found in the list + */ + private Integer[] findIndicesOfValues(final String [] values, + final String operator, final String searchType) { + + final Set indexSet = new HashSet(); + + for (int i = getStartingIndex(searchType); + i < getItemCount(); + ++i) { + + String str = getItem(i); + if (MatchUtil.getInstance(). + match(str, values, operator)) { + indexSet.add(new Integer(i)); + } + } + + + Integer[] indices = new Integer[indexSet.size()]; + indexSet.toArray(indices); + return indices; + + } + + /** + * @param searchType Determines where the search begins ("relative" or "absolute") + * @return The index from which to begin a search, based on the search type + * and (if appropriate) the currently selected item. + */ + private int getStartingIndex(final String searchType) { + int startingIndex = 0; + if (searchType.equalsIgnoreCase( + CompSystemConstants.SEARCH_TYPE_RELATIVE)) { + startingIndex = getSelectedIndex(); + } + return startingIndex; + } + + /** + * {@inheritDoc} + */ + public boolean containsValue(String value, String operator) { + Integer[] indices = null; + if (operator.equals(MatchUtil.NOT_EQUALS)) { + indices = findIndicesOfValues(new String[] { value }, + MatchUtil.EQUALS, CompSystemConstants.SEARCH_TYPE_ABSOLUTE); + return indices.length == 0; + } + indices = findIndicesOfValues(new String[] { value }, + operator, CompSystemConstants.SEARCH_TYPE_ABSOLUTE); + return indices.length > 0; + } + + /** + * {@inheritDoc} + */ + public boolean containsValue(String value) { + return containsValue(value, MatchUtil.EQUALS); + } + + /** + * Returns the number of items contained in the combo list. + * @return the number of items. + */ + protected abstract int getItemCount(); + + /** + * Returns the item at the given, zero-relative index in the combo list. + * Throws an exception if the index is out of range. + * @param index the index of the item to return + * @return the item at the given index + */ + protected abstract String getItem(final int index); + + /** + * {@inheritDoc} + */ + public void input(String text, boolean replace) + throws StepExecutionException, IllegalArgumentException { + + Validate.notNull(text, "text must not be null"); //$NON-NLS-1$ + Control editor = (Control) getRealComponent(); + if (editor == null) { + throw new StepExecutionException("could not find editor", //$NON-NLS-1$ + EventFactory.createActionError(TestErrorEvent.COMP_NOT_FOUND)); + } + if (replace) { + selectAll(); + } else { + selectNone(); + } + getRobot().type(editor, text); + getRobot().keyType(null, SWT.KEYPAD_CR); + } + + /** + * {@inheritDoc} + */ + public void click(Integer count) { + Control editor = (Control) getRealComponent(); + if (editor == null) { + throw new StepExecutionException("no editor found", //$NON-NLS-1$ + EventFactory.createActionError(TestErrorEvent.COMP_NOT_FOUND)); + } + getRobot().click(editor, null, ClickOptions.create().setClickCount( + count.intValue())); + } + + /** + * Give the text field focus without selecting any of the text. + */ + public void selectNone() { + // FIXME zeb: This places the caret at the center of the component, + // which may or may not be correct. Where should the text + // be inserted? + click(new Integer( + CLICK_COUNT_FOR_SELECTING_NONE)); + } + /** + * Toggles the combobox dropdown list by clicking on the combo box. + */ + protected void toggleDropdownList() { + + // Click in the center of the pulldown button + Rectangle r = findArrowIconArea(); + + if (log.isDebugEnabled()) { + log.debug("Toggling dropdown by clicking on rectangle: " + r //$NON-NLS-1$ + + "within component: " + getRealComponent()); //$NON-NLS-1$ + } + + getRobot().click(getRealComponent(), r, + ClickOptions.create().setScrollToVisible(false) + .setConfirmClick(false)); + + } + + /** + * @return a rectangle, where the arrow icon is expected, relative to the + * combo box's location. + */ + protected Rectangle findArrowIconArea() { + final Control editor = (Control) getRealComponent(); + Rectangle r = null; + if (editor == null) { + throw new StepExecutionException("could not find editor", //$NON-NLS-1$ + EventFactory.createActionError(TestErrorEvent.COMP_NOT_FOUND)); + } + + r = (Rectangle)getEventThreadQueuer().invokeAndWait( + AbstractComboBoxAdapter.class.getName() + + "findArrowIconArea", new IRunnable() { //$NON-NLS-1$ + public Object run() throws StepExecutionException { + return SwtUtils.getRelativeWidgetBounds(editor, editor); + } + }); + + // Assume that the arrow icon is approximately square + r.x += r.width - r.height; + r.width = r.height; + + return r; + } + + /** + * @return true, if combo is not read_only + */ + private boolean isComboEditable() { + + Integer comboStyle = (Integer)getEventThreadQueuer().invokeAndWait( + AbstractComboBoxAdapter.class.getName() + + "isComboEditable", new IRunnable() { //$NON-NLS-1$ + public Object run() throws StepExecutionException { + return new Integer(((Widget)getRealComponent()).getStyle()); + } + }); + + return ((comboStyle.intValue() & SWT.READ_ONLY) == 0); + } + + /** + * {@inheritDoc} + */ + public boolean isEditable() { + return isComboEditable(); + } +} diff --git a/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/AbstractComponentAdapter.java b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/AbstractComponentAdapter.java new file mode 100644 index 000000000..1fce2950e --- /dev/null +++ b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/AbstractComponentAdapter.java @@ -0,0 +1,29 @@ +package org.eclipse.jubula.rc.swt.uiadapter; + +import org.eclipse.jubula.rc.common.driver.IRobotFactory; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.IComponentAdapter; +import org.eclipse.jubula.rc.swt.driver.RobotFactoryConfig; +/** + * + * @author BREDEX GmBH + * + */ +public abstract class AbstractComponentAdapter implements IComponentAdapter { + + /** the RobotFactory from the AUT */ + private IRobotFactory m_robotFactory; + + + /** + * Gets the Robot factory. The factory is created once per instance. + * + * @return The Robot factory. + */ + public IRobotFactory getRobotFactory() { + if (m_robotFactory == null) { + m_robotFactory = new RobotFactoryConfig().getRobotFactory(); + } + return m_robotFactory; + } + +} diff --git a/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/ButtonAdapter.java b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/ButtonAdapter.java new file mode 100644 index 000000000..5d9f7effe --- /dev/null +++ b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/ButtonAdapter.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * 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.uiadapter; + +import org.eclipse.jubula.rc.common.driver.IRunnable; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.IButtonAdapter; +import org.eclipse.swt.widgets.Button; +/** + * Implements the Button interface for adapting a <code>SWT.Button</code> + * + * @author BREDEX GmbH + */ +public class ButtonAdapter extends WidgetAdapter implements IButtonAdapter { + + /** the Button from the AUT */ + private Button m_button; + + /** + * + * @param objectToAdapt graphics component which will be adapted + */ + public ButtonAdapter(Object objectToAdapt) { + super(objectToAdapt); + m_button = (Button) objectToAdapt; + } + + /** + * {@inheritDoc} + */ + public String getText() { + + return (String)getEventThreadQueuer() + .invokeAndWait("getText", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return m_button.getText(); // see findBugs; + } + }); + } + + /** + * {@inheritDoc} + */ + public boolean isSelected() { + Boolean actual = (Boolean)getEventThreadQueuer() + .invokeAndWait("isSelected", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return m_button.getSelection() + ? Boolean.TRUE : Boolean.FALSE; // see findBugs; + } + }); + return actual.booleanValue(); + } + + /** + * {@inheritDoc} + * + */ + public String readValue(String variable) { + + return getText(); + } +}
\ No newline at end of file diff --git a/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/CComboAdapter.java b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/CComboAdapter.java new file mode 100644 index 000000000..5ce6513ea --- /dev/null +++ b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/CComboAdapter.java @@ -0,0 +1,355 @@ +/******************************************************************************* + * 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.uiadapter; + +import org.eclipse.jubula.rc.common.driver.ClickOptions; +import org.eclipse.jubula.rc.common.driver.IRunnable; +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.swt.utils.SwtUtils; +import org.eclipse.jubula.tools.constants.TimeoutConstants; +import org.eclipse.jubula.tools.objects.event.EventFactory; +import org.eclipse.jubula.tools.objects.event.TestErrorEvent; +import org.eclipse.swt.custom.CCombo; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.List; +import org.eclipse.swt.widgets.Shell; +/** + * Implementation of the Interface <code>IComboBoxAdapter</code> as a + * adapter for the <code>CCombo</code> component. + * This class is sub classing <code>AbstractComboBoxAdapter</code> because + * <code>Combo</code> and <code>CCombo</code> have common parts + * @author BREDEX GmbH + * + */ +public class CComboAdapter extends AbstractComboBoxAdapter { + + /** the logger */ + private static AutServerLogger log = new AutServerLogger( + CComboAdapter.class); + + /** */ + private CCombo m_combobox; + + /** + * + * @param objectToAdapt + */ + public CComboAdapter(Object objectToAdapt) { + super(objectToAdapt); + m_combobox = (CCombo) objectToAdapt; + } + + /** + * {@inheritDoc} + */ + public void selectAll() { + + // Get focus + selectNone(); + + // FIXME zeb: Find a platform-independant way to select all text + // without calling CCombo methods directly. + // The current problem with clicking twice in the text area + // is that if there is any white space, only part of the + // text is selected. + getEventThreadQueuer().invokeAndWait("selectAll", //$NON-NLS-1$ + new IRunnable() { + + public Object run() throws StepExecutionException { + m_combobox.setSelection( + new Point(0, m_combobox.getText().length())); + + // return value is not used + return null; + } + + }); + + } + + /** + * {@inheritDoc} + */ + public int getSelectedIndex() { + int selectedIndex = ((Integer)getEventThreadQueuer().invokeAndWait( + CComboAdapter.class.getName() + + "getSelectedIndex", new IRunnable() { //$NON-NLS-1$ + public Object run() throws StepExecutionException { + return new Integer(m_combobox.getSelectionIndex()); + } + })).intValue(); + + return selectedIndex; + } + + + /** + * {@inheritDoc} + */ + public String getText() { + Object o = getEventThreadQueuer().invokeAndWait( + "getSelectedItem", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return m_combobox.getText(); + } + }); + return o != null ? o.toString() : null; + } + + /** + * {@inheritDoc} + */ + protected boolean isComboEnabled() { + boolean isEnabled = ((Boolean)getEventThreadQueuer().invokeAndWait( + CComboAdapter.class.getName() + + "isComboEnabled", new IRunnable() { //$NON-NLS-1$ + public Object run() throws StepExecutionException { + return m_combobox.isEnabled() + ? Boolean.TRUE : Boolean.FALSE; + } + })).booleanValue(); + + return isEnabled; + } + + /** + * {@inheritDoc} + */ + protected void selectImpl(final int index) { + scrollIndexToVisible(index); + + Rectangle clickConstraints = + (Rectangle)getEventThreadQueuer().invokeAndWait( + "setClickConstraints", //$NON-NLS-1$ + new IRunnable() { + + public Object run() throws StepExecutionException { + Rectangle constraints = + SwtUtils.getRelativeWidgetBounds( + getDropdownList(), getDropdownList()); + int displayedItemCount = getDisplayedItemCount(); + int numberBelowTop = 0; + if (displayedItemCount >= getItemCount()) { + numberBelowTop = index; + } else { + numberBelowTop = Math.max(0, index + - getItemCount() + displayedItemCount); + } + + // Set the constraints based on the numberBelowTop + constraints.height = getDropdownList().getItemHeight(); + constraints.y += (numberBelowTop * constraints.height); + + return constraints; + } + + }); + + // Note that we set scrollToVisible false because we have already done + // the scrolling. + getRobot().click(getDropdownList(), clickConstraints, + new ClickOptions().setScrollToVisible(false)); + + } + + /** + * {@inheritDoc} + */ + protected void openDropdownList() { + if (!isDropdownVisible()) { + toggleDropdownList(); + } + + long timeout = TimeoutConstants.SERVER_TIMEOUT_WAIT_FOR_POPUP; + long done = System.currentTimeMillis() + timeout; + long now; + while (!isDropdownVisible() && timeout >= 0) { + RobotTiming.sleepPreShowPopupDelay(); + now = System.currentTimeMillis(); + timeout = done - now; + } + + if (!isDropdownVisible()) { + log.debug("Dropdown list still not visible, must be an error"); //$NON-NLS-1$ + throw new StepExecutionException("dropdown list not visible", //$NON-NLS-1$ + EventFactory.createActionError( + TestErrorEvent.DROPDOWN_LIST_NOT_FOUND)); + } + + } + + /** + * Returns the number of items contained in the combo list. + * @return the number of items. + */ + protected int getItemCount() { + return ((Integer)getEventThreadQueuer().invokeAndWait( + "getItemCount", //$NON-NLS-1$ + new IRunnable() { + + public Object run() { + + return new Integer(m_combobox.getItemCount()); + } + + })).intValue(); + + } + + /** + * Returns the item at the given, zero-relative index in the combo list. + * Throws an exception if the index is out of range. + * @param index the index of the item to return + * @return the item at the given index + */ + protected String getItem(final int index) { + return (String)getEventThreadQueuer().invokeAndWait( + "getItem", //$NON-NLS-1$ + new IRunnable() { + + public Object run() { + + return m_combobox.getItem(index); + } + + }); + + } + + /** + * Tries to find the dropdown list from the combobox + * @return the dropdown of the combobox, or <code>null</code> if the + * dropdown could not be found + */ + protected List getDropdownList() + throws StepExecutionException { + + return (List)getEventThreadQueuer().invokeAndWait( + "getDropdownList", //$NON-NLS-1$ + new IRunnable() { + + public Object run() throws StepExecutionException { + + Shell mainShell = SwtUtils.getShell(m_combobox); + Display d = Display.getCurrent(); + Shell [] shells = d.getShells(); + for (int i = 0; i < shells.length; i++) { + Shell curShell = shells[i]; + if (mainShell == curShell.getParent() + && curShell.getChildren().length == 1 + && curShell.getChildren()[0] instanceof List) { + + List possibleDropdown = + (List)curShell.getChildren()[0]; + if (!possibleDropdown.isDisposed() + && possibleDropdown.isVisible() + && isDropdownList(possibleDropdown)) { + return possibleDropdown; + } + } + } + + return null; + } + }); + } + + /** + * Verifies that the given list is the dropdown list for this combo box. + * + * @param list The list to verify. + * @return <code>true</code> if <code>list</code> is the dropdown list for + * this combo box. Otherwise <code>false</code>. + */ + private boolean isDropdownList(List list) { + /* + * Verify that the list is close enough to the combo box. + */ + + Rectangle comboBounds = + SwtUtils.getWidgetBounds(m_combobox); + Rectangle listBounds = SwtUtils.getWidgetBounds(list); + + // Expand the bounding rectangle for the combo box by a small amount + int posFuzz = 5; + int dimFuzz = posFuzz * 2; + comboBounds.x -= posFuzz; + comboBounds.width += dimFuzz; + comboBounds.y -= posFuzz; + comboBounds.height += dimFuzz; + + return comboBounds.intersects(listBounds); + } + + /** + * Tries to set the given index as the top element of the CCombo. + * @param index The index to make visible + */ + private void scrollIndexToVisible(final int index) { + getEventThreadQueuer().invokeAndWait( + "scrollIndexToVisible", //$NON-NLS-1$ + new IRunnable() { + + public Object run() throws StepExecutionException { + + getDropdownList().setTopIndex(index); + + return null; + } + + }); + } + + /** + * + * @return the number of items displayed in the dropdown list, or 0 if + * the list is not showing. + */ + private int getDisplayedItemCount() { + return ((Integer)getEventThreadQueuer().invokeAndWait( + "getDisplayedItemCount", //$NON-NLS-1$ + new IRunnable() { + + public Object run() throws StepExecutionException { + List dropdown = getDropdownList(); + if (dropdown == null) { + return new Integer(0); + } + int listHeight = SwtUtils.getWidgetBounds(dropdown).height; + int itemHeight = dropdown.getItemHeight(); + + return new Integer(listHeight / itemHeight); + } + + })).intValue(); + } + + /** + * @return true, if the dropdown of the combobox is visible + */ + protected boolean isDropdownVisible() { + Boolean visible = (Boolean)getEventThreadQueuer().invokeAndWait( + CComboAdapter.class.getName() + + "isDropdownVisible", new IRunnable() { //$NON-NLS-1$ + public Object run() throws StepExecutionException { + List dropdownList = getDropdownList(); + return dropdownList != null + ? Boolean.TRUE : Boolean.FALSE; + } + }); + return visible.booleanValue(); + } + +} diff --git a/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/CLabelAdapter.java b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/CLabelAdapter.java new file mode 100644 index 000000000..df9d482a1 --- /dev/null +++ b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/CLabelAdapter.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * 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.uiadapter; + +import org.eclipse.jubula.rc.common.driver.IRunnable; +import org.eclipse.jubula.rc.common.exception.StepExecutionException; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.ITextVerifiable; +import org.eclipse.jubula.rc.swt.utils.SwtUtils; +import org.eclipse.jubula.tools.objects.event.EventFactory; +import org.eclipse.swt.custom.CLabel; +/** + * + * @author BREDEX GmbH + * + */ +public class CLabelAdapter extends WidgetAdapter implements ITextVerifiable { + + /** + * + * @param objectToAdapt the component to adapt + */ + public CLabelAdapter(Object objectToAdapt) { + super(objectToAdapt); + } + + /** + * {@inheritDoc} + */ + public String getText() { + final CLabel label = (CLabel) getRealComponent(); + return (String)getEventThreadQueuer().invokeAndWait( + "getText", new IRunnable() { //$NON-NLS-1$ + public Object run() { + try { + return SwtUtils.removeMnemonics(label.getText()); + } catch (NullPointerException e) { + throw new StepExecutionException( + "component must not be null", //$NON-NLS-1$ + EventFactory + .createComponentNotFoundErrorEvent()); + } + } + }); + } + +} diff --git a/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/CTabFolderAdapter.java b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/CTabFolderAdapter.java new file mode 100644 index 000000000..e07fb17d6 --- /dev/null +++ b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/CTabFolderAdapter.java @@ -0,0 +1,121 @@ +/******************************************************************************* + * 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.uiadapter; + +import org.eclipse.jubula.rc.common.driver.IRunnable; +import org.eclipse.jubula.rc.common.exception.StepExecutionException; +import org.eclipse.jubula.rc.common.logger.AutServerLogger; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.ITabPaneAdapter; +import org.eclipse.jubula.rc.swt.utils.SwtUtils; +import org.eclipse.swt.custom.CTabFolder; +import org.eclipse.swt.widgets.Control; +/** + * Implementation of the Interface <code>ITabPane</code> as a + * adapter for the <code>CTabFolder</code> component. + * @author BREDEX GmbH + * + */ +public class CTabFolderAdapter extends WidgetAdapter + implements ITabPaneAdapter { + + /** the logger */ + private static AutServerLogger log = + new AutServerLogger(CTabFolderAdapter.class); + + /** the CTabFolder from the AUT */ + private CTabFolder m_ctabFolder; + + /** + * + * @param objectToAdapt the component from the AUT + */ + public CTabFolderAdapter(Object objectToAdapt) { + super(objectToAdapt); + m_ctabFolder = (CTabFolder) objectToAdapt; + } + + /** + * {@inheritDoc} + */ + public int getTabCount() { + return ((Integer)getEventThreadQueuer().invokeAndWait( + "getSelectedIndex", //$NON-NLS-1$ + new IRunnable() { + + public Object run() throws StepExecutionException { + return new Integer(m_ctabFolder.getItemCount()); + } + })).intValue(); + } + + /** + * {@inheritDoc} + */ + public String getTitleofTab(final int index) { + return (String)getEventThreadQueuer().invokeAndWait( + "verifyTextOfTabByIndex", //$NON-NLS-1$ + new IRunnable() { + public Object run() throws StepExecutionException { + return m_ctabFolder.getItem(index).getText(); + } + }); + } + + /** + * {@inheritDoc} + */ + public Object getBoundsAt(final int index) { + return getEventThreadQueuer().invokeAndWait("getBoundsAt", //$NON-NLS-1$ + new IRunnable() { + public Object run() throws StepExecutionException { + return SwtUtils.getRelativeWidgetBounds( + m_ctabFolder.getItem(index), m_ctabFolder); + } + }); + } + + /** + * {@inheritDoc} + */ + public boolean isEnabledAt(final int index) { + return ((Boolean) getEventThreadQueuer().invokeAndWait("isEnabledAt", //$NON-NLS-1$ + new IRunnable() { + public Object run() throws StepExecutionException { + Control control = m_ctabFolder.getItem(index).getControl(); + if (control == null) { + // FIXME zeb: Strange workaround for CTabFolders, + // which somehow never seem to have an associated + // Control. + log.debug(this + ".getControl() returned null."); //$NON-NLS-1$ + return Boolean.TRUE; + } + + return control.isEnabled() ? Boolean.TRUE : Boolean.FALSE; + + } + })).booleanValue(); + } + + /** + * {@inheritDoc} + */ + public int getSelectedIndex() { + return ((Integer)getEventThreadQueuer().invokeAndWait( + "getSelectedIndex", //$NON-NLS-1$ + new IRunnable() { + + public Object run() throws StepExecutionException { + return new Integer(m_ctabFolder.getSelectionIndex()); + } + })).intValue(); + } + +} diff --git a/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/ComboAdapter.java b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/ComboAdapter.java new file mode 100644 index 000000000..484ea7ad9 --- /dev/null +++ b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/ComboAdapter.java @@ -0,0 +1,196 @@ +/******************************************************************************* + * 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.uiadapter; + +import org.apache.commons.lang.StringUtils; +import org.eclipse.jubula.rc.common.driver.IRunnable; +import org.eclipse.jubula.rc.common.exception.StepExecutionException; +import org.eclipse.jubula.tools.utils.EnvironmentUtils; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Event; +/** + * Implementation of the Interface <code>IComboBoxAdapter</code> as a + * adapter for the <code>Combo</code> component. + * This class is sub classing <code>AbstractComboBoxAdapter</code> because + * <code>Combo</code> and <code>CCombo</code> have common parts + * + * @author BREDEX GmbH + * + */ +public class ComboAdapter extends AbstractComboBoxAdapter { + + /** */ + private Combo m_combobox; + + /** + * + * @param objectToAdapt + */ + public ComboAdapter(Object objectToAdapt) { + super(objectToAdapt); + m_combobox = (Combo) objectToAdapt; + } + + /** + * Select the whole text of the textfield. + */ + public void selectAll() { + click(new Integer(1)); + + // fix for https://bxapps.bredex.de/bugzilla/show_bug.cgi?id=201 + // The keystroke "command + a" sometimes causes an "a" to be entered + // into the text field instead of selecting all text (or having no + // effect). + if (EnvironmentUtils.isMacOS()) { + getEventThreadQueuer().invokeAndWait("combo.selectAll", //$NON-NLS-1$ + new IRunnable() { + public Object run() { + int textLength = StringUtils.length( + m_combobox.getText()); + m_combobox.setSelection(new Point(0, textLength)); + return null; + } + }); + } else { + getRobot().keyStroke(getRobot().getSystemModifierSpec() + " A"); //$NON-NLS-1$ + } + } + + /** + * {@inheritDoc} + */ + public int getSelectedIndex() { + + int selectedIndex = ((Integer)getEventThreadQueuer().invokeAndWait( + ComboAdapter.class.getName() + + "getSelectedIndex", new IRunnable() { //$NON-NLS-1$ + public Object run() throws StepExecutionException { + return new Integer(m_combobox.getSelectionIndex()); + } + })).intValue(); + + return selectedIndex; + } + + /** + * {@inheritDoc} + */ + public String getText() { + Object o = getEventThreadQueuer().invokeAndWait( + "getSelectedItem", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return m_combobox.getText(); + } + }); + return o != null ? o.toString() : null; + } + + /** + * + * {@inheritDoc} + */ + protected boolean isComboEnabled() { + + boolean isEnabled = ((Boolean)getEventThreadQueuer().invokeAndWait( + ComboAdapter.class.getName() + + "isComboEnabled", new IRunnable() { //$NON-NLS-1$ + public Object run() throws StepExecutionException { + return m_combobox.isEnabled() + ? Boolean.TRUE : Boolean.FALSE; + } + })).booleanValue(); + + return isEnabled; + } + + /** + * {@inheritDoc} + */ + protected void selectImpl(int index) { + + // Press 'Escape' key to close the dropdown list + + getRobot().keyType(m_combobox, SWT.ESC); + + // Currently no method to select elements via mouse clicks + selectComboIndex(index); + } + + /** + * + * {@inheritDoc} + */ + protected void openDropdownList() { + // FIXME zeb: Figure out a way to check the status of the dropdown list + toggleDropdownList(); + } + + /** + * Returns the number of items contained in the combo list. + * @return the number of items. + */ + protected int getItemCount() { + return ((Integer)getEventThreadQueuer().invokeAndWait( + "getItemCount", //$NON-NLS-1$ + new IRunnable() { + + public Object run() { + + return new Integer(m_combobox.getItemCount()); + } + + })).intValue(); + + } + + /** + * Returns the item at the given, zero-relative index in the combo list. + * Throws an exception if the index is out of range. + * @param index the index of the item to return + * @return the item at the given index + */ + protected String getItem(final int index) { + return (String)getEventThreadQueuer().invokeAndWait( + "getItem", //$NON-NLS-1$ + new IRunnable() { + + public Object run() { + + return m_combobox.getItem(index); + } + + }); + + } + + /** + * + * @param index the index to select. + * @see Combo#select(int) + */ + private void selectComboIndex(final int index) { + final Combo combo = m_combobox; + getEventThreadQueuer().invokeAndWait("selectComboIndex", new IRunnable() { //$NON-NLS-1$ + public Object run() throws StepExecutionException { + combo.select(index); + Event selectionEvent = new Event(); + selectionEvent.type = SWT.Selection; + selectionEvent.widget = combo; + combo.notifyListeners(SWT.Selection, selectionEvent); + + return null; + } + }); + } + +} diff --git a/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/LabelAdapter.java b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/LabelAdapter.java new file mode 100644 index 000000000..6be795e9e --- /dev/null +++ b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/LabelAdapter.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * 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.uiadapter; + +import org.eclipse.jubula.rc.common.driver.IRunnable; +import org.eclipse.jubula.rc.common.exception.StepExecutionException; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.ITextVerifiable; +import org.eclipse.jubula.rc.swt.utils.SwtUtils; +import org.eclipse.jubula.tools.objects.event.EventFactory; +import org.eclipse.swt.widgets.Label; +/** + * + * @author BREDEX GmbH + * + */ +public class LabelAdapter extends WidgetAdapter implements ITextVerifiable { + + /** + * + * @param objectToAdapt the component to adapt + */ + public LabelAdapter(Object objectToAdapt) { + super(objectToAdapt); + } + + /** + * {@inheritDoc} + */ + public String getText() { + return (String)getEventThreadQueuer().invokeAndWait( + "getText", new IRunnable() { //$NON-NLS-1$ + public Object run() { + try { + Label label = (Label) getRealComponent(); + return SwtUtils.removeMnemonics(label.getText()); + } catch (NullPointerException e) { + throw new StepExecutionException( + "component must not be null", //$NON-NLS-1$ + EventFactory + .createComponentNotFoundErrorEvent()); + } + } + }); + } + +} diff --git a/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/ListAdapter.java b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/ListAdapter.java new file mode 100644 index 000000000..2f3deaf7e --- /dev/null +++ b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/ListAdapter.java @@ -0,0 +1,208 @@ +/******************************************************************************* + * 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.uiadapter; + +import java.util.ArrayList; + +import org.eclipse.jubula.rc.common.CompSystemConstants; +import org.eclipse.jubula.rc.common.driver.ClickOptions; +import org.eclipse.jubula.rc.common.driver.IRunnable; +import org.eclipse.jubula.rc.common.exception.StepExecutionException; +import org.eclipse.jubula.rc.common.implclasses.MatchUtil; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.IListAdapter; +import org.eclipse.jubula.rc.swt.utils.SwtUtils; +import org.eclipse.jubula.tools.objects.event.EventFactory; +import org.eclipse.jubula.tools.objects.event.TestErrorEvent; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.List; +/** + * + * @author BREDEX GmbH + * + */ +public class ListAdapter extends WidgetAdapter implements IListAdapter { + + /** */ + private List m_list; + /** + * + * @param objectToAdapt - + */ + public ListAdapter(Object objectToAdapt) { + super(objectToAdapt); + m_list = (List) objectToAdapt; + } + + /** + * {@inheritDoc} + */ + public String getText() { + String[] selected = getSelectedValues(); + if (selected.length > 0) { + return selected[0]; + } + throw new StepExecutionException("No list item selected", //$NON-NLS-1$ + EventFactory.createActionError(TestErrorEvent.NO_SELECTION)); + } + + /** + * {@inheritDoc} + */ + public int[] getSelectedIndices() { + return (int[])getEventThreadQueuer().invokeAndWait( + "getSelectedIndices", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return m_list.getSelectionIndices(); + } + }); + } + /** + * {@inheritDoc} + */ + public void clickOnIndex(Integer i, ClickOptions co) { + final int iVal = i.intValue(); + scrollIndexToVisible(iVal); + + final Rectangle clickConstraints = + (Rectangle)getEventThreadQueuer().invokeAndWait( + "setClickConstraints", //$NON-NLS-1$ + new IRunnable() { + + public Object run() throws StepExecutionException { + Rectangle constraints = new Rectangle(0, 0, 0, 0); + int displayedItemCount = getDisplayedItemCount(); + int numberBelowTop = 0; + if (displayedItemCount >= m_list.getItemCount()) { + numberBelowTop = iVal; + } else { + numberBelowTop = Math.max(0, iVal + - m_list.getItemCount() + displayedItemCount); + } + + // Set the constraints based on the numberBelowTop + constraints.height = m_list.getItemHeight(); + constraints.width = m_list.getBounds().width; + constraints.y += (numberBelowTop * constraints.height); + // explicitly use list relative bounds here - as e.g. on + // Mac OS systems list.getClientArea() is not relative + // see bug 353905 + Rectangle actualListBounds = + new Rectangle(0, 0, m_list.getClientArea().width, + m_list.getClientArea().height); + return constraints.intersection(actualListBounds); + } + }); + + // Note that we set scrollToVisible false because we have already done + // the scrolling. + getRobot().click(m_list, clickConstraints, + co.setScrollToVisible(false)); + + } + /** + * {@inheritDoc} + */ + public String[] getSelectedValues() { + return (String[])getEventThreadQueuer().invokeAndWait( + "getSelectedValues", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return m_list.getSelection(); + } + }); + } + /** + * {@inheritDoc} + */ + public Integer[] findIndicesOfValues(final String[] values, + final String operator, final String searchType) { + final java.util.List indexList = (java.util.List) + getEventThreadQueuer().invokeAndWait("findIndices", //$NON-NLS-1$ + new IRunnable() { + public Object run() { + final int valuesLength = values.length; + final java.util.List idxList = new ArrayList( + values.length); + final int listItemCount = m_list.getItemCount(); + final MatchUtil matchUtil = MatchUtil.getInstance(); + for (int i = 0; i < valuesLength; i++) { + final String value = values[i]; + for (int j = getStartingIndex(searchType); + j < listItemCount; j++) { + + final String listItem = m_list.getItem(j); + if (matchUtil.match(listItem, value, + operator)) { + + idxList.add(new Integer(j)); + } + } + } + return idxList; + } + }); + Integer[] indices = new Integer[indexList.size()]; + indexList.toArray(indices); + return indices; + } + + /** + * @return the number of items displayed in the list. + */ + private int getDisplayedItemCount() { + return ((Integer)getEventThreadQueuer().invokeAndWait( + "getDisplayedItemCount", //$NON-NLS-1$ + new IRunnable() { + + public Object run() throws StepExecutionException { + int listHeight = SwtUtils.getWidgetBounds(m_list).height; + int itemHeight = m_list.getItemHeight(); + + return new Integer(listHeight / itemHeight); + } + + })).intValue(); + } + + /** + * @param index The index to make visible + */ + private void scrollIndexToVisible(final int index) { + getEventThreadQueuer().invokeAndWait( + "scrollIndexToVisible", //$NON-NLS-1$ + new IRunnable() { + + public Object run() throws StepExecutionException { + + m_list.setTopIndex(index); + + return null; + } + + }); + } + /** + * @param searchType Determines where the search begins ("relative" or "absolute") + * @return The index from which to begin a search, based on the search type + * and (if appropriate) the currently selected cell. + */ + private int getStartingIndex(final String searchType) { + int startingIndex = 0; + if (searchType.equalsIgnoreCase( + CompSystemConstants.SEARCH_TYPE_RELATIVE)) { + int [] selectedIndices = getSelectedIndices(); + // Start from the last selected item, if any item(s) are selected + if (selectedIndices.length > 0) { + startingIndex = selectedIndices[selectedIndices.length - 1] + 1; + } + } + return startingIndex; + } +} diff --git a/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/MenuAdapter.java b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/MenuAdapter.java new file mode 100644 index 000000000..7cecbb143 --- /dev/null +++ b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/MenuAdapter.java @@ -0,0 +1,106 @@ +/******************************************************************************* + * 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.uiadapter; + +import org.eclipse.jubula.rc.common.driver.IEventThreadQueuer; +import org.eclipse.jubula.rc.common.driver.IRobot; +import org.eclipse.jubula.rc.common.driver.IRunnable; +import org.eclipse.jubula.rc.common.exception.RobotException; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.IMenuAdapter; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.IMenuItemAdapter; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.MenuItem; + +/** + * Implements the Menu interface for adapting a <code>SWT.Menu</code> + * + * @author BREDEX GmbH + */ +public class MenuAdapter extends AbstractComponentAdapter + implements IMenuAdapter { + /** the Menu from the AUT */ + private Menu m_menu; + + + /** + * + * @param component graphics component which will be adapted + */ + public MenuAdapter(Object component) { + m_menu = (Menu) component; + } + + /** + * Gets the IEventThreadQueuer. + * + * @return The Robot + * @throws RobotException + * If the Robot cannot be created. + */ + protected IRobot getRobot() throws RobotException { + return getRobotFactory().getRobot(); + } + + /** + * @return The event thread queuer. + */ + public IEventThreadQueuer getEventThreadQueuer() { + return getRobotFactory().getEventThreadQueuer(); + } + /** + * {@inheritDoc} + */ + public Object getRealComponent() { + return m_menu; + } + /** + * {@inheritDoc} + */ + public void setComponent(Object element) { + m_menu = (Menu) element; + + } + /** + * {@inheritDoc} + */ + public IMenuItemAdapter[] getItems() { + + MenuItem[] items = + (MenuItem[]) getEventThreadQueuer().invokeAndWait( + "getItems", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return m_menu.getItems(); + } + }); + IMenuItemAdapter[] adapters = new IMenuItemAdapter[items.length]; + for (int i = 0; i < items.length; i++) { + IMenuItemAdapter menuItem = new MenuItemAdapter(items[i]); + adapters[i] = menuItem; + } + return adapters; + } + /** + * {@inheritDoc} + */ + public int getItemCount() { + Integer itemCount = (Integer) getEventThreadQueuer().invokeAndWait( + "getItemCount", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return new Integer(m_menu.getItemCount()); + } + }); + return itemCount.intValue(); + } + + + + +} diff --git a/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/MenuItemAdapter.java b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/MenuItemAdapter.java new file mode 100644 index 000000000..bbc1fdf78 --- /dev/null +++ b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/MenuItemAdapter.java @@ -0,0 +1,532 @@ +/******************************************************************************* + * 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.uiadapter; + +import org.eclipse.jubula.rc.common.driver.ClickOptions; +import org.eclipse.jubula.rc.common.driver.IEventMatcher; +import org.eclipse.jubula.rc.common.driver.IEventThreadQueuer; +import org.eclipse.jubula.rc.common.driver.IRobot; +import org.eclipse.jubula.rc.common.driver.IRobotEventConfirmer; +import org.eclipse.jubula.rc.common.driver.IRobotEventInterceptor; +import org.eclipse.jubula.rc.common.driver.IRunnable; +import org.eclipse.jubula.rc.common.driver.InterceptorOptions; +import org.eclipse.jubula.rc.common.exception.RobotException; +import org.eclipse.jubula.rc.common.exception.StepExecutionException; +import org.eclipse.jubula.rc.common.listener.EventLock; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.IMenuAdapter; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.IMenuItemAdapter; +import org.eclipse.jubula.rc.swt.driver.EventThreadQueuerSwtImpl; +import org.eclipse.jubula.rc.swt.driver.RobotFactorySwtImpl; +import org.eclipse.jubula.rc.swt.driver.SelectionSwtEventMatcher; +import org.eclipse.jubula.rc.swt.driver.ShowSwtEventMatcher; +import org.eclipse.jubula.rc.swt.implclasses.EventListener; +import org.eclipse.jubula.rc.swt.implclasses.EventListener.Condition; +import org.eclipse.jubula.rc.swt.utils.SwtUtils; +import org.eclipse.jubula.tools.constants.TimeoutConstants; +import org.eclipse.jubula.tools.i18n.I18n; +import org.eclipse.jubula.tools.objects.event.EventFactory; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.MenuItem; + +/** + * Implements the MenuItem interface for adapting a <code>SWT.MenuItem</code> + * + * @author BREDEX GmbH + */ +public class MenuItemAdapter extends AbstractComponentAdapter + implements IMenuItemAdapter { + + /** the MenuItem from the AUT*/ + private MenuItem m_menuItem; + + + /** + * + * @param component graphics component which will be adapted + */ + public MenuItemAdapter(Object component) { + super(); + m_menuItem = (MenuItem) component; + } + + /** + * Gets the IEventThreadQueuer. + * + * @return The Robot + * @throws RobotException + * If the Robot cannot be created. + */ + protected IRobot getRobot() throws RobotException { + return getRobotFactory().getRobot(); + } + + /** + * @return The event thread queuer. + */ + public IEventThreadQueuer getEventThreadQueuer() { + return getRobotFactory().getEventThreadQueuer(); + } + + + /** + * {@inheritDoc} + */ + public Object getRealComponent() { + + return m_menuItem; + } + /** + * {@inheritDoc} + */ + public void setComponent(Object element) { + m_menuItem = (MenuItem) element; + + } + /** + * {@inheritDoc} + */ + public String getText() { + return (String) getEventThreadQueuer().invokeAndWait( + "getText", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return m_menuItem.getText(); + } + }); + } + + /** + * {@inheritDoc} + */ + public boolean isEnabled() { + final Boolean isEnabled = (Boolean) getEventThreadQueuer() + .invokeAndWait("isEnabled", new IRunnable() { //$NON-NLS-1$ + public Object run() throws StepExecutionException { + return m_menuItem.isEnabled() ? Boolean.TRUE + : Boolean.FALSE; + } + }); + return isEnabled.booleanValue(); + + } + /** + * {@inheritDoc} + */ + public boolean isExisting() { + if (m_menuItem != null) { + return true; + } + return false; + } + /** + * {@inheritDoc} + */ + public boolean isSelected() { + final Boolean isSelected = (Boolean)getEventThreadQueuer() + .invokeAndWait("isSelected", new IRunnable() { //$NON-NLS-1$ + public Object run() throws StepExecutionException { + return m_menuItem.getSelection() + ? Boolean.TRUE : Boolean.FALSE; + } + }); + return isSelected.booleanValue(); + } + + /** + * @return - + */ + public boolean isShowing() { + + return true; //FIXME is here a Showing implementation? + } + /** + * {@inheritDoc} + */ + public IMenuAdapter getMenu() { + + Menu menu = + (Menu) getEventThreadQueuer().invokeAndWait( + "getItems", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return m_menuItem.getMenu(); + } + }); + + + return new MenuAdapter(menu); + } + /** + * {@inheritDoc} + */ + public boolean hasSubMenu() { + + + + if (getMenu() != null) { + return true; + } + return false; + } + + + /** + * Checks whether the given menu item is a separator. + * This method runs in the GUI thread. + * @return <code>true</code> if <code>menuItem</code> is a separator item. + * Otherwise <code>false</code>. + */ + public boolean isSeparator() { + final Boolean isSeparator = (Boolean)getEventThreadQueuer() + .invokeAndWait( + ".isSeparator", new IRunnable() { //$NON-NLS-1$ + public Object run() throws StepExecutionException { + return (m_menuItem.getStyle() & SWT.SEPARATOR) != 0 + ? Boolean.TRUE : Boolean.FALSE; + } + }); + return isSeparator.booleanValue(); + } + + /** + * {@inheritDoc} + */ + public void selectMenuItem() { + Rectangle bounds = getMenuItemBounds(); + Rectangle nullBounds = new Rectangle(0, 0, 0, 0); + + if (bounds.equals(nullBounds)) { + selectProgramatically(); + } else { + clickMenuItem(getRobot(), m_menuItem, 1); + } + + } + + /** + * {@inheritDoc} + */ + public IMenuAdapter openSubMenu() { + final MenuItem menuItem = m_menuItem; + MenuShownCondition cond = new MenuShownCondition(menuItem); + EventLock lock = new EventLock(); + final EventListener listener = new EventListener(lock, cond); + final Display d = menuItem.getDisplay(); + final IEventThreadQueuer queuer = new EventThreadQueuerSwtImpl(); + + queuer.invokeAndWait("addMenuShownListeners", new IRunnable() { //$NON-NLS-1$ + public Object run() { + d.addFilter(SWT.Show, listener); + + return null; + } + }); + try { + // Menu bar items require a click in order to open the submenu. + // Cascading menus are opened with a mouse-over and + // may be closed by a click. + int clickCount = isMenuBarItem(menuItem) ? 1 : 0; + Menu menu = (Menu)getEventThreadQueuer().invokeAndWait( + "openSubMenu", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return menuItem.getMenu(); + } + }); + Rectangle bounds = getMenuItemBounds(); + Rectangle nullBounds = new Rectangle(0, 0, 0, 0); + if (bounds.equals(nullBounds)) { + openSubMenuProgramatically(menu); + } else { + clickMenuItem(getRobot(), menuItem, clickCount); + } + synchronized (lock) { + long timeout = TimeoutConstants.SERVER_TIMEOUT_WAIT_FOR_POPUP; + long done = System.currentTimeMillis() + timeout; + long now; + while (!lock.isReleased() && timeout > 0) { + lock.wait(timeout); + now = System.currentTimeMillis(); + timeout = done - now; + } + } + } catch (InterruptedException e) { // ignore + } finally { + queuer.invokeAndWait("removeMenuShownListeners", new IRunnable() { //$NON-NLS-1$ + public Object run() { + d.removeFilter(SWT.Show, listener); + + return null; + } + }); + } + if (!lock.isReleased()) { + String itemText = (String)getEventThreadQueuer().invokeAndWait( + "getItemText", new IRunnable() { //$NON-NLS-1$ + + public Object run() throws StepExecutionException { + if (menuItem != null && !menuItem.isDisposed()) { + return menuItem.getText(); + } + return "unknown menu item"; //$NON-NLS-1$ + } + + }); + itemText = SwtUtils.removeMnemonics(itemText); + throw new StepExecutionException( + I18n.getString("TestErrorEvent.MenuDidNotAppear", //$NON-NLS-1$ + new String [] {itemText}), + EventFactory.createActionError( + "TestErrorEvent.MenuDidNotAppear", //$NON-NLS-1$ + new String [] {itemText})); + } + return new MenuAdapter(cond.getMenu()); + } + + /** + * @param menuItem the menu item to check + * @return <code>true</code> of the given menu item is part of a menu + * bar. Otherwise, <code>false</code>. + */ + private boolean isMenuBarItem(final MenuItem menuItem) { + return ((Boolean)getEventThreadQueuer().invokeAndWait( + "isMenuBarItem", new IRunnable() { //$NON-NLS-1$ + + public Object run() throws StepExecutionException { + if (menuItem != null && !menuItem.isDisposed()) { + Menu parent = menuItem.getParent(); + if (parent != null && !parent.isDisposed()) { + return (parent.getStyle() & SWT.BAR) != 0 + ? Boolean.TRUE : Boolean.FALSE; + } + } + return Boolean.FALSE; + } + + })).booleanValue(); + } + + + /** + * Waits for a submenu to appear. Examples of submenus are cascading menus + * and pulldown menus. + * + * @author BREDEX GmbH + * @created Oct 30, 2008 + */ + public static class MenuShownCondition implements Condition { + /** the menu that was shown */ + private Menu m_shownMenu = null; + + /** the parent item of the expected menu */ + private MenuItem m_parentItem; + + /** + * Constructor + * + * @param parentItem The parent item of the expected menu. This + * condition only matches if a menu with parent item + * <code>parentItem</code> appears. + */ + MenuShownCondition(MenuItem parentItem) { + m_parentItem = parentItem; + } + + /** + * + * @return the menu that appeared + */ + public Menu getMenu() { + return m_shownMenu; + } + + /** + * + * {@inheritDoc} + */ + public boolean isTrue(Event event) { + if (event.type == SWT.Show && event.widget instanceof Menu + && ((Menu)(event.widget)).getParentItem() == m_parentItem) { + m_shownMenu = (Menu)event.widget; + return true; + } + + return false; + } + } + + /** + * Clicks on a menu item + * + * @param robot the robot + * @param item the menu item + * @param clickCount the number of times to click the menu item + */ + public static void clickMenuItem(IRobot robot, final MenuItem item, + int clickCount) { + // FIXME existiert so schon und kann man benutzen +// if (!isMenuItemEnabled(item)) { +// throw new StepExecutionException("menu item not enabled", //$NON-NLS-1$ +// EventFactory.createActionError( +// TestErrorEvent.MENU_ITEM_NOT_ENABLED)); +// } + + robot.click(item, null, + ClickOptions.create() + .setClickType(ClickOptions.ClickType.RELEASED) + .setStepMovement(false).setClickCount(clickCount)); + + } + /** + * + * @return bounds of MenuItem + */ + public Rectangle getMenuItemBounds() { + Rectangle bounds = (Rectangle)getEventThreadQueuer().invokeAndWait( + "getMenuItemBounds", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return SwtUtils.getBounds(m_menuItem); + } + }); + return bounds; + } + + /** + * open SubMenu programatically (for Mac OS) + * @param menu the Menu + */ + public void openSubMenuProgramatically(final Menu menu) { +// if (!isMenuEnabled(menu)) { +// throw new StepExecutionException("menu item not enabled", //$NON-NLS-1$ +// EventFactory.createActionError( +// TestErrorEvent.MENU_ITEM_NOT_ENABLED)); +// } + + final InterceptorOptions options = new InterceptorOptions( + new long[]{SWT.Show}); + final IEventMatcher matcher = + new ShowSwtEventMatcher(); + RobotFactorySwtImpl robotSwt = new RobotFactorySwtImpl(); + IRobotEventInterceptor interceptor = + robotSwt.getRobotEventInterceptor(); + final IRobotEventConfirmer confirmer = interceptor + .intercept(options); + + final Event event = new Event(); + event.time = (int) System.currentTimeMillis(); + event.widget = menu; + event.display = menu.getDisplay(); + event.type = SWT.Show; + + getEventThreadQueuer().invokeAndWait( + "openSubMenuProgramatically", new IRunnable() { //$NON-NLS-1$ + public Object run() { + + menu.notifyListeners(SWT.Show, event); + + return null; + } + }); + + try { + confirmer.waitToConfirm(menu, matcher); + } catch (RobotException re) { + final StringBuffer sb = new StringBuffer( + "Robot exception occurred while clicking...\n"); //$NON-NLS-1$ +// logRobotException(menuItem, re, sb); + sb.append("Component: "); //$NON-NLS-1$ + + getEventThreadQueuer().invokeAndWait( + "getBounds", new IRunnable() { //$NON-NLS-1$ + public Object run() + throws StepExecutionException { + sb.append(menu); + // Return value not used + return null; + } + }); +// log.error(sb.toString(), re); + throw re; + } + } + + /** + * select MenuItem programatically (for Mac OS) + */ + public void selectProgramatically() { +// FIXME must implement this check case +// if (!isMenuItemEnabled(menuItem)) { +// throw new StepExecutionException("menu item not enabled", //$NON-NLS-1$ +// EventFactory.createActionError( +// TestErrorEvent.MENU_ITEM_NOT_ENABLED)); +// } + final MenuItem menuItem = m_menuItem; + final InterceptorOptions options = new InterceptorOptions( + new long[]{SWT.Selection}); + final IEventMatcher matcher = + new SelectionSwtEventMatcher(); + RobotFactorySwtImpl robotSwt = new RobotFactorySwtImpl(); + IRobotEventInterceptor interceptor = + robotSwt.getRobotEventInterceptor(); + final IRobotEventConfirmer confirmer = interceptor + .intercept(options); + + final Event event = new Event(); + event.time = (int) System.currentTimeMillis(); + event.widget = menuItem; + event.display = menuItem.getDisplay(); + event.type = SWT.Selection; + + getEventThreadQueuer().invokeLater( + "selectProgramatically", new Runnable() { //$NON-NLS-1$ + public void run() { + //if menuitem is checkbox or radiobutton set Selection + if ((menuItem.getStyle() & SWT.CHECK) == 0 + || (menuItem.getStyle() & SWT.RADIO) == 0) { + if (menuItem.getSelection()) { + menuItem.setSelection(false); + } else { + menuItem.setSelection(true); + } + } + + menuItem.notifyListeners(SWT.Selection, event); + + } + }); + + try { + confirmer.waitToConfirm(menuItem, matcher); + } catch (RobotException re) { + final StringBuffer sb = new StringBuffer( + "Robot exception occurred while clicking...\n"); //$NON-NLS-1$ + //logRobotException(menuItem, re, sb); + sb.append("Component: "); //$NON-NLS-1$ + + getEventThreadQueuer().invokeAndWait( + "getBounds", new IRunnable() { //$NON-NLS-1$ + public Object run() + throws StepExecutionException { + sb.append(menuItem); + // Return value not used + return null; + } + }); +// FIXME LOG IS MISSING HERE +// log.error(sb.toString(), re); + throw re; + } + + } + + +} diff --git a/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/StyledTextAdapter.java b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/StyledTextAdapter.java new file mode 100644 index 000000000..45651e759 --- /dev/null +++ b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/StyledTextAdapter.java @@ -0,0 +1,151 @@ +/******************************************************************************* + * 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.uiadapter; + +import org.eclipse.jubula.rc.common.driver.IRunnable; +import org.eclipse.jubula.rc.common.exception.StepExecutionException; +import org.eclipse.jubula.rc.common.logger.AutServerLogger; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.ITextComponentAdapter; +import org.eclipse.jubula.tools.utils.EnvironmentUtils; +import org.eclipse.swt.custom.StyledText; + +/** + * Implementation of the Interface <code>ITextComponentAdapter</code> as a + * adapter for the <code>StyledText</code> component. + * @author BREDEX GmbH + * + */ +public class StyledTextAdapter extends WidgetAdapter + implements ITextComponentAdapter { + + /** the logger */ + private static AutServerLogger log = new AutServerLogger( + StyledTextAdapter.class); + /** */ + private StyledText m_styledText; + /** + * + * @param objectToAdapt + */ + public StyledTextAdapter(Object objectToAdapt) { + super(objectToAdapt); + m_styledText = (StyledText) objectToAdapt; + } + + /** + * {@inheritDoc} + */ + public String getText() { + String actual = (String)getEventThreadQueuer().invokeAndWait( + "getText", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return m_styledText.getText(); + } + }); + return actual; + } + + /** + * {@inheritDoc} + */ + public void setSelection(final int start) { + getEventThreadQueuer().invokeAndWait("setSelection", //$NON-NLS-1$ + new IRunnable() { + public Object run() { + m_styledText.setSelection(start); + return null; + } + }); + + } + + /** + * {@inheritDoc} + */ + public void setSelection(final int start, final int end) { + getEventThreadQueuer().invokeAndWait("setSelection", //$NON-NLS-1$ + new IRunnable() { + public Object run() { + m_styledText.setSelection(start, end); + return null; + } + }); + + } + + /** + * {@inheritDoc} + */ + public String getSelectionText() { + String actual = (String)getEventThreadQueuer().invokeAndWait( + "getText", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return m_styledText.getSelectionText(); + } + }); + return actual; + } + + /** + * {@inheritDoc} + */ + public void selectAll() { + final String totalText = getText(); + + // fix for https://bxapps.bredex.de/bugzilla/show_bug.cgi?id=201 + // The keystroke "command + a" sometimes causes an "a" to be entered + // into the text field instead of selecting all text (or having no + // effect). + if (!EnvironmentUtils.isMacOS()) { + try { + getRobot().keyStroke(getRobot().getSystemModifierSpec() + " A"); //$NON-NLS-1$ + } catch (StepExecutionException see) { + /*This might happen under certain circumstances e.g. on MacOS X see + bug 342691 */ + log.warn(see); + } + } + + if (!totalText.equals(getSelectionText())) { + // the selection failed for some reason + getEventThreadQueuer().invokeAndWait("text.selectAll", //$NON-NLS-1$ + new IRunnable() { + public Object run() { + m_styledText.selectAll(); + return null; + } + }); + } + + String selectionText = getSelectionText(); + if (!totalText.equals(selectionText)) { + log.warn("SelectAll failed!\n" //$NON-NLS-1$ + + "Total text: '" + totalText + "'\n" //$NON-NLS-1$//$NON-NLS-2$ + + "Selected text: '" + selectionText + "'"); //$NON-NLS-1$ //$NON-NLS-2$ + } + + } + + /** + * {@inheritDoc} + */ + public boolean isEditable() { + return ((Boolean)getEventThreadQueuer().invokeAndWait( + "isEditable", //$NON-NLS-1$ + new IRunnable() { + public Object run() { + return m_styledText.getEditable() + && m_styledText.getEnabled() + ? Boolean.TRUE : Boolean.FALSE; // see findBugs + } + })).booleanValue(); + } +} diff --git a/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/TabFolderAdapter.java b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/TabFolderAdapter.java new file mode 100644 index 000000000..2e0b4537d --- /dev/null +++ b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/TabFolderAdapter.java @@ -0,0 +1,105 @@ +/******************************************************************************* + * 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.uiadapter; + +import org.eclipse.jubula.rc.common.driver.IRunnable; +import org.eclipse.jubula.rc.common.exception.StepExecutionException; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.ITabPaneAdapter; +import org.eclipse.jubula.rc.swt.utils.SwtUtils; +import org.eclipse.swt.widgets.TabFolder; +/** + * Implementation of the Interface <code>ITabPane</code> as a + * adapter for the <code>TabFolder</code> component. + * @author BREDEX GmbH + * + */ +public class TabFolderAdapter extends WidgetAdapter implements ITabPaneAdapter { + + /** the tabFolder from the AUT */ + private TabFolder m_tabFolder; + + /** + * + * @param objectToAdapt the component from the AUT + */ + public TabFolderAdapter(Object objectToAdapt) { + super(objectToAdapt); + m_tabFolder = (TabFolder) objectToAdapt; + } + + /** + * {@inheritDoc} + */ + public int getTabCount() { + return ((Integer)getEventThreadQueuer().invokeAndWait( + "getSelectedIndex", //$NON-NLS-1$ + new IRunnable() { + + public Object run() throws StepExecutionException { + return new Integer(m_tabFolder.getItemCount()); + } + })).intValue(); + } + + /** + * {@inheritDoc} + */ + public String getTitleofTab(final int index) { + return (String)getEventThreadQueuer().invokeAndWait( + "verifyTextOfTabByIndex", //$NON-NLS-1$ + new IRunnable() { + public Object run() throws StepExecutionException { + return m_tabFolder.getItem(index).getText(); + } + }); + } + + /** + * {@inheritDoc} + */ + public Object getBoundsAt(final int index) { + return getEventThreadQueuer().invokeAndWait("getBoundsAt", //$NON-NLS-1$ + new IRunnable() { + public Object run() throws StepExecutionException { + return SwtUtils.getRelativeWidgetBounds( + m_tabFolder.getItem(index), m_tabFolder); + } + }); + } + + /** + * {@inheritDoc} + */ + public boolean isEnabledAt(final int index) { + return ((Boolean) getEventThreadQueuer().invokeAndWait("isEnabledAt", //$NON-NLS-1$ + new IRunnable() { + public Object run() throws StepExecutionException { + return m_tabFolder.getItem(index).getControl() + .isEnabled() ? Boolean.TRUE : Boolean.FALSE; + } + })).booleanValue(); + } + + /** + * {@inheritDoc} + */ + public int getSelectedIndex() { + return ((Integer)getEventThreadQueuer().invokeAndWait( + "getSelectedIndex", //$NON-NLS-1$ + new IRunnable() { + + public Object run() throws StepExecutionException { + return new Integer(m_tabFolder.getSelectionIndex()); + } + })).intValue(); + } + +} diff --git a/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/TableAdapter.java b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/TableAdapter.java new file mode 100644 index 000000000..a15db0381 --- /dev/null +++ b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/TableAdapter.java @@ -0,0 +1,534 @@ +/******************************************************************************* + * 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.uiadapter; + +import java.awt.Rectangle; + +import org.eclipse.jubula.rc.common.driver.ClickOptions; +import org.eclipse.jubula.rc.common.driver.IRunnable; +import org.eclipse.jubula.rc.common.exception.StepExecutionException; +import org.eclipse.jubula.rc.common.implclasses.IndexConverter; +import org.eclipse.jubula.rc.common.implclasses.MatchUtil; +import org.eclipse.jubula.rc.common.implclasses.table.Cell; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.ITableAdapter; +import org.eclipse.jubula.rc.swt.listener.TableSelectionTracker; +import org.eclipse.jubula.rc.swt.utils.SwtUtils; +import org.eclipse.jubula.tools.objects.event.EventFactory; +import org.eclipse.jubula.tools.objects.event.TestErrorEvent; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.TableCursor; +import org.eclipse.swt.graphics.FontMetrics; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.swt.widgets.TableItem; +/** + * Implements the Table interface for adapting a <code>SWT.Table</code> + * + * @author BREDEX GmbH + */ +public class TableAdapter extends WidgetAdapter implements ITableAdapter { + /** */ + private Table m_table; + + /** + * + * @param objectToAdapt graphics component which will be adapted + */ + public TableAdapter(Object objectToAdapt) { + super(objectToAdapt); + m_table = (Table) objectToAdapt; + } + + /** {@inheritDoc} */ + public int getColumnCount() { + Integer returnvalue = (Integer) getEventThreadQueuer().invokeAndWait( + "getColumnCount", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return new Integer(m_table.getColumnCount()); + } + }); + return returnvalue.intValue(); + } + + /** {@inheritDoc} */ + public int getRowCount() { + Integer returnvalue = (Integer) getEventThreadQueuer().invokeAndWait( + "getRowCount", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return new Integer(m_table.getItemCount()); + } + }); + return returnvalue.intValue(); + } + + /** {@inheritDoc} */ + public String getCellText(final int row, final int column) { + String current = (String)getEventThreadQueuer().invokeAndWait("getCellText", //$NON-NLS-1$ + new IRunnable() { + public Object run() { + String value = m_table.getItem(row).getText(column); +// if (log.isDebugEnabled()) { +// log.debug("Getting cell text:"); //$NON-NLS-1$ +// log.debug("Row, col: " + row + ", " + col); //$NON-NLS-1$ //$NON-NLS-2$ +// log.debug("Value: " + value); //$NON-NLS-1$ +// } + return value; + } + }); + return current; + } + + /** {@inheritDoc} */ + public String getColumnName(final int column) { + String current = (String)getEventThreadQueuer().invokeAndWait("getColumnName", //$NON-NLS-1$ + new IRunnable() { + public Object run() { + String value = m_table.getColumn(column).getText(); + return value; + } + }); + return current; + } + + /** {@inheritDoc} */ + public int getColumnFromString(final String col, final String operator) { + int column = -2; + try { + int usrIdxCol = Integer.parseInt(col); + if (usrIdxCol == 0) { + usrIdxCol = usrIdxCol + 1; + } + column = IndexConverter.toImplementationIndex( + usrIdxCol); + } catch (NumberFormatException nfe) { + try { + Boolean isVisible; + isVisible = (Boolean)getEventThreadQueuer().invokeAndWait( + "getColumnFromString", //$NON-NLS-1$ + new IRunnable() { + public Object run() { + return new Boolean(m_table.getHeaderVisible()); + } + }); + if (!(isVisible.booleanValue())) { + throw new StepExecutionException("No Header", //$NON-NLS-1$ + EventFactory.createActionError( + TestErrorEvent.NO_HEADER)); + } + + Integer implCol; + implCol = (Integer)getEventThreadQueuer().invokeAndWait( + "getColumnFromString", new IRunnable() { //$NON-NLS-1$ + public Object run() throws StepExecutionException { + for (int i = 0; i < m_table.getColumnCount(); i++) { + TableColumn tblCol = m_table.getColumn(i); + if (MatchUtil.getInstance().match( + tblCol.getText(), col, operator)) { + return new Integer (i); + } + } + return new Integer (-2); + } + }); + column = implCol.intValue(); + } catch (IllegalArgumentException iae) { + //do nothing here + } + } + return column; + } + + /** {@inheritDoc} */ + public String getRowName(final int row) { + String current = (String)getEventThreadQueuer().invokeAndWait("getRowName", //$NON-NLS-1$ + new IRunnable() { + public Object run() { + String value = m_table.getItem(row).getText(); + return value; + } + }); + return current; + } + + /** {@inheritDoc} */ + public int getRowFromString(final String row, final String operator) { + int rowInt = -2; + try { + rowInt = IndexConverter.toImplementationIndex( + Integer.parseInt(row)); + if (rowInt == -1) { + Boolean isVisible; + isVisible = (Boolean)getEventThreadQueuer().invokeAndWait( + "getRowFromString", //$NON-NLS-1$ + new IRunnable() { + public Object run() { + return new Boolean(m_table.getHeaderVisible()); + } + }); + if (!(isVisible.booleanValue())) { + throw new StepExecutionException("Header not visible", //$NON-NLS-1$ + EventFactory.createActionError( + TestErrorEvent.NO_HEADER)); + } + } + } catch (NumberFormatException nfe) { + Integer implRow; + implRow = (Integer)getEventThreadQueuer().invokeAndWait( + "getRowFromString", //$NON-NLS-1$ + new IRunnable() { + public Object run() throws StepExecutionException { + for (int i = 0; i < m_table.getItemCount(); i++) { + String cellTxt = getCellText(i, 0); + if (MatchUtil.getInstance().match( + cellTxt, row, operator)) { + return new Integer(i); + } + } + return new Integer(-2); + } + }); + rowInt = implRow.intValue(); + } + return rowInt; + } + + /** {@inheritDoc} */ + public Rectangle getBounds() { + Rectangle returnvalue = (Rectangle) getEventThreadQueuer() + .invokeAndWait("getBounds", //$NON-NLS-1$ + new IRunnable() { + public Object run() throws StepExecutionException { + return m_table.getBounds(); + } + }); + + return returnvalue; + } + + /** {@inheritDoc} */ + public Rectangle getHeaderBounds(final int col) { + Rectangle cellBounds; + cellBounds = (Rectangle)getEventThreadQueuer().invokeAndWait( + "getHeaderBounds", //$NON-NLS-1$ + new IRunnable() { + public Object run() throws StepExecutionException { + org.eclipse.swt.graphics.Rectangle rect = + m_table.getItem(0).getBounds(col); + rect.y = m_table.getClientArea().y; + return new Rectangle(rect.x, rect.y, rect.width, + rect.height); + } + }); + return cellBounds; + } + + /** {@inheritDoc} */ + public Cell getSelectedCell() throws StepExecutionException { + Cell cell = (Cell) getEventThreadQueuer().invokeAndWait( + "getSelectedSell", new IRunnable() { //$NON-NLS-1$ + public Object run() throws StepExecutionException { + return TableSelectionTracker.getInstance() + .getSelectedCell(m_table); + } + }); + return cell; + } + + /** {@inheritDoc} */ + public boolean isHeaderVisible() { + Boolean isVisible; + isVisible = (Boolean)getEventThreadQueuer().invokeAndWait( + "isHeaderVisible", //$NON-NLS-1$ + new IRunnable() { + public Object run() { + return new Boolean(m_table.getHeaderVisible()); + } + }); + return isVisible.booleanValue(); + } + + /** {@inheritDoc} */ + public boolean isCellEditable(final int row, final int col) { + final Control cellEditor = (Control) + activateEditor(new Cell(row, col)); + boolean isEditable = ((Boolean)getEventThreadQueuer().invokeAndWait( + "isCellEditable", //$NON-NLS-1$ + new IRunnable() { + public Object run() { + + return isEditable(cellEditor) + ? Boolean.TRUE : Boolean.FALSE; + } + })).booleanValue(); + return isEditable; + } + + /** {@inheritDoc} */ + public boolean hasCellSelection() { + TableItem[] selItems = (TableItem[])getEventThreadQueuer() + .invokeAndWait("hasCellSelection", //$NON-NLS-1$ + new IRunnable() { + public Object run() { + return m_table.getSelection(); + } + }); + return selItems.length > 0; + } + + /** + * {@inheritDoc} + */ + public Rectangle scrollCellToVisible(final int row, final int col) + throws StepExecutionException { + final Table table = m_table; + getEventThreadQueuer().invokeAndWait("scrollCellToVisible", //$NON-NLS-1$ + new IRunnable() { + public Object run() { + if (table.getColumnCount() > 0 || col > 0) { + table.showColumn(table.getColumn(col)); + } + table.showItem(table.getItem(row)); + return null; + } + }); + + final Rectangle cellBoundsRelativeToParent = getCellBounds(row, col); + + getEventThreadQueuer().invokeAndWait("getCellBoundsRelativeToParent", //$NON-NLS-1$ + new IRunnable() { + public Object run() { + org.eclipse.swt.graphics.Point cellOriginRelativeToParent = + table.getDisplay().map( + table, table.getParent(), + new org.eclipse.swt.graphics.Point( + cellBoundsRelativeToParent.x, + cellBoundsRelativeToParent.y)); + cellBoundsRelativeToParent.x = + cellOriginRelativeToParent.x; + cellBoundsRelativeToParent.y = + cellOriginRelativeToParent.y; + return null; + } + }); + + Control parent = (Control)getEventThreadQueuer().invokeAndWait("getParent", //$NON-NLS-1$ + new IRunnable() { + public Object run() { + table.getParent(); + return null; + } + }); + + + getRobot().scrollToVisible( + parent, cellBoundsRelativeToParent); + + return getVisibleBounds(getCellBounds(row, col)); + } + + /** + * + * @param row The row of the cell + * @param col The column of the cell + * @return The bounding rectangle for the cell, relative to the table's + * location. + */ + private Rectangle getCellBounds(final int row, final int col) { + Rectangle cellBounds = (Rectangle)getEventThreadQueuer().invokeAndWait( + "evaluateCellBounds", //$NON-NLS-1$ + new IRunnable() { + public Object run() { + checkRowColBounds(row, col); + TableItem ti = m_table.getItem(row); + int column = (m_table.getColumnCount() > 0 || col > 0) + ? col : 0; + org.eclipse.swt.graphics.Rectangle r = + ti.getBounds(column); + String text = ti.getText(column); + Image image = ti.getImage(column); + if (text != null && text.length() != 0) { + GC gc = new GC(m_table); + int charWidth = 0; + try { + FontMetrics fm = gc.getFontMetrics(); + charWidth = fm.getAverageCharWidth(); + } finally { + gc.dispose(); + } + r.width = text.length() * charWidth; + if (image != null) { + r.width += image.getBounds().width; + } + } else if (image != null) { + r.width = image.getBounds().width; + } + if (column > 0) { + TableColumn tc = m_table.getColumn(column); + int alignment = tc.getAlignment(); + if (alignment == SWT.CENTER) { + r.x += ((double)tc.getWidth() / 2) + - ((double)r.width / 2); + } + if (alignment == SWT.RIGHT) { + r.x += tc.getWidth() - r.width; + } + } + + return new Rectangle(r.x, r.y, r.width, r.height); + } + }); + return cellBounds; + } + + /** + * Checks wether <code>0 <= value < count</code>. + * @param value The value to check. + * @param count The upper bound. + */ + private void checkBounds(int value, int count) { + if (value < 0 || value >= count) { + throw new StepExecutionException("Invalid row/column: " + value, //$NON-NLS-1$ + EventFactory.createActionError( + TestErrorEvent.INVALID_INDEX_OR_HEADER)); + } + } + + /** + * Checks if the passed row and column are inside the bounds of the Table. + * @param row The row + * @param column The column + * @throws StepExecutionException If the row or the column is outside of the Table's bounds. + */ + protected void checkRowColBounds(int row, int column) + throws StepExecutionException { + checkBounds(row, getRowCount()); + + // Corner case: Only check the bounds if the table is not being + // used as a list or anything other than the first column + // is being checked. + int colCount = getColumnCount(); + if (colCount > 0 || column > 0) { + checkBounds(column, colCount); + } + } + + /** + * Computes the visible cellBounds inside the visible bounds of the table.<br> + * The result is the intersection of the visible bounds of the table and the + * bounds of the cell. + * @param cellBounds the bounds of the cell to click in. These bounds must + * be relative to the table's location. + * @return the visible cell bounds, relative to the table's location. + */ + private Rectangle getVisibleBounds(Rectangle cellBounds) { + org.eclipse.swt.graphics.Rectangle r = + (org.eclipse.swt.graphics.Rectangle) + getEventThreadQueuer().invokeAndWait("getVisibleCellBounds: " + cellBounds, //$NON-NLS-1$ + new IRunnable() { + + public Object run() { + return m_table.getClientArea(); + } + }); + + Rectangle visibleTableBounds = new Rectangle( + r.x, r.y, r.width, r.height); + Rectangle visibleCellBounds = + visibleTableBounds.intersection(cellBounds); + return visibleCellBounds; + } + + /** + * @param cellEditor The cell editor to check. + * @return <code>true</code> if the given cell editor is editable. + */ + private boolean isEditable(Control cellEditor) { + + if (cellEditor == null || cellEditor instanceof TableCursor + || cellEditor == m_table) { + // No actual editor found. + return false; + } + + return (cellEditor.getStyle() & SWT.READ_ONLY) == 0; + } + + /** + * @param cellEditor The cell editor to check. + * @return <code>true</code> if the given editor is editable. Otherwise + * <code>false</code>. + */ + private boolean invokeIsEditable(final Control cellEditor) { + + boolean isEditable = ((Boolean)getEventThreadQueuer().invokeAndWait( + "getSelectedCell", //$NON-NLS-1$ + new IRunnable() { + public Object run() { + return isEditable(cellEditor) + ? Boolean.TRUE : Boolean.FALSE; + } + })).booleanValue(); + return isEditable; + } + + /** + * {@inheritDoc} + */ + public Object activateEditor(final Cell cell) { + + Rectangle rect = scrollCellToVisible(cell.getRow(), cell.getCol()); + Control editor = getTableCellEditor(cell, rect); + // sometimes the editor only appears after doubleclick! + + if (!invokeIsEditable(editor)) { + org.eclipse.swt.graphics.Rectangle cellBounds = + new org.eclipse.swt.graphics.Rectangle( + rect.x, rect.y, rect.width, rect.height); + ClickOptions co = ClickOptions.create().setClickCount(2); + Control clickTarget = editor == null + || editor instanceof TableCursor ? m_table : editor; + getRobot().click(clickTarget, cellBounds, co); + editor = getTableCellEditor(cell, rect); + } + + return editor; + + } + /** + * Gets the TableCellEditor of the given cell. + * The Cell has to be activated before! + * @param cell the cell. + * @param rect + * @return the TableCellEditor + */ + private Control getTableCellEditor(final Cell cell, Rectangle rect) { + org.eclipse.swt.graphics.Rectangle swtRect = + new org.eclipse.swt.graphics.Rectangle(rect.x, rect.y, + rect.width, rect.height); + getRobot().click(m_table, + swtRect, + ClickOptions.create().setClickCount(1)); + + + return SwtUtils.getCursorControl(); + } + + /** + * {@inheritDoc} + */ + public String getText() { + final Cell selectedCell = getSelectedCell(); + return getCellText(selectedCell.getRow(), selectedCell.getCol()); + } +} diff --git a/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/TextComponentAdapter.java b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/TextComponentAdapter.java new file mode 100644 index 000000000..1d1a55e25 --- /dev/null +++ b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/TextComponentAdapter.java @@ -0,0 +1,153 @@ +/******************************************************************************* + * 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.uiadapter; + +import org.eclipse.jubula.rc.common.driver.IRunnable; +import org.eclipse.jubula.rc.common.exception.StepExecutionException; +import org.eclipse.jubula.rc.common.logger.AutServerLogger; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.ITextComponentAdapter; +import org.eclipse.jubula.tools.utils.EnvironmentUtils; +import org.eclipse.swt.widgets.Text; + +/** + * Implementation of the Interface <code>ITextComponentAdapter</code> as a + * adapter for the <code>Text</code> component. + * @author BREDEX GmbH + * + */ +public class TextComponentAdapter extends WidgetAdapter implements + ITextComponentAdapter { + + /** the logger */ + private static AutServerLogger log = new AutServerLogger( + TextComponentAdapter.class); + + /** */ + private Text m_textComponent; + /** + * + * @param objectToAdapt + */ + public TextComponentAdapter(Object objectToAdapt) { + super(objectToAdapt); + m_textComponent = (Text) objectToAdapt; + } + + /** + * {@inheritDoc} + */ + public String getText() { + String actual = (String)getEventThreadQueuer().invokeAndWait( + "getText", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return m_textComponent.getText(); + } + }); + return actual; + } + + /** + * {@inheritDoc} + */ + public void setSelection(final int start) { + getEventThreadQueuer().invokeAndWait("setSelection", //$NON-NLS-1$ + new IRunnable() { + public Object run() { + m_textComponent.setSelection(start); + return null; + } + }); + + } + + /** + * {@inheritDoc} + */ + public void setSelection(final int start, final int end) { + getEventThreadQueuer().invokeAndWait("setSelection", //$NON-NLS-1$ + new IRunnable() { + public Object run() { + m_textComponent.setSelection(start, end); + return null; + } + }); + + } + + /** + * {@inheritDoc} + */ + public String getSelectionText() { + String actual = (String)getEventThreadQueuer().invokeAndWait( + "getText", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return m_textComponent.getSelectionText(); + } + }); + return actual; + } + + /** + * {@inheritDoc} + */ + public void selectAll() { + final String totalText = getText(); + + // fix for https://bxapps.bredex.de/bugzilla/show_bug.cgi?id=201 + // The keystroke "command + a" sometimes causes an "a" to be entered + // into the text field instead of selecting all text (or having no + // effect). + if (!EnvironmentUtils.isMacOS()) { + try { + getRobot().keyStroke(getRobot().getSystemModifierSpec() + " A"); //$NON-NLS-1$ + } catch (StepExecutionException see) { + /*This might happen under certain circumstances e.g. on MacOS X see + bug 342691 */ + log.warn(see); + } + } + + if (!totalText.equals(getSelectionText())) { + // the selection failed for some reason + getEventThreadQueuer().invokeAndWait("text.selectAll", //$NON-NLS-1$ + new IRunnable() { + public Object run() { + m_textComponent.selectAll(); + return null; + } + }); + } + + String selectionText = getSelectionText(); + if (!totalText.equals(selectionText)) { + log.warn("SelectAll failed!\n" //$NON-NLS-1$ + + "Total text: '" + totalText + "'\n" //$NON-NLS-1$//$NON-NLS-2$ + + "Selected text: '" + selectionText + "'"); //$NON-NLS-1$ //$NON-NLS-2$ + } + + } + + /** + * {@inheritDoc} + */ + public boolean isEditable() { + return ((Boolean)getEventThreadQueuer().invokeAndWait( + "isEditable", //$NON-NLS-1$ + new IRunnable() { + public Object run() { + return m_textComponent.getEditable() + && m_textComponent.getEnabled() + ? Boolean.TRUE : Boolean.FALSE; // see findBugs + } + })).booleanValue(); + } + +} diff --git a/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/TreeAdapter.java b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/TreeAdapter.java new file mode 100644 index 000000000..7b78f2dc4 --- /dev/null +++ b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/TreeAdapter.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * 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.uiadapter; + +import org.eclipse.jubula.rc.common.driver.IRunnable; +import org.eclipse.jubula.rc.common.implclasses.tree.AbstractTreeOperationContext; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.ITreeAdapter; +import org.eclipse.jubula.rc.swt.implclasses.TreeOperationContext; +import org.eclipse.swt.widgets.Tree; +/** + * Implements the Tree interface for adapting a <code>SWT.Tree</code> + * + * @author BREDEX GmbH + */ +public class TreeAdapter extends WidgetAdapter implements ITreeAdapter { + + + /** + * + * @param objectToAdapt graphics component which will be adapted + */ + public TreeAdapter(Object objectToAdapt) { + super(objectToAdapt); + } + /** + * + * @return the caste object + */ + private Tree getTree() { + return (Tree) getRealComponent(); + } + /** + * {@inheritDoc} + */ + public Object getRootNode() { + return getEventThreadQueuer() + .invokeAndWait("getRootNode", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return getTree().getItems(); + } + }); + } + /** + * {@inheritDoc} + */ + public AbstractTreeOperationContext getContext() { + return new TreeOperationContext(getEventThreadQueuer(), + getRobot(), getTree()); + } + /** + * {@inheritDoc} + */ + public boolean isRootVisible() { + + return true; + } + +} diff --git a/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/WidgetAdapter.java b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/WidgetAdapter.java new file mode 100644 index 000000000..71888de82 --- /dev/null +++ b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/WidgetAdapter.java @@ -0,0 +1,420 @@ +/******************************************************************************* + * 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.uiadapter; + +import org.eclipse.jubula.rc.common.AUTServer; +import org.eclipse.jubula.rc.common.caps.AbstractMenuCAPs; +import org.eclipse.jubula.rc.common.caps.AbstractWidgetCAPs; +import org.eclipse.jubula.rc.common.driver.ClickOptions; +import org.eclipse.jubula.rc.common.driver.IEventThreadQueuer; +import org.eclipse.jubula.rc.common.driver.IRobot; +import org.eclipse.jubula.rc.common.driver.IRunnable; +import org.eclipse.jubula.rc.common.driver.RobotTiming; +import org.eclipse.jubula.rc.common.exception.RobotException; +import org.eclipse.jubula.rc.common.exception.StepExecutionException; +import org.eclipse.jubula.rc.common.listener.EventLock; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.IWidgetAdapter; +import org.eclipse.jubula.rc.swt.driver.KeyCodeConverter; +import org.eclipse.jubula.rc.swt.caps.CAPUtil; +import org.eclipse.jubula.rc.swt.caps.MenuCAPs; +import org.eclipse.jubula.rc.swt.driver.DragAndDropHelperSwt; +import org.eclipse.jubula.rc.swt.driver.EventThreadQueuerSwtImpl; +import org.eclipse.jubula.rc.swt.implclasses.EventListener; +import org.eclipse.jubula.rc.swt.implclasses.SimulatedTooltip; +import org.eclipse.jubula.rc.swt.utils.SwtUtils; +import org.eclipse.jubula.tools.constants.TimeoutConstants; +import org.eclipse.jubula.tools.objects.event.EventFactory; +import org.eclipse.jubula.tools.objects.event.TestErrorEvent; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.Widget; +/** + * Implements the interface for widgets and supports basic methods + * which are needed for nearly a lot of components. + * + * @author BREDEX GmbH + */ +public abstract class WidgetAdapter extends AbstractComponentAdapter + implements IWidgetAdapter { + + /** constants for communication */ + protected static final String POS_UNIT_PIXEL = "Pixel"; //$NON-NLS-1$ + /** constants for communication */ + protected static final String POS_UNI_PERCENT = "Percent"; //$NON-NLS-1$ + + + /** */ + private Control m_component; + + /** + * Is true, if a popup menu is shown + */ + protected static class PopupShownCondition implements + EventListener.Condition { + + /** + * the popup menu + */ + private Menu m_popup = null; + + /** + * + * @return the popup menu + */ + public Menu getPopup() { + return m_popup; + } + + /** + * {@inheritDoc} + * @param event event + * @return result of the condition + */ + public boolean isTrue(Event event) { + + if (event.type == SWT.Show && event.widget instanceof Menu) { + m_popup = (Menu)event.widget; + return true; + } + + return false; + } + } + + /** + * + * @param objectToAdapt + */ + protected WidgetAdapter(Object objectToAdapt) { + m_component = (Control) objectToAdapt; + } + + /** + * {@inheritDoc} + */ + public Object getRealComponent() { + return m_component; + } + + /** + * Gets the Robot. + * @return The Robot + * @throws RobotException If the Robot cannot be created. + */ + protected IRobot getRobot() throws RobotException { + return AUTServer.getInstance().getRobot(); + } + /** + * @return The event thread queuer. + */ + public IEventThreadQueuer getEventThreadQueuer() { + return getRobotFactory().getEventThreadQueuer(); + } + + /** + * {@inheritDoc} + */ + public String getPropteryValue(final String propertyname) { + Object prop = getEventThreadQueuer().invokeAndWait("getProperty", //$NON-NLS-1$ + new IRunnable() { + public Object run() throws StepExecutionException { + try { + return getRobot().getPropertyValue( + getRealComponent(), propertyname); + } catch (RobotException e) { + throw new StepExecutionException( + e.getMessage(), + EventFactory.createActionError( + TestErrorEvent.PROPERTY_NOT_ACCESSABLE)); + } + } + }); + return String.valueOf(prop); + } + + /** + * {@inheritDoc} + */ + public boolean isShowing() { + Boolean actual = (Boolean)getEventThreadQueuer() + .invokeAndWait("isShowing", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return m_component.isVisible() + ? Boolean.TRUE : Boolean.FALSE; // see findBugs; + } + }); + return actual.booleanValue(); + } + + /** + * {@inheritDoc} + */ + public boolean isEnabled() { + + Boolean actual = (Boolean)getEventThreadQueuer() + .invokeAndWait("isEnabled", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return m_component.isEnabled() + ? Boolean.TRUE : Boolean.FALSE; // see findBugs; + } + }); + return actual.booleanValue(); + } + + /** + * {@inheritDoc} + */ + public boolean hasFocus() { + Boolean actual = (Boolean)getEventThreadQueuer() + .invokeAndWait("hasFocus", new IRunnable() { //$NON-NLS-1$ + public Object run() { + return m_component.isFocusControl() + ? Boolean.TRUE : Boolean.FALSE; // see findBugs; + } + }); + return actual.booleanValue(); + } + + /** + * Shows and returns the popup menu + * @param button MouseButton + * @return the popup menu + */ + public AbstractMenuCAPs showPopup( + final int button) { + final Widget component = m_component; + if (SwtUtils.isMouseCursorInWidget(component)) { + return showPopup(component, new Runnable() { + public void run() { + RobotTiming.sleepPreShowPopupDelay(); + + getRobot().clickAtCurrentPosition(component, 1, + button); + } + }); + } + return showPopup(50, POS_UNI_PERCENT, 50, + POS_UNI_PERCENT, button); + } + + /** + * Shows and returns the popup menu + * + * @param xPos what x position + * @param xUnits should x position be pixel or percent values + * @param yPos what y position + * @param yUnits should y position be pixel or percent values + * @param button MouseButton + * @return the popup menu + * @throws StepExecutionException error + */ + public AbstractMenuCAPs showPopup( + final int xPos, final String xUnits, + final int yPos, final String yUnits, + final int button) throws StepExecutionException { + final Widget component = m_component; + return showPopup(component, new Runnable() { + public void run() { + RobotTiming.sleepPreShowPopupDelay(); + boolean isAbsoluteUnitsX = + POS_UNIT_PIXEL.equalsIgnoreCase( + xUnits); + boolean isAbsoluteUnitsY = + POS_UNIT_PIXEL.equalsIgnoreCase( + yUnits); + getRobot().click(component, null, + ClickOptions.create().setClickCount(1) + .setMouseButton(button), + xPos, isAbsoluteUnitsX, yPos, isAbsoluteUnitsY); + } + }); + } + + /** + * Shows and returns the popup menu + * + * @param component The component for which to open the popup menu. + * @param showPopup A <code>Runnable</code> that, when run, should display + * a popup menu for the given component. + * @return the popup menu + * @throws StepExecutionException error + */ + private AbstractMenuCAPs showPopup(final Widget component, + final Runnable showPopup) throws StepExecutionException { + + PopupShownCondition cond = new PopupShownCondition(); + EventLock lock = new EventLock(); + final EventListener listener = new EventListener(lock, cond); + final Display d = component.getDisplay(); + final IEventThreadQueuer queuer = new EventThreadQueuerSwtImpl(); + + queuer.invokeAndWait("addPopupShownListeners", new IRunnable() { //$NON-NLS-1$ + public Object run() { + d.addFilter(SWT.Show, listener); + + return null; + } + }); + + try { + // showPopup must run in the current thread in order to + // avoid a race condition. + showPopup.run(); + + synchronized (lock) { + long timeout = TimeoutConstants.SERVER_TIMEOUT_WAIT_FOR_POPUP; + long done = System.currentTimeMillis() + timeout; + long now; + while (!lock.isReleased() && (timeout > 0)) { + lock.wait(timeout); + now = System.currentTimeMillis(); + timeout = done - now; + } + } + } catch (InterruptedException e) { + // ignore + } finally { + queuer.invokeAndWait("removePopupShownListeners", new IRunnable() { //$NON-NLS-1$ + public Object run() { + d.removeFilter(SWT.Show, listener); + + return null; + } + }); + } + if (!lock.isReleased()) { + throw new StepExecutionException("popup not shown", //$NON-NLS-1$ + EventFactory.createActionError( + TestErrorEvent.POPUP_NOT_FOUND)); + } + + MenuCAPs contextMenu = new MenuCAPs(); + contextMenu.setComponent(cond.getPopup()); + contextMenu.setContextMenu(true); + return contextMenu; + } + + /** + * {@inheritDoc} + */ + public void showToolTip(final String text, final int textSize, + final int timePerWord, final int windowWidth) { + + final Rectangle bounds = (Rectangle)getEventThreadQueuer() + .invokeAndWait("gdShowText.getBounds", new IRunnable() { //$NON-NLS-1$ + + public Object run() { + return SwtUtils.getWidgetBounds(m_component); + } + }); + + SimulatedTooltip sp = (SimulatedTooltip)getEventThreadQueuer() + .invokeAndWait("gdShowText.initToolTip", new IRunnable() { //$NON-NLS-1$ + + public Object run() throws StepExecutionException { + return new SimulatedTooltip(timePerWord, text, + windowWidth, textSize, bounds); + } + + }); + sp.start(); + try { + sp.join(); + } catch (InterruptedException e) { + throw new StepExecutionException(e); + } + } + + /** + * {@inheritDoc} + */ + public void gdDrag(int mouseButton, String modifier, int xPos, + String xUnits, int yPos, String yUnits) { + // Only store the Drag-Information. Otherwise the GUI-Eventqueue + // blocks after performed Drag! + final DragAndDropHelperSwt dndHelper = DragAndDropHelperSwt + .getInstance(); + dndHelper.setMouseButton(mouseButton); + dndHelper.setModifier(modifier); + dndHelper.setDragComponent(null); + clickDirect(0, mouseButton, xPos, xUnits, yPos, yUnits); + } + + /** + * {@inheritDoc} + */ + public void gdDrop(final int xPos, final String xUnits, final int yPos, + final String yUnits, int delayBeforeDrop) { + final DragAndDropHelperSwt dndHelper = DragAndDropHelperSwt + .getInstance(); + final IRobot robot = getRobot(); + final String modifier = dndHelper.getModifier(); + final int mouseButton = dndHelper.getMouseButton(); + // Note: This method performs the drag AND drop action in one runnable + // in the GUI-Eventqueue because after the mousePress, the eventqueue + // blocks! + try { + CAPUtil.pressOrReleaseModifiers(modifier, true); + + getEventThreadQueuer().invokeAndWait("gdStartDrag", new IRunnable() { //$NON-NLS-1$ + public Object run() throws StepExecutionException { + // drag + robot.mousePress(dndHelper.getDragComponent(), null, + mouseButton); + + CAPUtil.shakeMouse(); + + // drop + clickDirect(0, mouseButton, xPos, xUnits, yPos, yUnits); + return null; + } + }); + + AbstractWidgetCAPs.waitBeforeDrop(delayBeforeDrop); + } finally { + getRobot().mouseRelease(null, null, mouseButton); + CAPUtil.pressOrReleaseModifiers(modifier, false); + } + } + + /** + * clicks into a component. + * @param count amount of clicks + * @param button what button should be clicked + * @param xPos what x position + * @param xUnits should x position be pixel or percent values + * @param yPos what y position + * @param yUnits should y position be pixel or percent values + * @throws StepExecutionException error + */ + protected void clickDirect(int count, int button, int xPos, String xUnits, + int yPos, String yUnits) + throws StepExecutionException { + + getRobot().click( + m_component, + null, + ClickOptions.create().setClickCount(count).setMouseButton( + button), xPos, xUnits.equalsIgnoreCase(POS_UNIT_PIXEL), + yPos, yUnits.equalsIgnoreCase(POS_UNIT_PIXEL)); + } + + /** + * {@inheritDoc} + */ + public int getKeyCode(String mod) { + return KeyCodeConverter.getKeyCode(mod); + } +}
\ No newline at end of file diff --git a/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/factory/SWTAdapterFactory.java b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/factory/SWTAdapterFactory.java new file mode 100644 index 000000000..0f9e24d16 --- /dev/null +++ b/org.eclipse.jubula.rc.swt/src/org/eclipse/jubula/rc/swt/uiadapter/factory/SWTAdapterFactory.java @@ -0,0 +1,104 @@ +/******************************************************************************* + * 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.uiadapter.factory; + +import org.eclipse.jubula.rc.common.uiadapter.factory.IUIAdapterFactory; +import org.eclipse.jubula.rc.common.uiadapter.interfaces.IComponentAdapter; +import org.eclipse.jubula.rc.swt.uiadapter.ButtonAdapter; +import org.eclipse.jubula.rc.swt.uiadapter.CComboAdapter; +import org.eclipse.jubula.rc.swt.uiadapter.CLabelAdapter; +import org.eclipse.jubula.rc.swt.uiadapter.CTabFolderAdapter; +import org.eclipse.jubula.rc.swt.uiadapter.ComboAdapter; +import org.eclipse.jubula.rc.swt.uiadapter.LabelAdapter; +import org.eclipse.jubula.rc.swt.uiadapter.ListAdapter; +import org.eclipse.jubula.rc.swt.uiadapter.MenuAdapter; +import org.eclipse.jubula.rc.swt.uiadapter.MenuItemAdapter; +import org.eclipse.jubula.rc.swt.uiadapter.StyledTextAdapter; +import org.eclipse.jubula.rc.swt.uiadapter.TabFolderAdapter; +import org.eclipse.jubula.rc.swt.uiadapter.TableAdapter; +import org.eclipse.jubula.rc.swt.uiadapter.TextComponentAdapter; +import org.eclipse.jubula.rc.swt.uiadapter.TreeAdapter; +import org.eclipse.swt.custom.CCombo; +import org.eclipse.swt.custom.CLabel; +import org.eclipse.swt.custom.CTabFolder; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.List; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.MenuItem; +import org.eclipse.swt.widgets.TabFolder; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.Text; +import org.eclipse.swt.widgets.Tree; + +/** + * This factory constructs the specific adapter out of the incoming + * graphics component from the AUT. + * + * @author BREDEX GmbH + */ +public class SWTAdapterFactory implements IUIAdapterFactory { + /** */ + private static final Class[] SUPPORTEDCLASSES = + new Class[]{Button.class, Menu.class, MenuItem.class, Tree.class, + Table.class, List.class, Text.class, StyledText.class, + Combo.class, CCombo.class, Label.class, CLabel.class, + TabFolder.class, CTabFolder.class}; + + + /** + * {@inheritDoc} + */ + public Class[] getSupportedClasses() { + return SUPPORTEDCLASSES; + } + + /** + * {@inheritDoc} + */ + public IComponentAdapter getAdapter(Object objectToAdapt) { + IComponentAdapter returnvalue = null; + if (objectToAdapt instanceof Button) { + returnvalue = new ButtonAdapter(objectToAdapt); + } else if (objectToAdapt instanceof Menu) { + returnvalue = new MenuAdapter(objectToAdapt); + } else if (objectToAdapt instanceof MenuItem) { + returnvalue = new MenuItemAdapter(objectToAdapt); + } else if (objectToAdapt instanceof Tree) { + returnvalue = new TreeAdapter(objectToAdapt); + } else if (objectToAdapt instanceof Table) { + returnvalue = new TableAdapter(objectToAdapt); + } else if (objectToAdapt instanceof List) { + returnvalue = new ListAdapter(objectToAdapt); + } else if (objectToAdapt instanceof Text) { + returnvalue = new TextComponentAdapter(objectToAdapt); + } else if (objectToAdapt instanceof StyledText) { + returnvalue = new StyledTextAdapter(objectToAdapt); + } else if (objectToAdapt instanceof Combo) { + returnvalue = new ComboAdapter(objectToAdapt); + } else if (objectToAdapt instanceof CCombo) { + returnvalue = new CComboAdapter(objectToAdapt); + } else if (objectToAdapt instanceof Label) { + returnvalue = new LabelAdapter(objectToAdapt); + } else if (objectToAdapt instanceof CLabel) { + returnvalue = new CLabelAdapter(objectToAdapt); + } else if (objectToAdapt instanceof TabFolder) { + returnvalue = new TabFolderAdapter(objectToAdapt); + } else if (objectToAdapt instanceof CTabFolder) { + returnvalue = new CTabFolderAdapter(objectToAdapt); + } + + return returnvalue; + } + +} diff --git a/org.eclipse.jubula.toolkit.provider.swing/resources/xml/ComponentConfiguration.xml b/org.eclipse.jubula.toolkit.provider.swing/resources/xml/ComponentConfiguration.xml index bd116a528..2d0aafee2 100644 --- a/org.eclipse.jubula.toolkit.provider.swing/resources/xml/ComponentConfiguration.xml +++ b/org.eclipse.jubula.toolkit.provider.swing/resources/xml/ComponentConfiguration.xml @@ -27,7 +27,7 @@ <toolkitComponent type="javax.swing.AbstractButton" visible="false">
<realizes>guidancer.concrete.Button</realizes>
- <testerClass>org.eclipse.jubula.rc.swing.swing.implclasses.AbstractButtonImplClass</testerClass>
+ <testerClass>org.eclipse.jubula.rc.swing.swing.caps.AbstractButtonCAPs</testerClass>
<componentClass name="javax.swing.AbstractButton" />
</toolkitComponent>
@@ -36,49 +36,49 @@ <typeFactory>org.eclipse.jubula.rc.common.implclasses.DefaultComponentFactory</typeFactory> </defaultMapping> <realizes>guidancer.concrete.MenuBar</realizes>
- <testerClass>org.eclipse.jubula.rc.swing.swing.implclasses.JMenuBarImplClass</testerClass>
+ <testerClass>org.eclipse.jubula.rc.swing.swing.caps.JMenuBarCAPs</testerClass>
<componentClass name="com.bredexsw.guidancer.autserver.swing.implclasses.JMenuBarDefaultMapping" />
</toolkitComponent>
<toolkitComponent type="javax.swing.JComboBox" visible="false">
<realizes>guidancer.concrete.ComboBox</realizes>
- <testerClass>org.eclipse.jubula.rc.swing.swing.implclasses.JComboBoxImplClass</testerClass>
+ <testerClass>org.eclipse.jubula.rc.common.caps.AbstractComboBoxCAPs</testerClass>
<componentClass name="javax.swing.JComboBox" />
</toolkitComponent>
<toolkitComponent type="javax.swing.JList" visible="false">
<realizes>guidancer.concrete.List</realizes>
- <testerClass>org.eclipse.jubula.rc.swing.swing.implclasses.JListImplClass</testerClass>
+ <testerClass>org.eclipse.jubula.rc.swing.swing.caps.JListCAPs</testerClass>
<componentClass name="javax.swing.JList" />
</toolkitComponent>
<toolkitComponent type="javax.swing.JLabel" visible="false">
<realizes>guidancer.concrete.Label</realizes>
- <testerClass>org.eclipse.jubula.rc.swing.swing.implclasses.JLabelImplClass</testerClass>
+ <testerClass>org.eclipse.jubula.rc.common.caps.LabelCAPs</testerClass>
<componentClass name="javax.swing.JLabel" />
</toolkitComponent>
<toolkitComponent type="javax.swing.JTabbedPane" visible="false">
<realizes>guidancer.concrete.TabbedPane</realizes>
- <testerClass>org.eclipse.jubula.rc.swing.swing.implclasses.JTabbedPaneImplClass</testerClass>
+ <testerClass>org.eclipse.jubula.rc.common.caps.TabbedPaneCAPs</testerClass>
<componentClass name="javax.swing.JTabbedPane" />
</toolkitComponent>
<toolkitComponent type="javax.swing.JTable" visible="false">
<realizes>guidancer.concrete.Table</realizes>
- <testerClass>org.eclipse.jubula.rc.swing.swing.implclasses.JTableImplClass</testerClass>
+ <testerClass>org.eclipse.jubula.rc.swing.swing.caps.JTableCAPs</testerClass>
<componentClass name="javax.swing.JTable" />
</toolkitComponent>
<toolkitComponent type="javax.swing.text.JTextComponent" visible="false">
<realizes>guidancer.concrete.TextComponent</realizes>
- <testerClass>org.eclipse.jubula.rc.swing.swing.implclasses.JTextComponentImplClass</testerClass>
+ <testerClass>org.eclipse.jubula.rc.common.caps.AbstractTextComponent</testerClass>
<componentClass name="javax.swing.text.JTextComponent" />
</toolkitComponent>
<toolkitComponent type="javax.swing.JTree" visible="false">
<realizes>guidancer.concrete.Tree</realizes>
- <testerClass>org.eclipse.jubula.rc.swing.swing.implclasses.JTreeImplClass</testerClass>
+ <testerClass>org.eclipse.jubula.rc.swing.swing.caps.JTreeCAPs</testerClass>
<componentClass name="javax.swing.JTree" />
</toolkitComponent>
diff --git a/org.eclipse.jubula.toolkit.provider.swt/resources/xml/ComponentConfiguration.xml b/org.eclipse.jubula.toolkit.provider.swt/resources/xml/ComponentConfiguration.xml index 069572474..1e2594078 100644 --- a/org.eclipse.jubula.toolkit.provider.swt/resources/xml/ComponentConfiguration.xml +++ b/org.eclipse.jubula.toolkit.provider.swt/resources/xml/ComponentConfiguration.xml @@ -160,31 +160,31 @@ <toolkitComponent type="org.eclipse.swt.widgets.Label" visible="false">
<realizes>guidancer.abstract.SwtLabel</realizes>
- <testerClass>org.eclipse.jubula.rc.swt.implclasses.LabelImplClass</testerClass>
+ <testerClass>org.eclipse.jubula.rc.common.caps.LabelCAPs</testerClass>
<componentClass name="org.eclipse.swt.widgets.Label" />
</toolkitComponent>
<toolkitComponent type="org.eclipse.swt.custom.CLabel" visible="false">
<realizes>guidancer.abstract.SwtLabel</realizes>
- <testerClass>org.eclipse.jubula.rc.swt.implclasses.CLabelImplClass</testerClass>
+ <testerClass>org.eclipse.jubula.rc.common.caps.LabelCAPs</testerClass>
<componentClass name="org.eclipse.swt.custom.CLabel" />
</toolkitComponent>
<toolkitComponent type="org.eclipse.swt.widgets.Text" visible="false">
<realizes>guidancer.abstract.SwtText</realizes>
- <testerClass>org.eclipse.jubula.rc.swt.implclasses.TextImplClass</testerClass>
+ <testerClass>org.eclipse.jubula.rc.common.caps.AbstractTextComponent</testerClass>
<componentClass name="org.eclipse.swt.widgets.Text" />
</toolkitComponent>
<toolkitComponent type="org.eclipse.swt.custom.StyledText" visible="false">
<realizes>guidancer.abstract.SwtText</realizes>
- <testerClass>org.eclipse.jubula.rc.swt.implclasses.StyledTextImplClass</testerClass>
+ <testerClass>org.eclipse.jubula.rc.common.caps.AbstractTextComponent</testerClass>
<componentClass name="org.eclipse.swt.custom.StyledText" />
</toolkitComponent>
<toolkitComponent type="org.eclipse.swt.widgets.Button" visible="false">
<realizes>guidancer.abstract.SwtButton</realizes>
- <testerClass>org.eclipse.jubula.rc.swt.implclasses.ButtonImplClass</testerClass>
+ <testerClass>org.eclipse.jubula.rc.swt.caps.ButtonCAPs</testerClass>
<componentClass name="org.eclipse.swt.widgets.Button" />
</toolkitComponent>
@@ -203,49 +203,49 @@ <typeFactory>org.eclipse.jubula.rc.common.implclasses.DefaultComponentFactory</typeFactory>
</defaultMapping>
<realizes>guidancer.concrete.MenuBar</realizes>
- <testerClass>org.eclipse.jubula.rc.swt.implclasses.MenuImplClass</testerClass>
+ <testerClass>org.eclipse.jubula.rc.swt.caps.MenuCAPs</testerClass>
<componentClass name="com.bredexsw.guidancer.autswtserver.implclasses.MenuDefaultMapping" />
</toolkitComponent>
<toolkitComponent type="org.eclipse.swt.widgets.Combo" visible="false">
<realizes>guidancer.abstract.SwtCombo</realizes>
- <testerClass>org.eclipse.jubula.rc.swt.implclasses.ComboImplClass</testerClass>
+ <testerClass>org.eclipse.jubula.rc.common.caps.AbstractComboBoxCAPs</testerClass>
<componentClass name="org.eclipse.swt.widgets.Combo" />
</toolkitComponent>
<toolkitComponent type="org.eclipse.swt.custom.CCombo" visible="false">
<realizes>guidancer.abstract.SwtCombo</realizes>
- <testerClass>org.eclipse.jubula.rc.swt.implclasses.CComboImplClass</testerClass>
+ <testerClass>org.eclipse.jubula.rc.common.caps.AbstractComboBoxCAPs</testerClass>
<componentClass name="org.eclipse.swt.custom.CCombo" />
</toolkitComponent>
<toolkitComponent type="org.eclipse.swt.widgets.List" visible="false">
<realizes>guidancer.concrete.List</realizes>
- <testerClass>org.eclipse.jubula.rc.swt.implclasses.ListImplClass</testerClass>
+ <testerClass>org.eclipse.jubula.rc.swt.caps.ListCAPs</testerClass>
<componentClass name="org.eclipse.swt.widgets.List" />
</toolkitComponent>
<toolkitComponent type="org.eclipse.swt.widgets.TabFolder" visible="false">
<realizes>guidancer.abstract.SwtTabFolder</realizes>
- <testerClass>org.eclipse.jubula.rc.swt.implclasses.TabFolderImplClass</testerClass>
+ <testerClass>org.eclipse.jubula.rc.common.caps.TabbedPaneCAPs</testerClass>
<componentClass name="org.eclipse.swt.widgets.TabFolder" />
</toolkitComponent>
<toolkitComponent type="org.eclipse.swt.custom.CTabFolder" visible="false">
<realizes>guidancer.abstract.SwtTabFolder</realizes>
- <testerClass>org.eclipse.jubula.rc.swt.implclasses.CTabFolderImplClass</testerClass>
+ <testerClass>org.eclipse.jubula.rc.common.caps.TabbedPaneCAPs</testerClass>
<componentClass name="org.eclipse.swt.custom.CTabFolder" />
</toolkitComponent>
<toolkitComponent type="org.eclipse.swt.widgets.Table" visible="false">
<realizes>guidancer.concrete.Table</realizes>
- <testerClass>org.eclipse.jubula.rc.swt.implclasses.TableImplClass</testerClass>
+ <testerClass>org.eclipse.jubula.rc.swt.caps.TableCAPs</testerClass>
<componentClass name="org.eclipse.swt.widgets.Table" />
</toolkitComponent>
<toolkitComponent type="org.eclipse.swt.widgets.Tree" observable="false"> <realizes>guidancer.concrete.Tree</realizes> - <testerClass>org.eclipse.jubula.rc.swt.implclasses.TableTreeImplClass</testerClass> + <testerClass>org.eclipse.jubula.rc.swt.caps.TreeCAPs</testerClass> <componentClass name="org.eclipse.swt.widgets.Tree" />
<action name="CompSystem.VerifyCheckboxOfSelectedEntry" changed="4.1">
<method>gdVerifySelectedCheckbox</method>
@@ -370,7 +370,7 @@ <toolkitComponent type="org.eclipse.swt.widgets.SwtTree">
<realizes>org.eclipse.swt.widgets.Tree</realizes> - <testerClass>org.eclipse.jubula.rc.swt.implclasses.TableTreeImplClass</testerClass>
+ <testerClass>org.eclipse.jubula.rc.swt.caps.TreeCAPs</testerClass>
<componentClass name="org.eclipse.swt.widgets.Tree" />
<action name="CompSystem.SelectByTextPathAtColumn" changed="1.22">
<method>gdSelect</method>
|
