/*******************************************************************************
* Copyright (c) 2012 Google, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Google, Inc. - initial API and implementation
*******************************************************************************/
package com.windowtester.runtime.swt.internal.selector;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Widget;
import abbot.tester.swt.ComboTester;
import com.windowtester.internal.runtime.IDiagnostic;
import com.windowtester.internal.runtime.IDiagnosticParticipant;
import com.windowtester.internal.runtime.provisional.WTInternal;
import com.windowtester.runtime.IUIContext;
import com.windowtester.runtime.WT;
import com.windowtester.runtime.WaitTimedOutException;
import com.windowtester.runtime.WidgetNotFoundException;
import com.windowtester.runtime.condition.ICondition;
import com.windowtester.runtime.swt.internal.ExceptionHandlingHelper;
import com.windowtester.runtime.swt.internal.debug.LogHandler;
import com.windowtester.runtime.swt.internal.operation.SWTControlLocation;
import com.windowtester.runtime.swt.internal.operation.SWTMouseOperation;
import com.windowtester.runtime.swt.internal.widgets.ComboReference;
import com.windowtester.runtime.swt.internal.widgets.SWTWidgetReference;
/**
* A Selector for Combos.
*
*/
public class ComboSelector extends BasicWidgetSelector {
private static final long SELECTION_TIMEOUT = 5000;
private static final int WAIT_INTERVAL = 200;
private static final int ITEM_NOT_FOUND = -1;
private ComboTester _comboTester = new ComboTester();
private final IUIContext _ui;
public ComboSelector() {
this(null);
}
//create with a backpointer to the ui for implementing conditional waits
public ComboSelector(IUIContext ui) {
_ui = ui;
}
protected IUIContext getUI() {
return _ui;
}
/**
* @throws WidgetNotFoundException
* @see com.windowtester.event.swt.ISWTWidgetSelectorDelegate#click(org.eclipse.swt.widgets.Widget, java.lang.String, int)
*/
public Widget click(Widget w, String itemLabel, int mask) throws WidgetNotFoundException {
//TODO: notice mask is ignored here...
Combo combo = (Combo)w;
/* We used to perform selections with keystrokes but this was error prone in cases where the
* selection failed and we tried a force (and the original combo was disposed).
* Now instead of trying to select the item with keystrokes we just do the force.
*/
mouseMove(w);
forceSelection(combo, itemLabel);
verifySelection(combo, itemLabel);
return w; //NOTE: this may in fact be NULL
}
/**
* Verify that the proper item is selected.
*/
private void verifySelection(final Combo combo, final String expectedSelection) throws WaitTimedOutException{
//TODO: verify that screen capture is still properly handled
IUIContext ui = getUI();
if (ui == null)
return; //no verification
class ItemSelectionCondition implements ICondition, IDiagnosticParticipant {
int index;
String actualSelection;
/* (non-Javadoc)
* @see com.windowtester.runtime.condition.ICondition#test()
*/
public boolean test() {
index = _comboTester.getSelectionIndex(combo);
if (index == -1)
return false; //there's a bit of a race here: we return false if we're "between" selections
actualSelection = _comboTester.getItem(combo, index);
return actualSelection.equals(expectedSelection);
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
public String toString() {
return "selection of index for Combo: " + actualSelection+ " != " + expectedSelection;
}
/* (non-Javadoc)
* @see com.windowtester.internal.runtime.IDiagnosticParticipant#diagnose(com.windowtester.internal.runtime.IDiagnostic)
*/
public void diagnose(IDiagnostic diagnostic) {
diagnostic.diagnose("Combo Item Selection", toString());
doScreenCapture(combo);
};
}
ui.wait(new ItemSelectionCondition(), SELECTION_TIMEOUT, WAIT_INTERVAL);
}
/*
* FORCE a selection in case selection failed for some reason.
*/
public void forceSelection(final Combo combo, final int index) {
combo.getDisplay().asyncExec(new Runnable(){
public void run() {
combo.select(index);
}
});
}
/*
* FORCE a selection in case selection failed for some reason.
*/
public void forceSelection(Combo combo, String item) throws WidgetNotFoundException {
int index = getIndex(item, combo);
if (index == ITEM_NOT_FOUND)
throw itemNotFoundException(combo, item);
forceSelection(combo, index);
}
private WidgetNotFoundException itemNotFoundException(Combo combo, String item) {
return new WidgetNotFoundException("item: \"" + item + "\" not found in combo [" + getItemListString(combo) + "]");
}
// /**
// * Select the given item from the Combo.
// *
// * @param combo Combo from which to select
// * @param item String to select
// * @throws WidgetNotFoundException
// */
// public void actionSelectItem(final Combo combo, String item) throws WidgetNotFoundException{
// String [] items = UIProxy.getItems(combo);
// boolean found = false;
// for (int i = 0; i < items.length; i++){
// if(item.equals(items[i])){
// found = true;
// actionSelectIndex(combo,i);
// break;
// }
// }
// if (!found) {
// LogHandler.log("actionSelectItem: item \""+item+"\" not found");
// throw itemNotFoundException(combo, item);
// }
// }
private String getItemListString(Combo combo) {
String[] items = new ComboReference(combo).getItems();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < items.length; i++) {
sb.append('"').append(items[i]).append('"');
if (i < items.length-1)
sb.append(", ");
}
return sb.toString();
}
// /**
// * Select the item from the Combo at the given index.
// *
// * @param combo Combo from which to select
// * @param index Index of item to select
// */
// public void actionSelectIndex(final Combo combo, final int index){
// setFocus(combo);
// Display display = combo.getDisplay();
// int current = UIProxy.getSelectionIndex(combo);
//
// dropDownCombo(combo);
// while (current != index) {
// if (current < index) {
// keyClick(SWT.ARROW_DOWN);
// waitForIdle(display);
// current++;
// } else {
// keyClick(SWT.ARROW_UP);
// waitForIdle(display);
// current--;
// }
// }
// setFocus(combo);
// keyClick(SWT.CR);
// dismissCombo(combo);
//
// waitForIdle(display);
//
// }
/**
* Dismiss the combo (by clicking outside it).
*/
protected void dismissCombo(Combo combo) {
if (combo.isDisposed()) {
LogHandler.log("attempt to dimiss combo ignored (combo disposed)");
return;
}
int style = getStyle(combo);
if((style&SWT.DROP_DOWN)==SWT.DROP_DOWN){
// Rectangle bounds = getGlobalBounds(combo);
//
// //move the mouse outside the combo
// mouseMove( bounds.x+bounds.width+2,
// bounds.y+bounds.height+2);
//
// //click
// mousePress(SWT.BUTTON1);
// mouseRelease(SWT.BUTTON1);
new SWTMouseOperation(WT.BUTTON1).at(new SWTControlLocation(combo, WTInternal.BOTTOMRIGHT).offset(2, 2)).execute();
//wait for the combo to disappear
waitForIdle(combo.getDisplay());
} else {
LogHandler.log("attempt to dimiss down combo ignored (unhandled style bit set:" + style+ ")");
}
}
private int getStyle(Combo combo) {
return SWTWidgetReference.forWidget(combo).getStyle();
}
/**
* Drop down the menu for the given Combo box
* WARNING: This method is platform-dependent.
*/
protected void dropDownCombo(Combo combo){
int style = getStyle(combo);
// final int BUTTON_SIZE = 16;
if((style&SWT.DROP_DOWN)==SWT.DROP_DOWN){
// Rectangle bounds = getGlobalBounds(combo);
//
// //move the mouse to the caret
// mouseMove( bounds.x+bounds.width-BUTTON_SIZE/2,
// bounds.y+bounds.height-BUTTON_SIZE/2);
//
// //click
// mousePress(SWT.BUTTON1);
// mouseRelease(SWT.BUTTON1);
new SWTMouseOperation(WT.BUTTON1).at(new SWTControlLocation(combo, WTInternal.RIGHT).offset(-8, 0)).execute();
//wait for the combo to appear
waitForIdle(combo.getDisplay());
} else {
LogHandler.log("attempt to drop down combo ignored (unhandled style bit set:" + style+ ")");
}
}
/**
* Get the index of the given item in the combo's item list.
* @return the item's index or {@link #ITEM_NOT_FOUND} if is not found
*/
private int getIndex(final String item, final Combo combo) {
final int[] index = new int[]{ITEM_NOT_FOUND};
Display.getDefault().syncExec(new Runnable() {
public void run() {
String[] items = combo.getItems();
for (int i = 0; i < items.length; i++){
if (item.equals(items[i])){
index[0] = i;
return;
}
}
}
});
return index[0];
}
///////////////////////////////////////////////////////////////////////////////////////////////
//
// Exception handling
//
///////////////////////////////////////////////////////////////////////////////////////////////
private void doScreenCapture(Combo combo) {
if (combo.isDisposed()) {
LogHandler.log("attempt to open combo on failed selection skipped (combo disposed)");
return;
}
dropDownCombo(combo);
ExceptionHandlingHelper.doScreenCapture("(combo selection failure)");
dismissCombo(combo);
}
}