package org.simantics.utils.ui;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.custom.CTabItem;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.eclipse.swt.widgets.Widget;
import org.simantics.utils.threads.IThreadWorkQueue;
import org.simantics.utils.threads.ThreadUtils;
public class SWTUtils {
/**
* When scheduling a runnable to be executed asynchronously in the SWT
* thread it is not possible to do this in a safe manner based on a
* {@link Display} instance. When invoking
* {@link Display#asyncExec(Runnable)} from a non-SWT thread, it may throw
* {@link SWTException} even if you've first checked
* {@link Display#isDisposed()}.
*
* This method will run {@link Display#asyncExec(Runnable)} using the
* display returned by the specified widget if the widget is or does not
* become disposed while trying to get the display from it.
*
* @param display the display to asyncExec with
* @param runnable the runnable to execute with
* {@link Display#asyncExec(Runnable)}
* @return true
if the executable was scheduled, false
* otherwise
*/
public static boolean asyncExec(Display display, Runnable runnable) {
try {
if (display.isDisposed())
return false;
display.asyncExec(runnable);
return true;
} catch (SWTException e) {
// widget was disposed between isDisposed and getDisplay.
return false;
}
}
/**
* When scheduling a runnable to be executed asynchronously in the SWT
* thread it is not possible to do this in a safe manner based on a
* {@link Widget} instance. When invoking {@link Widget#getDisplay()} from a
* non-SWT thread, it may throw {@link SWTException} even if you've first
* checked {@link Widget#isDisposed()}.
*
* This method will run {@link Display#asyncExec(Runnable)} using the
* display returned by the specified widget if the widget is or does not
* become disposed while trying to get the display from it.
*
* @param widget the widget to get {@link Display} from
* @param runnable the runnable to execute with {@link Display#asyncExec(Runnable)}
* @return true
if the executable was scheduled, false otherwise
*/
public static boolean asyncExec(Widget widget, Runnable runnable) {
try {
if (widget.isDisposed())
return false;
widget.getDisplay().asyncExec(runnable);
return true;
} catch (SWTException e) {
// widget was disposed between isDisposed and getDisplay.
return false;
}
}
/**
* Invokes a runnable in a specified thread and dispatches SWT events while
* waiting for the runnable to complete.
*
*
* The runnable must not perform any operations that may cause more SWT * events to be dispatched. * *
* To be invoked from SWT thread only.
*
* @param control
* @param inThread
* @param invoke
* @throws InterruptedException
*/
public static void invokeAndDispatchEvents(Display display, IThreadWorkQueue inThread, final Runnable invoke) throws InterruptedException {
if (display.isDisposed())
throw new IllegalArgumentException("display is disposed");
final Semaphore sem = new Semaphore(0);
ThreadUtils.asyncExec(inThread, new Runnable() {
@Override
public void run() {
try {
invoke.run();
} finally {
sem.release();
}
}
});
boolean done = false;
while (!done) {
done = sem.tryAcquire(10, TimeUnit.MILLISECONDS);
while (!done && display.readAndDispatch()) {
/*
* Note: readAndDispatch can cause this to be disposed.
*/
done = sem.tryAcquire();
}
}
}
/**
* Look for an object starting from an SWT (composite) control with a
* specific filter that can inspect the control freely.
*
* @return the first T returned by the control filter or null
* if the filter returned no results.
*/
public static