X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=tmf%2Forg.eclipse.tracecompass.tmf.ui.swtbot.tests%2Fshared%2Forg%2Feclipse%2Ftracecompass%2Ftmf%2Fui%2Fswtbot%2Ftests%2Fshared%2FSWTBotUtils.java;h=dc2189419a885ef14ce8b340d1125caf97989ba2;hb=b6fddb839ef7b61c5a418a5e05091c52b3d25c67;hp=7386e341f3ecca0004bd6b67d920fe1910bfe26a;hpb=a345ad253a3c5de924340f16ec03d2c30ab64426;p=deliverable%2Ftracecompass.git diff --git a/tmf/org.eclipse.tracecompass.tmf.ui.swtbot.tests/shared/org/eclipse/tracecompass/tmf/ui/swtbot/tests/shared/SWTBotUtils.java b/tmf/org.eclipse.tracecompass.tmf.ui.swtbot.tests/shared/org/eclipse/tracecompass/tmf/ui/swtbot/tests/shared/SWTBotUtils.java index 7386e341f3..dc2189419a 100644 --- a/tmf/org.eclipse.tracecompass.tmf.ui.swtbot.tests/shared/org/eclipse/tracecompass/tmf/ui/swtbot/tests/shared/SWTBotUtils.java +++ b/tmf/org.eclipse.tracecompass.tmf.ui.swtbot.tests/shared/org/eclipse/tracecompass/tmf/ui/swtbot/tests/shared/SWTBotUtils.java @@ -16,21 +16,30 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import java.util.Arrays; import java.util.List; +import java.util.TimeZone; +import java.util.concurrent.atomic.AtomicBoolean; +import org.apache.log4j.Logger; +import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceVisitor; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jface.bindings.keys.IKeyLookup; import org.eclipse.jface.bindings.keys.KeyStroke; import org.eclipse.jface.bindings.keys.ParseException; +import org.eclipse.swt.events.ControlAdapter; +import org.eclipse.swt.events.ControlEvent; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableItem; import org.eclipse.swtbot.eclipse.finder.SWTWorkbenchBot; @@ -39,8 +48,12 @@ import org.eclipse.swtbot.eclipse.finder.widgets.SWTBotEditor; import org.eclipse.swtbot.eclipse.finder.widgets.SWTBotView; import org.eclipse.swtbot.swt.finder.SWTBot; import org.eclipse.swtbot.swt.finder.finders.UIThreadRunnable; +import org.eclipse.swtbot.swt.finder.keyboard.Keyboard; +import org.eclipse.swtbot.swt.finder.keyboard.Keystrokes; import org.eclipse.swtbot.swt.finder.results.Result; import org.eclipse.swtbot.swt.finder.results.VoidResult; +import org.eclipse.swtbot.swt.finder.utils.MessageFormat; +import org.eclipse.swtbot.swt.finder.utils.SWTUtils; import org.eclipse.swtbot.swt.finder.waits.Conditions; import org.eclipse.swtbot.swt.finder.waits.DefaultCondition; import org.eclipse.swtbot.swt.finder.widgets.SWTBotButton; @@ -50,12 +63,19 @@ import org.eclipse.swtbot.swt.finder.widgets.SWTBotShell; import org.eclipse.swtbot.swt.finder.widgets.SWTBotTable; import org.eclipse.swtbot.swt.finder.widgets.SWTBotTree; import org.eclipse.swtbot.swt.finder.widgets.SWTBotTreeItem; +import org.eclipse.swtbot.swt.finder.widgets.TimeoutException; +import org.eclipse.tracecompass.internal.tmf.ui.project.operations.NewExperimentOperation; import org.eclipse.tracecompass.tmf.ui.editors.TmfEventsEditor; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfExperimentElement; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfExperimentFolder; import org.eclipse.tracecompass.tmf.ui.project.model.TmfOpenTraceHelper; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfProjectElement; import org.eclipse.tracecompass.tmf.ui.project.model.TmfProjectRegistry; +import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceElement; import org.eclipse.tracecompass.tmf.ui.project.model.TmfTraceFolder; import org.eclipse.tracecompass.tmf.ui.project.model.TmfTracesFolder; import org.eclipse.tracecompass.tmf.ui.swtbot.tests.shared.ConditionHelpers.ProjectElementHasChild; +import org.eclipse.tracecompass.tmf.ui.tests.shared.WaitUtils; import org.eclipse.tracecompass.tmf.ui.views.TracingPerspectiveFactory; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IEditorReference; @@ -70,20 +90,32 @@ import org.hamcrest.Matcher; * * @author Matthew Khouzam */ +@SuppressWarnings("restriction") public final class SWTBotUtils { + private static final String WINDOW_MENU = "Window"; + private static final String PREFERENCES_MENU_ITEM = "Preferences"; + private static boolean fPrintedEnvironment = false; + private static Logger log = Logger.getLogger(SWTBotUtils.class); + private SWTBotUtils() { + } private static final String TRACING_PERSPECTIVE_ID = TracingPerspectiveFactory.ID; /** - * Waits for all Eclipse jobs to finish + * Waits for all Eclipse jobs to finish. Times out after + * WaitUtils#MAX_JOBS_WAIT_TIME by default. + * + * @throws RuntimeException + * once the waiting time passes the default maximum value + * + * @deprecated Use {@link WaitUtils#waitForJobs()} instead */ + @Deprecated public static void waitForJobs() { - while (!Job.getJobManager().isIdle()) { - delay(100); - } + WaitUtils.waitForJobs(); } /** @@ -118,7 +150,7 @@ public final class SWTBotUtils { } }); - SWTBotUtils.waitForJobs(); + WaitUtils.waitForJobs(); } /** @@ -134,13 +166,20 @@ public final class SWTBotUtils { public static void deleteProject(final String projectName, boolean deleteResources, SWTWorkbenchBot bot) { // Wait for any analysis to complete because it might create // supplementary files - SWTBotUtils.waitForJobs(); + WaitUtils.waitForJobs(); try { ResourcesPlugin.getWorkspace().getRoot().getProject(projectName).refreshLocal(IResource.DEPTH_INFINITE, null); } catch (CoreException e) { } - SWTBotUtils.waitForJobs(); + WaitUtils.waitForJobs(); + + closeSecondaryShells(bot); + WaitUtils.waitForJobs(); + + if (!ResourcesPlugin.getWorkspace().getRoot().getProject(projectName).exists()) { + return; + } final SWTBotView projectViewBot = bot.viewById(IPageLayout.ID_PROJECT_EXPLORER); projectViewBot.setFocus(); @@ -161,7 +200,7 @@ public final class SWTBotUtils { bot.waitUntil(Conditions.widgetIsEnabled(okButton)); okButton.click(); - SWTBotUtils.waitForJobs(); + WaitUtils.waitForJobs(); } /** @@ -176,6 +215,38 @@ public final class SWTBotUtils { deleteProject(projectName, true, bot); } + /** + * Creates an experiment + * + * @param bot + * a given workbench bot + * @param projectName + * the name of the project, creates the project if needed + * @param expName + * the experiment name + */ + public static void createExperiment(SWTWorkbenchBot bot, String projectName, final @NonNull String expName) { + IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName); + TmfProjectElement tmfProject = TmfProjectRegistry.getProject(project, true); + TmfExperimentFolder expFolder = tmfProject.getExperimentsFolder(); + assertNotNull(expFolder); + NewExperimentOperation operation = new NewExperimentOperation(expFolder, expName); + operation.run(new NullProgressMonitor()); + + bot.waitUntil(new DefaultCondition() { + @Override + public boolean test() throws Exception { + TmfExperimentElement experiment = expFolder.getExperiment(expName); + return experiment != null; + } + + @Override + public String getFailureMessage() { + return "Experiment (" + expName + ") couldn't be created"; + } + }); + } + /** * Focus on the main window * @@ -183,11 +254,43 @@ public final class SWTBotUtils { * swtbotshells for all the shells */ public static void focusMainWindow(SWTBotShell[] shellBots) { + SWTBotShell mainShell = getMainShell(shellBots); + if (mainShell != null) { + mainShell.activate(); + } + } + + private static SWTBotShell getMainShell(SWTBotShell[] shellBots) { + SWTBotShell mainShell = null; for (SWTBotShell shellBot : shellBots) { if (shellBot.getText().toLowerCase().contains("eclipse")) { - shellBot.activate(); + mainShell = shellBot; } } + return mainShell; + } + + /** + * Close all non-main shells that are visible. + * + * @param bot + * the workbench bot + */ + public static void closeSecondaryShells(SWTWorkbenchBot bot) { + SWTBotShell[] shells = bot.shells(); + SWTBotShell mainShell = getMainShell(shells); + if (mainShell == null) { + return; + } + + // Close all non-main shell but make sure we don't close an invisible + // shell such the special "limbo shell" that Eclipse needs to work + Arrays.stream(shells) + .filter(shell -> shell != mainShell) + .filter(s -> !s.widget.isDisposed()) + .filter(SWTBotShell::isVisible) + .peek(shell -> log.debug(MessageFormat.format("Closing lingering shell with title {0}", shell.getText()))) + .forEach(SWTBotShell::close); } /** @@ -212,7 +315,8 @@ public final class SWTBotUtils { * Close a view with an id * * @param viewId - * the view id, like "org.eclipse.linuxtools.tmf.ui.views.histogram" + * the view id, like + * "org.eclipse.linuxtools.tmf.ui.views.histogram" * @param bot * the workbench bot */ @@ -249,15 +353,96 @@ public final class SWTBotUtils { }); } + /** + * Initialize the environment for SWTBot + */ + public static void initialize() { + failIfUIThread(); + + SWTWorkbenchBot bot = new SWTWorkbenchBot(); + UIThreadRunnable.syncExec(() -> { + printEnvironment(); + + // There seems to be problems on some system where the main shell is + // not in focus initially. This was seen using Xvfb and Xephyr on + // some occasions. + focusMainWindow(bot.shells()); + + Shell shell = bot.activeShell().widget; + + // Only adjust shell if it appears to be the top-most + if (shell.getParent() == null) { + makeShellFullyVisible(shell); + } + }); + } + + private static void printEnvironment() { + if (fPrintedEnvironment) { + return; + } + + // Print some information about the environment that could affect test + // outcome + Rectangle bounds = Display.getDefault().getBounds(); + System.out.println("Display size: " + bounds.width + "x" + bounds.height); + + String osVersion = System.getProperty("os.version"); + if (osVersion != null) { + System.out.println("OS version=" + osVersion); + } + String gtkVersion = System.getProperty("org.eclipse.swt.internal.gtk.version"); + if (gtkVersion != null) { + System.out.println("GTK version=" + gtkVersion); + // Try to print the GTK theme information as behavior can change + // depending on the theme + String gtkTheme = System.getProperty("org.eclipse.swt.internal.gtk.theme"); + System.out.println("GTK theme=" + (gtkTheme == null ? "unknown" : gtkTheme)); + + String overlayScrollbar = System.getenv("LIBOVERLAY_SCROLLBAR"); + if (overlayScrollbar != null) { + System.out.println("LIBOVERLAY_SCROLLBAR=" + overlayScrollbar); + } + String ubuntuMenuProxy = System.getenv("UBUNTU_MENUPROXY"); + if (ubuntuMenuProxy != null) { + System.out.println("UBUNTU_MENUPROXY=" + ubuntuMenuProxy); + } + } + + System.out.println("Time zone: " + TimeZone.getDefault().getDisplayName()); + + fPrintedEnvironment = true; + } + /** * If the test is running in the UI thread then fail */ - public static void failIfUIThread() { + private static void failIfUIThread() { if (Display.getCurrent() != null && Display.getCurrent().getThread() == Thread.currentThread()) { fail("SWTBot test needs to run in a non-UI thread. Make sure that \"Run in UI thread\" is unchecked in your launch configuration or" + " that useUIThread is set to false in the pom.xml"); } + } + /** + * Try to make the shell fully visible in the display. If the shell cannot + * fit the display, it will be positioned so that top-left corner is at + * (0, 0) in display-relative coordinates. + * + * @param shell + * the shell to make fully visible + */ + private static void makeShellFullyVisible(Shell shell) { + Rectangle displayBounds = shell.getDisplay().getBounds(); + Point absCoord = shell.toDisplay(0, 0); + Point shellSize = shell.getSize(); + + Point newLocation = new Point(absCoord.x, absCoord.y); + newLocation.x = Math.max(0, Math.min(absCoord.x, displayBounds.width - shellSize.x)); + newLocation.y = Math.max(0, Math.min(absCoord.y, displayBounds.height - shellSize.y)); + if (!newLocation.equals(absCoord)) { + shell.setLocation(newLocation); + } } /** @@ -307,7 +492,7 @@ public final class SWTBotUtils { if (delay) { delay(1000); - waitForJobs(); + WaitUtils.waitForJobs(); } } @@ -333,7 +518,7 @@ public final class SWTBotUtils { } }); - SWTBotUtils.waitForJobs(); + WaitUtils.waitForJobs(); SWTBotUtils.delay(1000); assertNotNull(tmfEd); return editorBot; @@ -366,7 +551,6 @@ public final class SWTBotUtils { SWTBotTreeItem currentItem = tracesNode; for (String segment : elementPath.segments()) { currentItem = getTraceProjectItem(projectExplorerBot, currentItem, segment); - currentItem.select(); currentItem.doubleClick(); } @@ -376,6 +560,26 @@ public final class SWTBotUtils { return (TmfEventsEditor) editorPart; } + /** + * Returns the child tree item of the specified item at the given sub-path. + * The project element labels may have a count suffix in the format ' [n]'. + * + * @param bot + * a given workbench bot + * @param parentItem + * the parent tree item + * @param path + * the desired child element sub-path (without suffix) + * @return the a {@link SWTBotTreeItem} with the specified name + */ + public static SWTBotTreeItem getTraceProjectItem(SWTBot bot, final SWTBotTreeItem parentItem, final String... path) { + SWTBotTreeItem item = parentItem; + for (String name : path) { + item = getTraceProjectItem(bot, item, name); + } + return item; + } + /** * Returns the child tree item of the specified item with the given name. * The project element label may have a count suffix in the format ' [n]'. @@ -412,18 +616,139 @@ public final class SWTBotUtils { return tracesFolderItem; } + /** + * Clear the traces folder + * + * @param bot + * a given workbench bot + * @param projectName + * the name of the project (needs to exist) + */ + public static void clearTracesFolder(SWTWorkbenchBot bot, String projectName) { + IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName); + TmfProjectElement tmfProject = TmfProjectRegistry.getProject(project, false); + TmfTraceFolder tracesFolder = tmfProject.getTracesFolder(); + try { + for (TmfTraceElement traceElement : tracesFolder.getTraces()) { + traceElement.delete(null); + } + + final IFolder resource = tracesFolder.getResource(); + resource.accept(new IResourceVisitor() { + @Override + public boolean visit(IResource visitedResource) throws CoreException { + if (visitedResource != resource) { + visitedResource.delete(true, null); + } + return true; + } + }, IResource.DEPTH_ONE, 0); + } catch (CoreException e) { + fail(e.getMessage()); + } + + bot.waitUntil(new DefaultCondition() { + private int fTraceNb = 0; + + @Override + public boolean test() throws Exception { + List traces = tracesFolder.getTraces(); + fTraceNb = traces.size(); + return fTraceNb == 0; + } + + @Override + public String getFailureMessage() { + return "Traces Folder not empty (" + fTraceNb + ")"; + } + }); + } + + /** + * Clear the trace folder (using the UI) + * + * @param bot + * a given workbench bot + * @param projectName + * the name of the project (needs to exist) + */ + public static void clearTracesFolderUI(SWTWorkbenchBot bot, String projectName) { + SWTBotTreeItem tracesFolder = selectTracesFolder(bot, projectName); + tracesFolder.contextMenu().menu("Clear").click(); + String CONFIRM_CLEAR_DIALOG_TITLE = "Confirm Clear"; + bot.waitUntil(Conditions.shellIsActive(CONFIRM_CLEAR_DIALOG_TITLE)); + + SWTBotShell shell = bot.shell(CONFIRM_CLEAR_DIALOG_TITLE); + shell.bot().button("Yes").click(); + bot.waitUntil(Conditions.shellCloses(shell)); + bot.waitWhile(ConditionHelpers.treeItemHasChildren(tracesFolder)); + } + + /** + * Clear the experiment folder + * + * @param bot + * a given workbench bot + * @param projectName + * the name of the project (needs to exist) + */ + public static void clearExperimentFolder(SWTWorkbenchBot bot, String projectName) { + IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName); + TmfProjectElement tmfProject = TmfProjectRegistry.getProject(project, false); + TmfExperimentFolder expFolder = tmfProject.getExperimentsFolder(); + expFolder.getExperiments().forEach(experiment -> { + IResource resource = experiment.getResource(); + try { + // Close the experiment if open + experiment.closeEditors(); + + IPath path = resource.getLocation(); + if (path != null) { + // Delete supplementary files + experiment.deleteSupplementaryFolder(); + } + // Finally, delete the experiment + resource.delete(true, null); + } catch (CoreException e) { + fail(e.getMessage()); + } + }); + + bot.waitUntil(new DefaultCondition() { + private int fExperimentNb = 0; + + @Override + public boolean test() throws Exception { + List experiments = expFolder.getExperiments(); + fExperimentNb = experiments.size(); + return fExperimentNb == 0; + } + + @Override + public String getFailureMessage() { + return "Experiment Folder not empty (" + fExperimentNb + ")"; + } + }); + } + /** * Select the project in Project Explorer * * @param bot * a given workbench bot * @param projectName - * the name of the project (it needs to exist or else it would time out) + * the name of the project (it needs to exist or else it would + * time out) * @return a {@link SWTBotTreeItem} of the project */ public static SWTBotTreeItem selectProject(SWTWorkbenchBot bot, String projectName) { SWTBotView projectExplorerBot = bot.viewByTitle("Project Explorer"); projectExplorerBot.show(); + // FIXME: Bug 496519. Sometimes, the tree becomes disabled for a certain + // amount of time. This can happen during a long running operation + // (BusyIndicator.showWhile) which brings up the modal dialog "operation + // in progress" and this disables all shells + projectExplorerBot.bot().waitUntil(Conditions.widgetIsEnabled(projectExplorerBot.bot().tree())); SWTBotTreeItem treeItem = projectExplorerBot.bot().tree().getTreeItem(projectName); treeItem.select(); return treeItem; @@ -450,7 +775,7 @@ public final class SWTBotUtils { if (res[0] != null) { fail(res[0].getMessage()); } - waitForJobs(); + WaitUtils.waitForJobs(); } /** @@ -460,11 +785,35 @@ public final class SWTBotUtils { * the {@link SWTBotTable} table */ public static void maximizeTable(SWTBotTable tableBot) { + final AtomicBoolean controlResized = new AtomicBoolean(); + UIThreadRunnable.syncExec(new VoidResult() { + @Override + public void run() { + tableBot.widget.addControlListener(new ControlAdapter() { + @Override + public void controlResized(ControlEvent e) { + tableBot.widget.removeControlListener(this); + controlResized.set(true); + } + }); + } + }); try { tableBot.pressShortcut(KeyStroke.getInstance(IKeyLookup.CTRL_NAME + "+"), KeyStroke.getInstance("M")); } catch (ParseException e) { fail(); } + new SWTBot().waitUntil(new DefaultCondition() { + @Override + public boolean test() throws Exception { + return controlResized.get(); + } + + @Override + public String getFailureMessage() { + return "Control was not resized"; + } + }); } /** @@ -511,11 +860,42 @@ public final class SWTBotUtils { bot.waitUntil(ConditionHelpers.IsTreeNodeAvailable(nodeNames[0], tree)); SWTBotTreeItem currentNode = tree.getTreeItem(nodeNames[0]); - for (int i = 1; i < nodeNames.length; i++) { + return getTreeItem(bot, currentNode, Arrays.copyOfRange(nodeNames, 1, nodeNames.length)); + } + + /** + * Get the tree item from a parent tree item at the specified location + * + * @param bot + * the SWTBot + * @param treeItem + * the treeItem to find the tree item under + * @param nodeNames + * the path to the tree item, in the form of node names (from + * parent to child). + * @return the tree item + */ + public static SWTBotTreeItem getTreeItem(SWTBot bot, SWTBotTreeItem treeItem, String... nodeNames) { + if (nodeNames.length == 0) { + return treeItem; + } + + SWTBotTreeItem currentNode = treeItem; + for (int i = 0; i < nodeNames.length; i++) { + bot.waitUntil(ConditionHelpers.treeItemHasChildren(treeItem)); currentNode.expand(); String nodeName = nodeNames[i]; - bot.waitUntil(ConditionHelpers.IsTreeChildNodeAvailable(nodeName, currentNode)); + try { + bot.waitUntil(ConditionHelpers.IsTreeChildNodeAvailable(nodeName, currentNode)); + } catch (TimeoutException e) { + // FIXME: Sometimes in a JFace TreeViewer, it expands to + // nothing. Need to find out why. + currentNode.collapse(); + currentNode.expand(); + bot.waitUntil(ConditionHelpers.IsTreeChildNodeAvailable(nodeName, currentNode)); + } + SWTBotTreeItem newNode = currentNode.getNode(nodeName); currentNode = newNode; } @@ -523,6 +903,21 @@ public final class SWTBotUtils { return currentNode; } + /** + * Press the keyboard shortcut that goes to the top of a tree widget. The + * key combination can differ on different platforms. + * + * @param keyboard + * the keyboard to use + */ + public static void pressShortcutGoToTreeTop(Keyboard keyboard) { + if (SWTUtils.isMac()) { + keyboard.pressShortcut(Keystrokes.ALT, Keystrokes.UP); + } else { + keyboard.pressShortcut(Keystrokes.HOME); + } + } + /** * Get the active events editor. Note that this will wait until such editor * is available. @@ -532,25 +927,50 @@ public final class SWTBotUtils { * @return the active events editor */ public static SWTBotEditor activeEventsEditor(final SWTWorkbenchBot workbenchBot) { - final SWTBotEditor editor[] = new SWTBotEditor[1]; - workbenchBot.waitUntil(new DefaultCondition() { - @Override - public boolean test() throws Exception { - List editors = workbenchBot.editors(WidgetMatcherFactory.withPartId(TmfEventsEditor.ID)); - for (SWTBotEditor e : editors) { - if (e.isActive() && !e.getWidget().isDisposed()) { - editor[0] = e; - return true; - } - } - return false; - } + ConditionHelpers.ActiveEventsEditor condition = new ConditionHelpers.ActiveEventsEditor(workbenchBot, null); + workbenchBot.waitUntil(condition); + return condition.getActiveEditor(); + } - @Override - public String getFailureMessage() { - return "Active events editor not found"; + /** + * Get the active events editor. Note that this will wait until such editor + * is available. + * + * @param workbenchBot + * a given workbench bot + * @param editorTitle + * the desired editor title. If null, any active events editor + * will be considered valid. + * @return the active events editor + */ + public static SWTBotEditor activeEventsEditor(final SWTWorkbenchBot workbenchBot, String editorTitle) { + ConditionHelpers.ActiveEventsEditor condition = new ConditionHelpers.ActiveEventsEditor(workbenchBot, editorTitle); + workbenchBot.waitUntil(condition); + return condition.getActiveEditor(); + } + + /** + * Open the preferences dialog and return the corresponding shell. + * + * @param bot + * a given workbench bot + * @return the preferences shell + */ + public static SWTBotShell openPreferences(SWTBot bot) { + if (SWTUtils.isMac()) { + // On Mac, the Preferences menu item is under the application name. + // For some reason, we can't access the application menu anymore so + // we use the keyboard shortcut. + try { + bot.activeShell().pressShortcut(KeyStroke.getInstance(IKeyLookup.COMMAND_NAME + "+"), KeyStroke.getInstance(",")); + } catch (ParseException e) { + fail(); } - }); - return editor[0]; + } else { + bot.menu(WINDOW_MENU).menu(PREFERENCES_MENU_ITEM).click(); + } + + bot.waitUntil(Conditions.shellIsActive(PREFERENCES_MENU_ITEM)); + return bot.activeShell(); } }