]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.utils.ui/src/org/simantics/utils/ui/SWTUtils.java
Sync git svn branch with SVN repository r33269.
[simantics/platform.git] / bundles / org.simantics.utils.ui / src / org / simantics / utils / ui / SWTUtils.java
1 package org.simantics.utils.ui;\r
2 \r
3 import java.util.concurrent.Semaphore;\r
4 import java.util.concurrent.TimeUnit;\r
5 \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
17 \r
18 public class SWTUtils {\r
19 \r
20     /**\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
27      * \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
31      * \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
36      *         otherwise\r
37      */\r
38     public static boolean asyncExec(Display display, Runnable runnable) {\r
39         try {\r
40             if (display.isDisposed())\r
41                 return false;\r
42             display.asyncExec(runnable);\r
43             return true;\r
44         } catch (SWTException e) {\r
45             // widget was disposed between isDisposed and getDisplay.\r
46             return false;\r
47         }\r
48     }\r
49 \r
50         /**\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
56          * \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
60          * \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
64          */\r
65         public static boolean asyncExec(Widget widget, Runnable runnable) {\r
66                 try {\r
67                         if (widget.isDisposed())\r
68                                 return false;\r
69                         widget.getDisplay().asyncExec(runnable);\r
70                         return true;\r
71                 } catch (SWTException e) {\r
72                         // widget was disposed between isDisposed and getDisplay.\r
73                         return false;\r
74                 }\r
75         }\r
76 \r
77         /**\r
78          * Invokes a runnable in a specified thread and dispatches SWT events while\r
79          * waiting for the runnable to complete.\r
80          * \r
81          * <p>\r
82          * The runnable must not perform any operations that may cause more SWT\r
83          * events to be dispatched.\r
84          * \r
85          * <p>\r
86          * To be invoked from SWT thread only.\r
87          * \r
88          * @param control\r
89          * @param inThread\r
90          * @param invoke\r
91          * @throws InterruptedException\r
92          */\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
98                         @Override\r
99                         public void run() {\r
100                                 try {\r
101                                         invoke.run();\r
102                                 } finally {\r
103                                         sem.release();\r
104                                 }\r
105                         }\r
106                 });\r
107                 boolean done = false;\r
108                 while (!done) {\r
109                         done = sem.tryAcquire(10, TimeUnit.MILLISECONDS);\r
110                         while (!done && display.readAndDispatch()) {\r
111                                 /*\r
112                                  * Note: readAndDispatch can cause this to be disposed.\r
113                                  */\r
114                                 done = sem.tryAcquire();\r
115                         }\r
116                 }\r
117         }\r
118 \r
119         /**\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
122          * \r
123          * @return the first T returned by the control filter or <code>null</code>\r
124          *         if the filter returned no results.\r
125          */\r
126         public static <T> T tryGetObject(Control control, ControlFilter<T> filter) {\r
127                 if (control == null || control.isDisposed())\r
128                         return null;\r
129                 T t = filter.accept(control);\r
130                 if (t != null)\r
131                         return t;\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
137                                         if (t != null)\r
138                                                 return t;\r
139                                 }\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
145                                         if (t != null)\r
146                                                 return t;\r
147                                 }\r
148                         } else {\r
149                                 Composite c = (Composite) control;\r
150                                 for (Control child : c.getChildren()) {\r
151                                         t = tryGetObject(child, filter);\r
152                                         if (t != null)\r
153                                                 return t;\r
154                                 }\r
155                         }\r
156                 }\r
157                 return null;\r
158         }\r
159 \r
160         @FunctionalInterface\r
161         public interface ControlFilter<T> {\r
162                 T accept(Control control);\r
163         }\r
164 \r
165 }\r