/******************************************************************************* * Copyright (c) 2012 Google, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Google, Inc. - initial API and implementation *******************************************************************************/ package com.windowtester.runtime.swt.internal.finder; import java.util.concurrent.Callable; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Widget; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PlatformUI; import abbot.tester.swt.ShellTester; import com.windowtester.internal.debug.Logger; import com.windowtester.internal.runtime.Platform; import com.windowtester.runtime.swt.internal.widgets.DisplayReference; /** * Find parent shells. */ public class ShellFinder { private static final ShellTester _shellTester = new ShellTester(); protected static final int MODAL_SHELL_MASK = SWT.PRIMARY_MODAL | SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL; //a hook to override --- used by the inspector (NOT CLEAN!) public static Shell CURRENT_SHELL_HINT; /** * Find the parent shell handle for the given widget. * @param w the widget * @return */ public static IShellHandle find(Widget w) { SWTHierarchyHelper helper = new SWTHierarchyHelper(w.getDisplay()); do { w = helper.getParent(w); if (w instanceof Shell) { Shell shell = (Shell)w; return new ShellHandle(_shellTester.getText(shell), isModal(shell)); } } while (w != null); //shouldn't happen! return null; } /** * Check if the given shell is modal. * * @param shell the shell in question (not <code>null</code>) * @return <code>true</code> if the shell is modal, and <code>false</code> * otherwise */ public static boolean isModal(Shell shell) { return (_shellTester.getStyle(shell) & MODAL_SHELL_MASK) != 0; } /** * Get the current modal shell or <code>null</code> if there is none. */ public static Shell getModalShell(final Display d) { final Shell[] focusShell = new Shell[1]; d.syncExec(new Runnable() { public void run() { Shell[] shells = d.getShells(); Shell shell; for (int i = 0; i < shells.length; i++) { shell = shells[i]; /** * Ensure: (1) shell is modal * (2) shell is not parent of any of the other shells (need they be modal?) */ if (ShellFinder.isModal(shell) && !intersect(shell.getShells(), shells)) focusShell[0] = shell; } } /** * Test whether any of the items in array 1 are contained in array 2 */ private boolean intersect(Object[] items1, Object[] items2) { if (items1 == null) return false; for (int i=0; i < items1.length; ++i ) { for (int j = 0; j < items2.length; j++) { if (items1[i] == items2[j]) return true; } } return false; } }); return focusShell[0]; } public static Shell getActiveShell(final Display display) { final Shell[] active = new Shell[1]; display.syncExec(new Runnable() { public void run() { active[0] = display.getActiveShell(); //hook for inspector override if (active[0] == null) { try { if (CURRENT_SHELL_HINT != null && !CURRENT_SHELL_HINT.isDisposed()) active[0] = CURRENT_SHELL_HINT; } catch(Throwable th) { //being extra safe } } } }); return active[0]; //backing out to address regressions // //1. get the active shell // Shell activeShell = display.getActiveShell(); // // //2. check to see if there is more than one modal shell up // Shell[] allShells = display.getShells(); // List modalShells = getModalShells(allShells); // // //if only one // if (modalShells.size() == 1) { // //2a. verify that it agrees with the active one // Shell modal = (Shell)modalShells.get(0); // if (modal != activeShell) { // trace("single modal shell (" + modal.getText()+ ") does not agree with display's active shell (" + activeShell.getText() + ")updating to modal shell"); // activeShell = modal; // } // } // //if more than one // if (modalShells.size() > 1) { // // // 2.b if the active shell is a modal child of another modal we // // assume it is the active one // if (isModal(activeShell)) { // boolean modalChild = false; // for (Iterator iter = modalShells.iterator(); iter.hasNext();) { // Shell modal = (Shell) iter.next(); // if (!modal.isDisposed()) { // try { // Shell[] children = modal.getShells(); // for (int i = 0; i < children.length; i++) { // if (children[i] == activeShell) // modalChild = true; // } // } catch (SWTException e) { // // ignore -- shell may be disposed // } // } // } // //2.c if not, check the ShellWatcher // if (!modalChild) { // activeShell = ShellWatcher.getInstance().getCurrent(); // trace("falling back on ShellWatcher to infer active shell: " + activeShell); // } // } // } // return activeShell; } /** * Bring the root display in front (if it is not already). */ public static void bringRootToFront(final Display d) { Shell activeShell = getActiveShell(d); if (activeShell != null) return; d.syncExec(new Runnable() { public void run() { Shell shell = getRootShell(d); if (shell == null) return; //TODO: consider a retry here? Logger.log("forcing root shell active and giving it focus"); shell.forceActive(); shell.setFocus(); //TODO: should we wait here? } }); } //note: called on the UI thread. protected static Shell getRootShell(Display d) { if (!Platform.isRunning()) return null; //TODO: add support for non-platform case IWorkbench workbench = PlatformUI.getWorkbench(); if (workbench == null) return null; IWorkbenchWindow window = workbench.getActiveWorkbenchWindow(); if (window == null) return null; return window.getShell(); } public static Shell getWorkbenchRoot(){ return DisplayReference.getDefault().execute(new Callable<Shell>() { public Shell call() throws Exception { return getRootShell(Display.getDefault()); } }); } // // private static void trace(String msg) { // TraceHandler.trace(IRuntimePluginTraceOptions.SHELL_FINDER, "(ShellFinder) - " + msg); // } // // // /** // * Prune out the modal shells. // */ // private static List getModalShells(Shell[] shells) { // List modals = new ArrayList(); // for (int i = 0; i < shells.length; i++) { // try { // if (!shells[i].isDisposed() && isModal(shells[i])) // modals.add(shells[i]); // } catch (SWTException e) { // // ignore -- shell may be disposed // } // } // return modals; // } }