Bug 456529 - Parameter "Name" should be "Command Parameter ID"

Label of Parameter Editor changed from "Name" to "Command Parameter ID".
A find button added that lets the user to choose only from the
parameters of the referenced command.

Bug: 456529
Change-Id: I63d100639cefda847eb79206ce5ae264bf41286f
Signed-off-by: Veselin Markov <veselin_m84@yahoo.com>
diff --git a/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/Messages.java b/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/Messages.java
index 4ba2c16..360ab30 100644
--- a/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/Messages.java
+++ b/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/Messages.java
@@ -426,9 +426,14 @@
 
 	public String ParameterEditor_TreeLabel;
 	public String ParameterEditor_TreeLabelDescription;
-	public String ParameterEditor_Name;
+	public String ParameterEditor_Command_Parameter_ID;
 	public String ParameterEditor_Value;
 
+	public String ParameterIdSelectionDialog_ShellTitle;
+	public String ParameterIdSelectionDialog_DialogTitle;
+	public String ParameterIdSelectionDialog_DialogMessage;
+	public String ParameterIdSelectionDialog_LabelText;
+
 	public String PopupMenuEditor_TreeLabel;
 	public String PopupMenuEditor_TreeLabelDescription;
 
diff --git a/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/Messages.properties b/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/Messages.properties
index c41e0e5..85a1900 100644
--- a/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/Messages.properties
+++ b/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/Messages.properties
@@ -397,9 +397,14 @@
 
 ParameterEditor_TreeLabel=Parameter
 ParameterEditor_TreeLabelDescription=Parameter Bla Bla Bla Bla
-ParameterEditor_Name=Name
+ParameterEditor_Command_Parameter_ID=Command Parameter ID
 ParameterEditor_Value=Value
 
+ParameterIdSelectionDialog_ShellTitle=Find command parameter id
+ParameterIdSelectionDialog_DialogTitle=Find command parameter id
+ParameterIdSelectionDialog_DialogMessage=Find the command parameter id to be referenced by this parameter.
+ParameterIdSelectionDialog_LabelText=Command Parameter Id
+
 PopupMenuEditor_TreeLabel=Popup Menu
 PopupMenuEditor_TreeLabelDescription=Popup Menu Bla Bla Bla Bla
 
diff --git a/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/common/component/ParameterEditor.java b/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/common/component/ParameterEditor.java
index e2b4d43..d198fe1 100644
--- a/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/common/component/ParameterEditor.java
+++ b/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/common/component/ParameterEditor.java
@@ -12,16 +12,23 @@
 package org.eclipse.e4.tools.emf.ui.internal.common.component;
 
 import javax.inject.Inject;
+
 import org.eclipse.core.databinding.observable.list.IObservableList;
 import org.eclipse.core.databinding.observable.value.WritableValue;
+import org.eclipse.e4.core.contexts.ContextInjectionFactory;
+import org.eclipse.e4.core.contexts.EclipseContextFactory;
+import org.eclipse.e4.core.contexts.IEclipseContext;
 import org.eclipse.e4.tools.emf.ui.common.Util;
 import org.eclipse.e4.tools.emf.ui.common.component.AbstractComponentEditor;
 import org.eclipse.e4.tools.emf.ui.internal.ResourceProvider;
+import org.eclipse.e4.tools.emf.ui.internal.common.component.ControlFactory.TextPasteHandler;
+import org.eclipse.e4.tools.emf.ui.internal.common.component.dialogs.ParameterIdSelectionDialog;
 import org.eclipse.e4.ui.model.application.commands.MParameter;
 import org.eclipse.e4.ui.model.application.commands.impl.CommandsPackageImpl;
 import org.eclipse.e4.ui.model.application.impl.ApplicationPackageImpl;
 import org.eclipse.emf.databinding.EMFDataBindingContext;
 import org.eclipse.emf.databinding.edit.EMFEditProperties;
+import org.eclipse.emf.databinding.edit.IEMFEditValueProperty;
 import org.eclipse.emf.ecore.EObject;
 import org.eclipse.jface.databinding.swt.IWidgetValueProperty;
 import org.eclipse.jface.databinding.swt.WidgetProperties;
@@ -29,10 +36,16 @@
 import org.eclipse.swt.custom.CTabFolder;
 import org.eclipse.swt.custom.CTabItem;
 import org.eclipse.swt.custom.StackLayout;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
 import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+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.Label;
+import org.eclipse.swt.widgets.Text;
 
 public class ParameterEditor extends AbstractComponentEditor {
 	private Composite composite;
@@ -41,6 +54,9 @@
 	private StackLayout stackLayout;
 
 	@Inject
+	private IEclipseContext eclipseContext;
+
+	@Inject
 	public ParameterEditor() {
 		super();
 	}
@@ -126,7 +142,7 @@
 		}
 
 		ControlFactory.createTextField(parent, Messages.ModelTooling_Common_Id, master, context, textProp, EMFEditProperties.value(getEditingDomain(), ApplicationPackageImpl.Literals.APPLICATION_ELEMENT__ELEMENT_ID));
-		ControlFactory.createTextField(parent, Messages.ParameterEditor_Name, master, context, textProp, EMFEditProperties.value(getEditingDomain(), CommandsPackageImpl.Literals.PARAMETER__NAME));
+		createParameterNameRow(parent, textProp);
 		ControlFactory.createTextField(parent, Messages.ParameterEditor_Value, master, context, textProp, EMFEditProperties.value(getEditingDomain(), CommandsPackageImpl.Literals.PARAMETER__VALUE));
 
 		item = new CTabItem(folder, SWT.NONE);
@@ -150,4 +166,39 @@
 		return null;
 	}
 
+	private void createParameterNameRow(Composite parent, IWidgetValueProperty textProp) {
+		{
+			Label commandParameterIdLabel = new Label(parent, SWT.NONE);
+			commandParameterIdLabel.setText(Messages.ParameterEditor_Command_Parameter_ID);
+			commandParameterIdLabel.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_END));
+
+			Text commandParameterIdValue = new Text(parent, SWT.BORDER);
+			GridData gd = new GridData(GridData.FILL_HORIZONTAL);
+			commandParameterIdValue.setLayoutData(gd);
+			TextPasteHandler.createFor(commandParameterIdValue);
+			IEMFEditValueProperty modelProp = EMFEditProperties.value(getEditingDomain(), CommandsPackageImpl.Literals.PARAMETER__NAME);
+			context.bindValue(textProp.observeDelayed(200, commandParameterIdValue), modelProp.observeDetail(getMaster()));
+		}
+
+		Button chooseParameterButton = new Button(parent, SWT.PUSH | SWT.FLAT);
+		chooseParameterButton.setText(Messages.ModelTooling_Common_FindEllipsis);
+		chooseParameterButton.setImage(createImage(ResourceProvider.IMG_Obj16_zoom));
+		chooseParameterButton.addSelectionListener(new ChooseParameterButtonSelectionListener());
+		chooseParameterButton.setLayoutData(new GridData());
+	}
+
+	private final class ChooseParameterButtonSelectionListener extends SelectionAdapter {
+		@Override
+		public void widgetSelected(SelectionEvent e) {
+			WritableValue master = getMaster();
+			if (master == null || !(master.getValue() instanceof MParameter)) {
+				return;
+			}
+
+			IEclipseContext staticContext = EclipseContextFactory.create("ParameterIdSelectionDialog static context"); //$NON-NLS-1$
+			staticContext.set(MParameter.class, (MParameter) master.getValue());
+			ParameterIdSelectionDialog dialog = ContextInjectionFactory.make(ParameterIdSelectionDialog.class, eclipseContext, staticContext);
+			dialog.open();
+		}
+	}
 }
diff --git a/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/common/component/dialogs/ParameterIdSelectionDialog.java b/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/common/component/dialogs/ParameterIdSelectionDialog.java
new file mode 100644
index 0000000..ca9ed68
--- /dev/null
+++ b/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/common/component/dialogs/ParameterIdSelectionDialog.java
@@ -0,0 +1,211 @@
+/*******************************************************************************
+ * Copyright (c) 2015-2015 Veselin Markov.
+ *
+ * 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:
+ * Veselin Markov <veselin_m84@yahoo.com> - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.e4.tools.emf.ui.internal.common.component.dialogs;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.inject.Inject;
+
+import org.eclipse.e4.core.services.nls.Translation;
+import org.eclipse.e4.tools.emf.ui.common.IModelResource;
+import org.eclipse.e4.tools.emf.ui.internal.Messages;
+import org.eclipse.e4.tools.emf.ui.internal.common.ComponentLabelProvider;
+import org.eclipse.e4.tools.emf.ui.internal.common.ModelEditor;
+import org.eclipse.e4.ui.model.application.commands.MCommand;
+import org.eclipse.e4.ui.model.application.commands.MCommandParameter;
+import org.eclipse.e4.ui.model.application.commands.MParameter;
+import org.eclipse.e4.ui.model.application.commands.impl.CommandsPackageImpl;
+import org.eclipse.e4.ui.model.application.ui.menu.impl.MenuPackageImpl;
+import org.eclipse.e4.ui.workbench.modeling.EModelService;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.common.util.TreeIterator;
+import org.eclipse.emf.ecore.EAttribute;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.emf.edit.domain.EditingDomain;
+import org.eclipse.jface.viewers.IBaseLabelProvider;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * This dialog presents to the user in a table the available {@link MCommandParameter}s that
+ * may be referenced by the specified {@link MParameter}.
+ *
+ * @author Markov
+ * @noinstantiate this dialog uses DI an should not be instantiated by the user.
+ */
+public class ParameterIdSelectionDialog extends AbstractIdDialog<MParameter, MCommandParameter> {
+
+	@Inject
+	protected ModelEditor editor;
+
+	/** The parameter, which {@link MParameter#getName() name} feature has to be modified. */
+	protected MParameter parameter;
+	protected Set<EStructuralFeature> parametersFeatures = new HashSet<EStructuralFeature>();
+	protected Set<EStructuralFeature> commandsFeatures = new HashSet<EStructuralFeature>();
+
+	@Inject
+	public ParameterIdSelectionDialog(Shell parentShell, IModelResource resource, MParameter parameter,
+		EditingDomain domain, EModelService modelService, @Translation Messages messages) {
+		super(parentShell, resource, parameter, domain, modelService, messages);
+
+		this.parameter = parameter;
+		parametersFeatures.add(MenuPackageImpl.Literals.HANDLED_ITEM__PARAMETERS);
+		commandsFeatures.add(MenuPackageImpl.Literals.HANDLED_ITEM__COMMAND);
+	}
+
+	@Override
+	protected IBaseLabelProvider getLabelProvider() {
+		return new ComponentLabelProvider(editor, messages);
+	}
+
+	@Override
+	protected String getShellTitle() {
+		return messages.ParameterIdSelectionDialog_ShellTitle;
+	}
+
+	@Override
+	protected String getDialogTitle() {
+		return messages.ParameterIdSelectionDialog_DialogTitle;
+	}
+
+	@Override
+	protected String getDialogMessage() {
+		return messages.ParameterIdSelectionDialog_DialogMessage;
+	}
+
+	@Override
+	protected String getLabelText() {
+		return messages.ParameterIdSelectionDialog_LabelText;
+	}
+
+	@Override
+	protected List<MCommandParameter> getViewerInput() {
+		return getParametersOfParentNodesCommand();
+	}
+
+	@Override
+	protected EAttribute getFeatureLiteral() {
+		return CommandsPackageImpl.Literals.PARAMETER__NAME;
+	}
+
+	@Override
+	protected String getListItemInformation(MCommandParameter listItem) {
+		return null;
+	}
+
+	/**
+	 * Reads the parameters of the MComand in the {@link EObject} referencing the given {@link #parameter}.
+	 *
+	 * Searches for the parent element of {@linkplain #parameter}. Once found reads the {@link MCommandParameter}s of
+	 * the referenced {@link MCommand}, given the found parent references a MCommand.
+	 *
+	 * @return all found MCommandParameters or an empty {@link List}, never a {@code null} value.
+	 */
+	protected List<MCommandParameter> getParametersOfParentNodesCommand() {
+		TreeIterator<EObject> it = EcoreUtil.getAllContents((EObject) resource.getRoot().get(0), true);
+		while (it.hasNext()) {
+			EObject containerObjectWithCommand = it.next();
+			if (containerObjectWithCommand != null && canSupplyParameters(containerObjectWithCommand)) {
+				List<MCommandParameter> commandParameters = getCommandParameters(containerObjectWithCommand);
+				return commandParameters;
+			}
+		}
+		return Collections.emptyList();
+	}
+
+	/**
+	 * Checks if the given {@code object} references a {@link MCommand} and the {@link #parameter}.
+	 *
+	 * @param object the object to be checked. May not be {@code null}.
+	 * @return {@code true} if {@code object} is a model-element that references a command and a list of parameters with
+	 *         {@link #parameter}, {@code false} otherwise.
+	 */
+	protected boolean canSupplyParameters(EObject object) {
+		return referencesCommand(object) && referencesParameters(object)
+			&& containsSearchedParameter(object);
+	}
+
+	/**
+	 * Checks whether the given {@code object} has a {@link EReference} to a {@link MCommand} feature.
+	 *
+	 * @param object that will be checked. May not be {@code null}.
+	 * @return {@code true} if the given {@code object} can reference a MCommand, {@code false} otherwise.
+	 */
+	protected boolean referencesCommand(EObject object) {
+		EList<EReference> eAllReferences = object.eClass().getEAllReferences();
+		for (EReference r : eAllReferences) {
+			if (commandsFeatures.contains(r)) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * Checks whether the given {@code object} has a {@link EReference} to a list of {@link MParameter}s feature.
+	 *
+	 * @param object that will be checked. May not be {@code null}.
+	 * @return {@code true} if the given {@code object} can reference a MParameters, {@code false} otherwise.
+	 */
+	protected boolean referencesParameters(EObject object) {
+		EList<EReference> eAllReferences = object.eClass().getEAllReferences();
+		for (EReference r : eAllReferences) {
+			if (parametersFeatures.contains(r)) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * Checks if the {@link #parameter} is contained in the {@link MParameter}s feature of the given {@code object}.
+	 *
+	 * @param object that may contain the {@code parameter} we look for.
+	 * @return true if {@code object} contains the {@code parameter}, false otherwise.
+	 */
+	protected boolean containsSearchedParameter(EObject object) {
+		for (EStructuralFeature parametersFeature : parametersFeatures) {
+			Object parameters = object.eGet(parametersFeature);
+			if (parameters != null && parameters instanceof Collection<?>) {
+				return ((Collection<?>) parameters).contains(parameter);
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * Reads the {@link MCommandParameter}s from the {@link MCommand} from the given {@code containerObjectWithCommand}.
+	 *
+	 * @param containerObjectWithCommand an object containing a {@link EReference} to an {@link MCommand}
+	 * @return a {@link List} with the {@link MCommandParameter}s or an empty list but never {@code null} value.
+	 *
+	 * @throws IllegalArgumentException if {@code containerObjectWithCommand} contains no {@link MCommand}. See
+	 *             {@link #referencesCommand(EObject)}.
+	 */
+	protected List<MCommandParameter> getCommandParameters(EObject containerObjectWithCommand) {
+		Object command = containerObjectWithCommand.eGet(MenuPackageImpl.Literals.HANDLED_ITEM__COMMAND);
+
+		if (command != null && command instanceof MCommand) {
+			List<MCommandParameter> parameters = ((MCommand) command).getParameters();
+			if (parameters != null)
+				return parameters;
+			return Collections.emptyList();
+		}
+		throw new IllegalArgumentException("The parameter contains no MCommand"); //$NON-NLS-1$
+	}
+}