1 package org.simantics.utils.ui;
\r
3 import java.util.concurrent.Semaphore;
\r
4 import java.util.concurrent.TimeUnit;
\r
6 import org.eclipse.swt.SWTException;
\r
7 import org.eclipse.swt.custom.CTabFolder;
\r
8 import org.eclipse.swt.custom.CTabItem;
\r
9 import org.eclipse.swt.widgets.Composite;
\r
10 import org.eclipse.swt.widgets.Control;
\r
11 import org.eclipse.swt.widgets.Display;
\r
12 import org.eclipse.swt.widgets.TabFolder;
\r
13 import org.eclipse.swt.widgets.TabItem;
\r
14 import org.eclipse.swt.widgets.Widget;
\r
15 import org.simantics.utils.threads.IThreadWorkQueue;
\r
16 import org.simantics.utils.threads.ThreadUtils;
\r
18 public class SWTUtils {
\r
21 * When scheduling a runnable to be executed asynchronously in the SWT
\r
22 * thread it is not possible to do this in a safe manner based on a
\r
23 * {@link Display} instance. When invoking
\r
24 * {@link Display#asyncExec(Runnable)} from a non-SWT thread, it may throw
\r
25 * {@link SWTException} even if you've first checked
\r
26 * {@link Display#isDisposed()}.
\r
28 * This method will run {@link Display#asyncExec(Runnable)} using the
\r
29 * display returned by the specified widget if the widget is or does not
\r
30 * become disposed while trying to get the display from it.
\r
32 * @param display the display to asyncExec with
\r
33 * @param runnable the runnable to execute with
\r
34 * {@link Display#asyncExec(Runnable)}
\r
35 * @return <code>true</code> if the executable was scheduled, false
\r
38 public static boolean asyncExec(Display display, Runnable runnable) {
\r
40 if (display.isDisposed())
\r
42 display.asyncExec(runnable);
\r
44 } catch (SWTException e) {
\r
45 // widget was disposed between isDisposed and getDisplay.
\r
51 * When scheduling a runnable to be executed asynchronously in the SWT
\r
52 * thread it is not possible to do this in a safe manner based on a
\r
53 * {@link Widget} instance. When invoking {@link Widget#getDisplay()} from a
\r
54 * non-SWT thread, it may throw {@link SWTException} even if you've first
\r
55 * checked {@link Widget#isDisposed()}.
\r
57 * This method will run {@link Display#asyncExec(Runnable)} using the
\r
58 * display returned by the specified widget if the widget is or does not
\r
59 * become disposed while trying to get the display from it.
\r
61 * @param widget the widget to get {@link Display} from
\r
62 * @param runnable the runnable to execute with {@link Display#asyncExec(Runnable)}
\r
63 * @return <code>true</code> if the executable was scheduled, false otherwise
\r
65 public static boolean asyncExec(Widget widget, Runnable runnable) {
\r
67 if (widget.isDisposed())
\r
69 widget.getDisplay().asyncExec(runnable);
\r
71 } catch (SWTException e) {
\r
72 // widget was disposed between isDisposed and getDisplay.
\r
78 * Invokes a runnable in a specified thread and dispatches SWT events while
\r
79 * waiting for the runnable to complete.
\r
82 * The runnable must not perform any operations that may cause more SWT
\r
83 * events to be dispatched.
\r
86 * To be invoked from SWT thread only.
\r
91 * @throws InterruptedException
\r
93 public static void invokeAndDispatchEvents(Display display, IThreadWorkQueue inThread, final Runnable invoke) throws InterruptedException {
\r
94 if (display.isDisposed())
\r
95 throw new IllegalArgumentException("display is disposed");
\r
96 final Semaphore sem = new Semaphore(0);
\r
97 ThreadUtils.asyncExec(inThread, new Runnable() {
\r
107 boolean done = false;
\r
109 done = sem.tryAcquire(10, TimeUnit.MILLISECONDS);
\r
110 while (!done && display.readAndDispatch()) {
\r
112 * Note: readAndDispatch can cause this to be disposed.
\r
114 done = sem.tryAcquire();
\r
120 * Look for an object starting from an SWT (composite) control with a
\r
121 * specific filter that can inspect the control freely.
\r
123 * @return the first T returned by the control filter or <code>null</code>
\r
124 * if the filter returned no results.
\r
126 public static <T> T tryGetObject(Control control, ControlFilter<T> filter) {
\r
127 if (control == null || control.isDisposed())
\r
129 T t = filter.accept(control);
\r
132 if (control instanceof Composite) {
\r
133 if (control instanceof TabFolder) {
\r
134 TabFolder tf = (TabFolder) control;
\r
135 for (TabItem item : tf.getSelection()) {
\r
136 t = tryGetObject(item.getControl(), filter);
\r
140 } else if (control instanceof CTabFolder) {
\r
141 CTabFolder tf = (CTabFolder) control;
\r
142 CTabItem item = tf.getSelection();
\r
143 if (item != null) {
\r
144 t = tryGetObject(item.getControl(), filter);
\r
149 Composite c = (Composite) control;
\r
150 for (Control child : c.getChildren()) {
\r
151 t = tryGetObject(child, filter);
\r
160 @FunctionalInterface
\r
161 public interface ControlFilter<T> {
\r
162 T accept(Control control);
\r