]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.utils.ui/src/org/simantics/utils/ui/SWTUtils.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.utils.ui / src / org / simantics / utils / ui / SWTUtils.java
diff --git a/bundles/org.simantics.utils.ui/src/org/simantics/utils/ui/SWTUtils.java b/bundles/org.simantics.utils.ui/src/org/simantics/utils/ui/SWTUtils.java
new file mode 100644 (file)
index 0000000..7ac2ce0
--- /dev/null
@@ -0,0 +1,165 @@
+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