/*******************************************************************************
* 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.locator.eclipse;
import java.util.concurrent.Callable;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.ToolItem;
import org.eclipse.swt.widgets.Widget;
import com.windowtester.runtime.IClickDescription;
import com.windowtester.runtime.IUIContext;
import com.windowtester.runtime.WidgetNotFoundException;
import com.windowtester.runtime.WidgetSearchException;
import com.windowtester.runtime.condition.HasIndex;
import com.windowtester.runtime.condition.HasIndexCondition;
import com.windowtester.runtime.condition.IUICondition;
import com.windowtester.runtime.condition.IsEnabled;
import com.windowtester.runtime.condition.IsEnabledCondition;
import com.windowtester.runtime.condition.IsSelected;
import com.windowtester.runtime.condition.IsSelectedCondition;
import com.windowtester.runtime.locator.IPathLocator;
import com.windowtester.runtime.locator.IWidgetLocator;
import com.windowtester.runtime.locator.IWidgetReference;
import com.windowtester.runtime.locator.WidgetReference;
import com.windowtester.runtime.swt.internal.condition.PullDownMenuItemStateAccessor;
import com.windowtester.runtime.swt.internal.drivers.MenuDriver;
import com.windowtester.runtime.swt.internal.finder.SWTHierarchyHelper;
import com.windowtester.runtime.swt.internal.finder.eclipse.views.ViewFinder;
import com.windowtester.runtime.swt.internal.locator.IControlRelativeLocator;
import com.windowtester.runtime.swt.internal.widgets.ISWTWidgetReference;
import com.windowtester.runtime.swt.internal.widgets.MenuReference;
import com.windowtester.runtime.swt.internal.widgets.ViewReference;
import com.windowtester.runtime.swt.locator.SWTWidgetLocator;
import com.windowtester.runtime.util.ScreenCapture;
/**
* Locates {@link MenuItem} widgets in {@link ToolItem} and view pull-downs.
* <p>
* Example tool item use:
* <pre> ui.click(new PullDownMenuItemLocator("Project...", new ContributedToolItemLocator("newWizardDropDown")));</pre>
* Selects the "Project..." menu item in the "New Wizard" action tool item contribution.
* <p>
* Example view use:
* <pre> ui.click(new PullDownMenuItemLocator("&Filters...", new ViewLocator("org.eclipse.ui.views.ResourceNavigator")));</pre>
* Selects the "Filters..." menu item in the Navigator view.
* <p>
* <b>Note:</b> View support is provisional and requires some fancy and dangerous (read: internal eclipse API) footwork.
* If the internal eclipse API changes this functionality MAY break.
*
*/
public class PullDownMenuItemLocator extends SWTWidgetLocator implements IPathLocator, IControlRelativeLocator, IsSelected, IsEnabled, HasIndex {
private static final long serialVersionUID = -5770390916590164722L;
private final String _menuItemPath;
private final SWTWidgetLocator _controlLocator;
/**
* Create a locator that selects the given menupath in the pulldown menu for the given host locator
* @param menuItemPath the path of the menu item to select
* @param pullDownHost the pull down control host locator (note: this MUST resolve to a ToolItem or a View)
*/
public PullDownMenuItemLocator(String menuItemPath, SWTWidgetLocator pullDownHost) {
super(MenuItem.class); //ignored
_menuItemPath = menuItemPath;
_controlLocator = pullDownHost;
}
/* (non-Javadoc)
* @see com.windowtester.runtime.WidgetLocator#findAll(com.windowtester.runtime.IUIContext)
*/
@Override
public IWidgetLocator[] findAll(IUIContext ui) {
SWTWidgetLocator controlLocator = getControlLocator();
//in the view locator case we can just return the associated control
if (controlLocator instanceof ViewLocator) {
IWidgetLocator ref = WidgetReference.create(ViewFinder.getViewControl(((ViewLocator)controlLocator).getViewId()));
return new IWidgetLocator[]{ref};
}
return controlLocator.findAll(ui);
}
/* (non-Javadoc)
* @see com.windowtester.runtime.swt.locator.SWTWidgetLocator#matches(java.lang.Object)
*/
public boolean matches(Object widget) {
//visibility check first and foremost
// if (!isVisible(widget))
// return false;
//matching to find the tool item
return getControlLocator().matches(widget);
}
private boolean isVisible(Object widget) {
return SWTHierarchyHelper.isVisible((Widget)widget);
}
/* (non-Javadoc)
* @see com.windowtester.runtime.swt.locator.SWTWidgetLocator#click(com.windowtester.runtime.IUIContext, com.windowtester.runtime.locator.WidgetReference, com.windowtester.runtime.IClickDescription)
*/
public IWidgetLocator click(IUIContext ui, IWidgetReference widget, final IClickDescription click) throws WidgetSearchException {
final IWidgetReference widgetToSelect = getMenuHost(widget);
return new MenuDriver().resolveAndSelect(new Callable<MenuReference>() {
public MenuReference call() throws Exception {
return ((ISWTWidgetReference<?>) widgetToSelect).showPulldownMenu(click);
}
}, getPath());
// openMenu(widget);
// //N.B. the passed in ref is ignored in the MenuItemLocator impl.
// return new MenuItemLocator(getPath()).click(ui, widget /* ignored */, click);
// SWTLocation location = getClickLocation(ref);
// Widget clicked = new MenuDriver().select(location, WT.BUTTON1, getPath());
// return new WidgetReference(clicked);
// throw new RuntimeException("Not implemented");
}
private IWidgetReference getMenuHost(IWidgetReference widget)
throws WidgetNotFoundException {
final Object ref = widget.getWidget();
if (!isVisible(ref)) {
ScreenCapture.createScreenCapture();
throw new WidgetNotFoundException("Menu host not visible");
}
/*
* TODO It seems like we should have a first class ViewReference instance here that provides
* atomic operations on a view and implements ISWTWidgetReferenceWithPullDownMenu
* Also, it seems like this method should be called with widget = this new ViewReference
* and thus our finder story should translate ViewLocator into ViewReference.
* Below is a hack to see/show how this new ViewReference concept would work for this method
* If we don't have a first class ViewReference, then this code needs to be moved somewhere else
* because it really does not belong here
*/
if (_controlLocator instanceof ViewLocator)
widget = new ViewReference(((ViewLocator) _controlLocator).getViewId());
final IWidgetReference widgetToSelect = widget;
return widgetToSelect;
}
private IWidgetReference getMenuHost(IUIContext ui)
throws WidgetSearchException, WidgetNotFoundException {
IWidgetReference widget = (IWidgetReference) ui.find(this);
final IWidgetReference menuHost = getMenuHost(widget);
return menuHost;
}
// private SWTLocation getClickLocation(final Object ref) {
// if (ref instanceof ToolItem) {
// return new SWTWidgetLocation((ToolItem) ref, WTInternal.RIGHT).offset(-3, 0);
// }
// if (_controlLocator instanceof ViewLocator) {
//// ViewPullDownSelector vpdSelector = new ViewPullDownSelector((ViewLocator)_controlLocator);
//// IViewReference viewRef = vpdSelector.getViewRef(vpdSelector.getViewId());
//// IViewPart viewPart = viewRef.getView(true);
//// IMenuManager menuManager = viewPart.getViewSite().getActionBars().getMenuManager();
//// final Control[] parent = new Control[1];
//// Display.getDefault().syncExec(new Runnable() {
//// public void run() {
//// parent[0] = ((Composite) ref).getParent();
//// }
//// });
//// return new SWTWidgetLocation(parent[0], WTInternal.TOPRIGHT);
// return new SWTWidgetLocation((Widget) ref, WTInternal.TOPRIGHT).offset(-5, -5);
// }
// throw new RuntimeException("Not implemented");
// }
// private void openMenu(IWidgetReference widget) {
// SWTWidgetLocator controlLocator = getControlLocator();
// if (controlLocator instanceof ViewLocator) {
// new ViewPullDownSelector((ViewLocator)controlLocator).openMenu();
// } else {
// ToolItem item = getToolItem(widget);
// new ToolItemSelector().clickExpand(item);
// }
// }
// private ToolItem getToolItem(IWidgetReference ref) {
// Object widget = ref.getWidget();
// if (!(widget instanceof ToolItem))
// throw new IllegalArgumentException("target widget must be a toolitem, got: " + widget);
// return (ToolItem)widget;
// }
/**
* Get the associated host control locator.
*/
public SWTWidgetLocator getControlLocator() {
return _controlLocator;
}
/* (non-Javadoc)
* @see com.windowtester.runtime.locator.IPathLocator#getPath()
*/
public String getPath() {
return _menuItemPath;
}
///////////////////////////////////////////////////////////////////////////
//
// Condition Factories
//
///////////////////////////////////////////////////////////////////////////
/**
* Create a condition that tests if the given menu item has an expected index
* in its parent menu.
* @param expectedIndex the expected index of the item
*/
public IUICondition hasIndex(int expectedIndex){
return new HasIndexCondition(this, expectedIndex);
}
/**
* Create a condition that tests if the given menu item is selected.
* Note that this is a convenience method, equivalent to:
* <code>isSelected(true)</code>
*/
public IUICondition isSelected() {
return isSelected(true);
}
/**
* Create a condition that tests if the given menu item is selected.
* @param expected <code>true</code> if the menu is expected to be selected, else
* <code>false</code>
*/
public IUICondition isSelected(boolean expected) {
return new IsSelectedCondition(this, expected);
}
/**
* Create a condition that tests if the given menu item is enabled.
* Note that this is a convenience method, equivalent to:
* <code>isEnabled(true)</code>
*/
public IUICondition isEnabled() {
return isEnabled(true);
}
/**
* Create a condition that tests if the given menu item is enabled.
* @param expected <code>true</code> if the menu is expected to be enabled, else
* <code>false</code>
*/
public IUICondition isEnabled(boolean expected) {
return new IsEnabledCondition(this, expected);
}
/* (non-Javadoc)
* @see com.windowtester.runtime.condition.IsSelected#isSelected(com.windowtester.runtime.IUIContext)
*/
public boolean isSelected(IUIContext ui) throws WidgetSearchException {
IWidgetReference menuHost = getMenuHost(ui);
return new PullDownMenuItemStateAccessor(menuHost, getPath()).isSelected(ui, true);
}
/* (non-Javadoc)
* @see com.windowtester.runtime.swt.locator.SWTWidgetLocator#isEnabled(com.windowtester.runtime.IUIContext)
*/
public boolean isEnabled(IUIContext ui) throws WidgetSearchException {
IWidgetReference menuHost = getMenuHost(ui);
return new PullDownMenuItemStateAccessor(menuHost, getPath()).isEnabled(ui, true);
}
/* (non-Javadoc)
* @see com.windowtester.runtime.condition.HasIndex#getIndex(com.windowtester.runtime.IUIContext)
*/
public int getIndex(IUIContext ui) throws WidgetSearchException {
IWidgetReference menuHost = getMenuHost(ui);
return new PullDownMenuItemStateAccessor(menuHost, getPath()).getIndex(ui);
}
}