--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ * VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+\r
+package org.simantics.workbench.splashHandlers;\r
+\r
+import java.util.Timer;\r
+import java.util.TimerTask;\r
+\r
+import org.eclipse.jface.dialogs.MessageDialog;\r
+import org.eclipse.jface.resource.ImageDescriptor;\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.events.SelectionAdapter;\r
+import org.eclipse.swt.events.SelectionEvent;\r
+import org.eclipse.swt.graphics.GC;\r
+import org.eclipse.swt.graphics.Image;\r
+import org.eclipse.swt.graphics.ImageData;\r
+import org.eclipse.swt.graphics.Point;\r
+import org.eclipse.swt.graphics.Rectangle;\r
+import org.eclipse.swt.graphics.Region;\r
+import org.eclipse.swt.layout.FillLayout;\r
+import org.eclipse.swt.layout.GridData;\r
+import org.eclipse.swt.layout.GridLayout;\r
+import org.eclipse.swt.widgets.Button;\r
+import org.eclipse.swt.widgets.Canvas;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.swt.widgets.Event;\r
+import org.eclipse.swt.widgets.Label;\r
+import org.eclipse.swt.widgets.Listener;\r
+import org.eclipse.swt.widgets.Shell;\r
+import org.eclipse.swt.widgets.Text;\r
+import org.eclipse.ui.splash.AbstractSplashHandler;\r
+import org.simantics.workbench.internal.Activator;\r
+\r
+\r
+/**\r
+ * @since 3.3\r
+ */\r
+@SuppressWarnings("unused")\r
+public class InteractiveSplashHandler extends AbstractSplashHandler {\r
+\r
+ private static final String SPLASH_IMAGE = "simantics.png";\r
+\r
+ private final static int FADE_TIME_MS = 250;\r
+\r
+ private final static int F_LABEL_HORIZONTAL_INDENT = 10;\r
+\r
+ private final static int F_BUTTON_WIDTH_HINT = 80;\r
+\r
+ private final static int F_TEXT_WIDTH_HINT = 175;\r
+\r
+ private final static int F_COLUMN_COUNT = 3;\r
+\r
+ private Composite fCompositeLogin;\r
+\r
+ private Text fTextUsername;\r
+\r
+ private Text fTextPassword;\r
+\r
+ private Button fButtonOK;\r
+\r
+ private Button fButtonCancel;\r
+\r
+ private boolean fAuthenticated;\r
+\r
+ private Image splashImage;\r
+\r
+ private Image currentBackground;\r
+\r
+ private long fadeStartTime = 0;\r
+\r
+ private boolean fadeComplete = false;\r
+\r
+ private Timer watchdogTimer = new Timer("splash-watchdog");\r
+\r
+ enum State {\r
+ INIT,\r
+ OK,\r
+ DIRTY,\r
+ UPDATED,\r
+ ;\r
+ State ok() {\r
+// System.out.println(this + " -> " + OK);\r
+ return OK;\r
+ }\r
+ State dirty() {\r
+// System.out.println(this + " -> " + DIRTY);\r
+ return DIRTY;\r
+ }\r
+ State updated() {\r
+// if (this != DIRTY) {\r
+// System.err.println("ERROR: transition from " + this + " to " + DIRTY);\r
+// }\r
+// System.out.println(this + " -> " + UPDATED);\r
+ return UPDATED;\r
+ }\r
+ }\r
+\r
+ private State state = State.INIT;\r
+\r
+ /**\r
+ * \r
+ */\r
+ public InteractiveSplashHandler() {\r
+ fCompositeLogin = null;\r
+ fTextUsername = null;\r
+ fTextPassword = null;\r
+ fButtonOK = null;\r
+ fButtonCancel = null;\r
+ fAuthenticated = false;\r
+ }\r
+\r
+ /**\r
+ * Takes a screenshot of the desktop and blends the splash screen PNG image\r
+ * on top of it. The blended result is then set as currentBackground.\r
+ * \r
+ * @param splash\r
+ */\r
+ private void updateBackground1(Shell splash) {\r
+// System.out.println("Screenshotting");\r
+ Point size = splash.getSize();\r
+ Point pt = splash.getLocation();\r
+ //System.out.println("location: " + pt + ", size: " + size);\r
+\r
+ splash.setRegion(new Region());\r
+\r
+ // Get screenshot into backgroundImage\r
+ Rectangle clientArea = splash.getDisplay().getClientArea();\r
+ //System.out.println("client area: " + clientArea);\r
+ final Image backgroundImage = new Image(splash.getDisplay(), clientArea.width, clientArea.height);\r
+ GC gc = new GC(splash.getDisplay());\r
+ gc.copyArea(backgroundImage, 0, 0);\r
+ gc.dispose();\r
+\r
+ // Combine the splash screen with the background\r
+ final Image newSplashBackground = new Image(splash.getDisplay(), size.x, size.y);\r
+ GC gc2 = new GC(newSplashBackground);\r
+ gc2.drawImage(backgroundImage, pt.x, pt.y, size.x, size.y, 0, 0, size.x, size.y);\r
+ gc2.drawImage(splashImage, 0, 0);\r
+ gc2.dispose();\r
+\r
+ // Screenshot no longer needed\r
+ backgroundImage.dispose();\r
+\r
+ Region r = new Region();\r
+ Rectangle r2 = splashImage.getBounds();\r
+ r.add(r2);\r
+ splash.setRegion(r);\r
+\r
+ // Switch shell background image, dispose the old one.\r
+ Image old = splash.getBackgroundImage();\r
+ splash.setBackgroundImage(newSplashBackground);\r
+ currentBackground = newSplashBackground;\r
+ if (old != null)\r
+ old.dispose();\r
+ }\r
+\r
+ /**\r
+ * Takes a screenshot of the desktop and uses that as the background of the\r
+ * splash as currentBackground.\r
+ * \r
+ * @param splash\r
+ */\r
+ private void updateBackground2(Shell splash) {\r
+ //System.out.println("Screenshotting");\r
+ Point size = splash.getSize();\r
+ Point pt = splash.getLocation();\r
+ //System.out.println("location: " + pt + ", size: " + size);\r
+\r
+ splash.setRegion(new Region());\r
+\r
+ // Get screenshot into backgroundImage\r
+ Rectangle clientArea = splash.getDisplay().getClientArea();\r
+ //System.out.println("client area: " + clientArea);\r
+ final Image backgroundImage = new Image(splash.getDisplay(), clientArea.width, clientArea.height);\r
+ GC gc = new GC(splash.getDisplay());\r
+ gc.copyArea(backgroundImage, 0, 0);\r
+ gc.dispose();\r
+\r
+ // Combine the splash screen with the background\r
+ final Image newSplashBackground = new Image(splash.getDisplay(), size.x, size.y);\r
+ GC gc2 = new GC(newSplashBackground);\r
+ gc2.drawImage(backgroundImage, pt.x, pt.y, size.x, size.y, 0, 0, size.x, size.y);\r
+ gc2.dispose();\r
+\r
+ // Screenshot no longer needed\r
+ backgroundImage.dispose();\r
+\r
+ Region r = new Region();\r
+ Rectangle r2 = newSplashBackground.getBounds();\r
+ r.add(r2);\r
+ splash.setRegion(r);\r
+\r
+ // Switch shell background image, dispose the old one.\r
+ Image old = splash.getBackgroundImage();\r
+ splash.setBackgroundImage(newSplashBackground);\r
+ currentBackground = newSplashBackground;\r
+ if (old != null)\r
+ old.dispose();\r
+ }\r
+\r
+ private void initializeBackground(Shell splash) {\r
+ Point size = splash.getSize();\r
+ Point pt = splash.getLocation();\r
+ //System.out.println("location: " + pt + ", size: " + size);\r
+\r
+ // Combine the splash screen with the background\r
+ Image newSplashBackground = new Image(splash.getDisplay(), size.x, size.y);\r
+ ImageData imgData = newSplashBackground.getImageData();\r
+ imgData.alpha = 0;\r
+\r
+ Region r = new Region();\r
+ Rectangle r2 = splashImage.getBounds();\r
+ Rectangle r3 = new Rectangle(r2.x, r2.y, r2.width, r2.height);\r
+ r.add(r3);\r
+ splash.setRegion(r);\r
+\r
+ // Switch shell background image, dispose the old one.\r
+ splash.setBackgroundImage(newSplashBackground);\r
+ currentBackground = newSplashBackground;\r
+ }\r
+\r
+ @Override\r
+ public void dispose() {\r
+ super.dispose();\r
+\r
+ // Destroy images\r
+ if (splashImage != null)\r
+ splashImage.dispose();\r
+ if (currentBackground != null)\r
+ currentBackground.dispose();\r
+ }\r
+\r
+ /*\r
+ * (non-Javadoc)\r
+ * \r
+ * @see org.eclipse.ui.splash.AbstractSplashHandler#init(org.eclipse.swt.widgets.Shell)\r
+ */\r
+ public void init(final Shell splash) {\r
+\r
+ super.init(splash);\r
+\r
+ ImageDescriptor splashDesc = Activator.getImageDescriptor(SPLASH_IMAGE);\r
+ if (splashDesc == null) {\r
+ // If splash-image is not available, do nothing.\r
+ return;\r
+ }\r
+ splashImage = splashDesc.createImage();\r
+// System.out.println("logo bounds: " + i.getBounds());\r
+\r
+ splash.setSize(splashImage.getBounds().width, splashImage.getBounds().height);\r
+// splash.setRegion(new Region());\r
+\r
+ Point pt = splash.getLocation();\r
+ pt.x -= splashImage.getBounds().width/2;\r
+ pt.y -= splashImage.getBounds().height/2;\r
+ splash.setLocation(pt);\r
+\r
+// updateSplashImage(splash);\r
+ updateBackground2(splash);\r
+ //initializeSplash(splash);\r
+ state = state.ok();\r
+\r
+// Configure the shell layout\r
+ configureUISplash();\r
+// Create UI\r
+ createUI();\r
+// Create UI listeners\r
+ createUIListeners();\r
+// Force the splash screen to layout\r
+ splash.layout(true);\r
+// Keep the splash screen visible and prevent the RCP application from \r
+// loading until the close button is clicked.\r
+ doEventLoop();\r
+ }\r
+\r
+ /**\r
+ * \r
+ */\r
+ private void doEventLoop() {\r
+ final Shell splash = getSplash();\r
+// while (fAuthenticated == false) {\r
+ \r
+ // Make sure that the splash doesn't block program startup when it is\r
+ // hidden.\r
+ watchdogTimer.schedule(new TimerTask() {\r
+ @Override\r
+ public void run() {\r
+ // Terminate the timer and complete the fade.\r
+// System.out.println("watchdog");\r
+ watchdogTimer.cancel();\r
+ fadeComplete = true;\r
+ }\r
+ }, FADE_TIME_MS + 50);\r
+\r
+ while (!fadeComplete) {\r
+ if (splash.getDisplay().readAndDispatch() == false) {\r
+ // Cannot use Display.sleep because it may not wake up until the\r
+ // window receives events which will not happen if the window is\r
+ // not visible.\r
+// splash.getDisplay().sleep();\r
+ try {\r
+ Thread.sleep(5);\r
+ } catch (InterruptedException e) {\r
+ e.printStackTrace();\r
+ }\r
+ }\r
+ }\r
+ splash.redraw();\r
+ while (splash.getDisplay().readAndDispatch());\r
+\r
+// System.out.println("ENDING EVENT LOOP");\r
+ }\r
+\r
+ /**\r
+ * \r
+ */\r
+ private void createUIListeners() {\r
+ // Update the translucency\r
+ /*\r
+ for (int in : new int[] { SWT.Activate, SWT.Deactivate, SWT.Show, SWT.Hide, SWT.Iconify, SWT.Deiconify }) {\r
+ getSplash().addListener(in, new Listener() {\r
+ @Override\r
+ public void handleEvent(Event event) {\r
+ int type = event.type;\r
+// System.out.println("[" + state + "][" + event.time + "] event: " + type);\r
+// System.out.flush();\r
+ \r
+// switch (state) {\r
+// case OK:\r
+// if (type == SWT.Deactivate) {\r
+// state = state.dirty();\r
+// }\r
+// break;\r
+// \r
+// case DIRTY:\r
+// if (type == SWT.Activate) {\r
+// state = state.updated();\r
+// updateSplashImage(getSplash());\r
+// }\r
+// break;\r
+// case UPDATED:\r
+// if (type == SWT.Activate) {\r
+// state = state.ok();\r
+// }\r
+// break;\r
+// default:\r
+// }\r
+ }\r
+ });\r
+ }\r
+ */\r
+\r
+ fCompositeLogin.addListener(SWT.Paint, new Listener() {\r
+ @Override\r
+ public void handleEvent(Event event) {\r
+ // Time elapsed in milliseconds from the beginning of the fade.\r
+ float timeElapsed = 0;\r
+ if (fadeStartTime == 0) {\r
+ fadeStartTime = System.currentTimeMillis();\r
+ } else {\r
+ timeElapsed = (System.currentTimeMillis() - fadeStartTime);\r
+ }\r
+ int fade = Math.min(255, (int) Math.round(255f * timeElapsed / (float) FADE_TIME_MS));\r
+ if (fade >= 255) {\r
+ fadeComplete = true;\r
+ }\r
+ \r
+ GC gc = event.gc;\r
+ gc.drawImage(currentBackground, 0, 0);\r
+ gc.setAlpha(fade);\r
+ gc.drawImage(splashImage, 0, 0);\r
+ \r
+ if (!fadeComplete) {\r
+ getSplash().getDisplay().timerExec(25, new Runnable() {\r
+ @Override\r
+ public void run() {\r
+ Shell s = getSplash();\r
+ if (s != null && !s.isDisposed()) {\r
+ Point size = s.getSize();\r
+ s.redraw(0,0, size.x, size.y, true);\r
+ }\r
+ }\r
+ });\r
+ }\r
+ }\r
+ });\r
+\r
+ // Create the OK button listeners\r
+// createUIListenersButtonOK();\r
+ // Create the cancel button listeners\r
+// createUIListenersButtonCancel();\r
+ }\r
+\r
+ /**\r
+ * \r
+ */\r
+ private void createUIListenersButtonCancel() {\r
+ fButtonCancel.addSelectionListener(new SelectionAdapter() {\r
+ public void widgetSelected(SelectionEvent e) {\r
+ handleButtonCancelWidgetSelected();\r
+ }\r
+ });\r
+ }\r
+\r
+ /**\r
+ * \r
+ */\r
+ private void handleButtonCancelWidgetSelected() {\r
+ // Abort the loading of the RCP application\r
+ getSplash().getDisplay().close();\r
+ System.exit(0);\r
+ }\r
+\r
+ /**\r
+ * configureUISplash\r
+ */\r
+ private void createUIListenersButtonOK() {\r
+ fButtonOK.addSelectionListener(new SelectionAdapter() {\r
+ public void widgetSelected(SelectionEvent e) {\r
+ handleButtonOKWidgetSelected();\r
+ }\r
+ });\r
+ }\r
+\r
+ /**\r
+ * \r
+ */\r
+ private void handleButtonOKWidgetSelected() {\r
+ String username = fTextUsername.getText();\r
+ String password = fTextPassword.getText();\r
+ // Aunthentication is successful if a user provides any username and\r
+ // any password\r
+ if ((username.length() > 0) &&\r
+ (password.length() > 0)) {\r
+ fAuthenticated = true;\r
+ } else {\r
+ MessageDialog.openError(\r
+ getSplash(),\r
+ "Authentication Failed", //NON-NLS-1\r
+ "A username and password must be specified to login."); //NON-NLS-1\r
+ }\r
+ }\r
+\r
+ /**\r
+ * \r
+ */\r
+ private void createUI() {\r
+ // Create the login panel\r
+ createUICompositeLogin();\r
+ // Create the blank spanner\r
+ //createUICompositeBlank();\r
+ // Create the user name label\r
+ //createUILabelUserName();\r
+ // Create the user name text widget\r
+ //createUITextUserName();\r
+ // Create the password label\r
+ //createUILabelPassword();\r
+ // Create the password text widget\r
+ //createUITextPassword();\r
+ // Create the blank label\r
+ //createUILabelBlank();\r
+ // Create the OK button\r
+ //createUIButtonOK();\r
+ // Create the cancel button\r
+ //createUIButtonCancel();\r
+ }\r
+\r
+ /**\r
+ * \r
+ */\r
+ private void createUIButtonCancel() {\r
+ // Create the button\r
+ fButtonCancel = new Button(fCompositeLogin, SWT.PUSH);\r
+ fButtonCancel.setText("Cancel"); //NON-NLS-1\r
+ // Configure layout data\r
+ GridData data = new GridData(SWT.NONE, SWT.NONE, false, false);\r
+ data.widthHint = F_BUTTON_WIDTH_HINT; \r
+ data.verticalIndent = 10;\r
+ fButtonCancel.setLayoutData(data);\r
+ }\r
+\r
+ /**\r
+ * \r
+ */\r
+ private void createUIButtonOK() {\r
+ // Create the button\r
+ fButtonOK = new Button(fCompositeLogin, SWT.PUSH);\r
+ fButtonOK.setText("OK"); //NON-NLS-1\r
+ // Configure layout data\r
+ GridData data = new GridData(SWT.NONE, SWT.NONE, false, false);\r
+ data.widthHint = F_BUTTON_WIDTH_HINT;\r
+ data.verticalIndent = 10;\r
+ fButtonOK.setLayoutData(data);\r
+ }\r
+\r
+ /**\r
+ * \r
+ */\r
+ private void createUILabelBlank() {\r
+ Label label = new Label(fCompositeLogin, SWT.NONE);\r
+ label.setVisible(false);\r
+ }\r
+\r
+ /**\r
+ * \r
+ */\r
+ private void createUITextPassword() {\r
+ // Create the text widget\r
+ int style = SWT.PASSWORD | SWT.BORDER;\r
+ fTextPassword = new Text(fCompositeLogin, style);\r
+ // Configure layout data\r
+ GridData data = new GridData(SWT.NONE, SWT.NONE, false, false);\r
+ data.widthHint = F_TEXT_WIDTH_HINT;\r
+ data.horizontalSpan = 2;\r
+ fTextPassword.setLayoutData(data);\r
+ }\r
+\r
+ /**\r
+ * \r
+ */\r
+ private void createUILabelPassword() {\r
+ // Create the label\r
+ Label label = new Label(fCompositeLogin, SWT.NONE);\r
+ label.setText("&Password:"); //NON-NLS-1\r
+ // Configure layout data\r
+ GridData data = new GridData();\r
+ data.horizontalIndent = F_LABEL_HORIZONTAL_INDENT;\r
+ label.setLayoutData(data);\r
+ }\r
+\r
+ /**\r
+ * \r
+ */\r
+ private void createUITextUserName() {\r
+ // Create the text widget\r
+ fTextUsername = new Text(fCompositeLogin, SWT.BORDER);\r
+ // Configure layout data\r
+ GridData data = new GridData(SWT.NONE, SWT.NONE, false, false);\r
+ data.widthHint = F_TEXT_WIDTH_HINT;\r
+ data.horizontalSpan = 2;\r
+ fTextUsername.setLayoutData(data);\r
+ }\r
+\r
+ /**\r
+ * \r
+ */\r
+ private void createUILabelUserName() {\r
+ // Create the label\r
+ Label label = new Label(fCompositeLogin, SWT.NONE);\r
+ label.setText("&User Name:"); //NON-NLS-1\r
+ // Configure layout data\r
+ GridData data = new GridData();\r
+ data.horizontalIndent = F_LABEL_HORIZONTAL_INDENT;\r
+ label.setLayoutData(data); \r
+ }\r
+\r
+ /**\r
+ * \r
+ */\r
+ private void createUICompositeBlank() {\r
+ Composite spanner = new Composite(fCompositeLogin, SWT.NONE);\r
+ GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);\r
+ data.horizontalSpan = F_COLUMN_COUNT;\r
+ spanner.setLayoutData(data);\r
+ }\r
+\r
+ /**\r
+ * \r
+ */\r
+ private void createUICompositeLogin() {\r
+ // Create the composite\r
+// fCompositeLogin = new Composite(getSplash(), SWT.NONE);\r
+ fCompositeLogin = new Canvas(getSplash(), SWT.DOUBLE_BUFFERED);\r
+ GridLayout layout = new GridLayout(F_COLUMN_COUNT, false);\r
+ fCompositeLogin.setLayout(layout);\r
+ }\r
+\r
+ /**\r
+ * \r
+ */\r
+ private void configureUISplash() {\r
+ // Configure layout\r
+ FillLayout layout = new FillLayout(); \r
+ getSplash().setLayout(layout);\r
+ // Force shell to inherit the splash background\r
+ getSplash().setBackgroundMode(SWT.INHERIT_DEFAULT);\r
+ }\r
+\r
+}\r