blob: fd3c30f27dbf1feb97258de28ffc950e4e9b186b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016, 2017 Obeo.
* 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:
* Obeo - initial API and implementation
*******************************************************************************/
package org.eclipse.eef.ide.ui.ext.widgets.reference.internal;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.eef.common.ui.api.IEEFFormContainer;
import org.eclipse.eef.core.api.EditingContextAdapter;
import org.eclipse.eef.core.ext.widgets.reference.internal.EEFExtReferenceController;
import org.eclipse.eef.ext.widgets.reference.eefextwidgetsreference.EEFExtReferenceDescription;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
import org.eclipse.emf.edit.provider.IItemPropertyDescriptor;
import org.eclipse.emf.edit.provider.IItemPropertySource;
import org.eclipse.emf.edit.provider.ReflectiveItemProviderAdapterFactory;
import org.eclipse.emf.edit.ui.celleditor.FeatureEditorDialog;
import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider;
import org.eclipse.emf.edit.ui.provider.ExtendedImageRegistry;
import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.wizard.IWizard;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.sirius.common.interpreter.api.IInterpreter;
import org.eclipse.sirius.common.interpreter.api.IVariableManager;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.graphics.Image;
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.Table;
/**
* This lifecycle manager is used to handle the EEF Extension reference widget for multi-valued EReferences.
*
* @author sbegaudeau
*/
public class EEFExtMultipleReferenceLifecycleManager extends AbstractEEFExtReferenceLifecycleManager {
/**
* Minimal height of the table widget.
*/
private static final int TABLE_MINIMAL_HEIGHT = 150;
/**
* The table viewer.
*/
private TableViewer tableViewer;
/**
* The up button.
*/
private Button upButton;
/**
* The listener for the up button.
*/
private ButtonSelectionListener upButtonListener;
/**
* The down button.
*/
private Button downButton;
/**
* The listener for the down button.
*/
private ButtonSelectionListener downButtonListener;
/**
* The constructor.
*
* @param description
* The description of the reference
* @param target
* The target
* @param eReference
* The EReference to display
* @param variableManager
* The variable manager
* @param interpreter
* The interpreter
* @param editingContextAdapter
* The context adapter
*/
public EEFExtMultipleReferenceLifecycleManager(EEFExtReferenceDescription description, EObject target, EReference eReference,
IVariableManager variableManager, IInterpreter interpreter, EditingContextAdapter editingContextAdapter) {
super(description, target, eReference, variableManager, interpreter, editingContextAdapter);
}
/**
* {@inheritDoc}
*
* @see org.eclipse.eef.ide.ui.api.widgets.AbstractEEFWidgetLifecycleManager#createMainControl(org.eclipse.swt.widgets.Composite,
* org.eclipse.eef.common.ui.api.IEEFFormContainer)
*/
@Override
protected void createMainControl(Composite parent, IEEFFormContainer formContainer) {
this.widgetFactory = formContainer.getWidgetFactory();
Composite referenceComposite = this.widgetFactory.createFlatFormComposite(parent);
GridLayout referenceGridLayout = new GridLayout(2, false);
referenceComposite.setLayout(referenceGridLayout);
GridData referenceCompositeGridData = new GridData(SWT.FILL, SWT.CENTER, true, false);
referenceComposite.setLayoutData(referenceCompositeGridData);
this.createTable(referenceComposite);
Composite buttonsComposite = this.widgetFactory.createFlatFormComposite(referenceComposite);
GridData buttonCompositeGridData = new GridData();
buttonCompositeGridData.verticalAlignment = SWT.BEGINNING;
buttonsComposite.setLayoutData(buttonCompositeGridData);
GridLayout buttonCompositeGridLayout = new GridLayout(1, false);
buttonCompositeGridLayout.marginHeight = 0;
buttonsComposite.setLayout(buttonCompositeGridLayout);
if (!this.eReference.isContainment()) {
Image browseImage = ExtendedImageRegistry.INSTANCE
.getImage(EEFExtReferenceUIPlugin.getPlugin().getImage(EEFExtReferenceUIPlugin.Implementation.BROWSE_ICON_PATH));
this.browseButton = this.createButton(buttonsComposite, browseImage);
}
Image addImage = ExtendedImageRegistry.INSTANCE
.getImage(EEFExtReferenceUIPlugin.getPlugin().getImage(EEFExtReferenceUIPlugin.Implementation.ADD_ICON_PATH));
Image removeImage = ExtendedImageRegistry.INSTANCE
.getImage(EEFExtReferenceUIPlugin.getPlugin().getImage(EEFExtReferenceUIPlugin.Implementation.REMOVE_ICON_PATH));
Image upImage = ExtendedImageRegistry.INSTANCE
.getImage(EEFExtReferenceUIPlugin.getPlugin().getImage(EEFExtReferenceUIPlugin.Implementation.UP_ICON_PATH));
Image downImage = ExtendedImageRegistry.INSTANCE
.getImage(EEFExtReferenceUIPlugin.getPlugin().getImage(EEFExtReferenceUIPlugin.Implementation.DOWN_ICON_PATH));
this.addButton = this.createButton(buttonsComposite, addImage);
this.removeButton = this.createButton(buttonsComposite, removeImage);
this.upButton = this.createButton(buttonsComposite, upImage);
this.downButton = this.createButton(buttonsComposite, downImage);
this.widgetFactory.paintBordersFor(parent);
this.controller = new EEFExtReferenceController(this.description, this.variableManager, this.interpreter, this.editingContextAdapter);
}
/**
* Creates the table used to display the reference.
*
* @param parent
* The parent composite
*/
private void createTable(Composite parent) {
ScrolledComposite scrolledComposite = this.widgetFactory.createScrolledComposite(parent, SWT.NONE);
GridData gridData = new GridData();
gridData.grabExcessHorizontalSpace = true;
gridData.horizontalAlignment = SWT.FILL;
scrolledComposite.setLayoutData(gridData);
// CHECKSTYLE:OFF
int style = SWT.READ_ONLY | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.BORDER | SWT.SINGLE | SWT.VIRTUAL;
// CHECKSTYLE:ON
Table table = this.widgetFactory.createTable(scrolledComposite, style);
this.tableViewer = new TableViewer(table);
GridData tableGridData = new GridData(SWT.FILL, SWT.TOP, true, false, 1, 1);
tableGridData.horizontalIndent = VALIDATION_MARKER_OFFSET;
this.tableViewer.getTable().setLayoutData(tableGridData);
this.composedAdapterFactory = new ComposedAdapterFactory(ComposedAdapterFactory.Descriptor.Registry.INSTANCE);
this.composedAdapterFactory.addAdapterFactory(new ReflectiveItemProviderAdapterFactory());
this.tableViewer.setContentProvider(new EReferenceContentProvider(this.eReference));
this.tableViewer.setLabelProvider(new DelegatingStyledCellLabelProvider(
new AdapterFactoryLabelProvider.StyledLabelProvider(this.composedAdapterFactory, this.tableViewer)));
scrolledComposite.setContent(table);
final int clientWidth = scrolledComposite.getClientArea().width;
this.tableViewer.getTable().setSize(clientWidth, TABLE_MINIMAL_HEIGHT);
scrolledComposite.setExpandHorizontal(true);
scrolledComposite.setAlwaysShowScrollBars(true);
}
/**
* {@inheritDoc}
*
* @see org.eclipse.eef.ide.ui.ext.widgets.reference.internal.AbstractEEFExtReferenceLifecycleManager#aboutToBeShown()
*/
@Override
public void aboutToBeShown() {
super.aboutToBeShown();
this.initializeMoveButton(Direction.UP);
this.initializeMoveButton(Direction.DOWN);
}
/**
* {@inheritDoc}
*
* @see org.eclipse.eef.ide.ui.ext.widgets.reference.internal.AbstractEEFExtReferenceLifecycleManager#browseButtonCallback()
*/
@Override
protected void browseButtonCallback() {
Object adapter = this.composedAdapterFactory.adapt(this.target, IItemPropertySource.class);
if (adapter instanceof IItemPropertySource) {
IItemPropertySource propertySource = (IItemPropertySource) adapter;
IItemPropertyDescriptor propertyDescriptor = propertySource.getPropertyDescriptor(this.target, this.eReference);
if (propertyDescriptor != null) {
ArrayList<Object> choiceOfValues = new ArrayList<Object>(propertyDescriptor.getChoiceOfValues(this.target));
final AdapterFactoryLabelProvider adapterFactoryLabelProvider = new AdapterFactoryLabelProvider(this.composedAdapterFactory);
LabelProvider labelProvider = new LabelProvider() {
@Override
public String getText(Object object) {
return adapterFactoryLabelProvider.getText(object);
}
@Override
public Image getImage(Object object) {
return ExtendedImageRegistry.getInstance().getImage(adapterFactoryLabelProvider.getImage(object));
}
};
FeatureEditorDialog dialog = new FeatureEditorDialog(this.tableViewer.getTable().getShell(), labelProvider, this.target,
this.eReference, propertyDescriptor.getDisplayName(this.target), choiceOfValues);
dialog.open();
EList<?> result = dialog.getResult();
if (result != null) {
this.target.eSet(this.eReference, result);
}
}
}
}
/**
* {@inheritDoc}
*
* @see org.eclipse.eef.ide.ui.ext.widgets.reference.internal.AbstractEEFExtReferenceLifecycleManager#addButtonCallback()
*/
@Override
protected void addButtonCallback() {
IWizard wizard = new EEFExtEObjectCreationWizard(this.target, this.eReference, this.editingContextAdapter);
WizardDialog wizardDialog = new WizardDialog(this.tableViewer.getTable().getShell(), wizard);
wizardDialog.open();
}
/**
* {@inheritDoc}
*
* @see org.eclipse.eef.ide.ui.ext.widgets.reference.internal.AbstractEEFExtReferenceLifecycleManager#removeButtonCallback()
*/
@Override
protected void removeButtonCallback() {
this.editingContextAdapter.performModelChange(() -> {
List<Object> objects = selectionToList(tableViewer.getSelection());
for (Object object : objects) {
EcoreUtil.remove(target, eReference, object);
}
});
}
/**
* Initializes the up button.
*
* @param direction
* The direction
*/
private void initializeMoveButton(final Direction direction) {
ButtonSelectionListener listener = new ButtonSelectionListener(this.editingContextAdapter, () -> this.moveButtonCallback(direction));
if (direction == Direction.UP) {
this.upButtonListener = listener;
this.upButton.addSelectionListener(this.upButtonListener);
this.upButton.setToolTipText(Messages.ReferenceUpButton_tooltipText);
} else {
this.downButtonListener = listener;
this.downButton.addSelectionListener(this.downButtonListener);
this.downButton.setToolTipText(Messages.ReferenceDownButton_tooltipText);
}
}
/**
* This method is called once the move button is clicked in order to move the selected element up or down depending
* of the given direction.
*
* @param direction
* The direction
*/
private void moveButtonCallback(Direction direction) {
List<Object> objects = this.selectionToList(this.tableViewer.getSelection());
EList<?> values = this.getValues();
for (Object object : objects) {
if (direction == Direction.UP) {
values.move(Math.max(0, values.indexOf(object) - 1), values.indexOf(object));
} else {
values.move(Math.min(values.size() - 1, values.indexOf(object) + 1), values.indexOf(object));
}
}
}
/**
* Returns the value of the reference for the self EObject.
*
* @return The value of the reference for the self EObject or <code>null</code> if it could not be found
*/
private EList<?> getValues() {
Object value = this.target.eGet(this.eReference);
if (value instanceof EList<?>) {
return (EList<?>) value;
}
return new BasicEList<>();
}
/**
* Returns a list containing all the objects of the given selection.
*
* @param selection
* The selection
* @return The objects of the given selection
*/
private List<Object> selectionToList(ISelection selection) {
List<Object> objects = new ArrayList<>();
if (selection instanceof IStructuredSelection) {
IStructuredSelection structuredSelection = (IStructuredSelection) selection;
for (Object object : structuredSelection.toArray()) {
objects.add(object);
}
}
return objects;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.eef.ide.ui.ext.widgets.reference.internal.AbstractEEFExtReferenceLifecycleManager#refresh()
*/
@Override
public void refresh() {
super.refresh();
this.tableViewer.setInput(this.target);
}
/**
* {@inheritDoc}
*
* @see org.eclipse.eef.ide.ui.ext.widgets.reference.internal.AbstractEEFExtReferenceLifecycleManager#setEnabled(boolean)
*/
@Override
protected void setEnabled(boolean isEnabled) {
super.setEnabled(isEnabled);
if (this.upButton != null && !this.upButton.isDisposed()) {
this.upButton.setEnabled(isEnabled);
}
if (this.downButton != null && !this.downButton.isDisposed()) {
this.downButton.setEnabled(isEnabled);
}
}
/**
* {@inheritDoc}
*
* @see org.eclipse.eef.ide.ui.ext.widgets.reference.internal.AbstractEEFExtReferenceLifecycleManager#aboutToBeHidden()
*/
@Override
public void aboutToBeHidden() {
super.aboutToBeHidden();
this.removeListener(this.upButton, this.upButtonListener);
this.removeListener(this.downButton, this.downButtonListener);
}
/**
* {@inheritDoc}
*
* @see org.eclipse.eef.ide.ui.api.widgets.AbstractEEFLifecycleManager#getValidationControl()
*/
@Override
protected Control getValidationControl() {
return this.tableViewer.getTable().getParent();
}
/**
* This enumeration is used for the direction of the up and down buttons.
*
* @author sbegaudeau
*/
private static enum Direction {
/**
* Up.
*/
UP,
/**
* Down.
*/
DOWN
}
}