I Want To Tell You a Story II

So, the story. Well, the story is still progressing. It’s wandered off into a tangent involving the installation of GeSHi and an attempt at finding a new home for examples that aren’t destined for the build. I will show example code now but there are fully functioning example projects that will be made available just as soon as they have a home.

Example 1: An Interactive Splash

Perhaps you want to use the splash screen as a log in screen. The code for such a splash handler might look something like this:

/*******************************************************************************
 * Copyright (c) 2007 IBM Corporation and others. 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: IBM Corporation - initial API and
 * implementation
 ******************************************************************************/
 
package org.eclipse.ui.examples.splash;
 
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.VerifyEvent;
import org.eclipse.swt.events.VerifyListener;
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.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.splash.AbstractSplashHandler;
 
/**
 * @since 3.3
 * 
 */
public class InteractiveSplashHandler
    extends
    AbstractSplashHandler {
  /*
   * (non-Javadoc)
   * 
   * @see
   * org.eclipse.ui.splash.AbstractSplashHandler#init(org
   * .eclipse.swt.widgets .Shell)
   */
  public void init(final Shell splash) {
    super.init(splash);
    splash.setLayout(new FillLayout());
    // make our composite inherit the splash background
    splash.setBackgroundMode(SWT.INHERIT_DEFAULT);
 
    final String[] username = new String[1], password = new String[1];
    final boolean[] loggedIn = new boolean[] { false };
    Composite panel = new Composite(splash, SWT.BORDER);
    panel.setLayout(new GridLayout(2, false));
    {
      Composite spanner = new Composite(panel, SWT.NONE);
      GridData data = new GridData(SWT.FILL, SWT.FILL,
          true, true);
      data.horizontalSpan = 2;
      spanner.setLayoutData(data);
    }
    {
      Label label = new Label(panel, SWT.NONE);
      label.setText("Name:"); //$NON-NLS-1$
      final Text text = new Text(panel, SWT.BORDER);
      text.addVerifyListener(new VerifyListener() {
 
        public void verifyText(VerifyEvent e) {
          username[0] = e.text;
        }
      });
      text.setLayoutData(new GridData(SWT.FILL, SWT.FILL,
          true, false));
    }
    {
      Label label = new Label(panel, SWT.NONE);
      label.setText("Password:"); //$NON-NLS-1$
      final Text text = new Text(panel, SWT.PASSWORD
          | SWT.BORDER);
      text.addVerifyListener(new VerifyListener() {
 
        public void verifyText(VerifyEvent e) {
          password[0] = e.text;
        }
      });
      text.setLayoutData(new GridData(SWT.FILL, SWT.FILL,
          true, false));
    }
    {
      Button logIn = new Button(panel, SWT.PUSH);
      logIn.setText("Log In"); //$NON-NLS-1$
      logIn.setLayoutData(new GridData(SWT.FILL, SWT.FILL,
          true, false, 2, 1));
      logIn.addSelectionListener(new SelectionAdapter() {
        /*
         * (non-Javadoc)
         * 
         * @seeorg.eclipse.swt.events.SelectionAdapter#
         * widgetSelected(org.eclipse
         * .swt.events.SelectionEvent)
         */
        public void widgetSelected(SelectionEvent e) {
          if (username[0] != null
              && !username[0].equals("") //$NON-NLS-1$
              && password[0] != null 
              && !password[0].equals("")) { //$NON-NLS-1$
            loggedIn[0] = true;
          } else {
            MessageDialog
                .openError(
                    splash,
                    "Could not Authenticate", "There was a problem logging in."); //$NON-NLS-1$//$NON-NLS-2$
          }
        }
 
      });
    }
    {
      Button quit = new Button(panel, SWT.PUSH);
      quit.setText("Quit"); //$NON-NLS-1$
      quit.setLayoutData(new GridData(SWT.FILL, SWT.FILL,
          true, false, 2, 1));
      quit.addSelectionListener(new SelectionAdapter() {
        /*
         * (non-Javadoc)
         * 
         * @seeorg.eclipse.swt.events.SelectionAdapter#
         * widgetSelected(org.eclipse
         * .swt.events.SelectionEvent)
         */
        public void widgetSelected(SelectionEvent e) {
          // quick and dirty exit. If people really need
          // this feature
          // we can talk about new API to abort startup down
          // the road
          splash.getDisplay().close();
          System.exit(0);
        }
 
      });
    }
    // layout the new controls
    splash.layout(true);
 
    // spin the loop until we're logged in
    while (loggedIn[0] == false) {
      if (!splash.getDisplay().readAndDispatch()) {
        splash.getDisplay().sleep();
      }
    }
  }
}

Resulting in:

Example 2: A Browser Splash

Perhaps there is some elaborate flash content you want to show in your browser. The code could look something like this. Note that while the code only points to static old eclipse.org I have tested this with flash animation. Having your Eclipse come up to the tune of “I’ve Got a Big Bag of Crabs” is priceless.

/*******************************************************************************
 * Copyright (c) 2007 IBM Corporation and others. 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: IBM Corporation - initial API and
 * implementation
 ******************************************************************************/
 
package org.eclipse.ui.examples.splash;
 
import org.eclipse.swt.SWT;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.browser.ProgressEvent;
import org.eclipse.swt.browser.ProgressListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.splash.AbstractSplashHandler;
 
/**
 * @since 3.3
 * 
 */
public class BrowserSplashHandler
    extends
    AbstractSplashHandler {
 
  private boolean movieLoaded = false, done = false;
 
  /*
   * (non-Javadoc)
   * 
   * @see
   * org.eclipse.ui.internal.splash.AbstractSplashHandler
   * #init(org.eclipse.swt.widgets.Shell,
   * org.eclipse.ui.IWorkbench)
   */
  public void init(final Shell splash) {
    super.init(splash);
    splash.setLayout(new GridLayout(1, true));
    final Browser browser = new Browser(splash, SWT.NONE);
    browser.setLayoutData(new GridData(SWT.FILL, SWT.FILL,
        true, true));
    final Button button = new Button(splash, SWT.PUSH);
    button.setText("Press to close"); //$NON-NLS-1$
    button.setBounds(570 / 2 - button.computeSize(
        SWT.DEFAULT, SWT.DEFAULT).x / 2,
        splash.getSize().y - 20, splash.getSize().x, 20);
    button.setVisible(false);
    button.setLayoutData(new GridData(SWT.CENTER, SWT.FILL,
        false, false));
    browser.addProgressListener(new ProgressListener() {
 
      public void changed(ProgressEvent event) {
      }
 
      public void completed(ProgressEvent event) {
        movieLoaded = true;
        button.setVisible(true);
        button
            .addSelectionListener(new SelectionListener() {
 
              public void widgetDefaultSelected(
                  SelectionEvent e) {
 
              }
 
              public void widgetSelected(SelectionEvent e) {
                done = true;
              }
            });
      }
    });
    browser.setUrl("http://eclipse.org"); //$NON-NLS-1$		
    splash.layout(true);
    while (!movieLoaded)
      while (getSplash().getDisplay().readAndDispatch())
        ;
  }
 
  /*
   * (non-Javadoc)
   * 
   * @see
   * org.eclipse.ui.internal.splash.AbstractSplashHandler
   * #endSplash()
   */
  public void dispose() {
    getSplash().setActive();
    if (movieLoaded) {
      while (!done)
        getSplash().getDisplay().readAndDispatch();
    }
    super.dispose();
  }
}

Resulting in:

Example 3: An Extensible Splash

Perhaps you want to have a splash screen that plug-ins can contribute to via an extension mechanism. The code for this may look something like the following:

/*******************************************************************************
 * Copyright (c) 2007 IBM Corporation and others. 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: IBM Corporation - initial API and
 * implementation
 ******************************************************************************/
 
package org.eclipse.ui.examples.splash;
 
import java.util.ArrayList;
import java.util.Iterator;
 
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.eclipse.ui.splash.AbstractSplashHandler;
 
public class ExtensibleSplashHandler
    extends
    AbstractSplashHandler {
  private ArrayList list = new ArrayList();
 
  public void init(Shell splash) {
    super.init(splash);
    IExtension[] extensions = Platform
        .getExtensionRegistry()
        .getExtensionPoint(
            "org.eclipse.ui.examples.splash.splashExtension")
        .getExtensions();
 
    ArrayList tooltips = new ArrayList();
    for (int i = 0; i < extensions.length; i++) {
      IExtension extension = extensions[i];
      IConfigurationElement[] elements = extension
          .getConfigurationElements();
      for (int j = 0; j < elements.length; j++) {
        IConfigurationElement configurationElement = elements[j];
        String iconName = configurationElement
            .getAttribute("icon");
        if (iconName == null)
          continue;
        ImageDescriptor imageDesc = AbstractUIPlugin
            .imageDescriptorFromPlugin(configurationElement
                .getNamespaceIdentifier(), iconName);
        Image image = imageDesc.createImage();
        if (image.getBounds().width != 50
            || image.getBounds().height != 50)
          image.dispose();
        else {
          list.add(image);
          tooltips.add(configurationElement
              .getAttribute("tooltip"));
        }
      }
    }
    if (list.isEmpty())
      return;
 
    // determine the number of images we can show per row
    int numPerRow = splash.getSize().x / 50;
 
    Composite iconPanel = new Composite(splash, SWT.NONE);
    iconPanel.setBackground(splash.getDisplay()
        .getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));
    GridLayout gridLayout = new GridLayout(Math.min(list
        .size(), numPerRow), true);
    gridLayout.horizontalSpacing = gridLayout.verticalSpacing = gridLayout.marginHeight = gridLayout.marginWidth = 0;
    iconPanel.setLayout(gridLayout);
    for (Iterator i = list.iterator(), k = tooltips
        .iterator(); i.hasNext();) {
      Image image = (Image) i.next();
      Label label = new Label(iconPanel, SWT.NONE);
      label.setImage(image);
      label.setToolTipText((String) k.next());
    }
    // create a new background panel to avoid scaling
    Composite backgroundPanel = new Composite(splash,
        SWT.NONE);
    backgroundPanel.setBackgroundImage(splash
        .getBackgroundImage());
    backgroundPanel.setBounds(0, 0, splash.getSize().x,
        splash.getSize().y);
 
    // determine the size for the new icon panel and
    // position it at the
    // bottom of the splash.
    Point panelSize = iconPanel.computeSize(SWT.DEFAULT,
        SWT.DEFAULT, true);
    iconPanel.setBounds(splash.getSize().x / 2
        - panelSize.x / 2, splash.getSize().y, panelSize.x,
        panelSize.y);
 
    // resize the splash to contain the icon panel
    splash.setSize(splash.getSize().x, splash.getSize().y
        + panelSize.y);
    iconPanel.layout(true);
    iconPanel.update();
 
    while (iconPanel.getDisplay().readAndDispatch())
      ;
  }
 
  public void dispose() {
    super.dispose();
    if (!list.isEmpty())
      for (Iterator i = list.iterator(); i.hasNext();) {
        Image image = (Image) i.next();
        image.dispose();
      }
  }
}

Resulting in:

This entry was posted in Eclipse. Bookmark the permalink. Follow any comments here with the RSS feed for this post. Both comments and trackbacks are currently closed.

14 thoughts on “I Want To Tell You a Story II

  1. Wayne

    That’s just friggin’ great. Now I’m going to be humming “I’ve got a big bag of crabs” all night. I sure hope that you’re happy.

  2. AlBlue

    This is really neat. I mentioned it to Neil who’s doing a talk on Eclipse JAAS and I hope he’s able to utilise this splash screen to put some code behind that login splash … that would be really cool.

  3. Min

    This looks really cool. My suggestion is that maybe by default the splash screen can display some of the “feature icons” that you can see at the help->about dialog. That way you can see what other add-ins you have installed on top of the Eclipse platform base.

  4. pookzilla

    min: we were discussing that very idea last year but thought it was a bit excessive for the platform. We preferred to focus on the API and let any downstream clients tackle that problem.

  5. Anonymous

    This look awesome. Is there an example with the progressbar. I am trying to have one but i kept getting swt exception invalid thread access

  6. Anonymous

    Hello,

    Great article !!

    What I want, is a mix between your first solution (Interactive Splash) and the BasicSplashHandler class that display the progress and text messages. Do You have any idea ?

    Thank You

    Laurent

  7. Anonymous

    Integrated splash screen, login window and startup progress looks great!

    Would it be possible to have the splash screen window visible in the windows task bar once the splash handler kicks in? With login implemented as a splash handler the user have to minimize all windows to access the login window.

  8. David

    Hello,
    I try to integrate JAAS with the login splash screen, but there is a problem, because with “org.eclipse.ui.splashHandlers” extension point the application start before the authentification. Whereas with JAAS we have the authentification and then we launch the application according to the authentification data. And I need to have the authentification before as I load/unload dynamically plugins.
    Do you know how we can use both?

    Thanks,
    David.

  9. David

    Hello,
    I find a solution to unload my plugin before my application starts. Indeed, I unload my plugins in the method preWindowOpen() in the class ApplicationWorkbenchWindowAdvisor. My plugins are unloaded without error and I can have my authentification before the unload.

    I hope that can help somenone.
    David

  10. Iain

    Hi, thanks for the article. Have you come across the following: the interactive splash screen works fine in the IDE, but when I export it as a product, the splash screen is no longer interactive, moreover, the file plugin.xml is rewritten.

    Iain

Comments are closed.

  • About Me

    Hi! My name is Kimberly Horne and I have absolutely nothing interesting to say. Unfortunately for you I DO have an overpowering need to tinker with technology which is explains the presence of this journal. I mostly talk about games (video and tabletop), technology, tattoos, and my pets.

    If you're an Eclipse user you may find my Eclipse category more interesting.

    Similarly, if you're an Arduino nerd then maybe my projects might be of interest.

    Since I've discovered Twitter this journal has been neglected somewhat. If you really want to stalk me your best bet is to follow me on twitter.