blob: 271d82c3c2583e4054842f157c0251f85638d7a7 [file] [log] [blame]
/*****************************************************************************
* Copyright (c) 2013 CEA LIST.
*
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Ansgar Radermacher ansgar.radermacher@cea.fr
*
*****************************************************************************/
package org.eclipse.papyrus.designer.transformation.ui.dialogs;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.papyrus.designer.deployment.tools.ConfigUtils;
import org.eclipse.papyrus.designer.deployment.tools.DepCreation;
import org.eclipse.papyrus.designer.deployment.tools.DepPlanUtils;
import org.eclipse.papyrus.designer.deployment.tools.DepUtils;
import org.eclipse.papyrus.designer.transformation.base.ElementFilter;
import org.eclipse.papyrus.designer.transformation.base.utils.DescriptionUtils;
import org.eclipse.papyrus.designer.transformation.core.sync.DepPlanSync;
import org.eclipse.papyrus.designer.transformation.ui.Messages;
import org.eclipse.papyrus.designer.transformation.ui.provider.AttributeLabelProvider;
import org.eclipse.papyrus.designer.transformation.ui.provider.InstanceLabelProvider;
import org.eclipse.papyrus.infra.widgets.toolbox.utils.DialogUtils;
import org.eclipse.papyrus.uml.tools.utils.PackageUtil;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
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.layout.RowLayout;
import org.eclipse.swt.widgets.Combo;
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.Text;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.dialogs.SelectionStatusDialog;
import org.eclipse.uml2.uml.Class;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.Connector;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Enumeration;
import org.eclipse.uml2.uml.EnumerationLiteral;
import org.eclipse.uml2.uml.Feature;
import org.eclipse.uml2.uml.InstanceSpecification;
import org.eclipse.uml2.uml.InstanceValue;
import org.eclipse.uml2.uml.LiteralBoolean;
import org.eclipse.uml2.uml.LiteralInteger;
import org.eclipse.uml2.uml.LiteralString;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.Slot;
import org.eclipse.uml2.uml.Type;
import org.eclipse.uml2.uml.ValueSpecification;
/**
* Select container rules, either from a list of globally defined rules or from
* local rules which may be created "on the fly" by this dialog.
*
* TODO: extend rule application to instances (problematic, since rules
* transformation is done on type level)
*/
public class ConfigureInstanceDialog extends SelectionStatusDialog {
private static final String INSTANCE_CONFIGURATION = "Instance configuration"; //$NON-NLS-1$
protected Class m_component;
protected Label fDescriptionLabel;
protected Text fDescription;
protected TreeViewer fInstanceList;
protected TableViewer fPropertyList;
protected Property m_currentAttribute;
protected final String valueLabelPrefix = "Value:"; //$NON-NLS-1$
protected Label fValueLabel;
protected Text fValue;
protected Combo fComboValue;
protected Package m_model;
protected Feature m_feature;
protected EList<Package> visitedPackages;
protected boolean m_rulePropertiesOnly;
protected InstanceSpecification m_instance;
EList<InstanceSpecification> m_instanceList;
public ConfigureInstanceDialog(Shell parent) {
super(parent);
}
public boolean init(Class component, ExecutionEvent from) {
// visitedPackages = new BasicEList<Package> ();
DepPlanSync.syncAllDepPlans(component);
m_component = component;
m_instance = null;
m_feature = null;
m_model = PackageUtil.getUserModel(from);
if (m_model == null) {
return false;
}
return checkAndGetInstances();
}
public boolean init(InstanceSpecification instance, ExecutionEvent from) {
// visitedPackages = new BasicEList<Package> ();
DepPlanSync.syncDepPlan(instance.getNearestPackage());
m_component = DepUtils.getImplementation(instance);
m_instance = instance;
m_feature = null;
m_model = PackageUtil.getUserModel(from);
return checkAndGetInstances();
}
public boolean init(Feature feature, ExecutionEvent from) {
// visitedPackages = new BasicEList<Package> ();
m_feature = feature;
m_model = PackageUtil.getUserModel(from);
if (m_model == null) {
m_model = PackageUtil.getRootPackage(feature);
}
m_instance = null;
// need to overload for connector support
if (feature instanceof Property) {
Type type = ((Property) feature).getType();
if (type instanceof Class) {
m_component = (Class) type;
return checkAndGetInstances();
}
}
return false;
}
/**
* A filter class that selects instances associated with the selected feature or component
*/
class InstanceFilter implements ElementFilter {
private String featureCandidateName;
@Override
public boolean acceptElement(Element element) {
if (element instanceof InstanceSpecification) {
InstanceSpecification instance = (InstanceSpecification) element;
if (m_feature instanceof Property) {
EList<Slot> slots = DepUtils.getReferencingSlots(instance);
for (Slot slot : slots) {
if (slot.getDefiningFeature() == m_feature) {
return true;
}
}
}
else if (m_feature instanceof Connector) {
// Connector instances cannot be found via a slot. Since a connector is not a structural feature,
// it cannot be referenced via the "definingFeature" property of a slot. Therefore, the deployment
// plan creation (@see DepCreation.createDepPlan) simply omits slots, but still creates instances
// for the interaction components referenced by an FCM connector.
// TODO: the following code relies on specific order of instances and might not always work.
Element owner = m_feature.getOwner();
if (DepUtils.getImplementation(instance) == owner) {
// instance is for owner of feature: examine name
featureCandidateName = instance.getName() + "." + m_feature.getName(); //$NON-NLS-1$
}
else if (featureCandidateName != null) {
if (featureCandidateName.equals(instance.getName())) {
return true;
}
}
} else if (DepUtils.getImplementation(instance) == m_component) {
return true;
}
}
return false;
}
}
/**
* retrieve the instance list.
*
* @return false, if no deployment plan could be found.
*/
public boolean checkAndGetInstances() {
visitedPackages = new BasicEList<Package>();
m_instanceList = new BasicEList<InstanceSpecification>();
ElementFilter filter = new InstanceFilter();
DepUtils.getAllInstances(m_model, m_instanceList, filter);
if (m_instanceList.size() == 0) {
Shell shell = Display.getCurrent().getActiveShell();
if (DepPlanUtils.getAllDepPlans(m_model).size() == 0) {
MessageDialog.openInformation(shell, INSTANCE_CONFIGURATION,
Messages.ConfigureInstanceDialog_NO_DEP_PLANS);
return false;
}
else if (MessageDialog.openConfirm(shell, INSTANCE_CONFIGURATION,
Messages.ConfigureInstanceDialog_INSTANCE_LIST_EMPTY)) {
DepPlanSync.syncAllDepPlans(m_model);
visitedPackages = new BasicEList<Package>();
DepUtils.getAllInstances(m_model, m_instanceList, filter);
if (m_instanceList.size() == 0) {
MessageDialog
.openInformation(
shell,
INSTANCE_CONFIGURATION,
Messages.ConfigureInstanceDialog_NO_INSTANCES);
return false;
}
}
}
return true;
}
/**
* @see SelectionStatusDialog#computeResult()
*/
@Override
protected void computeResult() {
// nothing to do
}
@Override
public Control createDialogArea(Composite parent) {
Composite contents = (Composite) super.createDialogArea(parent);
// (parent, "Container rules", "Avail. extensions/interceptors");
createInstanceSelectionGroup(contents);
createInstanceConfigurationGroup(contents);
return contents;
}
protected void createInstanceSelectionGroup(Composite parent) {
Composite instanceSelection = new Composite(parent, SWT.NONE);
GridLayout grid = new GridLayout(1, true);
GridData groupGridData = new GridData();
groupGridData.grabExcessVerticalSpace = true;
groupGridData.grabExcessHorizontalSpace = true;
groupGridData.horizontalAlignment = GridData.FILL;
groupGridData.verticalAlignment = GridData.FILL;
instanceSelection.setLayout(grid);
instanceSelection.setLayoutData(groupGridData);
/*
* fRules = DialogUtils.createFilteredList (ruleSelGroup, new
* RuleLabelProvider(), 200, 200, SWT.BORDER | SWT.V_SCROLL |
* SWT.H_SCROLL);
*/
//
// --------------- instance selection -------------------
//
Group instanceSelGroup = new Group(instanceSelection, SWT.BORDER);
instanceSelGroup.setText(addSpaces(Messages.ConfigureInstanceDialog_ASSOCIATED_INSTANCES));
// ruleGroup.setLayout(new RowLayout (SWT.VERTICAL));
instanceSelGroup.setLayout(new GridLayout(1, false));
instanceSelGroup.setLayoutData(groupGridData);
fInstanceList = new TreeViewer(instanceSelGroup, SWT.BORDER);
GridData data = new GridData(GridData.FILL_BOTH);
data.heightHint = 100;
data.widthHint = 350;
fInstanceList.getTree().setLayoutData(data);
fInstanceList.setLabelProvider(new InstanceLabelProvider());
fInstanceList.setContentProvider(new ITreeContentProvider() {
@Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
@Override
public void dispose() {
}
@Override
public boolean hasChildren(Object element) {
return getChildren(element).length > 0;
}
@Override
public Object getParent(Object element) {
return null;
}
@Override
public Object[] getElements(Object inputElement) {
return (Object[]) inputElement;
}
@Override
public Object[] getChildren(Object parentElement) {
if (parentElement instanceof InstanceSpecification) {
return DepUtils.getContainedInstances((InstanceSpecification) parentElement).toArray();
}
return new Object[0];
}
});
fInstanceList.setInput(m_instanceList.toArray());
fInstanceList.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
ISelection selection = fInstanceList.getSelection();
if (selection instanceof StructuredSelection) {
Object[] selected = ((StructuredSelection) selection)
.toArray();
if ((selected.length == 1)
&& (selected[0] instanceof InstanceSpecification)) {
m_instance = (InstanceSpecification) selected[0];
Classifier cl = DepUtils.getClassifier(m_instance);
fPropertyList.setInput(getConfigAttributes(cl).toArray());
selectProperty(m_currentAttribute);
}
}
}
});
if (m_instance != null) {
int index = m_instanceList.indexOf(m_instance);
if (index != -1) {
TreeItem treeItem = fInstanceList.getTree().getItem(index);
fInstanceList.getTree().setSelection(treeItem);
}
}
}
// create instance configuration group
protected void createInstanceConfigurationGroup(Composite parent) {
GridData groupGridData = DialogUtils.createFillGridData();
Group instanceConfigurationGroup = new Group(parent, SWT.BORDER);
instanceConfigurationGroup.setText(addSpaces(Messages.ConfigureInstanceDialog_CONFIGURATION));
instanceConfigurationGroup.setLayout(new RowLayout(SWT.VERTICAL));
instanceConfigurationGroup.setLayout(new GridLayout(1, false));
instanceConfigurationGroup.setLayoutData(groupGridData);
// fRuleName = new Text (ruleInfoGroup, SWT.NONE);
Label configL = new Label(instanceConfigurationGroup, SWT.NONE);
configL.setText(Messages.ConfigureInstanceDialog_AVAILABLE_PROPERTIES);
fPropertyList = new TableViewer(instanceConfigurationGroup, SWT.BORDER);
fPropertyList.setLabelProvider(new AttributeLabelProvider());
fPropertyList.setContentProvider(new ArrayContentProvider());
fPropertyList.setInput(getConfigAttributes(m_component).toArray());
fPropertyList
.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
ISelection selection = fPropertyList.getSelection();
if (selection instanceof StructuredSelection) {
Object[] selected = ((StructuredSelection) selection)
.toArray();
if ((selected.length == 1)
&& (selected[0] instanceof Property)) {
selectProperty((Property) selected[0]);
}
}
}
});
fValueLabel = new Label(instanceConfigurationGroup, SWT.NONE);
GridData span2 = new GridData();
span2.horizontalAlignment = GridData.FILL;
span2.grabExcessHorizontalSpace = true;
span2.heightHint = 70;
fPropertyList.getTable().setLayoutData(span2);
fValue = new Text(instanceConfigurationGroup, SWT.WRAP);
span2 = new GridData();
span2.horizontalAlignment = GridData.FILL;
span2.grabExcessHorizontalSpace = true;
fValue.setLayoutData(span2);
fValue.addFocusListener(new FocusListener() {
@Override
public void focusLost(FocusEvent e) {
// store value, once focus is lost (different element is
// selected)
String valueStr = fValue.getText();
Slot valueSlot = null;
if (m_instance == null) {
// no instance has been selected
// (field should be inactive, if not selected)
return;
}
for (Slot slot : m_instance.getSlots()) {
if (slot.getDefiningFeature() == m_currentAttribute) {
valueSlot = slot;
}
}
if (valueSlot == null) {
// slot does not exist yet, create
valueSlot = DepCreation.createSlotForConfigProp(m_instance,
m_currentAttribute);
}
for (ValueSpecification value : valueSlot.getValues()) {
if (value instanceof LiteralString) {
((LiteralString) value).setValue(valueStr);
} else if (value instanceof LiteralInteger) {
((LiteralInteger) value).setValue(Integer
.parseInt(valueStr));
} else if (value instanceof LiteralBoolean) {
((LiteralBoolean) value).setValue(Boolean
.parseBoolean(valueStr));
}
}
}
@Override
public void focusGained(FocusEvent e) {
}
});
fComboValue = new Combo(instanceConfigurationGroup, SWT.NONE);
span2 = new GridData();
span2.horizontalAlignment = GridData.FILL;
span2.grabExcessHorizontalSpace = true;
fComboValue.setLayoutData(span2);
fComboValue.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
// store value, once focus is lost (different element is
// selected)
int index = fComboValue.getSelectionIndex();
if (m_instance == null) {
// no instance has been selected
// (field should be inactive, if not selected)
return;
}
Slot valueSlot = null;
for (Slot slot : m_instance.getSlots()) {
if (slot.getDefiningFeature() == m_currentAttribute) {
// slot for enumerations can only be configured with instanceValues.
// Destroy slots with do not contain at least one instanceValue
boolean destroySlot = true;
for (ValueSpecification value : slot.getValues()) {
if (value instanceof InstanceValue) {
destroySlot = false;
}
}
if (destroySlot) {
slot.destroy();
}
else {
valueSlot = slot;
}
break;
}
}
if (valueSlot == null) {
// slot does not exist yet, create
valueSlot = DepCreation.createSlotForConfigProp(m_instance,
m_currentAttribute);
}
Enumeration enumeration = (Enumeration) m_currentAttribute.getType();
for (ValueSpecification value : valueSlot.getValues()) {
if (value instanceof InstanceValue) {
((InstanceValue) value).setInstance(enumeration.getOwnedLiterals().get(index));
}
}
}
});
fDescriptionLabel = new Label(instanceConfigurationGroup, SWT.NONE);
fDescriptionLabel.setText(Messages.ConfigureInstanceDialog_DESCRIPTION);
fDescriptionLabel.setLayoutData(span2);
span2 = new GridData();
span2.horizontalAlignment = GridData.FILL;
span2.grabExcessHorizontalSpace = true;
span2.grabExcessVerticalSpace = true;
span2.verticalAlignment = GridData.FILL;
span2.heightHint = 80;
fDescription = new Text(instanceConfigurationGroup, SWT.NONE | SWT.WRAP
| SWT.V_SCROLL | SWT.READ_ONLY);
fDescription.setLayoutData(span2);
// createMessageArea (ruleInfoGroup);
instanceConfigurationGroup.pack();
setEnabled(false);
}
/**
* Select a rule, i.e. update the visual representation from the rule
*
* @param rule
*/
protected void selectProperty(Property attribute) {
m_currentAttribute = attribute;
if ((attribute == null) || (fValue == null)) {
setEnabled(false);
return;
}
setEnabled(true);
fDescription.setText(DescriptionUtils.getDescription(attribute, Messages.ConfigureInstanceDialog_NOT_AVAILABLE));
fValueLabel.setText(getValueLabel(attribute));
boolean isEnum = m_currentAttribute.getType() instanceof Enumeration;
fValue.setVisible(!isEnum);
fComboValue.setVisible(isEnum);
if (isEnum) {
Enumeration enumeration = (Enumeration) m_currentAttribute.getType();
EList<EnumerationLiteral> literals = enumeration.getOwnedLiterals();
String items[] = new String[literals.size()];
for (int i = 0; i < literals.size(); i++) {
items[i] = literals.get(i).getName();
}
fComboValue.setItems(items);
}
for (Slot slot : m_instance.getSlots()) {
if (slot.getDefiningFeature() == m_currentAttribute) {
for (ValueSpecification value : slot.getValues()) {
if (value instanceof LiteralInteger) {
Integer intVal = ((LiteralInteger) value).getValue();
fValue.setText(intVal.toString());
return;
}
if (value instanceof InstanceValue) {
InstanceSpecification enumIS = ((InstanceValue) value).getInstance();
if (enumIS instanceof EnumerationLiteral) {
EnumerationLiteral literal = (EnumerationLiteral) enumIS;
int index = literal.getEnumeration().getOwnedLiterals().indexOf(literal);
if (index != -1) {
fComboValue.select(index);
}
}
return;
}
else if (value instanceof LiteralBoolean) {
Boolean boolVal = ((LiteralBoolean) value).booleanValue();
fValue.setText(boolVal.toString());
return;
}
else if (value instanceof LiteralString) {
fValue.setText(((LiteralString) value).getValue());
return;
}
}
}
}
fValue.setText(""); //$NON-NLS-1$
}
private void setEnabled(boolean enabled) {
fDescriptionLabel.setEnabled(enabled);
fDescription.setEnabled(enabled);
fValueLabel.setEnabled(enabled);
fValue.setEnabled(enabled);
if (!enabled) {
fValue.setText(""); //$NON-NLS-1$
fDescription.setText(""); //$NON-NLS-1$
fValueLabel.setText(valueLabelPrefix);
}
}
private String getValueLabel(Property attribute) {
String label = valueLabelPrefix;
if (attribute.getDefault() != null) {
return label + " " + String.format("(default = %s)", attribute.getDefault()); //$NON-NLS-1$ //$NON-NLS-2$
}
return label;
}
private EList<Property> getConfigAttributes(Classifier component) {
EList<Property> list = new BasicEList<Property>();
// add properties of component
list.addAll(ConfigUtils.getConfigAttributes(component));
// overload to add properties of container rules
return list;
}
/**
* Add a space before and after
*
* @param text
* @return "spaced" string
*/
public static String addSpaces(String text) {
return " " + text + " "; //$NON-NLS-1$ //$NON-NLS-2$
}
}