blob: f94d173716faaf37151db126e398f2086071a26f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2016 Xored Software Inc and others.
* 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:
* Xored Software Inc - initial API and implementation and/or initial documentation
*******************************************************************************/
package org.eclipse.rcptt.tesla.internal.ui.player;
import static org.eclipse.rcptt.tesla.internal.ui.player.PlayerTextUtils.getMenuText;
import static org.eclipse.rcptt.tesla.internal.ui.player.PlayerTextUtils.getRawText;
import static org.eclipse.rcptt.tesla.internal.ui.player.PlayerTextUtils.getText;
import static org.eclipse.rcptt.tesla.internal.ui.player.PlayerTextUtils.removeAcceleratorFromText;
import static org.eclipse.rcptt.tesla.internal.ui.player.PlayerTextUtils.safeMatches;
import static org.eclipse.rcptt.tesla.internal.ui.player.PlayerWidgetUtils.canClick;
import static org.eclipse.rcptt.tesla.internal.ui.player.PlayerWrapUtils.unwrap;
import static org.eclipse.rcptt.tesla.internal.ui.player.PlayerWrapUtils.unwrapWidget;
import static org.eclipse.rcptt.util.swt.Bounds.centerAbs;
import static org.eclipse.rcptt.util.swt.Bounds.centerRel;
import static org.eclipse.rcptt.util.swt.Events.createClick;
import static org.eclipse.rcptt.util.swt.Events.createMouseDown;
import static org.eclipse.rcptt.util.swt.Events.createMouseUp;
import static org.eclipse.rcptt.util.swt.Events.createSelection;
import static org.eclipse.rcptt.util.swt.TableTreeUtil.getItemBounds;
import static org.eclipse.rcptt.util.swt.Widgets.isToggleButton;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.lang.ref.WeakReference;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.bindings.keys.KeyStroke;
import org.eclipse.jface.preference.ColorSelector;
import org.eclipse.jface.viewers.EditingSupport;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerColumn;
import org.eclipse.osgi.util.NLS;
import org.eclipse.rcptt.sherlock.core.SherlockTimerRunnable;
import org.eclipse.rcptt.tesla.core.Q7WaitUtils;
import org.eclipse.rcptt.tesla.core.TeslaLimits;
import org.eclipse.rcptt.tesla.core.context.ContextManagement;
import org.eclipse.rcptt.tesla.core.context.ContextManagement.Context;
import org.eclipse.rcptt.tesla.core.info.Q7WaitInfoRoot;
import org.eclipse.rcptt.tesla.core.protocol.ElementKind;
import org.eclipse.rcptt.tesla.core.protocol.GenericElementKind;
import org.eclipse.rcptt.tesla.core.protocol.UIColor;
import org.eclipse.rcptt.tesla.internal.core.TeslaCore;
import org.eclipse.rcptt.tesla.internal.core.TeslaExecutionFailedException;
import org.eclipse.rcptt.tesla.internal.ui.player.specific.GetWindowPlayer;
import org.eclipse.rcptt.tesla.internal.ui.player.viewers.TableViewerItem;
import org.eclipse.rcptt.tesla.internal.ui.player.viewers.Viewers;
import org.eclipse.rcptt.tesla.swt.TeslaSWTMessages;
import org.eclipse.rcptt.tesla.swt.dialogs.SWTDialogManager;
import org.eclipse.rcptt.tesla.swt.events.ITimerExecHelper;
import org.eclipse.rcptt.tesla.swt.events.TeslaEventManager;
import org.eclipse.rcptt.tesla.swt.events.TeslaTimerExecManager;
import org.eclipse.rcptt.tesla.swt.events.TeslaTimerExecManager.TimerInfo;
import org.eclipse.rcptt.tesla.swt.workbench.EclipseWorkbenchProvider;
import org.eclipse.rcptt.tesla.ui.IViewerItem;
import org.eclipse.rcptt.util.ShellUtilsProvider;
import org.eclipse.rcptt.util.swt.Bounds;
import org.eclipse.rcptt.util.swt.Events;
import org.eclipse.rcptt.util.swt.TabCTabUtil;
import org.eclipse.rcptt.util.swt.TableTreeUtil;
import org.eclipse.swt.SWT;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.custom.CBanner;
import org.eclipse.swt.custom.CCombo;
import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.custom.CTabItem;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.ImageLoader;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.CoolBar;
import org.eclipse.swt.widgets.CoolItem;
import org.eclipse.swt.widgets.DateTime;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Link;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.ScrollBar;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Slider;
import org.eclipse.swt.widgets.Spinner;
import org.eclipse.swt.widgets.Synchronizer;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import org.eclipse.swt.widgets.ToolTip;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.ui.IEditorDescriptor;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorReference;
import org.eclipse.ui.IPerspectiveDescriptor;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IViewReference;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartReference;
import org.eclipse.ui.IWorkbenchPartSite;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.internal.registry.EditorRegistry;
@SuppressWarnings("restriction")
public final class SWTUIPlayer {
private static final boolean DEBUG_PROCEED = "true"
.equals(Platform.getDebugOption("org.eclipse.rcptt.tesla.swt/debug/proceed"));
final Display display;
private SWTUIElement[] ignoreWindows;
private Shell[] ignoredShells;
private final List<File> screenshotsDuringSession = null;
private final SWTEvents events;
private volatile Throwable error = null;
public Throwable getError() {
return error;
}
private static SWTKeyboard keyboard = new SWTKeyboard();
private final Map<Context, List<Runnable>> runnables = new HashMap<Context, List<Runnable>>();
private static Map<Display, SWTUIPlayer> players = new HashMap<Display, SWTUIPlayer>();
protected static Map<Class<?>, ElementKind> elementKinds = new LinkedHashMap<Class<?>, ElementKind>();
private final ITimerExecHelper timerListener;
private static List<ISWTUIPlayerExtension> extensions = new ArrayList<ISWTUIPlayerExtension>();
static {
elementKinds.put(Shell.class, ElementKind.Window);
elementKinds.put(CBanner.class, ElementKind.CBanner);
elementKinds.put(ToolBar.class, ElementKind.Toolbar);
elementKinds.put(CoolBar.class, ElementKind.CoolBar);
elementKinds.put(Button.class, ElementKind.Button);
elementKinds.put(ToolItem.class, ElementKind.Button);
elementKinds.put(Label.class, ElementKind.Label);
elementKinds.put(CLabel.class, ElementKind.Label);
elementKinds.put(Group.class, ElementKind.Group);
elementKinds.put(TabFolder.class, ElementKind.TabFolder);
elementKinds.put(CTabFolder.class, ElementKind.TabFolder);
elementKinds.put(Text.class, ElementKind.Text);
elementKinds.put(StyledText.class, ElementKind.Text);
elementKinds.put(Spinner.class, ElementKind.Text);
elementKinds.put(Link.class, ElementKind.Link);
elementKinds.put(Combo.class, ElementKind.Combo);
elementKinds.put(CCombo.class, ElementKind.Combo);
elementKinds.put(Tree.class, ElementKind.Tree);
elementKinds.put(org.eclipse.swt.widgets.List.class, ElementKind.List);
elementKinds.put(MenuItem.class, ElementKind.Menu);
elementKinds.put(Menu.class, ElementKind.Menu);
elementKinds.put(Table.class, ElementKind.Table);
elementKinds.put(CTabItem.class, ElementKind.TabItem);
elementKinds.put(TabItem.class, ElementKind.TabItem);
elementKinds.put(IViewReference.class, ElementKind.View);
elementKinds.put(IEditorReference.class, ElementKind.Editor);
elementKinds.put(DateTime.class, ElementKind.DateTime);
elementKinds.put(Slider.class, ElementKind.Slider);
elementKinds.put(Link.class, ElementKind.Link);
elementKinds.put(Shell.class, ElementKind.Window);
elementKinds.put(TreeItem.class, ElementKind.Item);
elementKinds.put(TableItem.class, ElementKind.Item);
elementKinds.put(Canvas.class, ElementKind.Canvas);
elementKinds.put(Browser.class, ElementKind.Browser);
elementKinds.put(TreeColumn.class, ElementKind.ColumnHeader);
elementKinds.put(TableColumn.class, ElementKind.ColumnHeader);
// Debug check right order of classes in elementKings Map
// checkIntegrity(elementKinds.keySet().toArray(new Class<?>[0]));
}
public Shell[] getIgnored() {
return ignoredShells;
}
protected SWTUIPlayer(Display display, Shell... ignoreWindows) {
this.display = display;
this.events = new SWTEvents(display);
if (ignoreWindows != null) {
this.ignoreWindows = new SWTUIElement[ignoreWindows.length];
this.ignoredShells = ignoreWindows;
int i = 0;
for (Shell shell : ignoreWindows) {
this.ignoreWindows[i++] = wrap(shell);
}
}
collector = new UIJobCollector();
Job.getJobManager().addJobChangeListener(collector);
timerListener = getTimerExecHelper();
TeslaTimerExecManager.getManager().addEventListener(timerListener);
}
private ITimerExecHelper getTimerExecHelper() {
return new ITimerExecHelper() {
@Override
public boolean needNullify(Runnable run, int time) {
String clName = null;
if (run instanceof SherlockTimerRunnable) {
clName = ((SherlockTimerRunnable) run).getRunnable().getClass().getName();
} else {
clName = run.getClass().getName();
}
if (!clName.contains("org.eclipse.swt") && !clName.contains("org.eclipse.gmf")
&& !clName.contains("org.eclipse.jface") && !clName.contains("org.eclipse.gef")) {
if (clName.contains(Display.class.getName())) {
return false;
}
if (clName.startsWith("org.eclipse.nebula.widgets.oscilloscope.OscilloscopeDispatcher")) {
return false;
}
if (clName.startsWith("org.eclipse.tm.internal.terminal.textcanvas.PollingTextCanvasModel")) {
return false;
}
if (time < TeslaLimits.getTimerExecsWaitNullify()) {
// Check if same thread is not already in stack trace.
Context currentCtx = ContextManagement.makeContext(Thread.currentThread().getStackTrace());
if (currentCtx.containsClass(clName)) {
// Do not allow to nullity timers executed from
// timers.
return false;
}
// System.out.println("Nullifying timerexec:" + clName);
return true;
}
}
return false;
}
};
}
private SWTUIPlayer(Display display) {
this(display, (Shell[]) null);
}
private static Class<?>[] one(Class<?> cl) {
return new Class[] { cl };
}
/**
* Determines the UI element matching the filter.
* <p>
* Can be extended by
* {@link ISWTUIPlayerExtension#select(SWTUIPlayer, PlayerSelectionFilter)}
*/
public SWTUIElement select(PlayerSelectionFilter filter) {
SWTUIElement result = null;
for (ISWTUIPlayerExtension ext : getExtensions()) {
result = ext.select(this, filter);
if (result != null) {
return result;
}
}
switch (filter.kind.kind) {
case Unknown:
result = null;
break;
case EclipseWindow:
result = selectEclipseWindow(filter.index);
break;
case QuickAccess:
result = selectQuickAccess();
break;
case Window:
result = new GetWindowPlayer(this, ignoreWindows).selectShell(filter);
break;
case Menu:
result = selectMenu(filter);
break;
case Button:
result = selectWidget(filter, Button.class, ToolItem.class);
if (result == null) {
result = selectButton(filter);
}
break;
case Group:
result = selectWidget(filter, Group.class);
break;
case Text:
result = selectWidget(filter, Text.class, StyledText.class, Spinner.class);
break;
case Combo:
result = selectWidget(filter, Combo.class, CCombo.class);
break;
case Tree:
result = selectWidget(filter.withoutPattern(), false, Tree.class);
break;
case Toolbar:
result = selectWidget(filter.withoutPattern(), false, ToolBar.class);
break;
case CBanner:
result = selectWidget(filter.withoutPattern(), false, CBanner.class);
break;
case CoolBar:
result = selectWidget(filter.withoutPattern(), false, CoolBar.class);
break;
case Canvas:
result = selectWidget(filter.withoutPattern(), false, Canvas.class);
break;
case List:
result = selectWidget(filter.withoutPattern(), false, org.eclipse.swt.widgets.List.class);
break;
case Table:
result = selectWidget(filter.withoutPattern(), false, Table.class);
break;
case Label:
result = selectWidget(filter, Label.class, CLabel.class);
break;
case TabItem:
result = selectWidget(filter, CTabItem.class, TabItem.class);
break;
case TabFolder:
result = selectWidget(filter, CTabFolder.class, TabFolder.class);
break;
case View:
result = selectView(filter);
break;
case Editor:
result = selectEditor(filter);
break;
case Any:
result = selectWidget(filter.withoutKind());
break;
case Item:
result = selectItem(filter);
break;
case Browser:
result = selectWidget(filter.withoutPattern(), Browser.class);
break;
case DateTime:
result = selectWidget(filter.withoutPattern(), DateTime.class);
break;
case Slider:
result = selectWidget(filter.withoutPattern(), Slider.class);
break;
case ColumnHeader:
result = selectColumnHeader(filter);
break;
}
// if (result != null) {
// if (isDisabled(result)) {
// // System.out.println("#");
// }
// }
if (result == null) {
makeScreenShot();
}
return result;
}
private SWTUIElement selectColumnHeader(PlayerSelectionFilter f) {
Widget unwrapped = unwrapWidget(f.parent);
if (!(unwrapped instanceof Tree || unwrapped instanceof Table))
return null;
return wrap(TableTreeUtil.findColumn(unwrapped, f.pattern, f.index == null ? 0 : f.index));
}
private SWTUIElement selectButton(PlayerSelectionFilter f) {
final String pattern = f.pattern;
if (pattern != null && pattern.contains("(") && pattern.endsWith(")")) {
// With accelerator
int pos = pattern.indexOf('(');
String prefix = pattern.substring(0, pos);
String accel = pattern.substring(pos + 1, pattern.length() - 1);
String[] split = accel.split("\\+");
Arrays.sort(split);
if (split.length > 2) {
SWTUIElement[] children = this.children.collectFor(f.parent, ignoreWindows, true,
new Class[] { Button.class, ToolItem.class }, f.after);
// Ctrl + Alt + S like combinations
int cur = 0;
for (SWTUIElement widget : children) {
String text = getText(widget);
if (text != null) {
text = removeAcceleratorFromText(text);
if (text != null && text.contains("(") && text.endsWith(")")) {
int pos2 = text.indexOf('(');
String prefix2 = text.substring(0, pos2);
String accel2 = text.substring(pos2 + 1, text.length() - 1);
String[] split2 = accel2.split("\\+");
Arrays.sort(split2);
if (prefix2.equals(prefix) && Arrays.equals(split2, split)) {
if ((f.index != null && cur == f.index.intValue()) || f.index == null) {
return widget;
}
cur++;
}
}
}
}
}
}
return null;
}
@SuppressWarnings("unused")
private SWTUIElement selectItem(PlayerSelectionFilter f) {
final SWTUIElement parent = f.parent;
if (parent != null && unwrapWidget(parent) instanceof Tree && f.path != null) {
final Tree tree = (Tree) unwrapWidget(parent);
TreeItem current = (TreeItem) Viewers.firstMatch(f.path, tree);
if (current != null) {
return wrap(current);
}
} else if (parent != null && unwrapWidget(parent) instanceof Tree && f.indexes != null
&& f.indexes.length == 2) {
// Select item with column
final Tree tree = (Tree) unwrapWidget(parent);
TreeItem[] items = getExpandedTreeItems(tree);
if (items.length > f.indexes[1]) {
return new ItemUIElement(items[f.indexes[1]], this, f.indexes[0]);
}
}
if (parent != null && unwrapWidget(parent) instanceof Table && f.path != null && f.path.length > 0) {
final Table table = (Table) unwrapWidget(parent);
Object current = unwrapWidget(parent);
TableItem[] items = ((Table) current).getItems();
if (items == null) {
return null;
}
IViewerItem[] viewerItems = Viewers.getViewerItems(items);
for (String part : f.path) {
for (TableItem item : items) {
if (item.isDisposed()) {
continue; // Skip disposed items
}
String itemText = toSelectionItem(
Viewers.getTableItemText(new TableViewerItem(item), part, viewerItems));
if (itemText != null) {
if (itemText.equals(part) || safeMatches(itemText, part)) {
return wrap(item);
}
}
}
}
} else if (parent != null && unwrapWidget(parent) instanceof Table && f.indexes != null
&& f.indexes.length == 2) {
Object current = unwrapWidget(parent);
TableItem[] items = ((Table) current).getItems();
if (items.length > f.indexes[1]) {
return new ItemUIElement(items[f.indexes[1]], this, f.indexes[0]);
}
}
return null;
}
public static TreeItem[] getExpandedTreeItems(Tree tree) {
List<TreeItem> items = new ArrayList<TreeItem>();
for (int i = 0; i < tree.getItemCount(); i++) {
TreeItem currentItem = tree.getItem(i);
if (currentItem.isDisposed()) {
continue;// Skip disposed items
}
items.add(currentItem);
if (currentItem.getExpanded()) {
items.addAll(getExpandedTreeItems(currentItem));
}
}
return items.toArray(new TreeItem[items.size()]);
}
private static List<TreeItem> getExpandedTreeItems(TreeItem item) {
List<TreeItem> items = new ArrayList<TreeItem>();
for (int i = 0; i < item.getItemCount(); i++) {
TreeItem currentItem = item.getItem(i);
items.add(currentItem);
if (currentItem.getExpanded()) {
items.addAll(getExpandedTreeItems(currentItem));
}
}
return items;
}
private SWTUIElement selectQuickAccess() {
Text quickAccess = EclipseWorkbenchProvider.getProvider().getQuickAccess();
return quickAccess == null ? null : wrap(quickAccess);
}
private SWTUIElement selectEclipseWindow(Integer index) {
IWorkbenchWindow[] windows = PlatformUI.getWorkbench().getWorkbenchWindows();
if (index == null) {
return wrap(windows[0].getShell());
} else if (index.intValue() < windows.length) {
return wrap(windows[index.intValue()].getShell());
}
return null;
}
// private IScreenCapturer screenCapturer = null;
private Context context;
private final UIJobCollector collector;
private final Map<Widget, Point> widgetToMouseForMenus = new HashMap<Widget, Point>();
private static Set<WeakReference<Menu>> shownMenus = new HashSet<WeakReference<Menu>>();
public void makeScreenShot() {
// Disable making of screenshots
// if (screenCapturer == null) {
// screenCapturer = new AWTScreenCapturer(TeslaCore.getDefault()
// .getStateLocation().append("screenshots").toFile());
// }
// final Rectangle bounds = display.getBounds();
// screenshotsDuringSession.add(screenCapturer.makeScreenShot(bounds.x,
// bounds.y, bounds.width, bounds.height));
}
public UIColor getSelectedColor(SWTUIElement uiElement) {
Widget widget = unwrapWidget(uiElement);
if (widget instanceof Button) {
ColorSelector colorSelector = TeslaSWTAccess.getColorSelector((Button) widget);
if (colorSelector != null) {
return new UIColor(colorSelector.getColorValue().red, colorSelector.getColorValue().green,
colorSelector.getColorValue().blue);// colorSelector.getColorValue();
}
}
return null;
}
public void setSelectedColor(SWTUIElement uiElement, final UIColor color) {
Widget widget = unwrapWidget(uiElement);
if (widget instanceof Button) {
ColorSelector colorSelector = TeslaSWTAccess.getColorSelector((Button) widget);
if (colorSelector != null) {
colorSelector.setColorValue(new RGB(color.r, color.g, color.b));
}
}
}
public SWTUIElement selectWidget(PlayerSelectionFilter filter, Class<?>... classes) {
return selectWidget(filter, true, classes);
}
public SWTUIElement selectWidget(PlayerSelectionFilter f, boolean checkText, Class<?>... classes) {
SWTUIElement[] children = this.children.collectFor(f.parent, ignoreWindows, true, classes, f.after);
final GenericElementKind kind = f.kind;
// filter the children by kind
if (kind != null) {
List<SWTUIElement> filteredByKind = new ArrayList<SWTUIElement>();
for (SWTUIElement element : children) {
if (element.isSuitableForKind(kind)) {
filteredByKind.add(element);
}
}
children = filteredByKind.toArray(new SWTUIElement[filteredByKind.size()]);
}
//
if (f.pattern == null) {
if (f.index == null && children.length > 0) {
// Locate first button without title
if (classes != null) {
List<Class<?>> classesList = Arrays.asList(classes);
if (classesList.contains(Button.class)) {
for (SWTUIElement swtuiElement : children) {
String text = swtuiElement.getText();
if (text != null && text.trim().length() == 0) {
return swtuiElement;
}
}
}
}
}
//
int index = (f.index == null) ? 0 : f.index;
if (children.length > index) {
// Search index same as calculated when record in
// SWTWidgetLocator
// the children array is already filtered
SWTUIElement child = children[index];
// TODO analyze usages & eliminate kind overriding
if (kind != null && !kind.is(child.getKind()))
child.overrideKind(kind);
return child;
}
}
if (checkText) {
int cur = 0;
Map<SWTUIElement, String> wtMap = new HashMap<SWTUIElement, String>();
if (f.pattern != null) {
for (SWTUIElement widget : children) {
String text = getText(widget);
if (text != null) {
text = removeAcceleratorFromText(text);
wtMap.put(widget, text);
if (text != null && text.equals(f.pattern)) {
if ((f.index != null && cur == f.index.intValue()) || f.index == null) {
return widget;
}
if (kind == null || widget.getKind().is(kind)) {
cur++;
}
}
}
}
cur = 0;
for (SWTUIElement widget : children) {
String text = getText(widget);
if (text != null) {
text = removeAcceleratorFromText(text);
wtMap.put(widget, text);
if (text != null && (safeMatches(text, f.pattern))) {
if ((f.index != null && cur == f.index.intValue()) || f.index == null) {
return widget;
}
if (kind == null || widget.getKind().is(kind)) {
cur++;
}
}
}
}
}
}
return null;
}
// stable view is a view that do not change its title, so
// we can skip it while gathering actual titles of views
private static final Set<String> stableViews = new HashSet<String>();
static {
stableViews.add("org.eclipse.ui.views.PropertySheet");
stableViews.add("org.eclipse.ui.views.ProblemView");
}
// @SuppressWarnings("restriction")
public SWTUIElement selectView(PlayerSelectionFilter f) {
final String pattern = f.pattern;
// IViewDescriptor[] views =
// PlatformUI.getWorkbench().getViewRegistry().getViews();
IViewReference[] views = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()
.getViewReferences();
int currIdx = 0;
for (IViewReference iViewRef : views) {
try {
String label = iViewRef.getPartName();
String id = iViewRef.getId();
if ((label != null && (label.equals(pattern) || safeMatches(label, pattern)))
|| (id != null && (id.equals(pattern) || safeMatches(id, pattern)))) {
if (f.index == null || f.index.equals(currIdx))
return wrap(iViewRef);
currIdx++;
}
} catch (Exception e) {
// Skip brokeb parts.
TeslaCore.log(e);
}
}
TeslaCore.log("Can not find view by pattern \"" + pattern + "\". Activating views...");
// Not found, lets go with resolve of view parts, it will initialize
// titles.
currIdx = 0;
for (IViewReference iViewRef : views) {
// try to skip well-known buggy views with immutable titles
if (stableViews.contains(iViewRef.getId()))
continue;
IWorkbenchPart part = iViewRef.getPart(true);
String title = part != null ? part.getTitle() : null;
if ((title != null && (title.equals(pattern) || safeMatches(title, pattern)))) {
if (f.index == null || f.index.equals(currIdx))
return wrap(iViewRef);
currIdx++;
}
}
return null;
}
private static boolean matches(String value, String pattern) {
return pattern == null || (value != null && (value.equals(pattern) || safeMatches(value, pattern)));
}
private static boolean matches(Integer value, Integer pattern) {
return pattern == null || (value != null && value.equals(pattern));
}
public SWTUIElement selectEditor(PlayerSelectionFilter f) {
String title = f.pattern;
if (title != null && title.length() == 0)
title = null;
String type = f.classPattern;
if (type != null && type.length() == 0)
type = null;
//
IEditorReference[] refs = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()
.getEditorReferences();
if (f.index != null && f.index < 0)
return null;
// -- old style
if (title != null && type == null && f.index == null) {
for (IEditorReference ref : refs)
if (matches(ref.getPartName(), title) || matches(ref.getId(), title))
return wrap(ref);
return null;
}
// -- new style
String id = null;
if (type != null)
for (IEditorDescriptor desc : ((EditorRegistry) PlatformUI.getWorkbench().getEditorRegistry())
.getSortedEditorsFromPlugins())
if (matches(desc.getLabel(), type))
id = desc.getId();
int counter = 0;
for (IEditorReference ref : refs)
if (matches(ref.getPartName(), title) && matches(ref.getId(), id))
if (matches(counter++, f.index))
return wrap(ref);
return null;
}
/**
* Put the caret at the given position in the styled text widget by clicking
* there. This also clears the current text selection.
*/
public void setTextOffset(final StyledText styledText, final int offset, final int line) {
exec("Set text offset", new Runnable() {
@Override
public void run() {
// styledText.setFocus();// forced focus (see QS-910)
// Point selectionRange = styledText.getSelection();
events.sendFocus(styledText);
int actualOffset = offset;
if (line != -1) {
actualOffset += styledText.getOffsetAtLine(line);
}
Point clickPoint = styledText.getLocationAtOffset(actualOffset);
styledText.setCaretOffset(actualOffset);
styledText.getAccessible().textCaretMoved(offset);
events.sendEvent(styledText, SWT.MouseDown, clickPoint, 1);
events.sendEvent(styledText, SWT.MouseUp, clickPoint, 1);
styledText.setSelectionRange(actualOffset, 0);
// styledText.setSelection(selectionRange.x,
// selectionRange.y);
}
});
}
public void click(final SWTUIElement w) {
click(w, false, false, false, Events.EMPTY_MASK);
}
public void click(final SWTUIElement w, final boolean isDefault, final boolean doubleClick, final boolean arrow,
final int mask) {
exec("click", new Runnable() {
@Override
public void run() {
for (ISWTUIPlayerExtension ext : getExtensions()) {
if (ext.canClick(w, isDefault, doubleClick, arrow)) {
ext.click(w, isDefault, doubleClick, arrow, mask);
return;
}
}
if (!canClick(w)) {
failClick(w);
}
IWorkbenchPage page = getTargetPage();
switch (w.getKind().kind) {
case View:
clickView(w, page);
break;
case Editor:
clickEditor(w, page);
break;
case TabItem:
clickTabItem(w, isDefault);
break;
case Link:
clickLink(w, doubleClick, mask);
break;
case Item:
clickTableTreeItem(w, doubleClick);
break;
case Label:
clickLabel(w, mask);
break;
default:
Widget widget = unwrapWidget(w);
if (widget.isDisposed()) {
break;
}
if (doubleClick) {
events.sendFocus(widget);
events.sendAll(widget, Events.createDoubleClick());
events.sendUnfocus(widget);
break;
}
if (widget instanceof MenuItem) {
clickMenuItem(w, isDefault, widget);
break;
}
final boolean isButton = widget instanceof Button;
final boolean isRadioButton = isButton && (widget.getStyle() & SWT.RADIO) != 0;
final boolean isWin32 = Platform.getOS().equals(Platform.OS_WIN32);
final boolean isSelectionButton = isButton && ((Button) widget).getSelection();
events.sendFocus(widget);
if (isRadioButton && (!isWin32 || !isSelectionButton)) {
sendEventsToRadioButtons(widget);
}
if (isButton && ((widget.getStyle() & SWT.CHECK) != 0)) {
Button b = (Button) widget;
b.setSelection(!b.getSelection());
}
if (widget instanceof ToolItem
&& ((widget.getStyle() & SWT.CHECK) != 0 || (widget.getStyle() & SWT.RADIO) != 0)) {
ToolItem b = (ToolItem) widget;
b.setSelection(!b.getSelection());
}
Point clickPoint = getClickPoint(w);
events.sendEvent(w, SWT.MouseEnter, mask);
events.sendEvent(w, SWT.MouseHover, mask);
events.sendEvent(w, SWT.MouseDown, clickPoint, 1, mask);
if (isToggleButton(widget)) {
((Button) widget).setSelection(!((Button) widget).getSelection());
}
if (!isRadioButton || !isWin32 || isSelectionButton) {
Event event = events.createEvent(w);
if (arrow) {
event.detail = SWT.ARROW;
}
event.type = isDefault ? SWT.DefaultSelection : SWT.Selection;
event.stateMask = mask;
events.sendEvent(w, event);
}
events.sendEvent(w, SWT.MouseUp, clickPoint, 1, mask);
events.sendEvent(w, SWT.MouseExit);
events.sendUnfocus(widget);
break;
}
}
private void sendEventsToRadioButtons(Widget widget) {
Button button = (Button) widget;
sendEventPreviousSelected(button);
button.setSelection(true);
}
private void sendEventPreviousSelected(Button button) {
SWTUIElement[] siblings = null;
int parentStyle = button.getParent().getStyle();
if ((parentStyle & SWT.NO_RADIO_GROUP) == 0) {
siblings = children.collectFor(wrap(button.getParent()), new SWTUIElement[] { w }, false,
Button.class);
}
if (siblings == null)
return;
for (SWTUIElement element : siblings) {
Button previousButton = (Button) unwrap(element);
if ((previousButton.getStyle() & SWT.RADIO) != 0 && previousButton.getSelection()) {
events.sendEvent(element, SWT.Selection);
previousButton.setSelection(false);
}
}
}
});
}
private static final Point LEGACY_CLICK_POINT = new Point(0, 0);
private static Point getMiddleClickPoint(Control w) {
Point size = w.getSize();
return new Point(size.x / 2, size.y / 2);
}
private static Point getClickPoint(SWTUIElement element) {
Widget widget = unwrapWidget(element);
switch (element.getKind().kind) {
case Tree:
Tree tree = (Tree) widget;
TreeItem[] selection = tree.getSelection();
if (selection.length < 1)
return LEGACY_CLICK_POINT;
TreeItem item = selection[0];
Point point = Viewers.getSafeToClickPoint(item);
if (point == Viewers.UNSAFE_CLICK_POINT)
return LEGACY_CLICK_POINT;
return point;
default:
if (widget instanceof Control)
return getMiddleClickPoint((Control) widget);
return LEGACY_CLICK_POINT;
}
}
private void clickMenuItem(final SWTUIElement w, final boolean isDefault, Widget widget) {
MenuItem menuItem = (MenuItem) widget;
hidePopupMenus(menuItem);
// Radio MenuItem
if ((menuItem.getStyle() & SWT.RADIO) != 0) {
Menu parentMenu = menuItem.getParent();
if (parentMenu != null && !parentMenu.isDisposed() && (parentMenu.getStyle() & SWT.NO_RADIO_GROUP) == 0) {
int index = 0;
MenuItem[] items = parentMenu.getItems();
while (index < items.length && items[index] != menuItem)
index++;
int lowBound = index - 1;
while (lowBound >= 0 && (items[lowBound].getStyle() & SWT.RADIO) != 0
&& !items[lowBound].isDisposed()) {
items[lowBound].setSelection(false);
--lowBound;
}
int upperBound = index + 1;
while (upperBound < items.length && (items[upperBound].getStyle() & SWT.RADIO) != 0
&& !items[upperBound].isDisposed()) {
items[upperBound].setSelection(false);
++upperBound;
}
}
if (!menuItem.isDisposed()) {
menuItem.setSelection(true);
events.sendEvent(menuItem, SWT.Selection);
}
}
// Other MenuItem
else {
boolean newSelection = menuItem.getSelection();
if ((menuItem.getStyle() & SWT.CHECK) != 0) {
newSelection = !menuItem.getSelection();
menuItem.setSelection(newSelection);
}
events.sendEvent(w, isDefault ? SWT.DefaultSelection : SWT.Selection);
if (!menuItem.isDisposed()) {
menuItem.setSelection(newSelection);
}
}
// -- simulate normal flow of events
if (menuItem.isDisposed())
return;
Menu parent = menuItem.getParent();
while (parent != null) {
if (parent.isDisposed())
return;
events.sendEvent(parent, SWT.Hide);
if (parent.isDisposed())
return;
parent = parent.getParentMenu();
}
}
private void hidePopupMenus(MenuItem menuItem) {
Menu parent = menuItem.getParent();
while (parent != null) {
List<WeakReference<Menu>> popupMenus = TeslaEventManager.getManager().getPopupMenus();
for (WeakReference<Menu> weakReference : popupMenus) {
Menu reffered = weakReference.get();
if (parent.equals(reffered)) {
popupMenus.remove(weakReference);
break;
}
}
parent = parent.getParentMenu();
}
}
private void failClick(final SWTUIElement w) {
setBackgroundColor(w, SWT.COLOR_RED);
makeScreenShot();
throw new RuntimeException(NLS.bind(TeslaSWTMessages.SWTUIPlayer_CannotClickOnDisabledControl, w.toString()));
}
private IWorkbenchPage getTargetPage() {
IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
if (page == null) {
IWorkbenchWindow window = PlatformUI.getWorkbench().getWorkbenchWindows()[0];
page = window.getActivePage();
if (page == null) {
page = window.getPages()[0];
}
}
return page;
}
private void clickView(final SWTUIElement w, IWorkbenchPage page) {
IViewReference view = (IViewReference) (((WorkbenchUIElement) w).reference);
IWorkbenchPart part = view.getPart(true);
if (part == null) {
return;
}
page.activate(part);
IWorkbenchPart activePart = page.getActivePart();
if (!part.equals(activePart)) {
throw new RuntimeException(NLS.bind(TeslaSWTMessages.SWTUIPlayer_WorkbenchPartNotActivated, w.toString()));
}
}
private void clickLink(final SWTUIElement w, boolean doubleClick, int mask) {
Widget widget = unwrapWidget(w);
if (widget.isDisposed()) {
return;
}
if (doubleClick) {
events.sendFocus(widget);
events.sendAll(widget, Events.createDoubleClick());
events.sendUnfocus(widget);
} else {
events.sendAll(widget,
new Event[] { createMouseDown(Events.DEFAULT_BUTTON, Events.SINGLE_COUNT, mask, 0, 0),
createSelection(false, mask), createMouseUp() });
}
}
private void clickEditor(final SWTUIElement w, IWorkbenchPage page) {
IEditorReference editor = (IEditorReference) (((WorkbenchUIElement) w).reference);
IWorkbenchPart editorPart = editor.getPart(true);
page.bringToTop(editorPart);
page.activate(editorPart);
}
private void clickTabItem(final SWTUIElement w, final boolean isDefault) {
Item rawItem = (Item) unwrapWidget(w);
Composite tabParent = TabCTabUtil.getParent(rawItem);
TabCTabUtil.setSelection(tabParent, rawItem);
Point pos = Bounds.centerAbs(TabCTabUtil.getBounds(rawItem));
events.sendAll(tabParent, rawItem, new Event[] { Events.createMouseDown(pos),
Events.createSelection(isDefault, Events.EMPTY_MASK),
Events.createMouseUp(pos) });
}
private void clickLabel(final SWTUIElement w, int stateMask) {
Widget widget = w.unwrap();
events.sendFocus(widget);
for (Event event : createClick(Events.DEFAULT_BUTTON, stateMask, centerRel(w.getBounds()).x,
centerRel(w.getBounds()).y)) {
events.sendEvent(w, event);
}
events.sendUnfocus(widget);
}
private void clickTableTreeItem(final SWTUIElement w, final boolean doubleClick) {
final int column = w instanceof ItemUIElement ? ((ItemUIElement) w).getColumn() : -1;
final Widget item = (Widget) unwrap(w);
final Widget itemParent = TableTreeUtil.getParent(item);
Viewers.selectItem(w, false);
final Point itemCenter = centerAbs(column >= 0 ? getItemBounds(item, column) : getItemBounds(item));
w.getPlayer().exec("click cell", new Runnable() {
@Override
public void run() {
if (doubleClick) {
getEvents().sendFocus(itemParent);
getEvents().sendAll(itemParent, Events.createDoubleClick(itemCenter));
getEvents().sendUnfocus(itemParent);
} else {
getEvents().sendEvent(itemParent, Events.createMouseDown(itemCenter));
getEvents().sendEvent(itemParent, Events.createMouseUp(itemCenter));
}
}
});
}
private static void checkCell(Item item, int column, boolean state) {
if (item instanceof TreeItem) {
Tree tree = ((TreeItem) item).getParent();
TreeViewer v = (TreeViewer) TeslaSWTAccess.getViewer(tree);
if (v == null)
throw new RuntimeException("No tree viewer.");
if (column < 0 || column >= tree.getColumnCount())
throw new RuntimeException("Invalid tree column index.");
TreeColumn c = tree.getColumn(column);
Object data = c.getData("org.eclipse.jface.columnViewer");
if (!(data instanceof ViewerColumn))
throw new RuntimeException("No tree column viewer.");
ViewerColumn cv = (ViewerColumn) data;
EditingSupport es = TeslaSWTAccess.getField(EditingSupport.class, cv, "editingSupport");
if (es == null)
throw new RuntimeException("No editing support for tree column viewer.");
Object value = TeslaSWTAccess.callMethod(EditingSupport.class, es, "getValue", new Class[] { Object.class },
item.getData());
if (!(value instanceof Boolean))
throw new RuntimeException("Does not look like a checkbox tree column.");
if ((Boolean) value == state)
return;
v.editElement(item.getData(), column);
} else if (item instanceof TableItem) {
Table table = ((TableItem) item).getParent();
TableViewer v = (TableViewer) TeslaSWTAccess.getViewer(table);
if (v == null)
throw new RuntimeException("No table viewer.");
if (column < 0 || column >= table.getColumnCount())
throw new RuntimeException("Invalid table column index.");
TableColumn c = table.getColumn(column);
Object data = c.getData("org.eclipse.jface.columnViewer");
if (!(data instanceof ViewerColumn))
throw new RuntimeException("No table column viewer.");
ViewerColumn cv = (ViewerColumn) data;
EditingSupport es = TeslaSWTAccess.getField(EditingSupport.class, cv, "editingSupport");
if (es == null)
throw new RuntimeException("No editing support for table column viewer.");
Object value = TeslaSWTAccess.callMethod(EditingSupport.class, es, "getValue", new Class[] { Object.class },
item.getData());
if (!(value instanceof Boolean))
throw new RuntimeException("Does not look like a checkbox table column.");
if ((Boolean) value == state)
return;
v.editElement(item.getData(), column);
}
}
public void check(final SWTUIElement w, final boolean state) {
Widget widget = unwrapWidget(w);
if (!widget.isDisposed()) {
if (w instanceof ItemUIElement && widget instanceof Item) {
checkCell((Item) widget, ((ItemUIElement) w).getColumn(), state);
} else if ((widget.getStyle() & SWT.CHECK) != 0) {
if (widget instanceof Button) {
if (((Button) widget).getSelection() != state) {
click(w);
}
} else if (widget instanceof MenuItem) {
if (((MenuItem) widget).getSelection() != state) {
click(w);
}
} else if (widget instanceof ToolItem) {
if (((ToolItem) widget).getSelection() != state) {
click(w);
}
}
}
}
}
/**
* Wraps an UI element (e.g. SWT widget, but not only them) into a
* convenient wrap to perform various actions on it with the wrap's methods.
* <p>
* The wrapping layer also serves as an unification of various kinds of UI
* elements.
* <p>
* The functionality of this method can be extended by
* {@link ISWTUIPlayerExtension#wrap(Object, SWTUIPlayer)} method.
*
* @see SWTUIElement
*/
public SWTUIElement wrap(Object s) {
for (ISWTUIPlayerExtension ext : getExtensions()) {
SWTUIElement result = ext.wrap(s, this);
if (result != null) {
return result;
}
}
//
if (s instanceof SWTUIElement) {
return (SWTUIElement) s;
}
if (s instanceof IWorkbenchPart) {
IWorkbenchPart part = (IWorkbenchPart) s;
IWorkbenchPartSite site = part.getSite();
if (site != null) {
// System.out.println("Site is not null");
IWorkbenchWindow window = site.getWorkbenchWindow();
IWorkbenchPage page = window.getActivePage();
if (page != null) {
IWorkbenchPartReference reference = page.getReference(part);
if (reference != null) {
return new WorkbenchUIElement(reference, this);
}
}
IWorkbenchPage[] pages = window.getPages();
for (IWorkbenchPage wp : pages) {
IWorkbenchPartReference ref = wp.getReference(part);
if (ref != null) {
return new WorkbenchUIElement(ref, this);
}
}
} else {
// System.out.println("Site is null");
}
// Obtain using initialization
IWorkbenchWindow[] windows = PlatformUI.getWorkbench().getWorkbenchWindows();
for (IWorkbenchWindow win : windows) {
IWorkbenchPage[] pages = win.getPages();
for (IWorkbenchPage wp : pages) {
IWorkbenchPartReference reference = wp.getReference(part);
if (reference != null) {
return new WorkbenchUIElement(reference, this);
}
}
}
// System.out.println("Failed to create wrap for item:"
// + part.getTitle());
}
if (s instanceof IWorkbenchPartReference) {
return new WorkbenchUIElement((IWorkbenchPartReference) s, this);
}
if (s instanceof Widget) {
return new SWTUIElement((Widget) s, this);
}
return null;
}
public final ChildrenCollector children = new ChildrenCollector(this);
Point getMousePos(Widget c) {
Point xy = new Point(0, 0);
Point point = widgetToMouseForMenus.get(c);
if (point != null) {
xy.x = point.x;
xy.y = point.y;
} else {
// Calculate correct position
if (c instanceof TabFolder) {
TabItem[] items = ((TabFolder) c).getSelection();
if (items.length > 0) {
Rectangle bounds = items[0].getBounds();
return new Point(bounds.x + bounds.width / 2, bounds.y + bounds.height / 2);
}
} else if (c instanceof CTabFolder) {
CTabItem selection = ((CTabFolder) c).getSelection();
if (selection != null) {
Rectangle bounds = selection.getBounds();
xy.x = bounds.x + bounds.width / 2;
xy.y = bounds.y + bounds.height / 2;
return new Point(bounds.x + bounds.width / 2, bounds.y + bounds.height / 2);
}
} else if (c instanceof Table) {
if (((Table) c).getItemCount() == 0) {
// Calculate center by x, and 1/10 from below
Rectangle bounds = ((Table) c).getBounds();
return new Point(bounds.width / 2, 9 * (bounds.height / 10));
}
} else if (c instanceof Tree) {
if (((Tree) c).getItemCount() == 0) {
// Calculate center by x, and 1/10 from below
Rectangle bounds = ((Tree) c).getBounds();
return new Point(bounds.width / 2, 9 * (bounds.height / 10));
}
}
}
return xy;
}
public UIColor getSystemColor(int color) {
return new SWTUIColor(display.getSystemColor(color));
}
public SWTUIElement selectMenu(PlayerSelectionFilter f) {
if (f.path == null) {
return null;
}
SWTUIElement currentParent = f.parent;
if (currentParent.getKind().is(ElementKind.Item)) {
// so that get-menu can be invoked in tree and table items
Widget unwrapped = unwrapWidget(currentParent);
if (unwrapped instanceof TreeItem || unwrapped instanceof TableItem) {
currentParent = getParentElement(currentParent);
}
} else if (currentParent.getKind().is(ElementKind.Button)) {
// support button drop-downs that are not children of Button itself
while (true) {
SWTUIElement[] children = this.children.collectFor(currentParent, ignoreWindows, false,
one(MenuItem.class), f.after);
if (children.length > 0)
break;
currentParent = getParentElement(currentParent);
if (currentParent == null) {
currentParent = f.parent;
break;
}
}
}
List<String> parts = Arrays.asList(f.path);
for (int i = 0, count = parts.size(); i < count; i++) {
String part = parts.get(i);
SWTUIElement[] children = this.children.collectFor(currentParent,
ignoreWindows, false, one(MenuItem.class), f.after);
boolean isLast = i == count - 1;
List<SWTUIElement> menuItems = findMenuItems(children, part, !isLast);
if (menuItems.isEmpty()) {
return null;
}
if (isLast && f.index != null) {
if (f.index < 0 || f.index >= menuItems.size()) {
return null;
}
currentParent = menuItems.get(f.index);
} else {
currentParent = menuItems.get(0);
}
}
return currentParent;
}
private List<SWTUIElement> findMenuItems(SWTUIElement[] items, String name, boolean returnFirstElement) {
List<SWTUIElement> result = new ArrayList<SWTUIElement>();
for (SWTUIElement uiElement : items) {
String elementName = getText(uiElement);
if (elementName == null) {
continue;
}
elementName = getMenuText(elementName);
if (elementName != null && (elementName.equals(name) || safeMatches(elementName, name))) {
// -- simulate normal flow of events
// disabled since probably it is not the best place to do
// such things, needs discussion
/*
* MenuItem menuItem = (MenuItem) unwrapWidget(uiElement);
* Menu menu = menuItem.getMenu();
* events.sendEvent(uiElement, SWT.Arm); if (menu != null) {
* events.sendEvent(menu, SWT.Show);
* menuItem.setSelection(true); events.sendEvent(menuItem,
* SWT.Selection); }
*/
// --
result.add(uiElement);
if (returnFirstElement) {
return result;
}
}
}
return result;
}
public UIColor getBackgroundColor(SWTUIElement uiElement) {
final Widget widget = unwrapWidget(uiElement);
if (widget instanceof Control) {
return new SWTUIColor(((Control) widget).getBackground());
}
return null;
}
public int countItems(SWTUIElement element, String[] selection) {
final Object widget = unwrap(element);
if (widget instanceof Tree) {
return Viewers.countTreeItemChildren(element, selection);
} else if (widget instanceof Table) {
return ((Table) widget).getItemCount();
} else if (widget instanceof org.eclipse.swt.widgets.List) {
return ((org.eclipse.swt.widgets.List) widget).getItemCount();
} else if (widget instanceof TabFolder) {
return ((TabFolder) widget).getItemCount();
} else if (widget instanceof CTabFolder) {
return ((CTabFolder) widget).getItemCount();
}
// TODO other controls?
return 0;
}
public void setBackgroundColor(final SWTUIElement uiElement, final int color) {
setBackgroundColor(uiElement, new SWTUIColor(display.getSystemColor(color)));
}
public void setBackgroundColor(SWTUIElement uiElement, final UIColor color) {
final Widget widget = unwrapWidget(uiElement);
if (widget instanceof Control && !widget.isDisposed()) {
exec("setBackground", new Runnable() {
@Override
public void run() {
if (!widget.isDisposed()) {
((Control) widget).setBackground(((SWTUIColor) color).getColor());
}
}
});
}
}
public void setDateTime(final SWTUIElement uiElement, final int year, final int month, final int day,
final int hours, final int minutes, final int second) {
final Widget widget = unwrapWidget(uiElement);
exec("setDateTime", new Runnable() {
@Override
public void run() {
if (widget.isDisposed()) {
return;
}
if (widget instanceof DateTime) {
DateTime dt = (DateTime) widget;
events.sendFocus(widget);
dt.setDate(year, month - 1, day);
dt.setTime(hours, minutes, second);
events.sendEvent(uiElement, SWT.Selection);
events.sendUnfocus(widget);
}
}
});
}
public void setText(final SWTUIElement uiElement, final String text) {
setText(uiElement, text, false);
}
public static final int COMBO_ITEM_NOT_FOUND = -1;
public static int findComboItem(String[] items, String item, boolean select) {
for (int i = 0; i < items.length; ++i)
if (items[i].equals(item))
return i;
if (!select)
return COMBO_ITEM_NOT_FOUND;
for (int i = 0; i < items.length; ++i)
if (safeMatches(items[i], item))
return i;
item = item.toLowerCase();
String[] lowerItems = new String[items.length];
for (int i = 0; i < items.length; ++i)
lowerItems[i] = items[i].toLowerCase();
for (int i = 0; i < items.length; ++i)
if (lowerItems[i].equals(item))
return i;
for (int i = 0; i < items.length; ++i)
if (safeMatches(lowerItems[i], item))
return i;
return COMBO_ITEM_NOT_FOUND;
}
public void setText(final SWTUIElement uiElement, final String text, final boolean select) {
final Widget widget = unwrapWidget(uiElement);
exec("setText", new Runnable() {
@Override
public void run() {
if (widget.isDisposed()) {
return;
}
if (widget instanceof Text) {
Text textElement = (Text) widget;
events.sendFocus(widget);
textElement.setText(text);
events.sendEvent(uiElement, SWT.Verify);
events.sendEvent(uiElement, SWT.Modify);
events.sendUnfocus(widget);
}
if (widget instanceof Spinner) {
events.sendFocus(widget);
int Val = (int) (Double.parseDouble(text) * Math.pow(10, ((Spinner) widget).getDigits()));
((Spinner) widget).setSelection(Val);
events.sendEvent(uiElement, SWT.Modify);
events.sendUnfocus(widget);
}
if (widget instanceof Slider) {
events.sendFocus(widget);
int Val = Integer.parseInt(text);
((Slider) widget).setSelection(Val);
events.sendEvent(uiElement, SWT.Modify);
events.sendEvent(uiElement, SWT.Selection);
events.sendUnfocus(widget);
}
if (widget instanceof StyledText) {
events.sendFocus(widget);
((StyledText) widget).setText(text);
if (widget instanceof StyledText) {
StyledText tt = (StyledText) widget;
int offset = tt.getCaretOffset();
String allText = tt.getText();
tt.setText(allText);
tt.setCaretOffset(offset);
}
events.sendUnfocus(widget);
}
if (widget instanceof Combo) {
Combo combo = (Combo) widget;
events.sendFocus(widget);
int itemIndex = findComboItem(combo.getItems(), text, select);
if (!select)
combo.setText(text);
if (itemIndex != COMBO_ITEM_NOT_FOUND)
combo.select(itemIndex);
events.sendEvent(uiElement, SWT.Modify);
events.sendEvent(uiElement, SWT.Selection);
events.sendUnfocus(widget);
}
if (widget instanceof CCombo) {
CCombo combo = (CCombo) widget;
events.sendFocus(widget);
int itemIndex = findComboItem(combo.getItems(), text, select);
if (!select)
combo.setText(text);
if (itemIndex != COMBO_ITEM_NOT_FOUND)
combo.select(itemIndex);
events.sendEvent(uiElement, SWT.Modify);
events.sendEvent(uiElement, SWT.Selection);
events.sendUnfocus(widget);
}
if (widget instanceof Browser) {
Browser browser = (Browser) widget;
events.sendFocus(widget);
browser.setText(text);
events.sendEvent(uiElement, SWT.Verify);
events.sendEvent(uiElement, SWT.Modify);
events.sendUnfocus(widget);
}
}
});
}
protected boolean checkContainsControl(Control control, Combo combo) {
return false;
}
public void show(SWTUIElement uiElement, int x, int y) {
Menu menu = (Menu) uiElement.unwrap();
Point pos = new Point(x, y);
if (pos.x == -1 && pos.y == -1) {
pos = getMousePos(menu);
}
if ((menu.getStyle() & SWT.BAR) == 0) { // Not a menu bar
synchronized (shownMenus) {
shownMenus.add(new WeakReference<Menu>(menu));
}
}
events.sendEvent(uiElement, SWT.Show, pos.x, pos.y, 0);
}
public boolean isDisposed(SWTUIElement uiElement) {
Widget widget = unwrapWidget(uiElement);
return widget == null || widget.isDisposed();
}
protected static void checkIntegrity(Class<?>[] classes) {
for (int i = 0; i < classes.length; i++) {
for (int j = i + 1; j < classes.length; j++) {
Class<?> ci = classes[i];
Class<?> cj = classes[j];
if (ci.isAssignableFrom(cj)) {
System.out.println(String.format("Achtung! %s should be after %s", ci.getName(), cj.getName()));
}
}
}
}
public static Class<?> getSearchableClass(Object widget) {
ElementKind kind = elementKinds.get(widget.getClass());
if (kind == null) {
// Try to find superclass for custom widget in extensions
for (ISWTUIPlayerExtension extension : getExtensions()) {
Class<?> searchableClass = extension.getSearchableClass(widget);
if (searchableClass != null) {
return searchableClass;
}
}
// Try to find superclass for custom widget in "default" elements
for (Map.Entry<Class<?>, ElementKind> entry : elementKinds.entrySet()) {
Class<?> key = entry.getKey();
if (key.isInstance(widget)) {
return key;
}
}
}
return widget.getClass();
}
public static GenericElementKind getKind(Object w) {
if (w == null)
return GenericElementKind.Unknown;
for (ISWTUIPlayerExtension extension : getExtensions()) {
GenericElementKind kind = extension.getKind(w);
if (kind != null) {
return kind;
}
}
ElementKind kind = elementKinds.get(w.getClass());
if (kind == null) {
for (Map.Entry<Class<?>, ElementKind> entry : elementKinds.entrySet()) {
Class<?> key = entry.getKey();
if (key.isInstance(w)) {
return new GenericElementKind(entry.getValue());
}
}
}
if (kind != null) {
return new GenericElementKind(kind);
}
return GenericElementKind.Unknown;
}
public void close(final SWTUIElement uiElement) {
exec("close", new Runnable() {
@Override
public void run() {
if (uiElement instanceof WorkbenchUIElement) {
IWorkbenchPartReference reference = ((WorkbenchUIElement) uiElement).getReference();
if (reference == null) {
return;
}
IWorkbenchPart part = reference.getPart(false);
if (part != null) {
IWorkbenchPage page = part.getSite().getPage();
if (part instanceof IEditorPart) {
page.closeEditor((IEditorPart) part, true);
} else if (part instanceof IViewPart) {
IViewPart vp = (IViewPart) part;
page.hideView(vp);
// hideView already call dispose for ViewPart
// vp.dispose();
}
}
} else {
Widget widget = unwrapWidget(uiElement);
if (widget instanceof CTabItem) {
CTabItem item = (CTabItem) widget;
Rectangle rect = TeslaSWTAccess.getCTabItemCloseRect(item);
if (rect != null && rect.width > 0 && rect.height > 0) {
events.sendEvent(item.getParent(), SWT.MouseDown, rect.x + 1, +rect.y + 1, 1);
events.sendEvent(item.getParent(), SWT.MouseUp, rect.x + 1, rect.y + 1, 1);
}
} else if (widget instanceof Shell) {
getEvents().sendEvent(widget, SWT.Deactivate);
((Shell) widget).close();
} else {
Event e = events.sendEvent(uiElement, SWT.Close);
if (e != null && e.doit) {
if (widget != null && !widget.isDisposed()) {
widget.dispose();
}
}
}
}
}
});
}
public List<File> getScreenshots() {
if (screenshotsDuringSession != null) {
return new ArrayList<File>(screenshotsDuringSession);
}
return new ArrayList<File>();
}
/**
* NOTE: check that used widgets are not disposed. See
* {@link Display#asyncExec(Runnable)} for details.
*/
public void exec(final String msg, final Runnable runnable) {
final Exception e = new Exception();
StackTraceElement stackTraceElement = e.getStackTrace()[1];
final String errorMethod = stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName() + ":"
+ stackTraceElement.getLineNumber();
final Context currentContext = context;
Runnable myr = new ExecRunnable(msg, currentContext, runnable, errorMethod);
if (context != null) {
synchronized (runnables) {
List<Runnable> runs = runnables.get(context);
if (runs == null) {
runs = new ArrayList<Runnable>();
runnables.put(context, runs);
}
runs.add(myr);
}
}
display.asyncExec(myr);
display.wake();
// runnable.run();
}
public boolean canProceed(Context context, Q7WaitInfoRoot info) {
if (!display.equals(Display.getCurrent())) {
// Q7WaitUtils.updateInfo("display", "non current", info);
debugProceed("Wrong display");
return false;
}
// Return false if we have SWT observable in timers
if (hasTimers(display, info)) {
debugProceed("Timers active");
return false;
}
// Check for asyncs in synchronizer
if (!TeslaEventManager.getManager().isNoWaitForJob() && hasRunnables(display)) {
// Q7WaitUtils.updateInfo("display", "runnables", info);
debugProceed("Display has runnables");
return false;
}
if (!BrowserManager.getInstance().isExecutionAllowed(info)) {
debugProceed("Browser active");
return false;
}
synchronized (runnables) {
this.context = context;
List<Runnable> runs = runnables.get(context);
if (runs != null && !runs.isEmpty()) {
debugProceed("Previous tsk is still pending");
return false;
}
if (!TeslaEventManager.getManager().isNoWaitForJob() && !collector.isEmpty(context, info)) {
debugProceed("There are active jobs");
return false;
}
}
debugProceed("Can proceed");
return true;
}
public static boolean hasRunnables(Display display) {
Synchronizer synchronizer = display.getSynchronizer();
if (TeslaSWTAccess.getRunnables(synchronizer) > 0) {
return true;
}
return false;
}
private static long lastTimersSucess = 0;
private static long lastTimeSucessStep = 0;
public static boolean hasTimers(Display display, Q7WaitInfoRoot infoRoot) {
Runnable[] timers = TeslaSWTAccess.getTimers(display);
List<TimerInfo> map = TeslaTimerExecManager.getManager().getTimers();
List<TimerInfo> waitFor = new ArrayList<TimerInfo>();
for (Runnable runnable : timers) {
if (runnable instanceof SherlockTimerRunnable) {
runnable = ((SherlockTimerRunnable) runnable).getRunnable();
}
TimerInfo current = null;
for (TimerInfo t : map) {
if (t.hasRunnable(runnable)) {
current = t;
break;
}
}
if (current == null) {
continue;
}
Class<? extends Runnable> cl = runnable.getClass();
String clName = cl.getName();
// Return true if some of delayed observables are pressent.
if (clName.startsWith("org.eclipse.core.internal.databinding.observable.DelayedObservableValue")) {
waitFor.add(current);
break;
}
if (clName.contains("org.eclipse.jface")) { // Wait
/*
* for all jface timer execs
*/
waitFor.add(current);
break;
}
if (isTimerIgnored(clName)) {
continue;
}
if (TeslaLimits.getTimerExecsWait() > 0) {
// Check if runnable in timers list and timeout is less then job
// timeout
boolean add = false;
for (TimerInfo info : map) {
if (info.hasRunnable(runnable)) {
if (info.time < TeslaLimits.getTimerExecsWait()) {
if ((System.currentTimeMillis() - info.firstSheduleTime) > TeslaLimits.getTimerExecsSkip()
&& info.resheduleCounter > 0) {
// Skip this runnable, since it rescheduling
// itself to much.
// System.out.println("Skip TimerExec:" +
// info.getRunnable().getClass().getName());
printTimers(map);
continue;
}
add = true;
break;
}
}
}
if (add) {
waitFor.add(current);
}
}
}
if (waitFor.size() > 0 && lastTimersSucess != 0) {
if ((System.currentTimeMillis() - lastTimersSucess) > TeslaLimits.getTimerExecsTotalWaitTime()) {
// Enable timers step mode.
if (lastTimeSucessStep == 0) {
lastTimeSucessStep = System.currentTimeMillis();
printTimers(waitFor);
return false; // Do a step mode.
} else {
if ((System.currentTimeMillis() - lastTimeSucessStep) > TeslaLimits
.getTimerExecsTotalWaitTimeStep()) {
lastTimeSucessStep = System.currentTimeMillis();
printTimers(waitFor);
return false;// Do a step mode.
}
}
}
}
if (waitFor.size() > 0) {
for (TimerInfo timerInfo : waitFor) {
String timerClassName = timerInfo.getRunnable().getClass().getName();
synchronized (infoRoot) {
if (timerInfo.execQualifier != null) {
infoRoot.getInnerClassMap().put(timerClassName, timerInfo.execQualifier);
}
}
Q7WaitUtils.updateInfo("timer", timerClassName, infoRoot);
}
return true;
}
lastTimersSucess = System.currentTimeMillis();
lastTimeSucessStep = 0;
return false;
}
public static boolean isTimerIgnored(String clName) {
return TeslaTimerExecManager.isTimerIgnored(clName);
}
private static void printTimers(List<TimerInfo> map) {
// StringBuilder bb = new StringBuilder();
// bb.append("\n<<<<<<---- Timer execs:\n");
// for (TimerInfo timer : map) {
// bb.append(timer.getRunnable().getClass().getName())
// .append(" delay: ")
// .append(timer.time)
// .append(" scheduled for time: " + (System.currentTimeMillis() -
// timer.firstSheduleTime)
// + " reshedules: " + timer.resheduleCounter)
// .append("\n");
// }
// String msg =
// "---->>> TimerExec Waiting timeout exceed then execute: "
// + ReportManager.getBuilder().getCurrentNode()
// .getName() + bb.toString() + " <<---\n(stepping)";
// System.err.println(msg);
// SWTTeslaActivator
// .log(msg);
}
public static String toSelectionItem(String toPattern) {
if (toPattern != null) {
toPattern = toPattern.replaceAll("\\+", "\\\\+");
toPattern = toPattern.replaceAll("\\(", "\\\\(");
toPattern = toPattern.replaceAll("\\)", "\\\\)");
toPattern = toPattern.replaceAll("\\[", "\\\\[");
toPattern = toPattern.replaceAll("\\]", "\\\\]");
toPattern = toPattern.replaceAll("\\*", "\\\\*");
}
return toPattern;
}
public static String buildPathFragment(String text, int index) {
return String.format("%s%%%d%%", toSelectionItem(text).replaceAll("/", "\\\\/"), index);
}
public static String buildPathFragment(String text) {
return toSelectionItem(text).replaceAll("/", "\\\\/");
}
public void setIgnores(Shell... ignoreWindows) {
if (ignoreWindows != null) {
this.ignoreWindows = new SWTUIElement[ignoreWindows.length];
this.ignoredShells = ignoreWindows;
int i = 0;
for (Shell shell : ignoreWindows) {
this.ignoreWindows[i++] = wrap(shell);
}
}
}
public void typeText(final SWTUIElement element, final String text, final int mask, final boolean fromDisplay) {
exec("typeText", new Runnable() {
@Override
public void run() {
switch (element.getKind().kind) {
default:
Widget widget = unwrapWidget(element);
if (!(widget instanceof Control))
break;
Control ctrl = (Control) widget;
if (fromDisplay) {
// Necessary for setting focus to control
try {
ShellUtilsProvider.getShellUtils().forceActive(ctrl.getShell());
} catch (CoreException e) {
throw new RuntimeException(e);
}
}
events.sendFocus(widget);
if (ctrl instanceof CCombo) {
CCombo combo = (CCombo) widget;
Text tW = getCComboText(combo);
events.sendFocus(tW);
tW.insert(text);
events.sendEvent(wrap(tW), SWT.Modify);
events.sendEvent(wrap(tW), SWT.Deactivate);
} else if (ctrl instanceof Text) {
Text tW = (Text) ctrl;
events.sendFocus(tW);
tW.insert(text);
type(element, 0, SWT.SHIFT, false, '\u0000', 1); // fake
events.sendEvent(wrap(tW), SWT.Modify);
events.sendEvent(wrap(tW), SWT.Deactivate);
} else {
sendKeysToWidget(text, mask, fromDisplay, widget);
events.sendEvent(wrap(widget), SWT.Deactivate);
}
break;
}
}
private void sendKeysToWidget(final String text, final int mask, final boolean fromDisplay, Widget widget) {
SWTUIElement element = wrap(widget);
if (!widget.isDisposed()) {
for (char ch : text.toCharArray()) {
updateStyledTextPos(widget);
List<KeyStroke> keys = keyboard.splitToKeys(KeyStroke.getInstance(mask, KeyStroke.NO_KEY));
if (fromDisplay) {
keys.add(SWTKeyboardLayout.getKeyboardLayout().keyStrokeFor(ch));
} else {
if (Character.isUpperCase(ch)) {
ch = Character.toLowerCase(ch);
keys.add(KeyStroke.getInstance(SWT.SHIFT, ch));
} else
keys.add(KeyStroke.getInstance(ch));
}
keyboard.typeKeys(widget, fromDisplay, keys.toArray(new KeyStroke[0]));
// For StyledText, modifyContent method will be called
// after MouseDown event and send correct
// Verify and Modify events
if (widget instanceof Text || widget instanceof Combo || widget instanceof CCombo) {
String textValue = getRawText(element);
Event ee = events.createEvent(element);
ee.start = 0;
ee.end = textValue.length();
ee.text = textValue;
ee.type = SWT.Verify;
events.sendEvent(element, ee);
events.sendEvent(element, SWT.Modify);
}
}
}
}
});
}
public void traverse(final SWTUIElement element, final int code, final char character, final int times) {
exec("traverse", new Runnable() {
@Override
public void run() {
Widget widget = unwrapWidget(element);
if (!(widget instanceof Control))
return;
for (int i = 0; i < times; i++) {
Control control = (Control) widget;
boolean traverseResult = false;
boolean isShellProcessed = false;
// send traverse event to control and ancestors up to Shell
// while the traversal succeeded
while (!traverseResult && !isShellProcessed && control != null) {
if (!control.isDisposed()) {
Event ee = new Event();
if (code == SWT.TRAVERSE_TAB_NEXT) {
ee.keyCode = SWT.TAB;
ee.stateMask = 0;
} else if (code == SWT.TRAVERSE_TAB_PREVIOUS) {
ee.keyCode = SWT.TAB;
ee.stateMask = SWT.SHIFT;
}
ee.widget = control;
ee.time = (int) System.currentTimeMillis();
ee.doit = true;
ee.detail = code;
try {
traverseResult = control.traverse(code, ee);
} catch (Exception e) {
// In case of invalid method
try {
Method method = Control.class.getDeclaredMethod("traverse", Event.class);
method.setAccessible(true);
method.invoke(control, ee);
} catch (Exception e1) {
traverseResult = control.traverse(code);
}
}
// method traverse(int, Event) since eclipse 3.6
// traverseResult = control.traverse(code,
// traverseEvent);
}
isShellProcessed = control instanceof Shell;
if (!control.isDisposed()) {
control = control.getParent();
} else {
control = null;
}
}
}
}
});
}
// * The field is set from
// org.eclipse.rcptt.tesla.workbench.aspects.WorkbenchAspect.
//
// * The field located here to break dependency loop
// with org.eclipse.rcptt.tesla.workbench.aspects.
//
// * There is only one Workbench per Eclipse instance,
// so for now that is pretty OK to have static field.
public static volatile Boolean lastWorkbenchKeyboardPressResult;
public void type(final SWTUIElement element, final int code, final int mask, final boolean fromDisplay,
final char character, final int times) {
exec("type", new Runnable() {
@Override
public void run() {
switch (element.getKind().kind) {
default:
Widget widget = unwrapWidget(element);
if (!(widget instanceof Control))
break;
if (fromDisplay) {
// Necessary for setting focus to control
try {
ShellUtilsProvider.getShellUtils().forceActive(((Control) widget).getShell());
} catch (CoreException e) {
throw new RuntimeException(e);
}
}
events.sendFocus(widget);
lastWorkbenchKeyboardPressResult = null;
boolean doModify = false;
if (widget instanceof CCombo) {
CCombo combo = (CCombo) widget;
Text text = getCComboText(combo);
for (int i = 0; i < times; i++) {
sendKeyEvent(code, mask, fromDisplay, character, text);
}
} else {
for (int i = 0; i < times; i++) {
sendKeyEvent(code, mask, fromDisplay, character, widget);
doModify |= lastWorkbenchKeyboardPressResult != null && !lastWorkbenchKeyboardPressResult;
}
}
if (widget instanceof Text) {
if (doModify)
events.sendEvent(element, SWT.Modify);
if (code == 13 && mask == 0)
events.sendEvent(element, SWT.DefaultSelection);
}
// events.sendEvent(element, SWT.Deactivate);
// events.sendEvent(element, SWT.FocusOut);
break;
}
}
private void sendKeyEvent(final int code, final int mask, final boolean fromDisplay, final char character,
Widget widget) {
if (widget.isDisposed())
return;
if (fromDisplay) {
KeyStroke[] keys = new KeyStroke[] { KeyStroke.getInstance(mask, code) };
keyboard.typeKeys(widget, fromDisplay, keys);
} else {
Event createEvent = keyboard.createEvent(code, mask, character);
createEvent.widget = widget;
updateStyledTextPos(widget);
events.sendEventRaw(SWT.KeyDown, createEvent);
if (widget.isDisposed())
return;
events.sendEventRaw(SWT.KeyUp, createEvent);
}
}
});
}
public void typeAction(final SWTUIElement element, final String actionId) {
exec("typeAction", new Runnable() {
@Override
public void run() {
@SuppressWarnings("cast") // IServiceLocator.getService was not
// generic in Eclipse 4.4 and older.
IHandlerService handlerService = (IHandlerService) PlatformUI.getWorkbench()
.getService(IHandlerService.class);
try {
handlerService.executeCommand(actionId, null);
} catch (Exception e) {
TeslaCore.log(e);
}
}
});
}
protected Text getCComboText(CCombo combo) {
return TeslaSWTAccess.getCComboText(combo);
}
public void clickAndWait(SWTUIElement w) {
click(w);
}
private void shutdown() {
Job.getJobManager().removeJobChangeListener(collector);
BrowserManager.getInstance().clear();
TeslaTimerExecManager.getManager().removeEventListener(timerListener);
}
public void waitFinish() {
// TODO Auto-generated method stub
}
public void save(final SWTUIElement w) {
exec("save", new Runnable() {
@Override
public void run() {
if (w.getKind().kind == ElementKind.Editor) {
IEditorReference editor = (IEditorReference) (((WorkbenchUIElement) w).reference);
IEditorPart editorPart = editor.getEditor(false);
if (editorPart != null) {
editorPart.doSave(new NullProgressMonitor());
}
}
}
});
}
public boolean isDirty(final SWTUIElement w) {
if (w.getKind().kind == ElementKind.Editor) {
IEditorReference editor = (IEditorReference) (((WorkbenchUIElement) w).reference);
return editor.isDirty();
}
return false;
}
private static Widget parentFromExtension(Widget current) {
for (ISWTUIPlayerExtension ext : getExtensions()) {
Widget result = ext.getIndirectParent(current);
if (result != null) {
return result;
}
}
return null;
}
public static List<Widget> collectParents(Widget widget, Map<Control, SWTUIElement> references, Widget... stopAt) {
List<Widget> parents = new ArrayList<Widget>();
if (widget == null || widget.isDisposed()) {
return parents;
}
Widget current = widget;
Widget prev = null;
while (current != null) {
prev = current;
Widget indirectParent = parentFromExtension(current);
if (indirectParent != null) {
current = indirectParent;
} else if (current instanceof Control) {
if (current instanceof ToolBar) {
/*
* Check work view/editor toolbars, they have different
* parent
*/
if (references != null && references.containsKey(current)) {
current = references.get(current).unwrap();
} else {
current = ((Control) current).getParent();
}
} else {
current = ((Control) current).getParent();
}
} else if (current instanceof TreeItem) {
current = ((TreeItem) current).getParent();
} else if (current instanceof TableItem) {
current = ((TableItem) current).getParent();
} else if (current instanceof MenuItem) {
current = ((MenuItem) current).getParent();
} else if (current instanceof ToolItem) {
current = ((ToolItem) current).getParent();
} else if (current instanceof Menu) {
Menu parentMenu = ((Menu) current).getParentMenu();
if (parentMenu == null) {
current = ((Menu) current).getParent();
} else {
current = parentMenu;
}
} else if (current instanceof ScrollBar) {
current = ((ScrollBar) current).getParent();
} else if (current instanceof ToolTip) {
current = ((ToolTip) current).getParent();
} else {
current = null;
}
if (current != null) {
if (current instanceof CoolBar) {
CoolBar bar = (CoolBar) current;
CoolItem[] items = bar.getItems();
for (CoolItem coolItem : items) {
if (coolItem != null) {
Control control = coolItem.getControl();
if (control != null && control.equals(prev)) {
parents.add(coolItem);
}
}
}
}
if (stopAt != null) {
boolean breakRequired = false;
for (Widget w : stopAt) {
if (w.equals(current)) {
breakRequired = true;
break;
}
}
if (breakRequired) {
break;
}
}
parents.add(current);
}
}
return parents;
}
public String getSelectedTabItem(SWTUIElement swtuiElement) {
Widget w = unwrapWidget(swtuiElement);
if (w instanceof CTabFolder) {
CTabFolder tf = (CTabFolder) w;
CTabItem item = tf.getSelection();
return item.getText();
} else if (w instanceof TabFolder) {
TabFolder tf = (TabFolder) w;
TabItem[] selection = tf.getSelection();
if (selection.length > 0) {
return selection[0].getText();
}
}
return null;
}
public static boolean isVisible(SWTUIElement swtuiElement) {
Widget widget = unwrapWidget(swtuiElement);
if (widget instanceof Control) {
return ((Control) widget).isVisible();
}
return true;
}
public static SWTUIElement getShell(SWTUIElement element) {
for (ISWTUIPlayerExtension ext : getExtensions()) {
SWTUIElement result = ext.getShell(element);
if (result != null) {
return result;
}
}
//
Widget widget = unwrapWidget(element);
// PartPane.control == null after disposal in case of WorkbenchUIElement
if (widget == null || widget.isDisposed()) {
return null;
}
SWTUIPlayer player = element.getPlayer();
if (widget instanceof Control) {
return player.wrap(((Control) widget).getShell());
} else if (widget instanceof MenuItem) {
return player.wrap(((MenuItem) widget).getParent().getShell());
} else if (widget instanceof ToolItem) {
return player.wrap(((ToolItem) widget).getParent().getShell());
} else if (widget instanceof TreeItem) {
return player.wrap(((TreeItem) widget).getParent().getShell());
} else if (widget instanceof TableItem) {
return player.wrap(((TableItem) widget).getParent().getShell());
} else if (widget instanceof CTabItem) {
return player.wrap(((CTabItem) widget).getParent().getShell());
} else if (widget instanceof CoolItem) {
return player.wrap(((CoolItem) widget).getParent().getShell());
} else if (widget instanceof TabItem) {
return player.wrap(((TabItem) widget).getParent().getShell());
} else if (widget instanceof TreeColumn) {
return player.wrap(((TreeColumn) widget).getParent().getShell());
} else if (widget instanceof TableColumn) {
return player.wrap(((TableColumn) widget).getParent().getShell());
} else if (widget instanceof Item) {
return player.wrap(((Item) widget).getDisplay().getActiveShell());
} else if (widget instanceof ScrollBar) {
return player.wrap(((ScrollBar) widget).getParent().getShell());
}
return null;
}
public void addMouseWidgetInfo(final Widget canvas, int x, int y) {
TeslaEventManager.getManager().setLastWidget(canvas, x, y);
widgetToMouseForMenus.put(canvas, new Point(x, y));
canvas.addDisposeListener(new DisposeListener() {
@Override
public void widgetDisposed(DisposeEvent e) {
widgetToMouseForMenus.remove(canvas);
try {
canvas.removeDisposeListener(this);
} catch (Throwable e2) {
}
}
});
}
public SWTEvents getEvents() {
return events;
}
public List<SWTUIElement> getParentsList(SWTUIElement swtuiElement) {
Map<Control, SWTUIElement> references = EclipseWorkbenchProvider.getProvider().getWorkbenchReference(this);
List<Widget> parents = collectParents(unwrapWidget(swtuiElement), references);
List<SWTUIElement> elements = new ArrayList<SWTUIElement>();
for (Widget widget : parents) {
SWTUIElement e = null;
if (references.containsKey(widget)) {
e = references.get(widget);
} else {
e = wrap(widget);
}
if (e != null) {
GenericElementKind kind = e.getKind();
if (kind.is(ElementKind.Any) || kind.is(ElementKind.Unknown) || kind.is(ElementKind.Toolbar)
|| kind.is(ElementKind.CoolBar) || kind.is(ElementKind.CBanner)
|| kind.is(ElementKind.TabFolder) || kind.is(ElementKind.Canvas)
|| kind.is(ElementKind.Combo)) {
continue;
}
if (isVisible(e))
elements.add(e);
}
}
return elements;
}
public UIJobCollector getCollector() {
return collector;
}
public SWTUIElement getParentElement(SWTUIElement uiElement) {
List<SWTUIElement> parentsList = getParentsList(uiElement);
if (parentsList.size() > 0) {
return parentsList.get(0);
}
return null;
}
public BrowserManager getBrowserManager() {
return BrowserManager.getInstance();
}
private void updateStyledTextPos(Widget widget) {
if (widget instanceof StyledText) {
// Update viewers based on textViewer about styled
// text position. So popups will not be hided on
// update
StyledText t = (StyledText) widget;
int topPixel = t.getTopPixel();
Viewer viewer = TeslaSWTAccess.getViewer(t);
if (viewer != null) {
JFaceTextSupport.setLastPixels(viewer, topPixel);
}
}
}
public static byte[] captureControlImage(Control ctrl, Rectangle subImageBounds) {
// selectionShell.setVisible(false);
// Rectangle selBounds = selectionShell.getBounds();
Image image = captureControlImageRaw(ctrl, subImageBounds);
ImageData data = image.getImageData();
ImageLoader loader = new ImageLoader();
loader.data = new ImageData[] { data };
ByteArrayOutputStream stream = new ByteArrayOutputStream();
loader.save(stream, SWT.IMAGE_PNG);
image.dispose();
return stream.toByteArray();
}
public static Image captureControlImageRaw(Control ctrl, Rectangle subImageBounds) {
ctrl.getShell().setActive();
if (ctrl instanceof Label) {
Image image = ((Label) ctrl).getImage();
if (image != null) {
return new Image(image.getDevice(), image, SWT.IMAGE_COPY);
}
}
GC gc = new GC(ctrl);
final Rectangle bounds = ctrl.getBounds();
Image image = null;
if (!bounds.equals(subImageBounds)) {
image = new Image(ctrl.getDisplay(), subImageBounds.width, subImageBounds.height);
gc.copyArea(image, subImageBounds.x, subImageBounds.y);
gc.dispose();
} else {
image = new Image(ctrl.getDisplay(), bounds.width, bounds.height);
gc.copyArea(image, 0, 0);
ScreenshotSupport.saveImage(image.getImageData(), "");
gc.dispose();
}
return image;
}
public static Image copyImagePart(Image img, Rectangle subImageBounds) {
GC gc = new GC(img);
final Rectangle bounds = img.getBounds();
Image image = null;
if (!bounds.equals(subImageBounds)) {
image = new Image(img.getDevice(), subImageBounds.width, subImageBounds.height);
gc.copyArea(image, subImageBounds.x, subImageBounds.y);
gc.dispose();
} else {
gc.dispose();
image = img;
}
ScreenshotSupport.saveImage(image.getImageData(), "copy_img");
return image;
}
public static byte[] captureControlImage(Image img) {
ImageData data = img.getImageData();
ImageLoader loader = new ImageLoader();
loader.data = new ImageData[] { data };
ByteArrayOutputStream stream = new ByteArrayOutputStream();
loader.save(stream, SWT.IMAGE_PNG);
img.dispose();
return stream.toByteArray();
}
public static Image prepateImageForOCR(byte[] image, int x, int y, int width, int height) {
Display display = PlatformUI.getWorkbench().getDisplay();
Image img = new Image(display, new ByteArrayInputStream(image));
ScreenshotSupport.saveImage(img.getImageData(), "ocr");
Image scaled = prepareImageForOCR(x, y, width, height, img);
ScreenshotSupport.saveImage(scaled.getImageData(), "ocr_scaled");
img.dispose();
return scaled;
}
public static Image prepareImageForOCR(int x, int y, int width, int height, Image img) {
int mult = 2;
Image scaled = new Image(img.getDevice(), width * mult, height * mult);
GC gc = new GC(scaled);
gc.drawImage(img, x, y, width, height, 0, 0, width * mult, height * mult);
ScreenshotSupport.saveImage(scaled.getImageData(), "ocr_part");
gc.dispose();
return scaled;
}
public static void disableMessageDialogs() {
SWTDialogManager.setCancelMessageBoxesDisplay(true);
}
public static void enableMessageDialogs() {
SWTDialogManager.setCancelMessageBoxesDisplay(false);
}
public synchronized static SWTUIPlayer getPlayer(Display display) {
SWTUIPlayer p = players.get(display);
if (p == null) {
p = new SWTUIPlayer(display);
players.put(display, p);
}
return p;
}
public synchronized static SWTUIPlayer getPlayer() {
return SWTUIPlayer.getPlayer(PlatformUI.getWorkbench().getDisplay());
}
public synchronized static void shutdown(SWTUIPlayer internalPlayer) {
if (internalPlayer != null) {
players.remove(internalPlayer.getDisplay());
internalPlayer.shutdown();
}
}
public Display getDisplay() {
return display;
}
public void minimize(SWTUIElement uiElement) {
final Widget widget = unwrapWidget(uiElement);
exec("minimize", new Runnable() {
@Override
public void run() {
processTabFolderButton(widget, IWorkbenchPage.STATE_MINIMIZED);
}
});
}
public void maximize(SWTUIElement uiElement) {
final Widget widget = unwrapWidget(uiElement);
exec("maximize", new Runnable() {
@Override
public void run() {
if (widget instanceof Shell) {
((Shell) widget).setMaximized(true);
try {
ShellUtilsProvider.getShellUtils().forceActive((Shell) widget);
} catch (CoreException e) {
throw new RuntimeException(e);
}
}
processTabFolderButton(widget, IWorkbenchPage.STATE_MAXIMIZED);
}
});
}
public void restore(SWTUIElement uiElement) {
final Widget widget = unwrapWidget(uiElement);
exec("restore", new Runnable() {
@Override
public void run() {
processTabFolderButton(widget, IWorkbenchPage.STATE_RESTORED);
}
});
}
private void processTabFolderButton(Widget widget, int buttonId) {
EclipseWorkbenchProvider.getProvider().processTabFolderButton(widget, buttonId);
}
public void showTabList(SWTUIElement uiElement) {
final Widget widget = unwrapWidget(uiElement);
exec("showTabList", new Runnable() {
@Override
public void run() {
processTabShowList(widget);
}
});
}
private void processTabShowList(Widget widget) {
EclipseWorkbenchProvider.getProvider().processTabShowList(widget);
}
public void setPerspective(final String perspectiveId) {
exec("setPerspective", new Runnable() {
@Override
public void run() {
IPerspectiveDescriptor persectiveDescriptor = PlatformUI.getWorkbench().getPerspectiveRegistry()
.findPerspectiveWithId(perspectiveId);
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()
.setPerspective(persectiveDescriptor);
}
});
}
public void wakeup() {
notifyUI(getDisplay());
}
public final class ExecRunnable implements Runnable {
private final Context currentContext;
private final Runnable runnable;
private final String errorMethod;
private String msg;
private ExecRunnable(String msg, Context currentContext, Runnable runnable, String errorMethod) {
this.msg = msg;
this.currentContext = currentContext;
this.runnable = runnable;
this.errorMethod = errorMethod;
}
@Override
public String toString() {
return errorMethod;
}
@Override
public void run() {
// ReportBuilder builder = ReportManager.getBuilder();
// if (builder != null) {
// builder.beginTask("Running raw command:" + msg);
// }
collector.enable();
try {
runnable.run();
// Wait for all jobs
display.wake();
} catch (Throwable t) {
if (error != null)
error = t;
TeslaCore.log(new TeslaExecutionFailedException(errorMethod, t));
} finally {
// if (builder != null) {
// builder.endTask();
// }
// collector.setNeedDisable();
// Will be called from next sleep state.
synchronized (runnables) {
if (currentContext != null) {
List<Runnable> runs = runnables.get(currentContext);
runs.remove(this);
}
}
}
}
}
private static class NotifyUINullRunnable implements Runnable {
@Override
public void run() {
}
};
private static NotifyUINullRunnable notifyUINullRunnable;
public static void notifyUI(Display display) {
display.wake();
display.asyncExec(notifyUINullRunnable);
}
public static synchronized void addExtension(ISWTUIPlayerExtension extension) {
extensions.add(extension);
}
public static synchronized void removeExtension(ISWTUIPlayerExtension extension) {
extensions.remove(extension);
}
public static synchronized List<ISWTUIPlayerExtension> getExtensions() {
return new ArrayList<ISWTUIPlayerExtension>(extensions);
}
public boolean cleanMenus(final Q7WaitInfoRoot info) {
final boolean result[] = { false };
Display curDisplay = PlatformUI.getWorkbench().getDisplay();
if (curDisplay == null || curDisplay.isDisposed()) {
return false;
}
final List<Menu> menusToProceed = new ArrayList<>();
synchronized (shownMenus) {
for (WeakReference<Menu> weakReference : shownMenus) {
Menu menu = weakReference.get();
if (menu == null) {
continue;
}
menusToProceed.add(menu);
}
shownMenus.clear();
}
if (!menusToProceed.isEmpty()) {
Q7WaitUtils.updateInfo("menu", "hide", info);
curDisplay.syncExec(new Runnable() {
@Override
public void run() {
for (Menu menu : menusToProceed) {
// We also need to hide all parent menus.
while (menu != null && !menu.isDisposed()) {
events.sendEvent(menu, SWT.Hide);
menu = menu.getParentMenu();
}
}
}
});
}
synchronized (shownMenus) {
result[0] = !shownMenus.isEmpty();
}
return result[0];
}
public void clean() {
getCollector().clean();
getBrowserManager().clear();
cleanMenus(null);
error = null;
}
public boolean isCollectable(SWTUIElement element, Class<?>[] classes) {
if (element == null)
return false;
if (classes == null)
return true;
for (ISWTUIPlayerExtension extension : getExtensions()) {
if (extension.isCollectable(element, classes)) {
return true;
}
}
return false;
}
private static void debugProceed(String message) {
if (DEBUG_PROCEED) {
System.out.println("SWTUIPlayer: " + message);
System.out.flush();
}
}
}