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