Merge branch 'master' into bugs/326915
diff --git a/plugins/org.eclipse.uml2.uml.editor/META-INF/MANIFEST.MF b/plugins/org.eclipse.uml2.uml.editor/META-INF/MANIFEST.MF
index fc27f35..bc3a3fe 100644
--- a/plugins/org.eclipse.uml2.uml.editor/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.uml2.uml.editor/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.uml2.uml.editor; singleton:=true
-Bundle-Version: 4.1.100.qualifier
+Bundle-Version: 4.2.0.qualifier
 Bundle-ClassPath: .
 Bundle-Activator: org.eclipse.uml2.uml.editor.UMLEditorPlugin$Implementation
 Bundle-Vendor: %providerName
diff --git a/plugins/org.eclipse.uml2.uml.editor/icons/full/etool16/ArrowDown.gif b/plugins/org.eclipse.uml2.uml.editor/icons/full/etool16/ArrowDown.gif
new file mode 100644
index 0000000..072b184
--- /dev/null
+++ b/plugins/org.eclipse.uml2.uml.editor/icons/full/etool16/ArrowDown.gif
Binary files differ
diff --git a/plugins/org.eclipse.uml2.uml.editor/icons/full/etool16/ArrowLeft.gif b/plugins/org.eclipse.uml2.uml.editor/icons/full/etool16/ArrowLeft.gif
new file mode 100644
index 0000000..4fb4150
--- /dev/null
+++ b/plugins/org.eclipse.uml2.uml.editor/icons/full/etool16/ArrowLeft.gif
Binary files differ
diff --git a/plugins/org.eclipse.uml2.uml.editor/icons/full/etool16/ArrowRight.gif b/plugins/org.eclipse.uml2.uml.editor/icons/full/etool16/ArrowRight.gif
new file mode 100644
index 0000000..1956789
--- /dev/null
+++ b/plugins/org.eclipse.uml2.uml.editor/icons/full/etool16/ArrowRight.gif
Binary files differ
diff --git a/plugins/org.eclipse.uml2.uml.editor/icons/full/etool16/ArrowUp.gif b/plugins/org.eclipse.uml2.uml.editor/icons/full/etool16/ArrowUp.gif
new file mode 100644
index 0000000..0716475
--- /dev/null
+++ b/plugins/org.eclipse.uml2.uml.editor/icons/full/etool16/ArrowUp.gif
Binary files differ
diff --git a/plugins/org.eclipse.uml2.uml.editor/plugin.properties b/plugins/org.eclipse.uml2.uml.editor/plugin.properties
index f654a85..8a25d85 100644
--- a/plugins/org.eclipse.uml2.uml.editor/plugin.properties
+++ b/plugins/org.eclipse.uml2.uml.editor/plugin.properties
@@ -1,4 +1,4 @@
-# Copyright (c) 2005, 2011 IBM Corporation, Embarcadero Technologies, CEA, and others.
+# Copyright (c) 2005, 2013 IBM Corporation, Embarcadero Technologies, CEA, 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
@@ -8,8 +8,8 @@
 #   IBM - initial API and implementation
 #   Kenn Hussey (Embarcadero Technologies) - 227392, 226178, 226101, 204200
 #   Kenn Hussey (CEA) - 327039
+#   Christian W. Damus (CEA) - 326915
 #
-# $Id: plugin.properties,v 1.18 2009/04/30 21:15:28 jbruck Exp $
 
 # NLS_MESSAGEFORMAT_VAR
 
@@ -131,6 +131,23 @@
 
 _UI_Save_All_Resources_As = Save all ''.{0}'' resources with new file extension of ''.{1}''?
 
+# 0 - the client-supplied dialog label
+# 1 - and the user-friendly label of the object being edited
+_UI_ChoicesDialog_title =  {0} -- {1}
+
+_UI_ApplicableStereotypes_label = Applicable Stereotypes
+_UI_AvailableProfiles_label = Available Profiles
+_UI_AppliedStereotypes_label = Applied Stereotypes
+_UI_AppliedProfiles_label = Applied Profiles
+
+_UI_StereotypesToApply_label = Stereotypes to Apply
+_UI_StereotypesToUnapply_label = Stereotypes to Unapply
+_UI_ProfilesToApply_label = Profiles to Apply
+_UI_ProfilesToUnapply_label = Profiles to Unapply
+
+_UI_Apply_label = Apply
+_UI_Unapply_label = Unapply
+
 # START NON-TRANSLATABLE
 _UI_UMLEditorFilenameExtensions = uml
 # END NON-TRANSLATABLE
diff --git a/plugins/org.eclipse.uml2.uml.editor/src/org/eclipse/uml2/uml/editor/actions/ApplyProfileAction.java b/plugins/org.eclipse.uml2.uml.editor/src/org/eclipse/uml2/uml/editor/actions/ApplyProfileAction.java
index 63fad7a..211f9f9 100644
--- a/plugins/org.eclipse.uml2.uml.editor/src/org/eclipse/uml2/uml/editor/actions/ApplyProfileAction.java
+++ b/plugins/org.eclipse.uml2.uml.editor/src/org/eclipse/uml2/uml/editor/actions/ApplyProfileAction.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2010 IBM Corporation, Embarcadero Technologies, and others.
+ * Copyright (c) 2005, 2013 IBM Corporation, Embarcadero Technologies, CEA, 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
@@ -9,8 +9,8 @@
  *   IBM - initial API and implementation
  *   Kenn Hussey (Embarcadero Technologies) - 215488
  *   Kenn Hussey - 286329
+ *   Christian W. Damus (CEA) - 326915
  *
- * $Id: ApplyProfileAction.java,v 1.9 2010/03/02 03:10:43 khussey Exp $
  */
 package org.eclipse.uml2.uml.editor.actions;
 
@@ -28,13 +28,15 @@
 import org.eclipse.emf.ecore.resource.Resource;
 import org.eclipse.emf.ecore.resource.ResourceSet;
 import org.eclipse.emf.edit.domain.EditingDomain;
-import org.eclipse.emf.edit.ui.celleditor.FeatureEditorDialog;
 import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.window.Window;
 import org.eclipse.uml2.uml.Profile;
 import org.eclipse.uml2.uml.ProfileApplication;
-import org.eclipse.uml2.uml.UMLPackage;
 import org.eclipse.uml2.uml.UMLPlugin;
 import org.eclipse.uml2.uml.editor.UMLEditorPlugin;
+import org.eclipse.uml2.uml.editor.dialogs.AbstractChoicesDialogDelegate;
+import org.eclipse.uml2.uml.editor.dialogs.ChoicesDialog;
 import org.eclipse.uml2.uml.util.UMLSwitch;
 
 public class ApplyProfileAction
@@ -113,20 +115,53 @@
 			String label = UMLEditorPlugin.INSTANCE
 				.getString("_UI_ApplyProfileActionCommand_label"); //$NON-NLS-1$
 
-			final FeatureEditorDialog dialog = new FeatureEditorDialog(
-				workbenchPart.getSite().getShell(), getLabelProvider(),
-				package_, UMLPackage.Literals.PROFILE, Collections.EMPTY_LIST,
-				label, choiceOfValues, false, false, true);
+			final ChoicesDialog<Profile> dialog = new ChoicesDialog<Profile>(
+				workbenchPart.getSite().getShell(), package_, label,
+				new AbstractChoicesDialogDelegate<Profile>(Profile.class) {
+
+					@Override
+					public String getChoicesLabelText() {
+						return UMLEditorPlugin.INSTANCE
+							.getString("_UI_AvailableProfiles_label"); //$NON-NLS-1$
+					}
+
+					@Override
+					public String getValuesLabelText() {
+						return UMLEditorPlugin.INSTANCE
+							.getString("_UI_ProfilesToApply_label"); //$NON-NLS-1$
+					}
+
+					@Override
+					public String getAddButtonText() {
+						return UMLEditorPlugin.INSTANCE
+							.getString("_UI_Apply_label"); //$NON-NLS-1$
+					}
+
+					@Override
+					public String getRemoveButtonText() {
+						return UMLEditorPlugin.INSTANCE
+							.getString("_UI_Unapply_label"); //$NON-NLS-1$
+					}
+
+					public ILabelProvider getLabelProvider() {
+						return ApplyProfileAction.this.getLabelProvider();
+					}
+
+					public Collection<Profile> getChoiceOfValues() {
+						return choiceOfValues;
+					}
+				});
 			dialog.open();
 
-			if (dialog.getReturnCode() == FeatureEditorDialog.OK) {
+			if ((dialog.getReturnCode() == Window.OK)
+				&& !dialog.getResult().isEmpty()) {
 				editingDomain.getCommandStack().execute(
 					new RefreshingChangeCommand(editingDomain, new Runnable() {
 
 						public void run() {
 
-							for (Object result : dialog.getResult()) {
-								package_.applyProfile((Profile) result);
+							for (Profile result : dialog.getResult()) {
+								package_.applyProfile(result);
 							}
 						}
 					}, label));
diff --git a/plugins/org.eclipse.uml2.uml.editor/src/org/eclipse/uml2/uml/editor/actions/ApplyStereotypeAction.java b/plugins/org.eclipse.uml2.uml.editor/src/org/eclipse/uml2/uml/editor/actions/ApplyStereotypeAction.java
index 0851f1f..f73bfb1 100644
--- a/plugins/org.eclipse.uml2.uml.editor/src/org/eclipse/uml2/uml/editor/actions/ApplyStereotypeAction.java
+++ b/plugins/org.eclipse.uml2.uml.editor/src/org/eclipse/uml2/uml/editor/actions/ApplyStereotypeAction.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2010 IBM Corporation and others.
+ * Copyright (c) 2005, 2013 IBM Corporation, CEA, 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
@@ -8,8 +8,8 @@
  * Contributors:
  *   IBM - initial API and implementation
  *   Kenn Hussey - 286329
+ *   Christian W. Damus (CEA) - 326915
  *
- * $Id: ApplyStereotypeAction.java,v 1.6 2010/03/02 03:10:43 khussey Exp $
  */
 package org.eclipse.uml2.uml.editor.actions;
 
@@ -22,12 +22,14 @@
 import org.eclipse.emf.common.command.IdentityCommand;
 import org.eclipse.emf.common.command.UnexecutableCommand;
 import org.eclipse.emf.edit.domain.EditingDomain;
-import org.eclipse.emf.edit.ui.celleditor.FeatureEditorDialog;
 import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.window.Window;
 import org.eclipse.uml2.uml.Element;
 import org.eclipse.uml2.uml.Stereotype;
-import org.eclipse.uml2.uml.UMLPackage;
 import org.eclipse.uml2.uml.editor.UMLEditorPlugin;
+import org.eclipse.uml2.uml.editor.dialogs.AbstractChoicesDialogDelegate;
+import org.eclipse.uml2.uml.editor.dialogs.ChoicesDialog;
 
 public class ApplyStereotypeAction
 		extends UMLCommandAction {
@@ -55,7 +57,7 @@
 		if (command != UnexecutableCommand.INSTANCE) {
 			final Element element = (Element) collection.iterator().next();
 
-			List<Stereotype> choiceOfValues = new ArrayList<Stereotype>();
+			final List<Stereotype> choiceOfValues = new ArrayList<Stereotype>();
 
 			for (Stereotype applicableStereotype : element
 				.getApplicableStereotypes()) {
@@ -71,20 +73,56 @@
 			String label = UMLEditorPlugin.INSTANCE
 				.getString("_UI_ApplyStereotypeActionCommand_label"); //$NON-NLS-1$
 
-			final FeatureEditorDialog dialog = new FeatureEditorDialog(
-				workbenchPart.getSite().getShell(), getLabelProvider(),
-				element, UMLPackage.Literals.ELEMENT, Collections.EMPTY_LIST,
-				label, choiceOfValues, false, false, true);
+			final ChoicesDialog<Stereotype> dialog = new ChoicesDialog<Stereotype>(
+				workbenchPart.getSite().getShell(),
+				element,
+				label,
+				new AbstractChoicesDialogDelegate<Stereotype>(Stereotype.class) {
+
+					@Override
+					public String getChoicesLabelText() {
+						return UMLEditorPlugin.INSTANCE
+							.getString("_UI_ApplicableStereotypes_label"); //$NON-NLS-1$
+					}
+
+					@Override
+					public String getValuesLabelText() {
+						return UMLEditorPlugin.INSTANCE
+							.getString("_UI_StereotypesToApply_label"); //$NON-NLS-1$
+					}
+
+					@Override
+					public String getAddButtonText() {
+						return UMLEditorPlugin.INSTANCE
+							.getString("_UI_Apply_label"); //$NON-NLS-1$
+					}
+
+					@Override
+					public String getRemoveButtonText() {
+						return UMLEditorPlugin.INSTANCE
+							.getString("_UI_Unapply_label"); //$NON-NLS-1$
+					}
+
+					public ILabelProvider getLabelProvider() {
+						return ApplyStereotypeAction.this.getLabelProvider();
+					}
+
+					public Collection<Stereotype> getChoiceOfValues() {
+						return choiceOfValues;
+					}
+				});
 			dialog.open();
 
-			if (dialog.getReturnCode() == FeatureEditorDialog.OK) {
+			if ((dialog.getReturnCode() == Window.OK)
+				&& !dialog.getResult().isEmpty()) {
+
 				editingDomain.getCommandStack().execute(
 					new RefreshingChangeCommand(editingDomain, new Runnable() {
 
 						public void run() {
 
-							for (Object result : dialog.getResult()) {
-								element.applyStereotype((Stereotype) result);
+							for (Stereotype result : dialog.getResult()) {
+								element.applyStereotype(result);
 							}
 						}
 					}, label));
diff --git a/plugins/org.eclipse.uml2.uml.editor/src/org/eclipse/uml2/uml/editor/actions/UMLCommandAction.java b/plugins/org.eclipse.uml2.uml.editor/src/org/eclipse/uml2/uml/editor/actions/UMLCommandAction.java
index 082a239..c5bf281 100644
--- a/plugins/org.eclipse.uml2.uml.editor/src/org/eclipse/uml2/uml/editor/actions/UMLCommandAction.java
+++ b/plugins/org.eclipse.uml2.uml.editor/src/org/eclipse/uml2/uml/editor/actions/UMLCommandAction.java
@@ -8,6 +8,7 @@
  * Contributors:
  *   IBM - initial API and implementation
  *   Kenn Hussey (CEA) - 173565
+ *   Christian W. Damus (CEA) - 326915
  *
  */
 package org.eclipse.uml2.uml.editor.actions;
@@ -92,6 +93,11 @@
 	public void setActiveEditor(IAction action, IEditorPart editorPart) {
 		super.setActiveEditor(action, editorPart);
 
+		if (labelProvider != null) {
+			// clean up the current label provider
+			labelProvider.dispose();
+		}
+
 		labelProvider = editorPart == null
 			? null
 			: new AdapterFactoryLabelProvider(getAdapterFactory()) {
diff --git a/plugins/org.eclipse.uml2.uml.editor/src/org/eclipse/uml2/uml/editor/actions/UnapplyProfileAction.java b/plugins/org.eclipse.uml2.uml.editor/src/org/eclipse/uml2/uml/editor/actions/UnapplyProfileAction.java
index 8cc9611..5925c3e 100644
--- a/plugins/org.eclipse.uml2.uml.editor/src/org/eclipse/uml2/uml/editor/actions/UnapplyProfileAction.java
+++ b/plugins/org.eclipse.uml2.uml.editor/src/org/eclipse/uml2/uml/editor/actions/UnapplyProfileAction.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2010 IBM Corporation and others.
+ * Copyright (c) 2005, 2013 IBM Corporation, CEA, 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
@@ -8,8 +8,8 @@
  * Contributors:
  *   IBM - initial API and implementation
  *   Kenn Hussey - 286329
+ *   Christian W. Damus (CEA) - 326915
  *
- * $Id: UnapplyProfileAction.java,v 1.6 2010/03/02 03:10:43 khussey Exp $
  */
 package org.eclipse.uml2.uml.editor.actions;
 
@@ -22,11 +22,13 @@
 import org.eclipse.emf.common.command.IdentityCommand;
 import org.eclipse.emf.common.command.UnexecutableCommand;
 import org.eclipse.emf.edit.domain.EditingDomain;
-import org.eclipse.emf.edit.ui.celleditor.FeatureEditorDialog;
 import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.window.Window;
 import org.eclipse.uml2.uml.Profile;
-import org.eclipse.uml2.uml.UMLPackage;
 import org.eclipse.uml2.uml.editor.UMLEditorPlugin;
+import org.eclipse.uml2.uml.editor.dialogs.AbstractChoicesDialogDelegate;
+import org.eclipse.uml2.uml.editor.dialogs.ChoicesDialog;
 
 public class UnapplyProfileAction
 		extends UMLCommandAction {
@@ -55,8 +57,8 @@
 			final org.eclipse.uml2.uml.Package package_ = (org.eclipse.uml2.uml.Package) collection
 				.iterator().next();
 
-			List<Profile> choiceOfValues = new ArrayList<Profile>(package_
-				.getAppliedProfiles());
+			final List<Profile> choiceOfValues = new ArrayList<Profile>(
+				package_.getAppliedProfiles());
 
 			Collections.<Profile> sort(choiceOfValues,
 				new TextComparator<Profile>());
@@ -65,20 +67,58 @@
 				"_UI_UnapplyProfileActionCommand_label", //$NON-NLS-1$
 				new Object[]{getLabelProvider().getText(package_)});
 
-			final FeatureEditorDialog dialog = new FeatureEditorDialog(
-				workbenchPart.getSite().getShell(), getLabelProvider(),
-				package_, UMLPackage.Literals.PROFILE, Collections.EMPTY_LIST,
-				label, choiceOfValues, false, false, true);
+			final ChoicesDialog<Profile> dialog = new ChoicesDialog<Profile>(
+				workbenchPart.getSite().getShell(), package_, label,
+				new AbstractChoicesDialogDelegate<Profile>(Profile.class) {
+
+					@Override
+					public String getChoicesLabelText() {
+						return UMLEditorPlugin.INSTANCE
+							.getString("_UI_AppliedProfiles_label"); //$NON-NLS-1$
+					}
+
+					@Override
+					public String getValuesLabelText() {
+						return UMLEditorPlugin.INSTANCE
+							.getString("_UI_ProfilesToUnapply_label"); //$NON-NLS-1$
+					}
+
+					@Override
+					public String getAddButtonText() {
+						return UMLEditorPlugin.INSTANCE
+							.getString("_UI_Unapply_label"); //$NON-NLS-1$
+					}
+
+					@Override
+					public String getRemoveButtonText() {
+						return UMLEditorPlugin.INSTANCE
+							.getString("_UI_Apply_label"); //$NON-NLS-1$
+					}
+
+					public Collection<Profile> getChoiceOfValues() {
+						return choiceOfValues;
+					}
+
+					public ILabelProvider getLabelProvider() {
+						return UnapplyProfileAction.this.getLabelProvider();
+					}
+
+					@Override
+					public boolean allowsReordering() {
+						return false;
+					}
+				});
 			dialog.open();
 
-			if (dialog.getReturnCode() == FeatureEditorDialog.OK) {
+			if ((dialog.getReturnCode() == Window.OK)
+				&& !dialog.getResult().isEmpty()) {
 				editingDomain.getCommandStack().execute(
 					new RefreshingChangeCommand(editingDomain, new Runnable() {
 
 						public void run() {
 
-							for (Object result : dialog.getResult()) {
-								package_.unapplyProfile((Profile) result);
+							for (Profile result : dialog.getResult()) {
+								package_.unapplyProfile(result);
 							}
 						}
 					}, label));
diff --git a/plugins/org.eclipse.uml2.uml.editor/src/org/eclipse/uml2/uml/editor/actions/UnapplyStereotypeAction.java b/plugins/org.eclipse.uml2.uml.editor/src/org/eclipse/uml2/uml/editor/actions/UnapplyStereotypeAction.java
index 306eaf3..a30e6d7 100644
--- a/plugins/org.eclipse.uml2.uml.editor/src/org/eclipse/uml2/uml/editor/actions/UnapplyStereotypeAction.java
+++ b/plugins/org.eclipse.uml2.uml.editor/src/org/eclipse/uml2/uml/editor/actions/UnapplyStereotypeAction.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2010 IBM Corporation and others.
+ * Copyright (c) 2005, 2013 IBM Corporation, CEA, 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
@@ -8,8 +8,8 @@
  * Contributors:
  *   IBM - initial API and implementation
  *   Kenn Hussey - 286329
- *
- * $Id: UnapplyStereotypeAction.java,v 1.6 2010/03/02 03:10:43 khussey Exp $
+ *   Christian W. Damus (CEA) - 326915
+ *   
  */
 package org.eclipse.uml2.uml.editor.actions;
 
@@ -22,12 +22,19 @@
 import org.eclipse.emf.common.command.IdentityCommand;
 import org.eclipse.emf.common.command.UnexecutableCommand;
 import org.eclipse.emf.edit.domain.EditingDomain;
-import org.eclipse.emf.edit.ui.celleditor.FeatureEditorDialog;
+import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider;
+import org.eclipse.emf.edit.ui.provider.DelegatingStyledCellLabelProvider;
 import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StyledString;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.window.Window;
 import org.eclipse.uml2.uml.Element;
 import org.eclipse.uml2.uml.Stereotype;
-import org.eclipse.uml2.uml.UMLPackage;
 import org.eclipse.uml2.uml.editor.UMLEditorPlugin;
+import org.eclipse.uml2.uml.editor.dialogs.AbstractChoicesDialogDelegate;
+import org.eclipse.uml2.uml.editor.dialogs.ChoicesDialog;
 
 public class UnapplyStereotypeAction
 		extends UMLCommandAction {
@@ -55,13 +62,10 @@
 		if (command != UnexecutableCommand.INSTANCE) {
 			final Element element = (Element) collection.iterator().next();
 
-			List<Stereotype> choiceOfValues = new ArrayList<Stereotype>();
+			final List<Stereotype> choiceOfValues = new ArrayList<Stereotype>();
 
 			for (Stereotype appliedStereotype : element.getAppliedStereotypes()) {
-
-				if (!element.isStereotypeRequired(appliedStereotype)) {
-					choiceOfValues.add(appliedStereotype);
-				}
+				choiceOfValues.add(appliedStereotype);
 			}
 
 			Collections.<Stereotype> sort(choiceOfValues,
@@ -70,25 +74,104 @@
 			String label = UMLEditorPlugin.INSTANCE
 				.getString("_UI_UnapplyStereotypeActionCommand_label"); //$NON-NLS-1$
 
-			final FeatureEditorDialog dialog = new FeatureEditorDialog(
-				workbenchPart.getSite().getShell(), getLabelProvider(),
-				element, UMLPackage.Literals.ELEMENT, Collections.EMPTY_LIST,
-				label, choiceOfValues, false, false, true);
+			final ChoicesDialog<Stereotype> dialog = new ChoicesDialog<Stereotype>(
+				workbenchPart.getSite().getShell(),
+				element,
+				label,
+				new AbstractChoicesDialogDelegate<Stereotype>(Stereotype.class) {
+
+					@Override
+					public String getChoicesLabelText() {
+						return UMLEditorPlugin.INSTANCE
+							.getString("_UI_AppliedStereotypes_label"); //$NON-NLS-1$
+					}
+
+					@Override
+					public String getValuesLabelText() {
+						return UMLEditorPlugin.INSTANCE
+							.getString("_UI_StereotypesToUnapply_label"); //$NON-NLS-1$
+					}
+
+					@Override
+					public String getAddButtonText() {
+						return UMLEditorPlugin.INSTANCE
+							.getString("_UI_Unapply_label"); //$NON-NLS-1$
+					}
+
+					@Override
+					public String getRemoveButtonText() {
+						return UMLEditorPlugin.INSTANCE
+							.getString("_UI_Apply_label"); //$NON-NLS-1$
+					}
+
+					public ILabelProvider getLabelProvider() {
+						return UnapplyStereotypeAction.this.getLabelProvider();
+					}
+
+					@Override
+					public ILabelProvider createLabelProvider(Viewer viewer) {
+						return new DelegatingStyledCellLabelProvider(
+							new AdapterFactoryLabelProvider.StyledLabelProvider(
+								getAdapterFactory(), viewer) {
+
+								@Override
+								public StyledString getStyledText(Object object) {
+									StyledString result = super
+										.getStyledText(object);
+
+									if (object instanceof Stereotype) {
+										if (element
+											.isStereotypeRequired(((Stereotype) object))) {
+											result.append(" (required)",
+												StyledString.QUALIFIER_STYLER);
+										}
+									}
+
+									return result;
+								}
+							});
+					}
+
+					public Collection<Stereotype> getChoiceOfValues() {
+						return choiceOfValues;
+					}
+
+					@Override
+					public boolean allowsReordering() {
+						return false;
+					}
+
+					@Override
+					public boolean canAdd(IStructuredSelection selection,
+							Collection<Stereotype> values) {
+
+						boolean result = true;
+
+						for (Object next : selection.toList()) {
+							if (element.isStereotypeRequired((Stereotype) next)) {
+								result = false;
+								break;
+							}
+						}
+
+						return result;
+					}
+				});
 			dialog.open();
 
-			if (dialog.getReturnCode() == FeatureEditorDialog.OK) {
+			if ((dialog.getReturnCode() == Window.OK)
+				&& !dialog.getResult().isEmpty()) {
 				editingDomain.getCommandStack().execute(
 					new RefreshingChangeCommand(editingDomain, new Runnable() {
 
 						public void run() {
 
-							for (Object result : dialog.getResult()) {
-								element.unapplyStereotype((Stereotype) result);
+							for (Stereotype result : dialog.getResult()) {
+								element.unapplyStereotype(result);
 							}
 						}
 					}, label));
 			}
 		}
 	}
-
 }
diff --git a/plugins/org.eclipse.uml2.uml.editor/src/org/eclipse/uml2/uml/editor/dialogs/AbstractChoicesDialogDelegate.java b/plugins/org.eclipse.uml2.uml.editor/src/org/eclipse/uml2/uml/editor/dialogs/AbstractChoicesDialogDelegate.java
new file mode 100644
index 0000000..6ce7e0c
--- /dev/null
+++ b/plugins/org.eclipse.uml2.uml.editor/src/org/eclipse/uml2/uml/editor/dialogs/AbstractChoicesDialogDelegate.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2013 CEA 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:
+ *   Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.uml2.uml.editor.dialogs;
+
+import java.util.Collection;
+
+import org.eclipse.emf.edit.ui.EMFEditUIPlugin;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.Viewer;
+
+/**
+ * A partial implementation of the {@link IChoicesDialogDelegate} protocol,
+ * useful for subclassing.
+ * 
+ * @since 4.2
+ */
+public abstract class AbstractChoicesDialogDelegate<T>
+		implements IChoicesDialogDelegate<T> {
+
+	private final Class<T> elementType;
+
+	public AbstractChoicesDialogDelegate(Class<T> elementType) {
+		this.elementType = elementType;
+	}
+
+	public Class<T> getElementType() {
+		return elementType;
+	}
+
+	public String getChoicesLabelText() {
+		return EMFEditUIPlugin.INSTANCE.getString("_UI_Choices_label"); //$NON-NLS-1$
+	}
+
+	public String getValuesLabelText() {
+		return EMFEditUIPlugin.INSTANCE.getString("_UI_Feature_label"); //$NON-NLS-1$
+	}
+
+	public String getAddButtonText() {
+		return EMFEditUIPlugin.INSTANCE.getString("_UI_Add_label"); //$NON-NLS-1$
+	}
+
+	public String getRemoveButtonText() {
+		return EMFEditUIPlugin.INSTANCE.getString("_UI_Remove_label"); //$NON-NLS-1$
+	}
+
+	public ILabelProvider createLabelProvider(Viewer viewer) {
+		return getLabelProvider();
+	}
+
+	public boolean canAdd(IStructuredSelection selection, Collection<T> values) {
+		return true;
+	}
+
+	public boolean canRemove(IStructuredSelection selection,
+			Collection<T> choices) {
+
+		return true;
+	}
+
+	public boolean allowsReordering() {
+		return true;
+	}
+
+	public boolean okPressed(Collection<T> values) {
+		return true;
+	}
+}
diff --git a/plugins/org.eclipse.uml2.uml.editor/src/org/eclipse/uml2/uml/editor/dialogs/ChoicesDialog.java b/plugins/org.eclipse.uml2.uml.editor/src/org/eclipse/uml2/uml/editor/dialogs/ChoicesDialog.java
new file mode 100644
index 0000000..f8e751c
--- /dev/null
+++ b/plugins/org.eclipse.uml2.uml.editor/src/org/eclipse/uml2/uml/editor/dialogs/ChoicesDialog.java
@@ -0,0 +1,505 @@
+/*
+ * Copyright (c) 2002, 2013 IBM Corporation, CEA, 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 - Initial API and implementation
+ *   Christian W. Damus (CEA) - Adapted FeatureEditorDialog from EMF for bug 326915
+ *
+ */
+package org.eclipse.uml2.uml.editor.dialogs;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+import org.eclipse.emf.common.notify.AdapterFactory;
+import org.eclipse.emf.common.notify.impl.AdapterFactoryImpl;
+import org.eclipse.emf.common.util.BasicEList;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
+import org.eclipse.emf.edit.provider.ItemProvider;
+import org.eclipse.emf.edit.ui.EMFEditUIPlugin;
+import org.eclipse.emf.edit.ui.provider.AdapterFactoryContentProvider;
+import org.eclipse.emf.edit.ui.provider.ExtendedImageRegistry;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.viewers.AbstractTreeViewer;
+import org.eclipse.jface.viewers.CellLabelProvider;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IContentProvider;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ControlAdapter;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+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.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.dialogs.PatternFilter;
+import org.eclipse.uml2.uml.editor.UMLEditorPlugin;
+
+/**
+ * A two-pane dialog that lets the user user choose elements from the left-side
+ * list to add to the right-side list. The elements on the right-side list may
+ * optionally be ordered by moving them up and down.
+ * 
+ * The dialog delegates a variety of decisions to a
+ * {@linkplain IChoicesDialogDelegate delegate}.
+ * 
+ * @since 4.2
+ * 
+ * @see IChoicesDialogDelegate
+ */
+public class ChoicesDialog<T>
+		extends Dialog {
+
+	protected IContentProvider contentProvider;
+
+	protected Object object;
+
+	protected String displayName;
+
+	protected ItemProvider values;
+
+	protected List<T> choiceOfValues;
+
+	protected EList<T> result;
+
+	protected final IChoicesDialogDelegate<T> delegate;
+
+	public ChoicesDialog(Shell parent, Object object, String displayName,
+			IChoicesDialogDelegate<T> delegate) {
+
+		super(parent);
+
+		setShellStyle(getShellStyle() | SWT.RESIZE | SWT.MAX);
+		this.object = object;
+		this.displayName = displayName;
+		this.choiceOfValues = new java.util.ArrayList<T>(
+			delegate.getChoiceOfValues());
+		this.delegate = delegate;
+
+		AdapterFactory adapterFactory = new ComposedAdapterFactory(
+			Collections.<AdapterFactory> emptyList());
+		values = new ItemProvider(adapterFactory, Collections.EMPTY_LIST);
+		contentProvider = new AdapterFactoryContentProvider(adapterFactory);
+	}
+
+	@Override
+	protected void configureShell(Shell shell) {
+		super.configureShell(shell);
+
+		ILabelProvider labelProvider = delegate.getLabelProvider();
+		shell.setText(UMLEditorPlugin.INSTANCE.getString(
+			"_UI_ChoicesDialog_title",
+			new Object[]{displayName,
+				labelProvider.getText(object)}));
+		shell.setImage(labelProvider.getImage(object));
+	}
+
+	@Override
+	protected Control createDialogArea(Composite parent) {
+		Composite contents = (Composite) super.createDialogArea(parent);
+
+		GridLayout contentsGridLayout = (GridLayout) contents.getLayout();
+		contentsGridLayout.numColumns = 3;
+
+		GridData contentsGridData = (GridData) contents.getLayoutData();
+		contentsGridData.horizontalAlignment = SWT.FILL;
+		contentsGridData.verticalAlignment = SWT.FILL;
+
+		Text patternText = null;
+
+		Group filterGroupComposite = new Group(contents, SWT.NONE);
+		filterGroupComposite.setText(EMFEditUIPlugin.INSTANCE
+			.getString("_UI_Choices_pattern_group"));
+		filterGroupComposite.setLayout(new GridLayout(2, false));
+		filterGroupComposite.setLayoutData(new GridData(SWT.FILL, SWT.DEFAULT,
+			true, false, 3, 1));
+
+		Label label = new Label(filterGroupComposite, SWT.NONE);
+		label.setText(EMFEditUIPlugin.INSTANCE
+			.getString("_UI_Choices_pattern_label"));
+
+		patternText = new Text(filterGroupComposite, SWT.BORDER | SWT.SEARCH);
+		patternText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+		Composite choiceComposite = new Composite(contents, SWT.NONE);
+		{
+			GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
+			data.horizontalAlignment = SWT.END;
+			choiceComposite.setLayoutData(data);
+
+			GridLayout layout = new GridLayout();
+			data.horizontalAlignment = SWT.FILL;
+			layout.marginHeight = 0;
+			layout.marginWidth = 0;
+			layout.numColumns = 1;
+			choiceComposite.setLayout(layout);
+		}
+
+		Label choiceLabel = new Label(choiceComposite, SWT.NONE);
+		choiceLabel.setText(delegate.getChoicesLabelText());
+		GridData choiceLabelGridData = new GridData();
+		choiceLabelGridData.verticalAlignment = SWT.FILL;
+		choiceLabelGridData.horizontalAlignment = SWT.FILL;
+		choiceLabel.setLayoutData(choiceLabelGridData);
+
+		final Table choiceTable = new Table(choiceComposite, SWT.MULTI
+			| SWT.BORDER);
+		GridData choiceTableGridData = new GridData();
+		choiceTableGridData.widthHint = Display.getCurrent().getBounds().width / 5;
+		choiceTableGridData.heightHint = Display.getCurrent().getBounds().height / 3;
+		choiceTableGridData.verticalAlignment = SWT.FILL;
+		choiceTableGridData.horizontalAlignment = SWT.FILL;
+		choiceTableGridData.grabExcessHorizontalSpace = true;
+		choiceTableGridData.grabExcessVerticalSpace = true;
+		choiceTable.setLayoutData(choiceTableGridData);
+
+		final TableViewer choiceTableViewer = new TableViewer(choiceTable);
+		choiceTableViewer.setContentProvider(new AdapterFactoryContentProvider(
+			new AdapterFactoryImpl()));
+		configureLabelProvider(choiceTableViewer);
+		final PatternFilter filter = new PatternFilter() {
+
+			@Override
+			protected boolean isParentMatch(Viewer viewer, Object element) {
+				return viewer instanceof AbstractTreeViewer
+					&& super.isParentMatch(viewer, element);
+			}
+		};
+		choiceTableViewer.addFilter(filter);
+		if (patternText != null) {
+			patternText.addModifyListener(new ModifyListener() {
+
+				public void modifyText(ModifyEvent e) {
+					filter.setPattern(((Text) e.widget).getText());
+					choiceTableViewer.refresh();
+				}
+			});
+		}
+
+		// enforce uniqueness
+		choiceTableViewer.addFilter(new ViewerFilter() {
+
+			@Override
+			public boolean select(Viewer viewer, Object parentElement,
+					Object element) {
+				return !values.getChildren().contains(element);
+			}
+		});
+		choiceTableViewer.setInput(new ItemProvider(choiceOfValues));
+
+		Composite controlButtons = new Composite(contents, SWT.NONE);
+		GridData controlButtonsGridData = new GridData();
+		controlButtonsGridData.verticalAlignment = SWT.FILL;
+		controlButtonsGridData.horizontalAlignment = SWT.FILL;
+		controlButtons.setLayoutData(controlButtonsGridData);
+
+		GridLayout controlsButtonGridLayout = new GridLayout();
+		controlButtons.setLayout(controlsButtonGridLayout);
+
+		new Label(controlButtons, SWT.NONE);
+
+		final Button addButton = new Button(controlButtons, SWT.PUSH);
+		addButton.setText(delegate.getAddButtonText());
+		addButton.setImage(ExtendedImageRegistry.getInstance().getImage(
+			UMLEditorPlugin.INSTANCE.getImage("full/etool16/ArrowRight.gif"))); //$NON-NLS-1$
+		GridData addButtonGridData = new GridData();
+		addButtonGridData.verticalAlignment = SWT.FILL;
+		addButtonGridData.horizontalAlignment = SWT.FILL;
+		addButton.setLayoutData(addButtonGridData);
+
+		final Button removeButton = new Button(controlButtons, SWT.PUSH);
+		removeButton.setText(delegate.getRemoveButtonText());
+		removeButton.setImage(ExtendedImageRegistry.getInstance().getImage(
+			UMLEditorPlugin.INSTANCE.getImage("full/etool16/ArrowLeft.gif"))); //$NON-NLS-1$
+		GridData removeButtonGridData = new GridData();
+		removeButtonGridData.verticalAlignment = SWT.FILL;
+		removeButtonGridData.horizontalAlignment = SWT.FILL;
+		removeButton.setLayoutData(removeButtonGridData);
+
+		Label spaceLabel = new Label(controlButtons, SWT.NONE);
+		GridData spaceLabelGridData = new GridData();
+		spaceLabelGridData.verticalSpan = 2;
+		spaceLabel.setLayoutData(spaceLabelGridData);
+
+		final boolean allowReorder = delegate.allowsReordering();
+		final Button upButton = allowReorder
+			? new Button(controlButtons, SWT.PUSH)
+			: null;
+		if (allowReorder) {
+			upButton
+				.setText(EMFEditUIPlugin.INSTANCE.getString("_UI_Up_label"));
+			upButton.setImage(ExtendedImageRegistry.getInstance().getImage(
+				UMLEditorPlugin.INSTANCE.getImage("full/etool16/ArrowUp.gif"))); //$NON-NLS-1$
+			GridData upButtonGridData = new GridData();
+			upButtonGridData.verticalAlignment = SWT.FILL;
+			upButtonGridData.horizontalAlignment = SWT.FILL;
+			upButton.setLayoutData(upButtonGridData);
+		}
+
+		final Button downButton = allowReorder
+			? new Button(controlButtons, SWT.PUSH)
+			: null;
+		if (allowReorder) {
+			downButton.setText(EMFEditUIPlugin.INSTANCE
+				.getString("_UI_Down_label"));
+			downButton.setImage(ExtendedImageRegistry.getInstance()
+				.getImage(
+					UMLEditorPlugin.INSTANCE
+						.getImage("full/etool16/ArrowDown.gif"))); //$NON-NLS-1$
+			GridData downButtonGridData = new GridData();
+			downButtonGridData.verticalAlignment = SWT.FILL;
+			downButtonGridData.horizontalAlignment = SWT.FILL;
+			downButton.setLayoutData(downButtonGridData);
+		}
+
+		Composite valuesComposite = new Composite(contents, SWT.NONE);
+		{
+			GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
+			data.horizontalAlignment = SWT.END;
+			valuesComposite.setLayoutData(data);
+
+			GridLayout layout = new GridLayout();
+			data.horizontalAlignment = SWT.FILL;
+			layout.marginHeight = 0;
+			layout.marginWidth = 0;
+			layout.numColumns = 1;
+			valuesComposite.setLayout(layout);
+		}
+
+		Label valuesLabel = new Label(valuesComposite, SWT.NONE);
+		valuesLabel.setText(delegate.getValuesLabelText());
+		GridData featureLabelGridData = new GridData();
+		featureLabelGridData.horizontalSpan = 2;
+		featureLabelGridData.horizontalAlignment = SWT.FILL;
+		featureLabelGridData.verticalAlignment = SWT.FILL;
+		valuesLabel.setLayoutData(featureLabelGridData);
+
+		final Table valuesTable = new Table(valuesComposite, SWT.MULTI
+			| SWT.BORDER);
+		GridData featureTableGridData = new GridData();
+		featureTableGridData.widthHint = Display.getCurrent().getBounds().width / 5;
+		featureTableGridData.heightHint = Display.getCurrent().getBounds().height / 3;
+		featureTableGridData.verticalAlignment = SWT.FILL;
+		featureTableGridData.horizontalAlignment = SWT.FILL;
+		featureTableGridData.grabExcessHorizontalSpace = true;
+		featureTableGridData.grabExcessVerticalSpace = true;
+		valuesTable.setLayoutData(featureTableGridData);
+
+		final TableViewer valuesTableViewer = new TableViewer(valuesTable);
+		valuesTableViewer.setContentProvider(contentProvider);
+		configureLabelProvider(valuesTableViewer);
+		valuesTableViewer.setInput(values);
+		final EList<Object> children = values.getChildren();
+		if (!children.isEmpty()) {
+			valuesTableViewer.setSelection(new StructuredSelection(children
+				.get(0)));
+		}
+
+		choiceTableViewer.addDoubleClickListener(new IDoubleClickListener() {
+
+			public void doubleClick(DoubleClickEvent event) {
+				if (addButton.isEnabled()) {
+					addButton.notifyListeners(SWT.Selection, null);
+				}
+			}
+		});
+
+		valuesTableViewer.addDoubleClickListener(new IDoubleClickListener() {
+
+			public void doubleClick(DoubleClickEvent event) {
+				if (removeButton.isEnabled()) {
+					removeButton.notifyListeners(SWT.Selection, null);
+				}
+			}
+		});
+
+		if (allowReorder) {
+			upButton.addSelectionListener(new SelectionAdapter() {
+
+				@Override
+				public void widgetSelected(SelectionEvent event) {
+					IStructuredSelection selection = (IStructuredSelection) valuesTableViewer
+						.getSelection();
+					int minIndex = 0;
+					for (Iterator<?> i = selection.iterator(); i.hasNext();) {
+						Object value = i.next();
+						int index = children.indexOf(value);
+						children.move(Math.max(index - 1, minIndex++), value);
+					}
+				}
+			});
+
+			downButton.addSelectionListener(new SelectionAdapter() {
+
+				@Override
+				public void widgetSelected(SelectionEvent event) {
+					IStructuredSelection selection = (IStructuredSelection) valuesTableViewer
+						.getSelection();
+					int maxIndex = children.size() - 1;
+					List<?> objects = selection.toList();
+					for (ListIterator<?> i = objects.listIterator(objects
+						.size()); i.hasPrevious();) {
+						Object value = i.previous();
+						int index = children.indexOf(value);
+						children.move(Math.min(index + 1, maxIndex--), value);
+					}
+				}
+			});
+		}
+
+		addButton.addSelectionListener(new SelectionAdapter() {
+
+			// event is null when choiceTableViewer is double clicked
+			@Override
+			public void widgetSelected(SelectionEvent event) {
+				IStructuredSelection selection = (IStructuredSelection) choiceTableViewer
+					.getSelection();
+				for (Iterator<?> i = selection.iterator(); i.hasNext();) {
+					Object value = i.next();
+					if (!children.contains(value)) {
+						children.add(value);
+					}
+				}
+				valuesTableViewer.refresh();
+				valuesTableViewer.setSelection(selection);
+				choiceTableViewer.refresh();
+			}
+		});
+
+		removeButton.addSelectionListener(new SelectionAdapter() {
+
+			// event is null when valuesTableViewer is double clicked
+			@Override
+			public void widgetSelected(SelectionEvent event) {
+				IStructuredSelection selection = (IStructuredSelection) valuesTableViewer
+					.getSelection();
+				Object firstValue = null;
+				for (Iterator<?> i = selection.iterator(); i.hasNext();) {
+					Object value = i.next();
+					if (firstValue == null) {
+						firstValue = value;
+					}
+					children.remove(value);
+				}
+
+				if (!children.isEmpty()) {
+					valuesTableViewer.setSelection(new StructuredSelection(
+						children.get(0)));
+				}
+
+				choiceTableViewer.refresh();
+				choiceTableViewer.setSelection(selection);
+			}
+		});
+
+		choiceTableViewer
+			.addSelectionChangedListener(new ISelectionChangedListener() {
+
+				public void selectionChanged(SelectionChangedEvent event) {
+					addButton.setEnabled(delegate.canAdd(
+						(IStructuredSelection) event.getSelection(),
+						getValues()));
+				}
+			});
+
+		valuesTableViewer
+			.addSelectionChangedListener(new ISelectionChangedListener() {
+
+				public void selectionChanged(SelectionChangedEvent event) {
+					removeButton.setEnabled(delegate.canRemove(
+						(IStructuredSelection) event.getSelection(),
+						getChoices()));
+				}
+			});
+
+		return contents;
+	}
+
+	protected void configureLabelProvider(TableViewer viewer) {
+		final ILabelProvider labelProvider = delegate
+			.createLabelProvider(viewer);
+		if (labelProvider instanceof CellLabelProvider) {
+			// create a table column to install styling support
+			final TableViewerColumn column = new TableViewerColumn(viewer,
+				SWT.LEFT);
+			column.setLabelProvider((CellLabelProvider) labelProvider);
+
+			// pin the width of the column to the table size (only column)
+			viewer.getTable().addControlListener(new ControlAdapter() {
+
+				@Override
+				public void controlResized(ControlEvent e) {
+					column.getColumn().setWidth(
+						((Control) e.widget).getSize().x);
+				}
+			});
+		} else {
+			viewer.setLabelProvider(labelProvider);
+		}
+
+	}
+
+	protected Collection<T> getChoices() {
+		return choiceOfValues;
+	}
+
+	protected EList<T> getValues() {
+		Class<T> type = delegate.getElementType();
+
+		EList<T> result = new BasicEList<T>(values.getChildren().size());
+		for (Object next : values.getChildren()) {
+			if (type.isInstance(next)) {
+				result.add(type.cast(next));
+			}
+		}
+
+		return result;
+	}
+
+	@Override
+	protected void okPressed() {
+		EList<T> values = getValues();
+		if (delegate.okPressed(values)) {
+			result = values;
+			super.okPressed();
+		}
+	}
+
+	@Override
+	public boolean close() {
+		contentProvider.dispose();
+		return super.close();
+	}
+
+	public EList<T> getResult() {
+		return result;
+	}
+}
diff --git a/plugins/org.eclipse.uml2.uml.editor/src/org/eclipse/uml2/uml/editor/dialogs/IChoicesDialogDelegate.java b/plugins/org.eclipse.uml2.uml.editor/src/org/eclipse/uml2/uml/editor/dialogs/IChoicesDialogDelegate.java
new file mode 100644
index 0000000..e1cb039
--- /dev/null
+++ b/plugins/org.eclipse.uml2.uml.editor/src/org/eclipse/uml2/uml/editor/dialogs/IChoicesDialogDelegate.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2013 CEA 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:
+ *   Christian W. Damus (CEA) - Initial API and implementation
+ *
+ */
+package org.eclipse.uml2.uml.editor.dialogs;
+
+import java.util.Collection;
+
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.Viewer;
+
+/**
+ * Protocol for a delegate that supplies application-specific information and
+ * decisions to a {@link ChoicesDialog}.
+ * 
+ * @since 4.2
+ * 
+ * @see ChoicesDialog
+ * @see AbstractChoicesDialogDelegate
+ */
+public interface IChoicesDialogDelegate<T> {
+
+	Class<T> getElementType();
+
+	String getChoicesLabelText();
+
+	String getValuesLabelText();
+
+	String getAddButtonText();
+
+	String getRemoveButtonText();
+
+	ILabelProvider getLabelProvider();
+
+	ILabelProvider createLabelProvider(Viewer viewer);
+
+	Collection<? extends T> getChoiceOfValues();
+
+	boolean canAdd(IStructuredSelection selection, Collection<T> values);
+
+	boolean canRemove(IStructuredSelection selection, Collection<T> choices);
+
+	boolean allowsReordering();
+
+	boolean okPressed(Collection<T> values);
+}