bug 297675: content assist/convert element dialog:
- show as list (instead of as a tree) with icons
- filtering: 'contains' instead of 'start with'
- highlight matching text (in bold)
diff --git a/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/META-INF/MANIFEST.MF b/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/META-INF/MANIFEST.MF
index 0b4e761..46c0955 100644
--- a/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/META-INF/MANIFEST.MF
+++ b/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/META-INF/MANIFEST.MF
@@ -20,7 +20,7 @@
  org.eclipse.wst.xml.core;bundle-version="[1.1.0,2.0.0)",
  org.eclipse.wst.xml.ui;bundle-version="[1.0.0,2.0.0)",
  org.eclipse.emf.ecore;bundle-version="[2.4.1,3.0.0)"
-Export-Package: org.eclipse.wst.xml.vex.ui.internal;x-internal:=true,
+Export-Package: org.eclipse.wst.xml.vex.ui.internal;x-friends:="org.eclipse.wst.xml.vex.ui.tests",
  org.eclipse.wst.xml.vex.ui.internal.config;x-internal:=true,
  org.eclipse.wst.xml.vex.ui.internal.editor;x-internal:=true,
  org.eclipse.wst.xml.vex.ui.internal.handlers;x-internal:=true,
diff --git a/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/icons/convert.gif b/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/icons/convert.gif
new file mode 100644
index 0000000..068e18d
--- /dev/null
+++ b/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/icons/convert.gif
Binary files differ
diff --git a/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/icons/element_obj.gif b/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/icons/element_obj.gif
new file mode 100644
index 0000000..3567815
--- /dev/null
+++ b/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/icons/element_obj.gif
Binary files differ
diff --git a/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/src/org/eclipse/wst/xml/vex/ui/internal/ContentAssist.java b/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/src/org/eclipse/wst/xml/vex/ui/internal/ContentAssist.java
deleted file mode 100644
index 627f48f..0000000
--- a/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/src/org/eclipse/wst/xml/vex/ui/internal/ContentAssist.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2004, 2008 John Krasnay 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:
- *     John Krasnay - initial implementation
- *     Holger Voormann
- *******************************************************************************/
-package org.eclipse.wst.xml.vex.ui.internal;
-
-import org.eclipse.jface.action.IAction;
-import org.eclipse.jface.dialogs.IDialogSettings;
-import org.eclipse.jface.dialogs.PopupDialog;
-import org.eclipse.jface.layout.GridDataFactory;
-import org.eclipse.jface.layout.GridLayoutFactory;
-import org.eclipse.jface.preference.JFacePreferences;
-import org.eclipse.jface.resource.JFaceResources;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.KeyAdapter;
-import org.eclipse.swt.events.KeyEvent;
-import org.eclipse.swt.events.ModifyEvent;
-import org.eclipse.swt.events.ModifyListener;
-import org.eclipse.swt.events.MouseAdapter;
-import org.eclipse.swt.events.MouseEvent;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.graphics.Color;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Text;
-import org.eclipse.swt.widgets.Tree;
-import org.eclipse.swt.widgets.TreeItem;
-import org.eclipse.wst.xml.vex.ui.internal.swt.VexWidget;
-
-/**
- * Content assist dialog that is popped up to show a list of actions to select
- * from. The input field above the list could be used to filter the content.
- */
-public class ContentAssist extends PopupDialog {
-
-	private static final String SETTINGS_SECTION =
-		"contentAssistant"; //$NON-NLS-1$
-
-	private final Point location;
-	private Text textWidget;
-	private Tree treeWidget;
-	private IAction[] actions;
-
-	/**
-	 * Constructs a new content assist dialog which can be opened by
-	 * {@link #open()}.
-	 *
-	 * @param vexWidget the vex widget this content assist belongs to
-	 * @param actions list of actions to select from
-	 * @param title the title of the dialog (e.g. "Add Element" or
-	 *              "Change 'xyz' To")
-	 */
-	public ContentAssist(VexWidget vexWidget, IAction[] actions, String title) {
-		super(vexWidget.getShell(),
-              SWT.RESIZE,
-              true,  // take focus on open
-              true,  // persist size
-              false, // persist location
-              false, // show dialog menu
-              false, // show persist actions
-              title,
-              null);
-		this.actions = actions;
-		location = vexWidget.toDisplay(vexWidget.getLocationForContentAssist());
-	}
-
-	@Override
-	protected IDialogSettings getDialogSettings() {
-		IDialogSettings root = VexPlugin.getInstance().getDialogSettings();
-		IDialogSettings settings = root.getSection(SETTINGS_SECTION);
-		if (settings == null) {
-			settings = root.addNewSection(SETTINGS_SECTION);
-		}
-		return settings;
-	}
-
-	@Override
-	protected Color getBackground() {
-		String colorId = JFacePreferences.CONTENT_ASSIST_BACKGROUND_COLOR;
-		return JFaceResources.getColorRegistry().get(colorId);
-	}
-
-	@Override
-	protected Control createDialogArea(Composite parent) {
-
-		// dialog area panel
-		Composite composite = new Composite(parent, SWT.NONE);
-		GridLayoutFactory.fillDefaults().applyTo(composite);
-
-		// 1. input field
-		textWidget = new Text(composite, SWT.SINGLE);
-		GridDataFactory.fillDefaults().grab(true, false).applyTo(textWidget);
-		textWidget.addModifyListener(new ModifyListener() {
-			public void modifyText(ModifyEvent e) {
-				repopulateList();
-			}
-		});
-		textWidget.addKeyListener(new KeyAdapter() {
-			@Override
-			public void keyPressed(KeyEvent e) {
-				if (e.keyCode == SWT.CR) {
-					doAction();
-				} else if (   e.widget == textWidget
-						   && e.keyCode == SWT.ARROW_DOWN) {
-					treeWidget.setFocus();
-				}
-			}
-		});
-
-		// 2. separator
-		int separatorStyle = SWT.SEPARATOR | SWT.HORIZONTAL | SWT.LINE_DOT;
-		Label separator = new Label(composite, separatorStyle);
-		GridDataFactory.fillDefaults().grab(true, false).applyTo(separator);
-
-		// 3. tree
-		treeWidget = new Tree(composite, SWT.SINGLE);
-		GridDataFactory.fillDefaults().grab(true, true).applyTo(treeWidget);
-		treeWidget.addSelectionListener(new SelectionAdapter() {
-			@Override
-			public void widgetDefaultSelected(SelectionEvent e) {
-				doAction();
-			}
-		});
-		treeWidget.addMouseListener(new MouseAdapter() {
-			@Override
-			public void mouseUp(MouseEvent e) {
-				if (e.button == 1) {
-					doAction();
-				}
-			}
-		});
-
-		// fill with content
-		repopulateList();
-
-		return composite;
-	}
-
-	@Override
-	protected Point getDefaultLocation(Point initialSize) {
-		return location;
-	}
-
-	/**
-	 * Perform the action that is currently selected in the tree view, if any,
-	 * and close the dialog.
-	 */
-	private void doAction() {
-		TreeItem[] items = treeWidget.getSelection();
-		if (items.length > 0) {
-			IAction action = (IAction) items[0].getData();
-			action.run();
-		}
-		close();
-	}
-
-	private void repopulateList() {
-		String prefix = textWidget.getText();
-		treeWidget.removeAll();
-		TreeItem first = null;
-		for (int i = 0; i < actions.length; i++) {
-			IAction action = actions[i];
-			if (action.getText().startsWith(prefix)) {
-				TreeItem item = new TreeItem(treeWidget, SWT.NONE);
-				if (first == null) {
-					first = item;
-				}
-				item.setData(action);
-				item.setText(action.getText());
-			}
-		}
-		if (first != null) {
-			treeWidget.setSelection(new TreeItem[] { first });
-		}
-	}
-
-}
diff --git a/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/src/org/eclipse/wst/xml/vex/ui/internal/Icon.java b/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/src/org/eclipse/wst/xml/vex/ui/internal/Icon.java
new file mode 100644
index 0000000..04e524e
--- /dev/null
+++ b/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/src/org/eclipse/wst/xml/vex/ui/internal/Icon.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Holger Voormann 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:
+ *     Holger Voormann - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xml.vex.ui.internal;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.ImageRegistry;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+/**
+ * This enumeration contains the icons used by this plug-in that are very
+ * frequently used and so need to be globally shared within the plug-in. The
+ * icons are lazy loaded and disposed when the plug-in/bundle is stopped.
+ */
+public enum Icon {
+
+    /** 16x16 icon: XML element (resource). */
+    ELEMENT("icons/element_obj.gif"), //$NON-NLS-1$
+
+    /** 16x16 icon: Convert (action). */
+    CONVERT("icons/convert.gif"); //$NON-NLS-1$
+
+    private final String iconFilePath;
+
+    private Icon(String iconFilePath) {
+        this.iconFilePath = iconFilePath;
+    }
+
+    /**
+     * @param icon the icon to be returned as {@link Image}
+     * @return the specified icon as {@link Image}
+     */
+    public static Image get(Icon icon) {
+        ImageRegistry registry = VexPlugin.getInstance().getImageRegistry();
+        Image value = registry.get(icon.iconFilePath);
+        if (value == null) {
+            ImageDescriptor imageDescriptor =
+                createImageDescriptor(icon.iconFilePath);
+            registry.put(icon.iconFilePath, imageDescriptor);
+            value = registry.get(icon.iconFilePath);
+        }
+        return value;
+    }
+
+    private static ImageDescriptor createImageDescriptor(String filePath) {
+        ImageDescriptor descriptor =
+            AbstractUIPlugin.imageDescriptorFromPlugin(VexPlugin.ID, filePath);
+
+        Assert.isNotNull(descriptor,
+                         "Image file not found: " + filePath); //$NON-NLS-1$
+        return descriptor;
+    }
+
+}
diff --git a/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/src/org/eclipse/wst/xml/vex/ui/internal/VexPlugin.java b/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/src/org/eclipse/wst/xml/vex/ui/internal/VexPlugin.java
index 8b3eda6..8f46620 100644
--- a/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/src/org/eclipse/wst/xml/vex/ui/internal/VexPlugin.java
+++ b/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/src/org/eclipse/wst/xml/vex/ui/internal/VexPlugin.java
@@ -4,7 +4,7 @@
  * 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:
  *     John Krasnay - initial API and implementation
  *******************************************************************************/
@@ -13,7 +13,6 @@
 import org.eclipse.core.resources.IWorkspace;
 import org.eclipse.core.resources.ResourcesPlugin;
 import org.eclipse.core.runtime.Status;
-import org.eclipse.swt.widgets.Display;
 import org.eclipse.ui.plugin.AbstractUIPlugin;
 import org.eclipse.wst.xml.vex.core.internal.core.DisplayDevice;
 import org.eclipse.wst.xml.vex.ui.internal.config.ConfigLoaderJob;
@@ -25,107 +24,76 @@
  */
 public class VexPlugin extends AbstractUIPlugin {
 
-	// The plugin's id
-	public static final String ID = "org.eclipse.wst.xml.vex.ui"; //$NON-NLS-1$
+    /** The plugin's ID */
+    public static final String ID = "org.eclipse.wst.xml.vex.ui"; //$NON-NLS-1$
 
-	/**
-	 * The constructor.
-	 */
-	public VexPlugin() {
+    private static VexPlugin instance;
+
+    /**
+     * Returns the shared instance.
+     */
+    public static VexPlugin getInstance() {
+        return instance;
+    }
+
+    /**
+     * Returns the workspace instance.
+     */
+    public static IWorkspace getWorkspace() {
+        return ResourcesPlugin.getWorkspace();
+    }
+
+    /**
+     * Log an error message without an exception.
+     *
+     * @param severity
+     *            One of the IStatus severity levels, e.g. IStatus.ERROR.
+     * @param message
+     *            Message describing the error.
+     */
+    public void log(int severity, String message) {
+        this.getLog().log(new Status(severity, ID, 0, message, null));
+    }
+
+    /**
+     * Log an error message.
+     *
+     * @param severity One of the IStatus severity levels, e.g. IStatus.ERROR.
+     * @param message Message describing the error.
+     * @param exception exception related to the error, or null if none.
+     */
+    public void log(int severity, String message, Throwable exception) {
+		getLog().log(new Status(severity, ID, 0, message, exception));
+    }
+
+    /**
+     * Override the plugin startup to intialize the resource tracker.
+     */
+    public void start(BundleContext bundleContext) throws Exception {
+        super.start(bundleContext);
         if(instance != null) {
-        	throw new IllegalStateException("This plug-in must be a singleton.");
+            throw new IllegalStateException("This plug-in must be a singleton.");
         }
-		instance = this;
-	}
+        instance = this;
 
-	/**
-	 * Asserts that this method is called from the display thread. If not, an
-	 * IllegalStateException is thrown.
-	 */
-	public static void assertIsDisplayThread() {
-		if (Thread.currentThread() != Display.getDefault().getThread()) {
-			throw new IllegalStateException(
-					"This method must be called from the display thread."); //$NON-NLS-1$
-		}
-	}
+        // TODO Remove DisplayDevice.setCurrent from VexPlugin.start
+        // This has been added to the VexWidget ctor, but the problem is that
+        // when loading an editor, we load the document before creating the
+        // widget, and to do that we need to load the stylesheet, and *this*
+        // needs the DisplayDevice to be set properly.
+        //
+        // One solution might be to do a simplified stylesheet load that only
+        // looks at the display property, which is enough to do space
+        // normalization but doesn't need to look at the display device.
 
-	/**
-	 * Returns the shared instance.
-	 */
-	public static VexPlugin getInstance() {
-		return instance;
-	}
+        DisplayDevice.setCurrent(new SwtDisplayDevice());
 
-	/**
-	 * Returns the workspace instance.
-	 */
-	public static IWorkspace getWorkspace() {
-		return ResourcesPlugin.getWorkspace();
-	}
+        new ConfigLoaderJob().schedule();
+    }
 
-	/**
-	 * Log an error message without an exception.
-	 * 
-	 * @param severity
-	 *            One of the IStatus severity levels, e.g. IStatus.ERROR.
-	 * @param message
-	 *            Message describing the error.
-	 */
-	public void log(int severity, String message) {
-		this.getLog().log(new Status(severity, ID, 0, message, null));
-	}
-
-	/**
-	 * Log an error message.
-	 * 
-	 * @param severity
-	 *            One of the IStatus severity levels, e.g. IStatus.ERROR.
-	 * @param message
-	 *            Message describing the error.
-	 * @param exception
-	 *            Exception related to the error, or null of none.
-	 */
-	public void log(int severity, String message, Throwable exception) {
-		this.getLog().log(
-				new Status(severity,
-						"org.eclipse.wst.xml.vex.ui", 0, message, exception)); //$NON-NLS-1$
-	}
-
-	/**
-	 * Override the plugin startup to intialize the resource tracker.
-	 */
-	public void start(BundleContext bundleContext) throws Exception {
-
-		super.start(bundleContext);
-
-		// TODO Remove DisplayDevice.setCurrent from VexPlugin.start
-		// This has been added to the VexWidget ctor, but the problem is that
-		// when loading an editor, we load the document before creating the
-		// widget, and to do that we need to load the stylesheet, and *this*
-		// needs the DisplayDevice to be set properly.
-		//
-		// One solution might be to do a simplified stylesheet load that only
-		// looks at the display property, which is enough to do space
-		// normalization but doesn't need to look at the display device.
-
-		DisplayDevice.setCurrent(new SwtDisplayDevice());
-
-		// boolean configDebug = this.isDebugging() &&
-		// "true".equalsIgnoreCase(Platform.getDebugOption(ID +
-		// "/debug/config"));
-
-		this.initJob.schedule();
-
-	}
-
-	public void stop(BundleContext context) throws Exception {
-		super.stop(context);
-	}
-
-	// ========================================================= PRIVATE
-
-	private static VexPlugin instance;
-
-	private ConfigLoaderJob initJob = new ConfigLoaderJob();
+    public void stop(BundleContext context) throws Exception {
+    	instance = null;
+        super.stop(context);
+    }
 
 }
diff --git a/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/src/org/eclipse/wst/xml/vex/ui/internal/editor/messages.properties b/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/src/org/eclipse/wst/xml/vex/ui/internal/editor/messages.properties
index 4ea0670..e95f65e 100644
--- a/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/src/org/eclipse/wst/xml/vex/ui/internal/editor/messages.properties
+++ b/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/src/org/eclipse/wst/xml/vex/ui/internal/editor/messages.properties
@@ -5,9 +5,7 @@
 command.removeTag.dynamicName= Remove ''{0}'' Tag
 command.removeTag.inRemoveMenu.dynamicName= ''{0}'' &Tag
 command.convertElement.dynamicName= &Convert ''{0}'' To...
-
-dialog.addElement.title= Add Element
-dialog.convertElement.dynamicTitle= Convert ''{0}''
+command.convertElement.dynamicCommandName= Convert ''{0}'' to ''{1}''
 
 DebugView.noActiveEditor=No Vex editor is currently active.
 
diff --git a/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/src/org/eclipse/wst/xml/vex/ui/internal/handlers/AddElementHandler.java b/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/src/org/eclipse/wst/xml/vex/ui/internal/handlers/AddElementHandler.java
index 0386658..fe7c090 100644
--- a/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/src/org/eclipse/wst/xml/vex/ui/internal/handlers/AddElementHandler.java
+++ b/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/src/org/eclipse/wst/xml/vex/ui/internal/handlers/AddElementHandler.java
@@ -11,9 +11,7 @@
 package org.eclipse.wst.xml.vex.ui.internal.handlers;
 
 import org.eclipse.core.commands.ExecutionException;
-import org.eclipse.jface.action.IAction;
-import org.eclipse.wst.xml.vex.ui.internal.ContentAssist;
-import org.eclipse.wst.xml.vex.ui.internal.editor.Messages;
+import org.eclipse.wst.xml.vex.ui.internal.swt.ContentAssist;
 import org.eclipse.wst.xml.vex.ui.internal.swt.VexWidget;
 
 /**
@@ -21,12 +19,9 @@
  */
 public class AddElementHandler extends AbstractVexWidgetHandler {
 
-	@Override
+    @Override
     public void execute(VexWidget widget) throws ExecutionException {
-		String title = Messages.getString("dialog.addElement.title"); //$NON-NLS-1$
-		IAction[] actions = widget.getValidInsertActions();
-		ContentAssist assist = new ContentAssist(widget, actions, title);
-		assist.open();
+        ContentAssist.openAddElementsContentAssist(widget);
     }
 
 }
diff --git a/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/src/org/eclipse/wst/xml/vex/ui/internal/handlers/ConvertElementHandler.java b/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/src/org/eclipse/wst/xml/vex/ui/internal/handlers/ConvertElementHandler.java
index fe1e2ac..e867599 100644
--- a/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/src/org/eclipse/wst/xml/vex/ui/internal/handlers/ConvertElementHandler.java
+++ b/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/src/org/eclipse/wst/xml/vex/ui/internal/handlers/ConvertElementHandler.java
@@ -10,15 +10,12 @@
  *******************************************************************************/
 package org.eclipse.wst.xml.vex.ui.internal.handlers;
 
-import java.text.MessageFormat;
 import java.util.Map;
 
 import org.eclipse.core.commands.ExecutionException;
-import org.eclipse.jface.action.IAction;
 import org.eclipse.ui.commands.IElementUpdater;
 import org.eclipse.ui.menus.UIElement;
-import org.eclipse.wst.xml.vex.ui.internal.ContentAssist;
-import org.eclipse.wst.xml.vex.ui.internal.editor.Messages;
+import org.eclipse.wst.xml.vex.ui.internal.swt.ContentAssist;
 import org.eclipse.wst.xml.vex.ui.internal.swt.VexWidget;
 
 /**
@@ -35,17 +32,7 @@
 
     @Override
     public void execute(VexWidget widget) throws ExecutionException {
-
-    	// compute title
-		String message = Messages
-				.getString("dialog.convertElement.dynamicTitle"); //$NON-NLS-1$
-		String name = widget.getCurrentElement().getName();
-		String title = MessageFormat.format(message, new Object[] { name });
-
-        // show content assist
-		IAction[] actions = widget.getValidMorphActions();
-		ContentAssist assist = new ContentAssist(widget, actions, title);
-		assist.open();
+        ContentAssist.openQuickFixContentAssist(widget);
     }
 
     public void updateElement(UIElement element, Map parameters) {
diff --git a/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/src/org/eclipse/wst/xml/vex/ui/internal/swt/ContentAssist.java b/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/src/org/eclipse/wst/xml/vex/ui/internal/swt/ContentAssist.java
new file mode 100644
index 0000000..2057faf
--- /dev/null
+++ b/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/src/org/eclipse/wst/xml/vex/ui/internal/swt/ContentAssist.java
@@ -0,0 +1,377 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2008 John Krasnay 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:
+ *     John Krasnay - initial implementation
+ *     Holger Voormann
+ *******************************************************************************/
+package org.eclipse.wst.xml.vex.ui.internal.swt;
+
+import java.text.MessageFormat;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.dialogs.PopupDialog;
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.jface.preference.JFacePreferences;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.StyledCellLabelProvider;
+import org.eclipse.jface.viewers.StyledString;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.ViewerCell;
+import org.eclipse.jface.viewers.StyledString.Styler;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyAdapter;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.TextStyle;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.wst.xml.vex.core.internal.dom.Element;
+import org.eclipse.wst.xml.vex.core.internal.provisional.dom.I.VEXElement;
+import org.eclipse.wst.xml.vex.ui.internal.Icon;
+import org.eclipse.wst.xml.vex.ui.internal.VexPlugin;
+import org.eclipse.wst.xml.vex.ui.internal.editor.Messages;
+
+/**
+ * Content assist dialog that is popped up to show a list of actions to select
+ * from. The input field at the top above the list could be used to filter the
+ * content.
+ */
+public class ContentAssist extends PopupDialog {
+
+    private static final String SETTINGS_SECTION =
+        "contentAssistant"; //$NON-NLS-1$
+
+    private final VexWidget vexWidget;
+    private final AbstractVexAction[] actions;
+    private final boolean autoExecute;
+    private final Point location;
+    private Text textWidget;
+    private TableViewer viewer;
+    private Font boldFont;
+
+    /**
+     * Constructs a new content assist dialog which can be opened by
+     * {@link #open()}.
+     *
+     * @param vexWidget the vex widget this content assist belongs to
+     * @param actions list of actions to select from
+     * @param autoExecute if {@code true} and if there is only one action then
+     *                    {@link #open()} does not show dialog but executes the
+     *                    only action
+     */
+    private ContentAssist(VexWidget vexWidget,
+                          AbstractVexAction[] actions,
+                          boolean autoExecute) {
+        super(vexWidget.getShell(),
+              SWT.RESIZE,
+              true,  // take focus on open
+              true,  // persist size
+              false, // persist location
+              false, // show dialog menu
+              false, // show persist actions
+              null,  // title
+              null); // footer line
+        this.vexWidget = vexWidget;
+        this.actions = actions;
+        this.autoExecute = autoExecute;
+        location = vexWidget.toDisplay(vexWidget.getLocationForContentAssist());
+    }
+
+    public int open() {
+        if (autoExecute && actions.length == 1) {
+            actions[0].execute(vexWidget);
+            return Window.OK;
+        }
+        return super.open();
+    }
+
+    @Override
+    protected IDialogSettings getDialogSettings() {
+        IDialogSettings root = VexPlugin.getInstance().getDialogSettings();
+        IDialogSettings settings = root.getSection(SETTINGS_SECTION);
+        if (settings == null) {
+            settings = root.addNewSection(SETTINGS_SECTION);
+        }
+        return settings;
+    }
+
+    @Override
+    protected Color getBackground() {
+        String colorId = JFacePreferences.CONTENT_ASSIST_BACKGROUND_COLOR;
+        return JFaceResources.getColorRegistry().get(colorId);
+    }
+
+    @Override
+    protected Control createDialogArea(Composite parent) {
+
+        // dialog area panel
+        Composite composite = new Composite(parent, SWT.NONE);
+        GridLayoutFactory.fillDefaults()
+                         .extendedMargins(0, 0, 4, 0)
+                         .applyTo(composite);
+
+        // 1. input field
+        textWidget = new Text(composite, SWT.SINGLE);
+        GridDataFactory.fillDefaults().grab(true, false).applyTo(textWidget);
+        textWidget.addModifyListener(new ModifyListener() {
+            public void modifyText(ModifyEvent e) {
+                repopulateList();
+            }
+        });
+        textWidget.addKeyListener(new KeyAdapter() {
+            @Override
+            public void keyPressed(KeyEvent e) {
+                if (e.keyCode == SWT.CR) {
+                    doAction();
+                } else if (   e.widget == textWidget
+                           && e.keyCode == SWT.ARROW_DOWN) {
+                    viewer.getControl().setFocus();
+                }
+            }
+        });
+
+        // 2. separator
+        int separatorStyle = SWT.SEPARATOR | SWT.HORIZONTAL | SWT.LINE_DOT;
+        Label separator = new Label(composite, separatorStyle);
+        GridDataFactory.fillDefaults().grab(true, false).applyTo(separator);
+
+        // 3. list of proposals
+        viewer = new TableViewer(composite, SWT.H_SCROLL | SWT.V_SCROLL);
+        Control viewerControl = viewer.getControl();
+        GridDataFactory.fillDefaults().grab(true, true).applyTo(viewerControl);
+        boldFont = getModifiedFont(viewerControl.getFont(), SWT.BOLD);
+        viewer.setLabelProvider(new MyLabelProvider());
+        viewer.setContentProvider(new ArrayContentProvider());
+        viewer.getTable().addSelectionListener(new SelectionAdapter() {
+            @Override
+            public void widgetDefaultSelected(SelectionEvent e) {
+                doAction();
+            }
+        });
+        viewer.getTable().addMouseListener(new MouseAdapter() {
+            @Override
+            public void mouseUp(MouseEvent e) {
+                if (e.button == 1) {
+                    doAction();
+                }
+            }
+        });
+
+        // fill with content
+        repopulateList();
+
+        return composite;
+    }
+
+    @Override
+    protected Point getDefaultLocation(Point initialSize) {
+        return location;
+    }
+
+    @Override
+    public boolean close() {
+        if (boldFont != null) {
+            boldFont.dispose();
+        }
+        return super.close();
+    }
+
+    /**
+     * Perform the action that is currently selected in the tree view, if any,
+     * and close the dialog.
+     */
+    private void doAction() {
+        ISelection selection = viewer.getSelection();
+        if (selection instanceof StructuredSelection) {
+            Object first = ((StructuredSelection) selection).getFirstElement();
+            if (first instanceof AbstractVexAction) {
+                ((AbstractVexAction) first).execute(vexWidget);
+            }
+        }
+        close();
+    }
+
+    private void repopulateList() {
+        String filterText = textWidget.getText();
+        List<AbstractVexAction> actionList = new LinkedList<AbstractVexAction>();
+        for (int i = 0; i < actions.length; i++) {
+            AbstractVexAction action = actions[i];
+            if (action.getText().contains(filterText)) {
+                actionList.add(action);
+            }
+        }
+        viewer.setInput(actionList.toArray(new AbstractVexAction[actionList.size()]));
+        viewer.getTable().setSelection(0);
+    }
+
+    private class MyLabelProvider extends StyledCellLabelProvider {
+
+        private final Styler boldStyler = new Styler() {
+            public void applyStyles(TextStyle textStyle) {
+                textStyle.font = boldFont;
+            }
+        };
+
+        @Override
+        public void update(ViewerCell cell) {
+            AbstractVexAction action = (AbstractVexAction) cell.getElement();
+            String filterText = textWidget.getText();
+            String text = action.getText();
+            StyledString styledString = new StyledString(action.getText());
+
+            // show matching text in bold
+            if (text.contains(filterText)) {
+                int start = text.indexOf(filterText);
+                int end = start + filterText.length();
+                styledString = new StyledString(text.substring(0, start));
+                styledString.append(text.substring(start, end), boldStyler);
+                styledString.append(text.substring(end));
+            }
+
+            cell.setText(styledString.toString());
+            cell.setStyleRanges(styledString.getStyleRanges());
+            cell.setImage(Icon.get(action.getImage()));
+            super.update(cell);
+        }
+
+    }
+
+    private static abstract class AbstractVexAction {
+
+        private final VexWidget widget;
+        private final String text;
+        private final String parameter;
+        private final Icon image;
+
+        public AbstractVexAction(VexWidget widget,
+                                 String text,
+                                 Icon image) {
+            this(widget, text, null, image);
+        }
+
+        public AbstractVexAction(VexWidget widget,
+                                 String text,
+                                 String parameter,
+                                 Icon image) {
+            this.widget = widget;
+            this.text = text;
+            this.parameter = parameter;
+            this.image = image;
+        }
+
+        abstract void execute(VexWidget vexWidget);
+
+        public VexWidget getWidget() {
+            return widget;
+        }
+
+        public String getText() {
+            return text;
+        }
+
+        public String getParameter() {
+            return parameter;
+        }
+
+        public Icon getImage() {
+            return image;
+        }
+
+    }
+
+    /**
+     * Shows the content assist to add a new element.
+     *
+     * @param widget the VexWidget which hosts the content assist
+     */
+    public static void openAddElementsContentAssist(VexWidget widget) {
+        AbstractVexAction[] addActions = computeAddElementsActions(widget);
+        ContentAssist assist = new ContentAssist(widget,
+                                                 addActions,
+                                                 true);
+        assist.open();
+    }
+
+    /**
+     * Shows the content assist to convert current element.
+     *
+     * @param widget the VexWidget which hosts the content assist
+     */
+    public static void openQuickFixContentAssist(VexWidget widget) {
+        AbstractVexAction[] quickFixActions = computeQuickFixActions(widget);
+        ContentAssist assist = new ContentAssist(widget,
+                                                 quickFixActions,
+                                                 true);
+        assist.open();
+    }
+
+    private static AbstractVexAction[] computeAddElementsActions(VexWidget widget) {
+        String[] names = widget.getValidInsertElements();
+        AbstractVexAction[] actions = new AbstractVexAction[names.length];
+        for (int i = 0; i < names.length; i++) {
+			actions[i] = new AbstractVexAction(widget, names[i], Icon.ELEMENT) {
+                public void execute(VexWidget vexWidget) {
+                    getWidget().insertElement(new Element(getText()));
+                }
+            };
+        }
+        return actions;
+    }
+
+    private static AbstractVexAction[] computeQuickFixActions(VexWidget widget) {
+        String[] names = widget.getValidMorphElements();
+        AbstractVexAction[] actions = new AbstractVexAction[names.length];
+        int caretOffset = widget.getCaretOffset();
+        VEXElement element = widget.getDocument().getElementAt(caretOffset);
+        String sourceName = element.getName();
+        for (int i = 0; i < names.length; i++) {
+            String message = Messages.getString(
+                    "command.convertElement.dynamicCommandName"); //$NON-NLS-1$
+            String text = MessageFormat.format(message, sourceName, names[i]);
+            Icon icon = Icon.CONVERT;
+            actions[i] = new AbstractVexAction(widget, text, names[i], icon) {
+                public void execute(VexWidget vexWidget) {
+                    getWidget().morph(getParameter());
+                }
+            };
+        }
+        return actions;
+    }
+
+    private static Font getModifiedFont(Font baseFont, int additionalStyle) {
+        FontData[] baseData = baseFont.getFontData();
+        FontData[] styleData = new FontData[baseData.length];
+        for (int i = 0; i < styleData.length; i++) {
+            FontData data = baseData[i];
+            styleData[i] = new FontData(data.getName(),
+                                        data.getHeight(),
+                                        data.getStyle() | additionalStyle);
+        }
+           return  new Font(Display.getCurrent(), styleData);
+    }
+
+}
diff --git a/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/src/org/eclipse/wst/xml/vex/ui/internal/swt/VexWidget.java b/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/src/org/eclipse/wst/xml/vex/ui/internal/swt/VexWidget.java
index 6698de3..376effa 100644
--- a/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/src/org/eclipse/wst/xml/vex/ui/internal/swt/VexWidget.java
+++ b/sourceediting/plugins/org.eclipse.wst.xml.vex.ui/src/org/eclipse/wst/xml/vex/ui/internal/swt/VexWidget.java
@@ -22,14 +22,12 @@
 import javax.xml.parsers.ParserConfigurationException;
 
 import org.eclipse.core.commands.ExecutionException;
-import org.eclipse.jface.action.IAction;
 import org.eclipse.jface.viewers.ISelection;
 import org.eclipse.jface.viewers.ISelectionChangedListener;
 import org.eclipse.jface.viewers.ISelectionProvider;
 import org.eclipse.jface.viewers.SelectionChangedEvent;
 import org.eclipse.jface.viewers.StructuredSelection;
 import org.eclipse.swt.SWT;
-import org.eclipse.swt.custom.PopupList;
 import org.eclipse.swt.dnd.Clipboard;
 import org.eclipse.swt.dnd.TextTransfer;
 import org.eclipse.swt.dnd.Transfer;
@@ -110,14 +108,10 @@
 		// is disposed before focus is lost.
 	}
 
-	// ----------------------------------------- IInputProvider methods
-
 	public Object getInput() {
 		return this.impl.getDocument();
 	}
 
-	// ----------------------------------------- ISelectionProvider methods
-
 	public void addSelectionChangedListener(ISelectionChangedListener listener) {
 		this.selectionListeners.add(listener);
 	}
@@ -281,11 +275,16 @@
 		this.impl.insertFragment(frag);
 	}
 
+	public void insertElement(String elementName)
+			throws DocumentValidationException {
+		insertElement(new Element(elementName));
+	}
+
 	public void insertElement(Element element)
 			throws DocumentValidationException {
 		this.impl.insertElement(element);
 	}
-
+	
 	public void insertText(String text) throws DocumentValidationException {
 		this.impl.insertText(text);
 	}
@@ -294,10 +293,14 @@
 		return impl.isDebugging();
 	}
 
+	public void morph(String elementName) throws DocumentValidationException {
+		morph(new Element(elementName));
+	}
+
 	public void morph(Element element) throws DocumentValidationException {
 		this.impl.morph(element);
 	}
-
+	
 	public void moveBy(int distance) {
 		this.impl.moveBy(distance);
 	}
@@ -346,24 +349,6 @@
 		this.impl.moveToPreviousWord(select);
 	}
 
-	public IAction[] getValidInsertActions() {
-		String[] names = this.getValidInsertElements();
-		IAction[] actions = new IAction[names.length];
-		for (int i = 0; i < names.length; i++) {
-			actions[i] = new InsertElementAction(names[i]);
-		}
-		return actions;
-	}
-
-	public IAction[] getValidMorphActions() {
-		String[] names = this.getValidMorphElements();
-		IAction[] actions = new IAction[names.length];
-		for (int i = 0; i < names.length; i++) {
-			actions[i] = new MorphElementAction(names[i]);
-		}
-		return actions;
-	}
-
 	/**
 	 * @see org.eclipse.wst.xml.vex.core.internal.widget.IVexWidget#paste()
 	 */
@@ -443,50 +428,6 @@
 		this.impl.setStyleSheet(ssUrl);
 	}
 
-	/**
-	 * Show a popup list of elements that are valid to be inserted at the
-	 * current position. If one of the elements is selected, it is inserted
-	 * before returning.
-	 */
-	public void showInsertElementPopup() {
-		PopupList list = new PopupList(this.getShell());
-		list.setItems(this.getValidInsertElements());
-
-		Rectangle caret = this.impl.getCaret().getBounds();
-		Point display = this.toDisplay(caret.getX() + 10, caret.getY());
-		String selected = list.open(new org.eclipse.swt.graphics.Rectangle(
-				display.x, display.y, 200, 0));
-		if (selected != null) {
-			try {
-				this.insertElement(new Element(selected));
-			} catch (DocumentValidationException e) {
-				e.printStackTrace();
-			}
-		}
-	}
-
-	/**
-	 * Show a popup list of elements to which it is valid to morph the current
-	 * element. If one of the elements is selected, the current element is
-	 * morphed before returning.
-	 */
-	public void showMorphElementPopup() {
-		PopupList list = new PopupList(this.getShell());
-		list.setItems(this.getValidMorphElements());
-
-		Rectangle caret = this.impl.getCaret().getBounds();
-		Point display = this.toDisplay(caret.getX() + 10, caret.getY());
-		String selected = list.open(new org.eclipse.swt.graphics.Rectangle(
-				display.x, display.y, 200, 0));
-		if (selected != null) {
-			try {
-				this.morph(new Element(selected));
-			} catch (DocumentValidationException e) {
-				e.printStackTrace();
-			}
-		}
-	}
-
 	public void split() throws DocumentValidationException {
 		this.impl.split();
 	}
@@ -732,46 +673,14 @@
 		}
 	};
 
-	private class InsertElementAction extends org.eclipse.jface.action.Action {
-		public InsertElementAction(String name) {
-			this.name = name;
-			this.setText(name);
-		}
-
-		public void run() {
-			try {
-				insertElement(new Element(name));
-			} catch (DocumentValidationException e) {
-			}
-		}
-
-		private String name;
-	}
-
-	private class MorphElementAction extends org.eclipse.jface.action.Action {
-		public MorphElementAction(String elementName) {
-			this.elementName = elementName;
-			this.setText(elementName);
-		}
-
-		public void run() {
-			try {
-				morph(new Element(elementName));
-			} catch (DocumentValidationException e) {
-				// TODO Auto-generated catch block
-				e.printStackTrace();
-			}
-		}
-
-		private String elementName;
-	}
-
 	private static void addKey(char character, int keyCode, int stateMask,
 			Action action) {
 		keyMap.put(new KeyStroke(character, keyCode, stateMask), action);
 	}
 	
 	private static void buildKeyMap() {
+		
+		// arrows: (Shift) Up/Down, {-, Shift, Ctrl, Shift+Ctrl} + Left/Right 
 		addKey(CHAR_NONE, SWT.ARROW_DOWN, SWT.NONE, new Action() {
 			public void runEx(IVexWidget w) {
 				w.moveToNextLine(false);
@@ -782,7 +691,16 @@
 				w.moveToNextLine(true);
 			}
 		});
-
+		addKey(CHAR_NONE, SWT.ARROW_UP, SWT.NONE, new Action() {
+			public void runEx(IVexWidget w) {
+				w.moveToPreviousLine(false);
+			}
+		});
+		addKey(CHAR_NONE, SWT.ARROW_UP, SWT.SHIFT, new Action() {
+			public void runEx(IVexWidget w) {
+				w.moveToPreviousLine(true);
+			}
+		});
 		addKey(CHAR_NONE, SWT.ARROW_LEFT, SWT.NONE, new Action() {
 			public void runEx(IVexWidget w) {
 				w.moveBy(-1);
@@ -804,7 +722,6 @@
 						w.moveToPreviousWord(true);
 					}
 				});
-
 		addKey(CHAR_NONE, SWT.ARROW_RIGHT, SWT.NONE, new Action() {
 			public void runEx(IVexWidget w) {
 				w.moveBy(+1);
@@ -827,17 +744,7 @@
 					}
 				});
 
-		addKey(CHAR_NONE, SWT.ARROW_UP, SWT.NONE, new Action() {
-			public void runEx(IVexWidget w) {
-				w.moveToPreviousLine(false);
-			}
-		});
-		addKey(CHAR_NONE, SWT.ARROW_UP, SWT.SHIFT, new Action() {
-			public void runEx(IVexWidget w) {
-				w.moveToPreviousLine(true);
-			}
-		});
-
+		// Delete/Backspace
 		addKey(SWT.BS, SWT.BS, SWT.NONE, new Action() {
 			public void runEx(IVexWidget w) throws ExecutionException {
 				try {
@@ -857,6 +764,7 @@
 			}
 		});
 
+		// {-, Shift, Ctrl, Shift+Ctrl} + Home/End
 		addKey(CHAR_NONE, SWT.END, SWT.NONE, new Action() {
 			public void runEx(IVexWidget w) {
 				w.moveToLineEnd(false);
@@ -877,7 +785,6 @@
 				w.moveTo(w.getDocument().getLength() - 1, true);
 			}
 		});
-
 		addKey(CHAR_NONE, SWT.HOME, SWT.NONE, new Action() {
 			public void runEx(IVexWidget w) {
 				w.moveToLineStart(false);
@@ -899,6 +806,7 @@
 			}
 		});
 
+		// (Shift) Page Up/Down
 		addKey(CHAR_NONE, SWT.PAGE_DOWN, SWT.NONE, new Action() {
 			public void runEx(IVexWidget w) {
 				w.moveToNextPage(false);
@@ -909,7 +817,6 @@
 				w.moveToNextPage(true);
 			}
 		});
-
 		addKey(CHAR_NONE, SWT.PAGE_UP, SWT.NONE, new Action() {
 			public void runEx(IVexWidget w) {
 				w.moveToPreviousPage(false);
@@ -920,17 +827,6 @@
 				w.moveToPreviousPage(true);
 			}
 		});
-
-		addKey(' ', 0, SWT.CONTROL, new Action() { // Ctrl-Space
-					public void runEx(IVexWidget w) {
-						((VexWidget) w).showInsertElementPopup();
-					}
-				});
-		addKey('\r', 0, SWT.CONTROL, new Action() { // Ctrl-M
-					public void runEx(IVexWidget w) {
-						((VexWidget) w).showMorphElementPopup();
-					}
-				});
 	}
 
 	/**
diff --git a/sourceediting/tests/org.eclipse.wst.xml.vex.core.tests/src/org/eclipse/wst/xml/vex/core/tests/VEXCoreTestSuite.java b/sourceediting/tests/org.eclipse.wst.xml.vex.core.tests/src/org/eclipse/wst/xml/vex/core/tests/VEXCoreTestSuite.java
index 2e1404a..5f798dd 100755
--- a/sourceediting/tests/org.eclipse.wst.xml.vex.core.tests/src/org/eclipse/wst/xml/vex/core/tests/VEXCoreTestSuite.java
+++ b/sourceediting/tests/org.eclipse.wst.xml.vex.core.tests/src/org/eclipse/wst/xml/vex/core/tests/VEXCoreTestSuite.java
@@ -23,7 +23,7 @@
 	}
 
 	public VEXCoreTestSuite() {
-		super("VEX Core Tests");
+		super("Vex Core Tests");
 		addTestSuite(CssTest.class);
 		addTestSuite(PropertyTest.class);
 		addTestSuite(RuleTest.class);
diff --git a/sourceediting/tests/org.eclipse.wst.xml.vex.tests/src/org/eclipse/wst/xml/vex/tests/AllTestsSuite.java b/sourceediting/tests/org.eclipse.wst.xml.vex.tests/src/org/eclipse/wst/xml/vex/tests/AllTestsSuite.java
index 4369548..b3d8c7b 100644
--- a/sourceediting/tests/org.eclipse.wst.xml.vex.tests/src/org/eclipse/wst/xml/vex/tests/AllTestsSuite.java
+++ b/sourceediting/tests/org.eclipse.wst.xml.vex.tests/src/org/eclipse/wst/xml/vex/tests/AllTestsSuite.java
@@ -10,13 +10,10 @@
  *******************************************************************************/
 package org.eclipse.wst.xml.vex.tests;
 
-import org.eclipse.wst.xml.vex.core.tests.VEXCoreTestSuite;
-import org.eclipse.wst.xml.vex.ui.internal.editor.tests.FindReplaceTargetTest;
-import org.eclipse.wst.xml.vex.ui.internal.tests.ResourceTrackerTest;
-
 import junit.framework.TestSuite;
 
-
+import org.eclipse.wst.xml.vex.core.tests.VEXCoreTestSuite;
+import org.eclipse.wst.xml.vex.ui.tests.VexUiTestSuite;
 
 /**
  * This class specifies all the bundles of this component that provide a test
@@ -24,12 +21,10 @@
  */
 public class AllTestsSuite extends TestSuite {
 
-
 	public AllTestsSuite() {
-		super("All VEX Test Suites");
+		super("All Vex Test Suites"); //$NON-NLS-1$
 		addTest(VEXCoreTestSuite.suite());
-		addTestSuite(ResourceTrackerTest.class);
-		addTestSuite(FindReplaceTargetTest.class);
+		addTest(VexUiTestSuite.suite());
 	}
 
 	/**
diff --git a/sourceediting/tests/org.eclipse.wst.xml.vex.ui.tests/META-INF/MANIFEST.MF b/sourceediting/tests/org.eclipse.wst.xml.vex.ui.tests/META-INF/MANIFEST.MF
index 36205fd..d710011 100644
--- a/sourceediting/tests/org.eclipse.wst.xml.vex.ui.tests/META-INF/MANIFEST.MF
+++ b/sourceediting/tests/org.eclipse.wst.xml.vex.ui.tests/META-INF/MANIFEST.MF
@@ -3,7 +3,6 @@
 Bundle-Name: VEX UI Test Plugin
 Bundle-SymbolicName: org.eclipse.wst.xml.vex.ui.tests
 Bundle-Version: 0.5.0.qualifier
-Bundle-Activator: org.eclipse.wst.xml.vex.ui.tests.Activator
 Bundle-Vendor: Eclipse
 Require-Bundle: org.eclipse.ui,
  org.eclipse.core.runtime,
diff --git a/sourceediting/tests/org.eclipse.wst.xml.vex.ui.tests/src/org/eclipse/wst/xml/vex/ui/tests/Activator.java b/sourceediting/tests/org.eclipse.wst.xml.vex.ui.tests/src/org/eclipse/wst/xml/vex/ui/tests/Activator.java
deleted file mode 100644
index 4e2b66a..0000000
--- a/sourceediting/tests/org.eclipse.wst.xml.vex.ui.tests/src/org/eclipse/wst/xml/vex/ui/tests/Activator.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package org.eclipse.wst.xml.vex.ui.tests;
-
-import org.eclipse.ui.plugin.AbstractUIPlugin;
-import org.osgi.framework.BundleContext;
-
-/**
- * The activator class controls the plug-in life cycle
- */
-public class Activator extends AbstractUIPlugin {
-
-	// The plug-in ID
-	public static final String PLUGIN_ID = "org.eclipse.wst.xml.vex.ui.tests";
-
-	// The shared instance
-	private static Activator plugin;
-
-	/**
-	 * The constructor
-	 */
-	public Activator() {
-	}
-
-	/*
-	 * (non-Javadoc)
-	 * 
-	 * @see
-	 * org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext
-	 * )
-	 */
-	public void start(BundleContext context) throws Exception {
-		super.start(context);
-		plugin = this;
-	}
-
-	/*
-	 * (non-Javadoc)
-	 * 
-	 * @see
-	 * org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext
-	 * )
-	 */
-	public void stop(BundleContext context) throws Exception {
-		plugin = null;
-		super.stop(context);
-	}
-
-	/**
-	 * Returns the shared instance
-	 * 
-	 * @return the shared instance
-	 */
-	public static Activator getDefault() {
-		return plugin;
-	}
-
-}
diff --git a/sourceediting/tests/org.eclipse.wst.xml.vex.ui.tests/src/org/eclipse/wst/xml/vex/ui/tests/IconTest.java b/sourceediting/tests/org.eclipse.wst.xml.vex.ui.tests/src/org/eclipse/wst/xml/vex/ui/tests/IconTest.java
new file mode 100644
index 0000000..774252f
--- /dev/null
+++ b/sourceediting/tests/org.eclipse.wst.xml.vex.ui.tests/src/org/eclipse/wst/xml/vex/ui/tests/IconTest.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Holger Voormann 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:
+ *     Holger Voormann - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xml.vex.ui.tests;
+
+import org.eclipse.wst.xml.vex.ui.internal.Icon;
+
+import junit.framework.TestCase;
+
+public class IconTest extends TestCase {
+
+	public void testAllImagesExists() throws Exception {
+		for (Icon vexImage : Icon.values()) {
+			assertNotNull(Icon.get(vexImage));
+		}
+	}
+
+}
diff --git a/sourceediting/tests/org.eclipse.wst.xml.vex.ui.tests/src/org/eclipse/wst/xml/vex/ui/tests/VexUiTestSuite.java b/sourceediting/tests/org.eclipse.wst.xml.vex.ui.tests/src/org/eclipse/wst/xml/vex/ui/tests/VexUiTestSuite.java
new file mode 100644
index 0000000..bfe65cb
--- /dev/null
+++ b/sourceediting/tests/org.eclipse.wst.xml.vex.ui.tests/src/org/eclipse/wst/xml/vex/ui/tests/VexUiTestSuite.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Holger Voormann 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:
+ *     Holger Voormann - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xml.vex.ui.tests;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.eclipse.wst.xml.vex.ui.internal.editor.tests.FindReplaceTargetTest;
+import org.eclipse.wst.xml.vex.ui.internal.tests.ResourceTrackerTest;
+
+public class VexUiTestSuite extends TestSuite {
+	public static Test suite() {
+		return new VexUiTestSuite();
+	}
+
+	public VexUiTestSuite() {
+		super("Vex Core Tests"); //$NON-NLS-1$
+		addTestSuite(IconTest.class);
+		addTestSuite(FindReplaceTargetTest.class);
+		addTestSuite(ResourceTrackerTest.class);
+	}
+
+}