]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.workbench/src/org/simantics/workbench/splashHandlers/InteractiveSplashHandler.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.workbench / src / org / simantics / workbench / splashHandlers / InteractiveSplashHandler.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
3  * in Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 \r
13 package org.simantics.workbench.splashHandlers;\r
14 \r
15 import java.util.Timer;\r
16 import java.util.TimerTask;\r
17 \r
18 import org.eclipse.jface.dialogs.MessageDialog;\r
19 import org.eclipse.jface.resource.ImageDescriptor;\r
20 import org.eclipse.swt.SWT;\r
21 import org.eclipse.swt.events.SelectionAdapter;\r
22 import org.eclipse.swt.events.SelectionEvent;\r
23 import org.eclipse.swt.graphics.GC;\r
24 import org.eclipse.swt.graphics.Image;\r
25 import org.eclipse.swt.graphics.ImageData;\r
26 import org.eclipse.swt.graphics.Point;\r
27 import org.eclipse.swt.graphics.Rectangle;\r
28 import org.eclipse.swt.graphics.Region;\r
29 import org.eclipse.swt.layout.FillLayout;\r
30 import org.eclipse.swt.layout.GridData;\r
31 import org.eclipse.swt.layout.GridLayout;\r
32 import org.eclipse.swt.widgets.Button;\r
33 import org.eclipse.swt.widgets.Canvas;\r
34 import org.eclipse.swt.widgets.Composite;\r
35 import org.eclipse.swt.widgets.Event;\r
36 import org.eclipse.swt.widgets.Label;\r
37 import org.eclipse.swt.widgets.Listener;\r
38 import org.eclipse.swt.widgets.Shell;\r
39 import org.eclipse.swt.widgets.Text;\r
40 import org.eclipse.ui.splash.AbstractSplashHandler;\r
41 import org.simantics.workbench.internal.Activator;\r
42 \r
43 \r
44 /**\r
45  * @since 3.3\r
46  */\r
47 @SuppressWarnings("unused")\r
48 public class InteractiveSplashHandler extends AbstractSplashHandler {\r
49 \r
50     private static final String SPLASH_IMAGE              = "simantics.png";\r
51 \r
52     private final static int    FADE_TIME_MS              = 250;\r
53 \r
54     private final static int    F_LABEL_HORIZONTAL_INDENT = 10;\r
55 \r
56     private final static int    F_BUTTON_WIDTH_HINT       = 80;\r
57 \r
58     private final static int    F_TEXT_WIDTH_HINT         = 175;\r
59 \r
60     private final static int    F_COLUMN_COUNT            = 3;\r
61 \r
62     private Composite           fCompositeLogin;\r
63 \r
64     private Text                fTextUsername;\r
65 \r
66     private Text                fTextPassword;\r
67 \r
68     private Button              fButtonOK;\r
69 \r
70     private Button              fButtonCancel;\r
71 \r
72     private boolean             fAuthenticated;\r
73 \r
74     private Image               splashImage;\r
75 \r
76     private Image               currentBackground;\r
77 \r
78     private long                fadeStartTime             = 0;\r
79 \r
80     private boolean             fadeComplete              = false;\r
81 \r
82     private Timer               watchdogTimer             = new Timer("splash-watchdog");\r
83 \r
84     enum State {\r
85         INIT,\r
86         OK,\r
87         DIRTY,\r
88         UPDATED,\r
89         ;\r
90         State ok() {\r
91 //            System.out.println(this + " -> " + OK);\r
92             return OK;\r
93         }\r
94         State dirty() {\r
95 //            System.out.println(this + " -> " + DIRTY);\r
96             return DIRTY;\r
97         }\r
98         State updated() {\r
99 //            if (this != DIRTY) {\r
100 //                System.err.println("ERROR: transition from " + this + " to " + DIRTY);\r
101 //            }\r
102 //            System.out.println(this + " -> " + UPDATED);\r
103             return UPDATED;\r
104         }\r
105     }\r
106 \r
107     private State state = State.INIT;\r
108 \r
109     /**\r
110      * \r
111      */\r
112     public InteractiveSplashHandler() {\r
113         fCompositeLogin = null;\r
114         fTextUsername = null;\r
115         fTextPassword = null;\r
116         fButtonOK = null;\r
117         fButtonCancel = null;\r
118         fAuthenticated = false;\r
119     }\r
120 \r
121     /**\r
122      * Takes a screenshot of the desktop and blends the splash screen PNG image\r
123      * on top of it. The blended result is then set as currentBackground.\r
124      * \r
125      * @param splash\r
126      */\r
127     private void updateBackground1(Shell splash) {\r
128 //        System.out.println("Screenshotting");\r
129         Point size = splash.getSize();\r
130         Point pt = splash.getLocation();\r
131         //System.out.println("location: " + pt + ", size: " + size);\r
132 \r
133         splash.setRegion(new Region());\r
134 \r
135         // Get screenshot into backgroundImage\r
136         Rectangle clientArea = splash.getDisplay().getClientArea();\r
137         //System.out.println("client area: " + clientArea);\r
138         final Image backgroundImage = new Image(splash.getDisplay(), clientArea.width, clientArea.height);\r
139         GC gc = new GC(splash.getDisplay());\r
140         gc.copyArea(backgroundImage, 0, 0);\r
141         gc.dispose();\r
142 \r
143         // Combine the splash screen with the background\r
144         final Image newSplashBackground = new Image(splash.getDisplay(), size.x, size.y);\r
145         GC gc2 = new GC(newSplashBackground);\r
146         gc2.drawImage(backgroundImage, pt.x, pt.y, size.x, size.y, 0, 0, size.x, size.y);\r
147         gc2.drawImage(splashImage, 0, 0);\r
148         gc2.dispose();\r
149 \r
150         // Screenshot no longer needed\r
151         backgroundImage.dispose();\r
152 \r
153         Region r = new Region();\r
154         Rectangle r2 = splashImage.getBounds();\r
155         r.add(r2);\r
156         splash.setRegion(r);\r
157 \r
158         // Switch shell background image, dispose the old one.\r
159         Image old = splash.getBackgroundImage();\r
160         splash.setBackgroundImage(newSplashBackground);\r
161         currentBackground = newSplashBackground;\r
162         if (old != null)\r
163             old.dispose();\r
164     }\r
165 \r
166     /**\r
167      * Takes a screenshot of the desktop and uses that as the background of the\r
168      * splash as currentBackground.\r
169      * \r
170      * @param splash\r
171      */\r
172     private void updateBackground2(Shell splash) {\r
173         //System.out.println("Screenshotting");\r
174         Point size = splash.getSize();\r
175         Point pt = splash.getLocation();\r
176         //System.out.println("location: " + pt + ", size: " + size);\r
177 \r
178         splash.setRegion(new Region());\r
179 \r
180         // Get screenshot into backgroundImage\r
181         Rectangle clientArea = splash.getDisplay().getClientArea();\r
182         //System.out.println("client area: " + clientArea);\r
183         final Image backgroundImage = new Image(splash.getDisplay(), clientArea.width, clientArea.height);\r
184         GC gc = new GC(splash.getDisplay());\r
185         gc.copyArea(backgroundImage, 0, 0);\r
186         gc.dispose();\r
187 \r
188         // Combine the splash screen with the background\r
189         final Image newSplashBackground = new Image(splash.getDisplay(), size.x, size.y);\r
190         GC gc2 = new GC(newSplashBackground);\r
191         gc2.drawImage(backgroundImage, pt.x, pt.y, size.x, size.y, 0, 0, size.x, size.y);\r
192         gc2.dispose();\r
193 \r
194         // Screenshot no longer needed\r
195         backgroundImage.dispose();\r
196 \r
197         Region r = new Region();\r
198         Rectangle r2 = newSplashBackground.getBounds();\r
199         r.add(r2);\r
200         splash.setRegion(r);\r
201 \r
202         // Switch shell background image, dispose the old one.\r
203         Image old = splash.getBackgroundImage();\r
204         splash.setBackgroundImage(newSplashBackground);\r
205         currentBackground = newSplashBackground;\r
206         if (old != null)\r
207             old.dispose();\r
208     }\r
209 \r
210     private void initializeBackground(Shell splash) {\r
211         Point size = splash.getSize();\r
212         Point pt = splash.getLocation();\r
213         //System.out.println("location: " + pt + ", size: " + size);\r
214 \r
215         // Combine the splash screen with the background\r
216         Image newSplashBackground = new Image(splash.getDisplay(), size.x, size.y);\r
217         ImageData imgData = newSplashBackground.getImageData();\r
218         imgData.alpha = 0;\r
219 \r
220         Region r = new Region();\r
221         Rectangle r2 = splashImage.getBounds();\r
222         Rectangle r3 = new Rectangle(r2.x, r2.y, r2.width, r2.height);\r
223         r.add(r3);\r
224         splash.setRegion(r);\r
225 \r
226         // Switch shell background image, dispose the old one.\r
227         splash.setBackgroundImage(newSplashBackground);\r
228         currentBackground = newSplashBackground;\r
229     }\r
230 \r
231     @Override\r
232     public void dispose() {\r
233         super.dispose();\r
234 \r
235         // Destroy images\r
236         if (splashImage != null)\r
237             splashImage.dispose();\r
238         if (currentBackground != null)\r
239             currentBackground.dispose();\r
240     }\r
241 \r
242     /*\r
243      * (non-Javadoc)\r
244      * \r
245      * @see org.eclipse.ui.splash.AbstractSplashHandler#init(org.eclipse.swt.widgets.Shell)\r
246      */\r
247     public void init(final Shell splash) {\r
248 \r
249         super.init(splash);\r
250 \r
251         ImageDescriptor splashDesc = Activator.getImageDescriptor(SPLASH_IMAGE);\r
252         if (splashDesc == null) {\r
253             // If splash-image is not available, do nothing.\r
254             return;\r
255         }\r
256         splashImage  = splashDesc.createImage();\r
257 //        System.out.println("logo bounds: " + i.getBounds());\r
258 \r
259         splash.setSize(splashImage.getBounds().width, splashImage.getBounds().height);\r
260 //        splash.setRegion(new Region());\r
261 \r
262         Point pt = splash.getLocation();\r
263         pt.x -= splashImage.getBounds().width/2;\r
264         pt.y -= splashImage.getBounds().height/2;\r
265         splash.setLocation(pt);\r
266 \r
267 //        updateSplashImage(splash);\r
268         updateBackground2(splash);\r
269         //initializeSplash(splash);\r
270         state = state.ok();\r
271 \r
272 //      Configure the shell layout\r
273         configureUISplash();\r
274 //      Create UI\r
275         createUI();\r
276 //      Create UI listeners\r
277         createUIListeners();\r
278 //      Force the splash screen to layout\r
279         splash.layout(true);\r
280 //      Keep the splash screen visible and prevent the RCP application from \r
281 //      loading until the close button is clicked.\r
282         doEventLoop();\r
283     }\r
284 \r
285     /**\r
286      * \r
287      */\r
288     private void doEventLoop() {\r
289         final Shell splash = getSplash();\r
290 //        while (fAuthenticated == false) {\r
291         \r
292         // Make sure that the splash doesn't block program startup when it is\r
293         // hidden.\r
294         watchdogTimer.schedule(new TimerTask() {\r
295             @Override\r
296             public void run() {\r
297                 // Terminate the timer and complete the fade.\r
298 //                System.out.println("watchdog");\r
299                 watchdogTimer.cancel();\r
300                 fadeComplete = true;\r
301             }\r
302         }, FADE_TIME_MS + 50);\r
303 \r
304         while (!fadeComplete) {\r
305             if (splash.getDisplay().readAndDispatch() == false) {\r
306                 // Cannot use Display.sleep because it may not wake up until the\r
307                 // window receives events which will not happen if the window is\r
308                 // not visible.\r
309 //                splash.getDisplay().sleep();\r
310                 try {\r
311                     Thread.sleep(5);\r
312                 } catch (InterruptedException e) {\r
313                     e.printStackTrace();\r
314                 }\r
315             }\r
316         }\r
317         splash.redraw();\r
318         while (splash.getDisplay().readAndDispatch());\r
319 \r
320 //        System.out.println("ENDING EVENT LOOP");\r
321     }\r
322 \r
323     /**\r
324      * \r
325      */\r
326     private void createUIListeners() {\r
327         // Update the translucency\r
328         /*\r
329         for (int in : new int[] { SWT.Activate, SWT.Deactivate, SWT.Show, SWT.Hide, SWT.Iconify, SWT.Deiconify }) {\r
330             getSplash().addListener(in, new Listener() {\r
331                 @Override\r
332                 public void handleEvent(Event event) {\r
333                     int type = event.type;\r
334 //                    System.out.println("[" + state + "][" + event.time + "] event: " + type);\r
335 //                    System.out.flush();\r
336                     \r
337 //                    switch (state) {\r
338 //                        case OK:\r
339 //                            if (type == SWT.Deactivate) {\r
340 //                                state = state.dirty();\r
341 //                            }\r
342 //                            break;\r
343 //                            \r
344 //                        case DIRTY:\r
345 //                            if (type == SWT.Activate) {\r
346 //                                state = state.updated();\r
347 //                                updateSplashImage(getSplash());\r
348 //                            }\r
349 //                            break;\r
350 //                        case UPDATED:\r
351 //                            if (type == SWT.Activate) {\r
352 //                                state = state.ok();\r
353 //                            }\r
354 //                            break;\r
355 //                        default:\r
356 //                    }\r
357                 }\r
358             });\r
359         }\r
360         */\r
361 \r
362         fCompositeLogin.addListener(SWT.Paint, new Listener() {\r
363             @Override\r
364             public void handleEvent(Event event) {\r
365                 // Time elapsed in milliseconds from the beginning of the fade.\r
366                 float timeElapsed = 0;\r
367                 if (fadeStartTime == 0) {\r
368                     fadeStartTime = System.currentTimeMillis();\r
369                 } else {\r
370                     timeElapsed = (System.currentTimeMillis() - fadeStartTime);\r
371                 }\r
372                 int fade = Math.min(255, (int) Math.round(255f * timeElapsed / (float) FADE_TIME_MS));\r
373                 if (fade >= 255) {\r
374                     fadeComplete = true;\r
375                 }\r
376                 \r
377                 GC gc = event.gc;\r
378                 gc.drawImage(currentBackground, 0, 0);\r
379                 gc.setAlpha(fade);\r
380                 gc.drawImage(splashImage, 0, 0);\r
381                 \r
382                 if (!fadeComplete) {\r
383                     getSplash().getDisplay().timerExec(25, new Runnable() {\r
384                         @Override\r
385                         public void run() {\r
386                             Shell s = getSplash();\r
387                             if (s != null && !s.isDisposed()) {\r
388                                 Point size = s.getSize();\r
389                                 s.redraw(0,0, size.x, size.y, true);\r
390                             }\r
391                         }\r
392                     });\r
393                 }\r
394             }\r
395         });\r
396 \r
397         // Create the OK button listeners\r
398 //        createUIListenersButtonOK();\r
399         // Create the cancel button listeners\r
400 //        createUIListenersButtonCancel();\r
401     }\r
402 \r
403     /**\r
404      * \r
405      */\r
406     private void createUIListenersButtonCancel() {\r
407         fButtonCancel.addSelectionListener(new SelectionAdapter() {\r
408             public void widgetSelected(SelectionEvent e) {\r
409                 handleButtonCancelWidgetSelected();\r
410             }\r
411         });\r
412     }\r
413 \r
414     /**\r
415      * \r
416      */\r
417     private void handleButtonCancelWidgetSelected() {\r
418         // Abort the loading of the RCP application\r
419         getSplash().getDisplay().close();\r
420         System.exit(0);\r
421     }\r
422 \r
423     /**\r
424      * configureUISplash\r
425      */\r
426     private void createUIListenersButtonOK() {\r
427         fButtonOK.addSelectionListener(new SelectionAdapter() {\r
428             public void widgetSelected(SelectionEvent e) {\r
429                 handleButtonOKWidgetSelected();\r
430             }\r
431         });\r
432     }\r
433 \r
434     /**\r
435      * \r
436      */\r
437     private void handleButtonOKWidgetSelected() {\r
438         String username = fTextUsername.getText();\r
439         String password = fTextPassword.getText();\r
440         // Aunthentication is successful if a user provides any username and\r
441         // any password\r
442         if ((username.length() > 0) &&\r
443                 (password.length() > 0)) {\r
444             fAuthenticated = true;\r
445         } else {\r
446             MessageDialog.openError(\r
447                     getSplash(),\r
448                     "Authentication Failed",  //NON-NLS-1\r
449             "A username and password must be specified to login.");  //NON-NLS-1\r
450         }\r
451     }\r
452 \r
453     /**\r
454      * \r
455      */\r
456     private void createUI() {\r
457         // Create the login panel\r
458         createUICompositeLogin();\r
459         // Create the blank spanner\r
460         //createUICompositeBlank();\r
461         // Create the user name label\r
462         //createUILabelUserName();\r
463         // Create the user name text widget\r
464         //createUITextUserName();\r
465         // Create the password label\r
466         //createUILabelPassword();\r
467         // Create the password text widget\r
468         //createUITextPassword();\r
469         // Create the blank label\r
470         //createUILabelBlank();\r
471         // Create the OK button\r
472         //createUIButtonOK();\r
473         // Create the cancel button\r
474         //createUIButtonCancel();\r
475     }\r
476 \r
477     /**\r
478      * \r
479      */\r
480     private void createUIButtonCancel() {\r
481         // Create the button\r
482         fButtonCancel = new Button(fCompositeLogin, SWT.PUSH);\r
483         fButtonCancel.setText("Cancel"); //NON-NLS-1\r
484         // Configure layout data\r
485         GridData data = new GridData(SWT.NONE, SWT.NONE, false, false);\r
486         data.widthHint = F_BUTTON_WIDTH_HINT;   \r
487         data.verticalIndent = 10;\r
488         fButtonCancel.setLayoutData(data);\r
489     }\r
490 \r
491     /**\r
492      * \r
493      */\r
494     private void createUIButtonOK() {\r
495         // Create the button\r
496         fButtonOK = new Button(fCompositeLogin, SWT.PUSH);\r
497         fButtonOK.setText("OK"); //NON-NLS-1\r
498         // Configure layout data\r
499         GridData data = new GridData(SWT.NONE, SWT.NONE, false, false);\r
500         data.widthHint = F_BUTTON_WIDTH_HINT;\r
501         data.verticalIndent = 10;\r
502         fButtonOK.setLayoutData(data);\r
503     }\r
504 \r
505     /**\r
506      * \r
507      */\r
508     private void createUILabelBlank() {\r
509         Label label = new Label(fCompositeLogin, SWT.NONE);\r
510         label.setVisible(false);\r
511     }\r
512 \r
513     /**\r
514      * \r
515      */\r
516     private void createUITextPassword() {\r
517         // Create the text widget\r
518         int style = SWT.PASSWORD | SWT.BORDER;\r
519         fTextPassword = new Text(fCompositeLogin, style);\r
520         // Configure layout data\r
521         GridData data = new GridData(SWT.NONE, SWT.NONE, false, false);\r
522         data.widthHint = F_TEXT_WIDTH_HINT;\r
523         data.horizontalSpan = 2;\r
524         fTextPassword.setLayoutData(data);\r
525     }\r
526 \r
527     /**\r
528      * \r
529      */\r
530     private void createUILabelPassword() {\r
531         // Create the label\r
532         Label label = new Label(fCompositeLogin, SWT.NONE);\r
533         label.setText("&Password:"); //NON-NLS-1\r
534         // Configure layout data\r
535         GridData data = new GridData();\r
536         data.horizontalIndent = F_LABEL_HORIZONTAL_INDENT;\r
537         label.setLayoutData(data);\r
538     }\r
539 \r
540     /**\r
541      * \r
542      */\r
543     private void createUITextUserName() {\r
544         // Create the text widget\r
545         fTextUsername = new Text(fCompositeLogin, SWT.BORDER);\r
546         // Configure layout data\r
547         GridData data = new GridData(SWT.NONE, SWT.NONE, false, false);\r
548         data.widthHint = F_TEXT_WIDTH_HINT;\r
549         data.horizontalSpan = 2;\r
550         fTextUsername.setLayoutData(data);\r
551     }\r
552 \r
553     /**\r
554      * \r
555      */\r
556     private void createUILabelUserName() {\r
557         // Create the label\r
558         Label label = new Label(fCompositeLogin, SWT.NONE);\r
559         label.setText("&User Name:"); //NON-NLS-1\r
560         // Configure layout data\r
561         GridData data = new GridData();\r
562         data.horizontalIndent = F_LABEL_HORIZONTAL_INDENT;\r
563         label.setLayoutData(data);              \r
564     }\r
565 \r
566     /**\r
567      * \r
568      */\r
569     private void createUICompositeBlank() {\r
570         Composite spanner = new Composite(fCompositeLogin, SWT.NONE);\r
571         GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);\r
572         data.horizontalSpan = F_COLUMN_COUNT;\r
573         spanner.setLayoutData(data);\r
574     }\r
575 \r
576     /**\r
577      * \r
578      */\r
579     private void createUICompositeLogin() {\r
580         // Create the composite\r
581 //        fCompositeLogin = new Composite(getSplash(), SWT.NONE);\r
582         fCompositeLogin = new Canvas(getSplash(), SWT.DOUBLE_BUFFERED);\r
583         GridLayout layout = new GridLayout(F_COLUMN_COUNT, false);\r
584         fCompositeLogin.setLayout(layout);\r
585     }\r
586 \r
587     /**\r
588      * \r
589      */\r
590     private void configureUISplash() {\r
591         // Configure layout\r
592         FillLayout layout = new FillLayout(); \r
593         getSplash().setLayout(layout);\r
594         // Force shell to inherit the splash background\r
595         getSplash().setBackgroundMode(SWT.INHERIT_DEFAULT);\r
596     }\r
597 \r
598 }\r