catch up with development

Signed-off-by: Ralf Mollik <ramollik@compex-commerce.com>
diff --git a/org.mihalis.opal/META-INF/MANIFEST.MF b/org.mihalis.opal/META-INF/MANIFEST.MF
index 2a062fc..2bbcee4 100644
--- a/org.mihalis.opal/META-INF/MANIFEST.MF
+++ b/org.mihalis.opal/META-INF/MANIFEST.MF
@@ -49,6 +49,10 @@
  org.mihalis.opal.transitionComposite,
  org.mihalis.opal.utils
 Require-Bundle: org.eclipse.swt;bundle-version="3.7.2",
- org.eclipse.osbp.gitinfo;bundle-version="[0.9.0,0.10.0)"
+ org.eclipse.osbp.gitinfo;bundle-version="[0.9.0,0.10.0)",
+ org.slf4j.api,
+ org.eclipse.core.runtime;bundle-version="3.12.0"
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Import-Package: org.osgi.framework
+Import-Package: org.apache.commons.io,
+ org.eclipse.osbp.utils.themes.ui;version="0.9.0",
+ org.osgi.framework
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/imageSelector/ISItem.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/imageSelector/ISItem.java
index de0a946..e60a940 100644
--- a/org.mihalis.opal/src/main/java/org/mihalis/opal/imageSelector/ISItem.java
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/imageSelector/ISItem.java
@@ -10,10 +10,19 @@
  *******************************************************************************/
 package org.mihalis.opal.imageSelector;
 
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+import org.apache.commons.io.FilenameUtils;
 import org.eclipse.swt.graphics.Image;
 import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Display;
 import org.mihalis.opal.OpalItem;
 import org.mihalis.opal.utils.SWTGraphicUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * Instances of this class represents items manipulated by the ImageSelector
@@ -30,6 +39,13 @@
 	/** The lower right corner. */
 	private Point lowerRightCorner;
 
+	private Image swtImage;
+
+	private URL url;
+
+	/** The Constant LOGGER. */
+	private static final Logger LOGGER = LoggerFactory.getLogger( ISItem.class );
+
 	/**
 	 * Constructor.
 	 *
@@ -62,6 +78,50 @@
 	}
 
 	/**
+	 * Constructor.
+	 *
+	 * @param imgFile
+	 *            the img file
+	 */
+	public ISItem(final File imgFile) {
+		try (InputStream is = imgFile.toURI().toURL().openStream()) {
+			swtImage = new Image( Display.getCurrent(), is );
+			setImage( swtImage );
+			setText(FilenameUtils.removeExtension(imgFile.getName()));
+			setUrl(imgFile.toURI().toURL());
+		} catch (IOException e) {
+			LOGGER.error(e.getLocalizedMessage());
+		}
+
+	}
+	
+	/**
+	 * Dispose SWT image.
+	 */
+	public void dispose () {
+		swtImage.dispose();
+	}
+
+	/**
+	 * Gets the url.
+	 *
+	 * @return the url
+	 */
+	public URL getUrl() {
+		return url;
+	}
+
+	/**
+	 * Sets the url.
+	 *
+	 * @param url
+	 *            the new url
+	 */
+	public void setUrl(URL url) {
+		this.url = url;
+	}
+
+	/**
 	 * Gets the z position.
 	 *
 	 * @return the zPosition
@@ -148,7 +208,8 @@
 	 */
 	@Override
 	public int compareTo(final ISItem o) {
-		return new Double(Math.abs(zPosition)).compareTo(Math.abs(o.getzPosition())) * -1;
+//		return new Double(Math.abs(zPosition)).compareTo(Math.abs(o.getzPosition())) * -1;
+		return this.getText().compareTo(o.getText());
 	}
 
 	/**
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/imageSelector/ImageSelector.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/imageSelector/ImageSelector.java
index 8cf7d58..a4a8e9b 100644
--- a/org.mihalis.opal/src/main/java/org/mihalis/opal/imageSelector/ImageSelector.java
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/imageSelector/ImageSelector.java
@@ -10,10 +10,19 @@
  *******************************************************************************/
 package org.mihalis.opal.imageSelector;
 
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.net.URI;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.LinkedList;
 import java.util.List;
+import java.util.Set;
 
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.osbp.utils.themes.ui.VaaclipseUiTheme;
+import org.eclipse.osbp.utils.themes.ui.VaaclipseUiTheme.ThemeList;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.SWTException;
 import org.eclipse.swt.events.KeyAdapter;
@@ -34,6 +43,8 @@
 import org.eclipse.swt.widgets.Event;
 import org.eclipse.swt.widgets.Listener;
 import org.mihalis.opal.utils.SWTGraphicUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * Instances of this class are controls that allow the user to select images.
@@ -59,6 +70,8 @@
 	
 	/** The Constant DEFAULT_WIDTH. */
 	private static final int DEFAULT_WIDTH = 148;
+
+	public static final int WIDTH_FACTOR = 3;
 	
 	/** The max item width. */
 	private int maxItemWidth = DEFAULT_WIDTH;
@@ -102,6 +115,16 @@
 	/** The cached gc. */
 	private GC cachedGC;
 
+	private String imagePlatformPath;
+
+	private String imageName;
+
+	// to avoid stupid actions from xtext
+	boolean firstAction = true;
+
+	/** The Constant LOGGER. */
+	private static final Logger LOGGER = LoggerFactory.getLogger( ImageSelector.class );
+
 	/**
 	 * Constructs a new instance of this class given its parent and a style
 	 * value describing its behavior and appearance.
@@ -129,11 +152,13 @@
 	 *                </ul>
 	 *
 	 */
-	public ImageSelector(final Composite parent, final int style) {
+	public ImageSelector(final Composite parent, final int style, final int defaultWidth) {
 		super(parent, style | SWT.NO_BACKGROUND | SWT.DOUBLE_BUFFERED);
 		final Font defaultFont = new Font(getDisplay(), "Lucida Sans", 24, SWT.NONE);
 		font = defaultFont;
 		SWTGraphicUtil.addDisposer(this, defaultFont);
+		
+		maxItemWidth = defaultWidth * WIDTH_FACTOR;
 
 		setSigma(0.5);
 		gradientStart = getDisplay().getSystemColor(SWT.COLOR_BLACK);
@@ -193,18 +218,26 @@
 					scrollAndAnimateBy(1);
 					break;
 				case SWT.HOME:
-					scrollBy(-1 * index);
+					scrollBy(-1 * ImageSelector.this.index);
 					break;
 				case SWT.END:
-					scrollBy(index);
+					scrollBy(ImageSelector.this.index);
 					break;
 				case SWT.PAGE_UP:
-					scrollBy(-1 * pageIncrement);
+					scrollBy(-1 * ImageSelector.this.pageIncrement);
 					break;
 				case SWT.PAGE_DOWN:
-					scrollBy(pageIncrement);
+					scrollBy(ImageSelector.this.pageIncrement);
 					break;
+				case SWT.KEYPAD_CR:
+				case SWT.CR:
+					if (!firstAction) {
+						selectImage();
+					}
+					break;
+				default: scrollToItem(Character.toString(e.character));
 				}
+				firstAction = false;
 			}
 		});
 	}
@@ -325,6 +358,10 @@
 
 		// Draw the offscreen buffer to the screen
 		e.gc.drawImage(cachedImage, 0, 0);
+		
+		cachedGC.dispose();
+		cachedImage.dispose();
+		cachedImage = null;
 	}
 
 	/**
@@ -512,6 +549,35 @@
 
 	}
 
+	
+	/**
+	 * Scrolls to an item in {@link #items} whose name
+	 * starts with the given prefix.
+	 * @param prefix the prefix
+	 */
+	private void scrollToItem(String prefix){
+		int idx = findIndexOfFirstItemWithStartingName(prefix);
+		if(idx != -1) {
+			this.index = idx;
+			redraw();
+		}
+	}
+	
+	/**
+	 * Returns the index of the first item element whose names
+	 * starts with the given prefix. 
+	 * @param prefix the prefix
+	 * @return the item index or -1 if none is found
+	 */
+	private int findIndexOfFirstItemWithStartingName(String prefix){
+		for(ISItem item : ImageSelector.this.items){
+			if(item.getText().startsWith(prefix)){
+				return ImageSelector.this.items.indexOf(item);
+			}
+		}
+		return -1;
+	}
+
 	/**
 	 * Gets the items.
 	 *
@@ -534,6 +600,64 @@
 	}
 
 	/**
+	 * Sets the items.
+	 *
+	 * @param filterExtensions
+	 *            the new items
+	 */
+	public void setItems(final String [] filterExtensions) {
+		// Create the list of images
+		final List<ISItem> items = new LinkedList<ISItem>();
+		URI iconsUri = null;
+		Set<VaaclipseUiTheme> themes = VaaclipseUiTheme.values(ThemeList.forProduct);
+		for (VaaclipseUiTheme vaaclipseUiTheme : themes) {
+			if(vaaclipseUiTheme.hasIconsUri()) {
+				iconsUri = vaaclipseUiTheme.getIconsUri();
+				break;
+			}
+		}
+		if(iconsUri == null) {
+			LOGGER.error("no theme provider bundle found");
+			return;
+		}
+		try {
+			File pathFolder = new File(FileLocator.toFileURL(iconsUri.toURL()).getPath());
+			if (pathFolder.isDirectory()) {
+				File[] imgFiles = pathFolder.listFiles(new FilenameFilter() {
+					public boolean accept(File dir, String filename) {
+						for (int i = 0; i < filterExtensions.length; i++) {
+							boolean fileNameFound = filename.endsWith(filterExtensions[i]);
+							if (fileNameFound) return fileNameFound;
+						}
+						return false;
+					}
+				});
+				if	( imgFiles != null ) {
+					for (File imgFile : imgFiles) {
+						items.add( new ISItem(imgFile));
+					}
+				}
+			}
+			setItems(items);
+		} catch (IOException e) {
+			LOGGER.error(e.getLocalizedMessage()+e.getCause().getLocalizedMessage());
+		}
+	}
+
+	/**
+	 * Disposes all SWT-items within CCISItem-list {@literal}items. Clears list
+	 * afterwards.
+	 *
+	 * @return void
+	 */
+	public void clearItems () {
+		for ( ISItem item : this.items ) {
+			item.dispose();
+		}
+		this.items.clear();
+	}
+
+	/**
 	 * Gets the font.
 	 *
 	 * @return the font used for the title
@@ -676,4 +800,39 @@
 		this.pageIncrement = pageIncrement;
 	}
 
+	/**
+	 * Select image.
+	 */
+	private void selectImage() {
+		int idx = ImageSelector.this.index;
+
+		try {
+			ISItem isItem = ImageSelector.this.originalItems.get(idx);
+			imagePlatformPath = isItem.getUrl().toString();
+			imageName = isItem.getText();
+			getParent().dispose();
+		} catch (IndexOutOfBoundsException e) {
+			// do nothing
+			e.printStackTrace();	// NOSONAR
+			LOGGER.warn( String.format( "selectImage(): no index %d in originalItems", idx ), e );
+		}
+	}
+	
+	/**
+	 * Gets the image platform path.
+	 *
+	 * @return the image platform path
+	 */
+	public String getImagePlatformPath() {
+		return imagePlatformPath;
+	}
+
+	/**
+	 * Gets the image name.
+	 *
+	 * @return the image name
+	 */
+	public String getImageName() {
+		return imageName;
+	}
 }
diff --git a/org.mihalis.opal/src/main/java/org/mihalis/opal/imageSelector/ImageSelectorDialog.java b/org.mihalis.opal/src/main/java/org/mihalis/opal/imageSelector/ImageSelectorDialog.java
new file mode 100644
index 0000000..75268e3
--- /dev/null
+++ b/org.mihalis.opal/src/main/java/org/mihalis/opal/imageSelector/ImageSelectorDialog.java
@@ -0,0 +1,195 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2012 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.mihalis.opal.imageSelector;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.widgets.Dialog;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * Instances of this class allow the user to navigate the file system and select
+ * or enter a file name.
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>SAVE, OPEN, MULTI</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>(none)</dd>
+ * </dl>
+ * <p>
+ * Note: Only one of the styles SAVE and OPEN may be specified.
+ * </p>
+ * <p>
+ * IMPORTANT: This class is <em>not</em> intended to be subclassed.
+ * </p>
+ * 
+ * @see <a href="http://www.eclipse.org/swt/snippets/#filedialog">FileDialog
+ *      snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example:
+ *      ControlExample, Dialog tab</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further
+ *      information</a>
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+public class ImageSelectorDialog extends Dialog {
+	
+	/** The image width. */
+	int imageWidth;
+	
+	/** The filter extensions. */
+	String[] filterExtensions = new String[0];
+
+	/**
+	 * Constructs a new instance of this class given only its parent.
+	 *
+	 * @param parent
+	 *            a shell which will be the parent of the new instance
+	 * @param imageWidth
+	 *            the image width
+	 * @exception IllegalArgumentException
+	 *                <ul>
+	 *                <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+	 *                </ul>
+	 * @exception SWTException
+	 *                <ul>
+	 *                <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+	 *                thread that created the parent</li>
+	 *                <li>ERROR_INVALID_SUBCLASS - if this class is not an
+	 *                allowed subclass</li>
+	 *                </ul>
+	 */
+	public ImageSelectorDialog(Shell parent, int imageWidth) {
+		this(parent, SWT.APPLICATION_MODAL, imageWidth);
+	}
+
+	/**
+	 * Constructs a new instance of this class given its parent and a style
+	 * value describing its behavior and appearance.
+	 * <p>
+	 * The style value is either one of the style constants defined in class
+	 * <code>SWT</code> which is applicable to instances of this class, or must
+	 * be built by <em>bitwise OR</em>'ing together (that is, using the
+	 * <code>int</code> "|" operator) two or more of those <code>SWT</code>
+	 * style constants. The class description lists the style constants that are
+	 * applicable to the class. Style bits are also inherited from superclasses.
+	 * </p>
+	 *
+	 * @param parent
+	 *            a shell which will be the parent of the new instance
+	 * @param style
+	 *            the style of dialog to construct
+	 * @param imageWidth
+	 *            the image width
+	 * @see SWT#SAVE
+	 * @see SWT#OPEN
+	 * @see SWT#MULTI
+	 * @exception IllegalArgumentException
+	 *                <ul>
+	 *                <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+	 *                </ul>
+	 * @exception SWTException
+	 *                <ul>
+	 *                <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+	 *                thread that created the parent</li>
+	 *                <li>ERROR_INVALID_SUBCLASS - if this class is not an
+	 *                allowed subclass</li>
+	 *                </ul>
+	 */
+	public ImageSelectorDialog(Shell parent, int style, int imageWidth) {
+		super(parent, style);
+		this.imageWidth = imageWidth;
+	}
+
+	/**
+	 * Returns the file extensions which the dialog will use to filter the files
+	 * it shows.
+	 *
+	 * @return the file extensions filter
+	 */
+	public String[] getFilterExtensions() {
+		return filterExtensions;
+	}
+
+	/**
+	 * Makes the dialog visible and brings it to the front of the display.
+	 *
+	 * @return a string describing the absolute path of the first selected file,
+	 *         or null if the dialog was cancelled or an error occurred
+	 *
+	 * @exception SWTException
+	 *                <ul>
+	 *                <li>ERROR_WIDGET_DISPOSED - if the dialog has been
+	 *                disposed</li>
+	 *                <li>ERROR_THREAD_INVALID_ACCESS - if not called from the
+	 *                thread that created the dialog</li>
+	 *                </ul>
+	 */
+	public String open() {
+		return open(false);
+	}
+	
+	/**
+	 * Open.
+	 *
+	 * @param returnSimpleName
+	 *            the return simple name
+	 * @return the string
+	 */
+	public String open(boolean returnSimpleName) {
+		/* Make the parent shell be temporary modal */
+		Display display = getParent().getDisplay();
+
+		/*
+		 * Open the dialog.
+		 */
+		final ImageSelector imageSelector = new ImageSelector(getParent(),
+				getStyle(), imageWidth);
+		imageSelector.setItems(filterExtensions);
+
+		// Open the shell
+		getParent().setSize(6*ImageSelector.WIDTH_FACTOR*imageWidth, 3*ImageSelector.WIDTH_FACTOR*imageWidth);
+		getParent().open();
+		while (!getParent().isDisposed()) {
+			if (!display.readAndDispatch()) {
+				display.sleep();
+			}
+		}
+
+		imageSelector.clearItems();
+
+		if (returnSimpleName) {
+			return imageSelector.getImageName();
+		} else {
+			return imageSelector.getImagePlatformPath();
+		}
+	}
+
+	/**
+	 * Set the file extensions which the dialog will use to filter the files it
+	 * shows to the argument, which may be null.
+	 * <p>
+	 * The strings are platform specific. For example, on some platforms, an
+	 * extension filter string is typically of the form "*.extension", where
+	 * "*.*" matches all files. For filters with multiple extensions, use
+	 * semicolon as a separator, e.g. "*.jpg;*.png".
+	 * </p>
+	 *
+	 * @param extensions
+	 *            the file extension filter
+	 * 
+	 * @see #setFilterNames to specify the user-friendly names corresponding to
+	 *      the extensions
+	 */
+	public void setFilterExtensions(String[] extensions) {
+		filterExtensions = extensions;
+	}
+}
diff --git a/org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/ImageSelectorSnippet.java b/org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/ImageSelectorSnippet.java
index 776aaf0..9da67fc 100644
--- a/org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/ImageSelectorSnippet.java
+++ b/org.mihalis.opal/src/test/java/org/mihalis/opal/imageSelector/ImageSelectorSnippet.java
@@ -40,7 +40,7 @@
 		items.add(new ISItem("Shivaree", "org/mihalis/opal/imageSelector/images/Shivaree.jpg"));
 		items.add(new ISItem("Sin City", "org/mihalis/opal/imageSelector/images/Sin City.jpg"));
 
-		final ImageSelector imageSelector = new ImageSelector(shell, SWT.NONE);
+		final ImageSelector imageSelector = new ImageSelector(shell, SWT.NONE, 148);
 		imageSelector.setItems(items);
 
 		// Open the shell