blob: e2b5f4d10e8eaf054a4dfda0dfaa0cacb05ca3d3 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008 Oracle. 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:
* Oracle - initial API and implementation
******************************************************************************/
package org.eclipse.jpt.ui.internal.util;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.AssertionFailedException;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jpt.ui.internal.widgets.NullPostExecution;
import org.eclipse.jpt.ui.internal.widgets.PostExecution;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.forms.widgets.ScrolledForm;
/**
* A suite of utility methods related to the user interface.
*
* @version 2.0
* @since 1.0
*/
@SuppressWarnings("nls")
public class SWTUtil {
/**
* Causes the <code>run()</code> method of the given runnable to be invoked
* by the user-interface thread at the next reasonable opportunity. The caller
* of this method continues to run in parallel, and is not notified when the
* runnable has completed.
*
* @param runnable Code to run on the user-interface thread
* @exception org.eclipse.swt.SWTException
* <ul>
* <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
* </ul>
* @see #syncExec
*/
public static void asyncExec(Runnable runnable) {
getStandardDisplay().asyncExec(runnable);
}
/**
* Creates the <code>Runnable</code> that will invoke the given
* <code>PostExecution</code> in order to its execution to be done in the
* UI thread.
*
* @param dialog The dialog that was just diposed
* @param postExecution The post execution once the dialog is disposed
* @return The <code>Runnable</code> that will invoke
* {@link PostExecution#execute(Dialog)}
*/
@SuppressWarnings("unchecked")
private static <D1 extends Dialog, D2 extends D1>
Runnable buildPostExecutionRunnable(
final D1 dialog,
final PostExecution<D2> postExecution) {
return new Runnable() {
public void run() {
setUserInterfaceActive(false);
try {
postExecution.execute((D2) dialog);
}
finally {
setUserInterfaceActive(true);
}
}
};
}
/**
* Convenience method for getting the current shell. If the current thread is
* not the UI thread, then an invalid thread access exception will be thrown.
*
* @return The shell, never <code>null</code>
*/
public static Shell getShell() {
// Retrieve the active shell, which can be the shell from any window
Shell shell = getStandardDisplay().getActiveShell();
// No shell could be found, revert back to the active workbench window
if (shell == null) {
shell = getWorkbench().getActiveWorkbenchWindow().getShell();
}
// Make sure it's never null
if (shell == null) {
shell = new Shell(getStandardDisplay().getActiveShell());
}
return shell;
}
/**
* Returns the standard display to be used. The method first checks, if the
* thread calling this method has an associated display. If so, this display
* is returned. Otherwise the method returns the default display.
*
* @return The current display if not <code>null</code> otherwise the default
* display is returned
*/
public static Display getStandardDisplay()
{
Display display = Display.getCurrent();
if (display == null) {
display = Display.getDefault();
}
return display;
}
public static int getTableHeightHint(Table table, int rows) {
if (table.getFont().equals(JFaceResources.getDefaultFont()))
table.setFont(JFaceResources.getDialogFont());
int result= table.getItemHeight() * rows + table.getHeaderHeight();
if (table.getLinesVisible())
result+= table.getGridLineWidth() * (rows - 1);
return result;
}
/**
* Returns the Platform UI workbench.
*
* @return The workbench for this plug-in
*/
public static IWorkbench getWorkbench() {
return PlatformUI.getWorkbench();
}
/**
* Relays out the parents of the <code>Control</code>. This was taken from
* the widget <code>Section</code>.
*
* @param pane The pane to revalidate as well as its parents
*/
public static void reflow(Composite pane) {
for (Composite composite = pane; composite != null; ) {
composite.setRedraw(false);
composite = composite.getParent();
if (composite instanceof ScrolledForm) {
break;
}
}
for (Composite composite = pane; composite != null; ) {
composite.layout(true);
composite = composite.getParent();
if (composite instanceof ScrolledForm) {
((ScrolledForm) composite).reflow(true);
break;
}
}
for (Composite composite = pane; composite != null; ) {
composite.setRedraw(true);
composite = composite.getParent();
if (composite instanceof ScrolledForm) {
break;
}
}
}
/**
* Sets whether the entire shell and its widgets should be enabled or
* everything should be unaccessible.
*
* @param active <code>true</code> to make all the UI active otherwise
* <code>false</code> to deactivate it
*/
public static void setUserInterfaceActive(boolean active) {
Shell[] shells = getStandardDisplay().getShells();
for (Shell shell : shells) {
shell.setEnabled(active);
}
}
/**
* Asynchronously launches the specified dialog in the UI thread.
*
* @param dialog The dialog to show on screen
* @param postExecution This interface let the caller to invoke a piece of
* code once the dialog is disposed
*/
public static <D1 extends Dialog, D2 extends D1>
void show(final D1 dialog, final PostExecution<D2> postExecution) {
try {
Assert.isNotNull(dialog, "The dialog cannot be null");
Assert.isNotNull(postExecution, "The PostExecution cannot be null");
}
catch (AssertionFailedException e) {
// Make sure the UI is interactive
setUserInterfaceActive(true);
throw e;
}
new Thread() {
@Override
public void run() {
asyncExec(
new Runnable() { public void run() {
showImp(dialog, postExecution);
}
}
);
}}.start();
}
/**
* Asynchronously launches the specified dialog in the UI thread.
*
* @param dialog The dialog to show on screen
*/
public static void show(Dialog dialog) {
show(dialog, NullPostExecution.<Dialog>instance());
}
/**
* Asynchronously launches the specified dialog in the UI thread.
*
* @param dialog The dialog to show on screen
* @param postExecution This interface let the caller to invoke a piece of
* code once the dialog is disposed
*/
private static <D1 extends Dialog, D2 extends D1>
void showImp(D1 dialog, PostExecution<D2> postExecution) {
setUserInterfaceActive(true);
dialog.open();
if (postExecution != NullPostExecution.<D2>instance()) {
asyncExec(buildPostExecutionRunnable(dialog, postExecution));
}
}
/**
* Causes the <code>run()</code> method of the given runnable to be invoked
* by the user-interface thread at the next reasonable opportunity. The
* thread which calls this method is suspended until the runnable completes.
*
* @param runnable code to run on the user-interface thread.
* @see #asyncExec
*/
public static void syncExec(Runnable runnable) {
getStandardDisplay().syncExec(runnable);
}
/**
* Determines if the current thread is the UI event thread.
*
* @return <code>true</code> if it's the UI event thread, <code>false</code>
* otherwise
*/
public static boolean uiThread() {
return getStandardDisplay().getThread() == Thread.currentThread();
}
/**
* Determines if the current thread is the UI event thread by using the
* thread from which the given viewer's display was instantiated.
*
* @param viewer The viewer used to determine if the current thread
* is the UI event thread
* @return <code>true</code> if the current thread is the UI event thread;
* <code>false</code> otherwise
*/
public static boolean uiThread(Viewer viewer) {
return uiThread(viewer.getControl());
}
/**
* Determines if the current thread is the UI event thread by using the
* thread from which the given widget's display was instantiated.
*
* @param widget The widget used to determine if the current thread
* is the UI event thread
* @return <code>true</code> if the current thread is the UI event thread;
* <code>false</code> otherwise
*/
public static boolean uiThread(Widget widget) {
return widget.getDisplay().getThread() == Thread.currentThread();
}
}