package org.jboss.tools.common.reddeer.ext; import java.util.LinkedList; import java.util.List; import java.util.ListIterator; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.CLabel; import org.eclipse.swt.custom.CTabFolder; import org.eclipse.swt.custom.CTabItem; import org.eclipse.swt.layout.FormData; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.TabFolder; import org.eclipse.swt.widgets.TabItem; import org.eclipse.swt.widgets.TableItem; import org.eclipse.swt.widgets.ToolItem; import org.eclipse.swt.widgets.Widget; import org.jboss.reddeer.core.exception.CoreLayerException; import org.jboss.reddeer.core.handler.CTabFolderHandler; import org.jboss.reddeer.core.handler.CTabItemHandler; import org.jboss.reddeer.core.handler.ShellHandler; import org.jboss.reddeer.core.handler.TabFolderHandler; import org.jboss.reddeer.core.handler.TabItemHandler; import org.jboss.reddeer.core.handler.TableItemHandler; import org.jboss.reddeer.core.handler.ToolItemHandler; import org.jboss.reddeer.core.lookup.WidgetLookup; import org.jboss.reddeer.core.resolver.WidgetResolver; import org.jboss.reddeer.core.util.Display; import org.jboss.reddeer.core.util.ObjectUtil; import org.jboss.reddeer.core.util.ResultRunnable; /** * Contains methods for handling UI operations on {@link Widget}. * * @author Jiri Peterka * @author Rastislav Wagner * @author Jaroslav Jankovic */ public class WidgetHandlerExt { private static WidgetHandlerExt instance; private WidgetHandlerExt() { } /** * Gets instance of WidgetHandlerExt. * * @return instance of WidgetHandlerExt */ public static WidgetHandlerExt getInstance() { if (instance == null) { instance = new WidgetHandlerExt(); } return instance; } /** * Finds out whether specified {@link Widget} is enabled or not. * * @param widget * widget to handle * @return true if widget is enabled, false otherwise */ public boolean isEnabled(Widget widget) { boolean ret = true; Object o = null; try { o = ObjectUtil.invokeMethod(widget, "isEnabled"); } catch (RuntimeException e) { return true; } if (o == null) { return ret; } if (o instanceof Boolean) { ret = ((Boolean) o).booleanValue(); } return ret; } /** * Finds out whether specified {@link Widget} is disposed or not. * * @param widget * widget to handle * @return true if widget is disposed, false otherwise */ public boolean isDisposed(final Widget widget) { return Display.syncExec(new ResultRunnable<Boolean>() { @Override public Boolean run() { return widget.isDisposed(); } }); } /** * Finds out whether specified {@link Widget} is visible or not. * * @param widget * widget to handle * @return true if widget is visible, false otherwise */ public boolean isVisible(Widget widget) { boolean ret = true; Object o = null; try { o = ObjectUtil.invokeMethod(widget, "isVisible"); } catch (RuntimeException e) { throw new CoreLayerException("Runtime error during checking widget visibility", e); } if (o == null) { return ret; } if (o instanceof Boolean) { ret = ((Boolean) o).booleanValue(); } return ret; } /** * Gets style of specified widget. * * @param <T> * the generic type * @param w * widget to handle * @return style of specified widget */ public <T extends Widget> int getStyle(final T w) { int style = Display.syncExec(new ResultRunnable<Integer>() { @Override public Integer run() { if (w instanceof Widget) { return ((Widget) w).getStyle(); } else { throw new CoreLayerException("Unsupported type"); } } }); return style; } /** * Sets specified text to specified widget. * * @param <T> * the generic type * @param widget * widget to handle * @param text * text to set */ public <T extends Widget> void setText(final T widget, final String text) { try { ObjectUtil.invokeMethod(widget, "setText", new Class[] { String.class }, new Object[] { text }); } catch (RuntimeException e) { throw new CoreLayerException("Runtime error during setting widget's text", e); } } /** * Gets text of specified widget. * * @param <T> * the generic type * @param widget * widget to handle * @return text of specified widget */ public <T extends Widget> String getText(final T widget) { Object o = ObjectUtil.invokeMethod(widget, "getText"); if (o == null) { return null; } if (o instanceof String) { return (String) o; } throw new CoreLayerException("Return value of method getText() on class " + o.getClass() + " should be String, but was " + o.getClass()); } /** * Gets label of specified widget. * * @param <T> * the generic type * @param w * widget to handle * @return label of specified widget */ public <T extends Widget> String getLabel(final T w) { String label = Display.syncExec(new ResultRunnable<String>() { @Override public String run() { Control parent = ((Control) w).getParent(); java.util.List<Widget> children = WidgetResolver.getInstance().getChildren(parent); // check whether a label is defined using form data layout for (Widget child : children) { if (child instanceof Label || child instanceof CLabel) { Object layoutData = ((Control) child).getLayoutData(); if (layoutData instanceof FormData) { FormData formData = (FormData) layoutData; if (formData.right != null && w.equals(formData.right.control)) { if (child instanceof Label) { return ((Label) child).getText(); } else if (child instanceof CLabel) { return ((CLabel) child).getText(); } } } } } List<Control> allWidgets = WidgetLookupExt.getInstance().findAllParentWidgets(); int widgetIndex = allWidgets.indexOf(w); if (widgetIndex < 0) { throw new CoreLayerException("Wrong implementation for finding labels!"); } ListIterator<? extends Widget> listIterator = allWidgets.listIterator(widgetIndex); while (listIterator.hasPrevious()) { Widget previousWidget = listIterator.previous(); if (previousWidget instanceof Label) { Label label = (Label) previousWidget; if (label.getImage() == null) { return label.getText(); } } if (previousWidget instanceof CLabel) { CLabel cLabel = (CLabel) previousWidget; if (cLabel.getImage() == null) { return cLabel.getText(); } } } return null; } }); if (label != null) { label = label.replaceAll("&", "").split("\t")[0]; } return label; } /** * Gets tool tip text of specified widget. * * @param <T> * the generic type * @param widget * widget to handle * @return tool tip text of specified widget */ public <T extends Widget> String getToolTipText(final T widget) { Object o = null; try { o = ObjectUtil.invokeMethod(widget, "getToolTipText"); } catch (RuntimeException e) { throw new CoreLayerException("Runtime error during retrieving widget's text", e); } if (o == null) { return null; } if (o instanceof String) { return (String) o; } throw new CoreLayerException("Return value of method getText() on class " + o.getClass() + " should be String, but was " + o.getClass()); } /** * Sets focus to specified widget. The method is called from {@link WidgetLookup} so it need to be common for all * widgets and cannot be decomposed to separate handlers. * * @param <T> * the generic type * @param w * widget to handle */ public <T extends Widget> void setFocus(final T w) { if (w instanceof CTabItem) { CTabItemHandler.getInstance().setFocus((CTabItem) w); } else if (w instanceof CTabFolder) { CTabFolderHandler.getInstance().setFocus((CTabFolder) w); } else if (w instanceof TabItem) { TabItemHandler.getInstance().setFocus((TabItem) w); } else if (w instanceof TableItem) { TableItemHandler.getInstance().setFocus((TableItem) w); } else if (w instanceof TabFolder) { TabFolderHandler.getInstance().setFocus((TabFolder) w); } else if (w instanceof Shell) { ShellHandler.getInstance().setFocus((Shell) w); } else if (w instanceof ToolItem) { // ToolItem can't have focus -> set focus to parent ToolBar setFocus(ToolItemHandler.getInstance().getParent((ToolItem) w)); } else { Display.syncExec(new Runnable() { @Override public void run() { if (w instanceof Control) { ((Control) w).setFocus(); } else { throw new CoreLayerException("Unsupported type"); } } }); } } /** * Sends a click (SWT.Selection) notification to specified widget. * * @param widget * widget to handle */ public void sendClickNotifications(Widget widget) { notify(SWT.Selection, widget); } /** * Notifies specified widget about the event of specified event type. See {@link Event}. * * @param eventType * type of the event * @param widget * widget to handle */ public void notify(int eventType, Widget widget) { Event event = createEvent(widget); notify(eventType, event, widget); } /** * Notifies specified widget about the event of specified event type with specified details and item. See * {@link Event}. * * @param eventType * type of the event * @param detail * details of the event * @param widget * widget to handle * @param widgetItem * item of the event */ public void notifyItem(int eventType, int detail, Widget widget, Widget widgetItem) { Event event = createEventItem(eventType, detail, widget, widgetItem); notify(eventType, event, widget); } /** * Notifies specified widget about the mouse event of specified event type, specified position, button and item. See * {@link Event}. * * @param eventType * type of the event * @param detail * details of the event * @param widget * widget to handle * @param widgetItem * item of the event * @param x * x of the event * @param y * y of the event * @param button * button of the event */ public void notifyItemMouse(int eventType, int detail, Widget widget, Widget widgetItem, int x, int y, int button) { Event event = createMouseItemEvent(eventType, detail, widget, widgetItem, x, y, button); notify(eventType, event, widget); } /** * Notifies specified widget about specified event of specified type. See {@link Event}. * * @param eventType * type of specified event * @param createEvent * event * @param widget * widget to handle */ public void notify(final int eventType, final Event createEvent, final Widget widget) { createEvent.type = eventType; Display.asyncExec(new Runnable() { public void run() { if ((widget == null) || widget.isDisposed()) { return; } widget.notifyListeners(eventType, createEvent); } }); // Wait for synchronization Display.syncExec(new Runnable() { public void run() { // do nothing here } }); } private Event createEvent(Widget widget) { Event event = new Event(); event.time = (int) System.currentTimeMillis(); event.widget = widget; event.display = Display.getDisplay(); return event; } private Event createEventItem(int eventType, int detail, Widget widget, Widget widgetItem) { Event event = new Event(); event.display = Display.getDisplay(); event.time = (int) System.currentTimeMillis(); event.item = widgetItem; event.widget = widget; event.detail = detail; event.type = eventType; return event; } private Event createMouseItemEvent(int eventType, int detail, Widget widget, Widget widgetItem, int x, int y, int button) { Event event = new Event(); event.display = Display.getDisplay(); event.time = (int) System.currentTimeMillis(); event.item = widgetItem; event.widget = widget; event.detail = detail; event.type = eventType; event.button = button; event.x = x; event.y = y; return event; } /** * Gets path to widget within widget tree including widget getting path for as last element of returned list. * * @param widget * widget to get path for * @param classFilter * optional array of classes included in returned list * @return ordered list of widgets */ public List<Widget> getPathToWidget(final Widget widget, final Class<?>... classFilter) { final Control firstParent = getParent(widget); List<Widget> parents = Display.syncExec(new ResultRunnable<List<Widget>>() { @Override public List<Widget> run() { LinkedList<Widget> result = new LinkedList<Widget>(); if (WidgetHandlerExt.isClassOf(widget.getClass(), classFilter)) { result.add(widget); } Control control = firstParent; while (control != null) { if (WidgetHandlerExt.isClassOf(control.getClass(), classFilter)) { result.addFirst(control); } control = control.getParent(); } return result; } }); return parents; } /** * Gets parent of specified widget. * * @param widget * widget to find parent * @return parent widget of specified widget */ public Control getParent(final Widget widget) { Object o = ObjectUtil.invokeMethod(widget, "getParent"); if (o == null) { return null; } if (o instanceof Control) { return (Control) o; } throw new CoreLayerException("Return value of method getObject() on class " + o.getClass() + " should be Control, but was " + o.getClass()); } /** * Returns control children. * * @param composite * the composite * @return the children */ public Control[] getChildren(final Composite composite) { return Display.syncExec(new ResultRunnable<Control[]>() { @Override public Control[] run() { return composite.getChildren(); } }); } private static boolean isClassOf(Class<?> clazz, Class<?>[] classes) { boolean filterPassed = false; if (classes != null && classes.length > 0) { int index = 0; while (!filterPassed && index < classes.length) { if (clazz.getName().equals(classes[index].getName())) { filterPassed = true; } index++; } } else { filterPassed = true; } return filterPassed; } }