--- /dev/null
+package net.mograsim.rcp.splashhandlers;
+
+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;
+
+/**
+ * @since 3.3
+ *
+ */
+public class ExtensibleSplashHandler extends AbstractSplashHandler
+{
+
+ private ArrayList<Image> fImageList;
+
+ private ArrayList<String> fTooltipList;
+
+ private static final String F_SPLASH_EXTENSION_ID = "Sample.splashExtension"; // NON-NLS-1
+
+ private static final String F_ELEMENT_ICON = "icon"; // NON-NLS-1
+
+ private static final String F_ELEMENT_TOOLTIP = "tooltip"; // NON-NLS-1
+
+ private static final String F_DEFAULT_TOOLTIP = "Image"; // NON-NLS-1
+
+ private static final int F_IMAGE_WIDTH = 50;
+
+ private static final int F_IMAGE_HEIGHT = 50;
+
+ private static final int F_SPLASH_SCREEN_BEVEL = 5;
+
+ private Composite fIconPanel;
+
+ /**
+ *
+ */
+ public ExtensibleSplashHandler()
+ {
+ fImageList = new ArrayList<>();
+ fTooltipList = new ArrayList<>();
+ fIconPanel = null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.ui.splash.AbstractSplashHandler#init(org.eclipse.swt.widgets. Shell)
+ */
+ @Override
+ public void init(Shell splash)
+ {
+ // Store the shell
+ super.init(splash);
+ // Configure the shell layout
+ configureUISplash();
+ // Load all splash extensions
+ loadSplashExtensions();
+ // If no splash extensions were loaded abort the splash handler
+ if (!hasSplashExtensions())
+ {
+ return;
+ }
+ // Create UI
+ createUI();
+ // Configure the image panel bounds
+ configureUICompositeIconPanelBounds();
+ // Enter event loop and prevent the RCP application from
+ // loading until all work is done
+ doEventLoop();
+ }
+
+ /**
+ * @return
+ */
+ private boolean hasSplashExtensions()
+ {
+ return !fImageList.isEmpty();
+ }
+
+ /**
+ *
+ */
+ private void createUI()
+ {
+ // Create the icon panel
+ createUICompositeIconPanel();
+ // Create the images
+ createUIImages();
+ }
+
+ /**
+ *
+ */
+ private void createUIImages()
+ {
+ Iterator<Image> imageIterator = fImageList.iterator();
+ Iterator<String> tooltipIterator = fTooltipList.iterator();
+ int i = 1;
+ int columnCount = ((GridLayout) fIconPanel.getLayout()).numColumns;
+ // Create all the images
+ // Abort if we run out of columns (left-over images will not fit within
+ // the usable splash screen width)
+ while (imageIterator.hasNext() && (i <= columnCount))
+ {
+ Image image = imageIterator.next();
+ String tooltip = tooltipIterator.next();
+ // Create the image using a label widget
+ createUILabel(image, tooltip);
+ i++;
+ }
+ }
+
+ /**
+ * @param image
+ * @param tooltip
+ */
+ private void createUILabel(Image image, String tooltip)
+ {
+ // Create the label (no text)
+ Label label = new Label(fIconPanel, SWT.NONE);
+ label.setImage(image);
+ label.setToolTipText(tooltip);
+ }
+
+ /**
+ *
+ */
+ private void createUICompositeIconPanel()
+ {
+ Shell splash = getSplash();
+ // Create the composite
+ fIconPanel = new Composite(splash, SWT.NONE);
+ // Determine the maximum number of columns that can fit on the splash
+ // screen. One 50x50 image per column.
+ int maxColumnCount = getUsableSplashScreenWidth() / F_IMAGE_WIDTH;
+ // Limit size to the maximum number of columns if the number of images
+ // exceed this amount; otherwise, use the exact number of columns
+ // required.
+ int actualColumnCount = Math.min(fImageList.size(), maxColumnCount);
+ // Configure the layout
+ GridLayout layout = new GridLayout(actualColumnCount, true);
+ layout.horizontalSpacing = 0;
+ layout.verticalSpacing = 0;
+ layout.marginHeight = 0;
+ layout.marginWidth = 0;
+ fIconPanel.setLayout(layout);
+ }
+
+ /**
+ *
+ */
+ private void configureUICompositeIconPanelBounds()
+ {
+ // Determine the size of the panel and position it at the bottom-right
+ // of the splash screen.
+ Point panelSize = fIconPanel.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
+
+ int xCoord = getSplash().getSize().x - F_SPLASH_SCREEN_BEVEL - panelSize.x;
+ int yCoord = getSplash().getSize().y - F_SPLASH_SCREEN_BEVEL - panelSize.y;
+ int xWidth = panelSize.x;
+ int yWidth = panelSize.y;
+
+ fIconPanel.setBounds(xCoord, yCoord, xWidth, yWidth);
+ }
+
+ /**
+ * @return
+ */
+ private int getUsableSplashScreenWidth()
+ {
+ // Splash screen width minus two graphic border bevel widths
+ return getSplash().getSize().x - (F_SPLASH_SCREEN_BEVEL * 2);
+ }
+
+ /**
+ *
+ */
+ private void loadSplashExtensions()
+ {
+ // Get all splash handler extensions
+ IExtension[] extensions = Platform.getExtensionRegistry().getExtensionPoint(F_SPLASH_EXTENSION_ID).getExtensions();
+ // Process all splash handler extensions
+ for (int i = 0; i < extensions.length; i++)
+ {
+ processSplashExtension(extensions[i]);
+ }
+ }
+
+ /**
+ * @param extension
+ */
+ private void processSplashExtension(IExtension extension)
+ {
+ // Get all splash handler configuration elements
+ IConfigurationElement[] elements = extension.getConfigurationElements();
+ // Process all splash handler configuration elements
+ for (int j = 0; j < elements.length; j++)
+ {
+ processSplashElements(elements[j]);
+ }
+ }
+
+ /**
+ * @param configurationElement
+ */
+ private void processSplashElements(IConfigurationElement configurationElement)
+ {
+ // Attribute: icon
+ processSplashElementIcon(configurationElement);
+ // Attribute: tooltip
+ processSplashElementTooltip(configurationElement);
+ }
+
+ /**
+ * @param configurationElement
+ */
+ private void processSplashElementTooltip(IConfigurationElement configurationElement)
+ {
+ // Get attribute tooltip
+ String tooltip = configurationElement.getAttribute(F_ELEMENT_TOOLTIP);
+ // If a tooltip is not defined, give it a default
+ if ((tooltip == null) || (tooltip.length() == 0))
+ {
+ fTooltipList.add(F_DEFAULT_TOOLTIP);
+ } else
+ {
+ fTooltipList.add(tooltip);
+ }
+ }
+
+ /**
+ * @param configurationElement
+ */
+ private void processSplashElementIcon(IConfigurationElement configurationElement)
+ {
+ // Get attribute icon
+ String iconImageFilePath = configurationElement.getAttribute(F_ELEMENT_ICON);
+ // Abort if an icon attribute was not specified
+ if ((iconImageFilePath == null) || (iconImageFilePath.length() == 0))
+ {
+ return;
+ }
+ // Create a corresponding image descriptor
+ ImageDescriptor descriptor = AbstractUIPlugin.imageDescriptorFromPlugin(configurationElement.getNamespaceIdentifier(),
+ iconImageFilePath);
+ // Abort if no corresponding image was found
+ if (descriptor == null)
+ {
+ return;
+ }
+ // Create the image
+ Image image = descriptor.createImage();
+ // Abort if image creation failed
+ if (image == null)
+ {
+ return;
+ }
+ // Abort if the image does not have dimensions of 50x50
+ if ((image.getBounds().width != F_IMAGE_WIDTH) || (image.getBounds().height != F_IMAGE_HEIGHT))
+ {
+ // Dipose of the image
+ image.dispose();
+ return;
+ }
+ // Store the image and tooltip
+ fImageList.add(image);
+ }
+
+ /**
+ *
+ */
+ private void configureUISplash()
+ {
+ // Configure layout
+ GridLayout layout = new GridLayout(1, true);
+ getSplash().setLayout(layout);
+ // Force shell to inherit the splash background
+ getSplash().setBackgroundMode(SWT.INHERIT_DEFAULT);
+ }
+
+ /**
+ *
+ */
+ private void doEventLoop()
+ {
+ Shell splash = getSplash();
+ if (!splash.getDisplay().readAndDispatch())
+ {
+ splash.getDisplay().sleep();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.ui.splash.AbstractSplashHandler#dispose()
+ */
+ @Override
+ public void dispose()
+ {
+ super.dispose();
+ // Check to see if any images were defined
+ if ((fImageList == null) || fImageList.isEmpty())
+ {
+ return;
+ }
+ // Dispose of all the images
+ Iterator<Image> iterator = fImageList.iterator();
+ while (iterator.hasNext())
+ {
+ Image image = iterator.next();
+ image.dispose();
+ }
+ }
+}