/*******************************************************************************
* Copyright (c) 2012 BREDEX GmbH.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* BREDEX GmbH - initial API and implementation
*******************************************************************************/
package org.eclipse.jubula.rc.swt.tester.adapter;
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.tester.util.CAPUtil;
import org.eclipse.jubula.rc.swt.utils.SwtUtils;
import org.eclipse.jubula.tools.internal.constants.TimeoutConstants;
import org.eclipse.jubula.tools.internal.objects.event.EventFactory;
import org.eclipse.jubula.tools.internal.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-independent 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<Void>() {
public Void run() throws StepExecutionException {
m_combobox.setSelection(
new Point(0, m_combobox.getText().length()));
// return value is not used
return null;
}
});
}
/**
* {@inheritDoc}
*/
public int getSelectedIndex() {
return getEventThreadQueuer().invokeAndWait(
CComboAdapter.class.getName()
+ "getSelectedIndex", new IRunnable<Integer>() { //$NON-NLS-1$
public Integer run() throws StepExecutionException {
return m_combobox.getSelectionIndex();
}
});
}
/**
* {@inheritDoc}
*/
public String getText() {
String o = getEventThreadQueuer().invokeAndWait(
"getText", new IRunnable<String>() { //$NON-NLS-1$
public String run() {
return CAPUtil.getWidgetText(m_combobox,
m_combobox.getText());
}
});
return String.valueOf(o);
}
/**
* {@inheritDoc}
*/
protected boolean isComboEnabled() {
return getEventThreadQueuer().invokeAndWait(
CComboAdapter.class.getName()
+ "isComboEnabled", new IRunnable<Boolean>() { //$NON-NLS-1$
public Boolean run() throws StepExecutionException {
return m_combobox.isEnabled();
}
});
}
/**
* {@inheritDoc}
*/
protected void selectImpl(final int index) {
scrollIndexToVisible(index);
Rectangle clickConstraints =
getEventThreadQueuer().invokeAndWait(
"setClickConstraints", //$NON-NLS-1$
new IRunnable<Rectangle>() {
public Rectangle 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 getEventThreadQueuer().invokeAndWait("getItemCount", //$NON-NLS-1$
new IRunnable<Integer>() {
public Integer run() {
return m_combobox.getItemCount();
}
});
}
/**
* 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 getEventThreadQueuer().invokeAndWait(
"getDropdownList", //$NON-NLS-1$
new IRunnable<List>() {
public List 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<Void>() {
public Void 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 getEventThreadQueuer().invokeAndWait(
"getDisplayedItemCount", //$NON-NLS-1$
new IRunnable<Integer>() {
public Integer run() throws StepExecutionException {
List dropdown = getDropdownList();
if (dropdown == null) {
return new Integer(0);
}
int listHeight = SwtUtils.getWidgetBounds(dropdown).height;
int itemHeight = dropdown.getItemHeight();
return listHeight / itemHeight;
}
});
}
/**
* @return true, if the dropdown of the combobox is visible
*/
protected boolean isDropdownVisible() {
return getEventThreadQueuer().invokeAndWait(
CComboAdapter.class.getName()
+ "isDropdownVisible", new IRunnable<Boolean>() { //$NON-NLS-1$
public Boolean run() throws StepExecutionException {
return getDropdownList() != null;
}
});
}
/**
* {@inheritDoc}
*/
public String[] getValues() {
return getEventThreadQueuer().invokeAndWait("getItems", //$NON-NLS-1$
new IRunnable<String[]>() {
public String[] run() {
return m_combobox.getItems();
}
});
}
}