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