blob: bfbd2c8ce49c3196a1ec597016684c36a3ca9161 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011-2014 EclipseSource Muenchen GmbH 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:
* Eugen Neufeld - initial API and implementation
******************************************************************************/
package org.eclipse.emf.ecp.view.internal.control.multireference;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.databinding.edit.EMFEditObservables;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EStructuralFeature.Setting;
import org.eclipse.emf.ecp.edit.internal.swt.controls.TableViewerColumnBuilder;
import org.eclipse.emf.ecp.edit.spi.DeleteService;
import org.eclipse.emf.ecp.edit.spi.ReferenceService;
import org.eclipse.emf.ecp.view.model.common.edit.provider.CustomReflectiveItemProviderAdapterFactory;
import org.eclipse.emf.ecp.view.spi.core.swt.AbstractControlSWTRenderer;
import org.eclipse.emf.ecp.view.spi.model.VControl;
import org.eclipse.emf.ecp.view.spi.renderer.NoPropertyDescriptorFoundExeption;
import org.eclipse.emf.ecp.view.spi.renderer.NoRendererFoundException;
import org.eclipse.emf.ecp.view.spi.swt.layout.GridDescriptionFactory;
import org.eclipse.emf.ecp.view.spi.swt.layout.SWTGridCell;
import org.eclipse.emf.ecp.view.spi.swt.layout.SWTGridDescription;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
import org.eclipse.emf.edit.provider.IItemPropertyDescriptor;
import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider;
import org.eclipse.emf.emfforms.spi.localization.LocalizationServiceHelper;
import org.eclipse.jface.databinding.viewers.ObservableListContentProvider;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.layout.TableColumnLayout;
import org.eclipse.jface.viewers.ColumnViewerEditor;
import org.eclipse.jface.viewers.ColumnViewerEditorActivationEvent;
import org.eclipse.jface.viewers.ColumnViewerEditorActivationStrategy;
import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.TableViewerEditor;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
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.Label;
import org.eclipse.swt.widgets.TableColumn;
/**
* Renderer for MultiReferenceControl.
*
* @author Eugen Neufeld
*
*/
@SuppressWarnings("restriction")
public class MultiReferenceSWTRenderer extends AbstractControlSWTRenderer<VControl> {
private Label validationIcon;
private AdapterFactoryLabelProvider labelProvider;
private ComposedAdapterFactory composedAdapterFactory;
private TableViewer tableViewer;
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.ecp.view.spi.swt.AbstractSWTRenderer#getGridDescription(org.eclipse.emf.ecp.view.spi.swt.layout.SWTGridDescription)
*/
@Override
public SWTGridDescription getGridDescription(SWTGridDescription gridDescription) {
return GridDescriptionFactory.INSTANCE.createSimpleGrid(1, 1, this);
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.ecp.view.spi.swt.AbstractSWTRenderer#renderControl(org.eclipse.emf.ecp.view.spi.swt.layout.SWTGridCell,
* org.eclipse.emf.ecp.view.spi.swt.Composite)
*/
@Override
protected Control renderControl(SWTGridCell cell, Composite parent) throws NoRendererFoundException,
NoPropertyDescriptorFoundExeption {
if (cell.getRow() != 0 || cell.getColumn() != 0 || cell.getRenderer() != this) {
throw new IllegalArgumentException("Wrong parameter passed!"); //$NON-NLS-1$
}
final Composite composite = new Composite(parent, SWT.NONE);
composite.setLayout(new GridLayout(1, false));
composite.setBackgroundMode(SWT.INHERIT_FORCE);
final Iterator<Setting> settings = getVElement().getDomainModelReference().getIterator();
if (!settings.hasNext()) {
return null;
}
final Setting mainSetting = settings.next();
createTitleComposite(composite, mainSetting);
createLabelProvider();
final Composite controlComposite = new Composite(composite, SWT.NONE);
GridDataFactory.fillDefaults().grab(true, true).align(SWT.FILL, SWT.FILL)
.hint(1, 300)
.applyTo(controlComposite);
GridLayoutFactory.fillDefaults().numColumns(1).applyTo(controlComposite);
createContent(controlComposite, mainSetting);
return composite;
}
private void createLabelProvider() {
composedAdapterFactory = new ComposedAdapterFactory(new AdapterFactory[] {
new CustomReflectiveItemProviderAdapterFactory(),
new ComposedAdapterFactory(ComposedAdapterFactory.Descriptor.Registry.INSTANCE) });
labelProvider = new AdapterFactoryLabelProvider(composedAdapterFactory);
labelProvider.setFireLabelUpdateNotifications(true);
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.ecp.view.spi.core.swt.AbstractControlSWTRenderer#dispose()
*/
@Override
protected void dispose() {
composedAdapterFactory.dispose();
labelProvider.dispose();
super.dispose();
}
private void createTitleComposite(Composite composite, final Setting mainSetting)
throws NoPropertyDescriptorFoundExeption {
final Composite titleComposite = new Composite(composite, SWT.NONE);
titleComposite.setBackgroundMode(SWT.INHERIT_FORCE);
GridDataFactory.fillDefaults().grab(true, false).align(SWT.FILL, SWT.BEGINNING)
.applyTo(titleComposite);
GridLayoutFactory.fillDefaults().numColumns(3).equalWidth(false).applyTo(titleComposite);
final Label filler = new Label(titleComposite, SWT.NONE);
GridDataFactory.fillDefaults().grab(true, false).align(SWT.FILL, SWT.BEGINNING).applyTo(filler);
// VALIDATION
// // set the size of the label to the size of the image
validationIcon = createValidationIcon(titleComposite);
GridDataFactory.fillDefaults().hint(16, 17).grab(false, false).applyTo(validationIcon);
final Composite buttonComposite = new Composite(titleComposite, SWT.NONE);
GridLayoutFactory.fillDefaults().numColumns(3).equalWidth(true).applyTo(buttonComposite);
GridDataFactory.fillDefaults().grab(true, false).align(SWT.END, SWT.FILL)
.applyTo(buttonComposite);
final Button btnAddExisting = new Button(buttonComposite, SWT.PUSH);
GridDataFactory.fillDefaults().grab(true, true).align(SWT.FILL, SWT.FILL).applyTo(btnAddExisting);
btnAddExisting.setImage(Activator.getImage("icons/link.png")); //$NON-NLS-1$
btnAddExisting.setToolTipText(LocalizationServiceHelper.getString(getClass(),
MessageKeys.MultiReferenceSWTRenderer_addExistingTooltip));
btnAddExisting.addSelectionListener(new SelectionAdapter() {
/**
* {@inheritDoc}
*
* @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
*/
@Override
public void widgetSelected(SelectionEvent e) {
super.widgetSelected(e);
handleAddExisting(tableViewer, mainSetting);
}
});
final Button btnAddNew = new Button(buttonComposite, SWT.PUSH);
GridDataFactory.fillDefaults().grab(true, true).align(SWT.FILL, SWT.FILL).applyTo(btnAddNew);
btnAddNew.setImage(Activator.getImage("icons/link_add.png")); //$NON-NLS-1$
btnAddNew.setToolTipText(LocalizationServiceHelper.getString(getClass(),
MessageKeys.MultiReferenceSWTRenderer_addNewTooltip));
btnAddNew.addSelectionListener(new SelectionAdapter() {
/**
* {@inheritDoc}
*
* @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
*/
@Override
public void widgetSelected(SelectionEvent e) {
super.widgetSelected(e);
handleAddNew(tableViewer, mainSetting);
}
});
final Button btnDelete = new Button(buttonComposite, SWT.PUSH);
GridDataFactory.fillDefaults().grab(true, true).align(SWT.FILL, SWT.FILL).applyTo(btnDelete);
btnDelete.setImage(Activator.getImage("icons/delete.png")); //$NON-NLS-1$
btnDelete.setToolTipText(LocalizationServiceHelper.getString(getClass(),
MessageKeys.MultiReferenceSWTRenderer_deleteTooltip));
btnDelete.addSelectionListener(new SelectionAdapter() {
/**
* {@inheritDoc}
*
* @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent)
*/
@Override
public void widgetSelected(SelectionEvent e) {
super.widgetSelected(e);
handleDelete(tableViewer, mainSetting);
}
});
if (getVElement().isReadonly()) {
btnAddExisting.setEnabled(false);
btnAddNew.setEnabled(false);
btnDelete.setEnabled(false);
}
}
private void createContent(Composite composite, Setting mainSetting) {
tableViewer = new TableViewer(composite, SWT.MULTI | SWT.V_SCROLL | SWT.FULL_SELECTION
| SWT.BORDER);
tableViewer.getTable().setData(CUSTOM_VARIANT, "org_eclipse_emf_ecp_control_multireference"); //$NON-NLS-1$
tableViewer.getTable().setHeaderVisible(true);
tableViewer.getTable().setLinesVisible(true);
final ColumnViewerEditorActivationStrategy actSupport = new ColumnViewerEditorActivationStrategy(tableViewer) {
@Override
protected boolean isEditorActivationEvent(ColumnViewerEditorActivationEvent event) {
return event.eventType == ColumnViewerEditorActivationEvent.TRAVERSAL
|| event.eventType == ColumnViewerEditorActivationEvent.MOUSE_CLICK_SELECTION
|| event.eventType == ColumnViewerEditorActivationEvent.KEY_PRESSED && event.keyCode == SWT.CR
|| event.eventType == ColumnViewerEditorActivationEvent.PROGRAMMATIC;
}
};
TableViewerEditor.create(tableViewer, null, actSupport, ColumnViewerEditor.TABBING_HORIZONTAL
| ColumnViewerEditor.TABBING_MOVE_TO_ROW_NEIGHBOR | ColumnViewerEditor.TABBING_VERTICAL
| ColumnViewerEditor.KEYBOARD_ACTIVATION);
ColumnViewerToolTipSupport.enableFor(tableViewer);
final ECPTableViewerComparator comparator = new ECPTableViewerComparator();
tableViewer.setComparator(comparator);
final ObservableListContentProvider cp = new ObservableListContentProvider();
final EStructuralFeature eStructuralFeature = mainSetting.getEStructuralFeature();
String text = eStructuralFeature.getName();
String tooltipText = eStructuralFeature.getName();
final IItemPropertyDescriptor itemPropertyDescriptor = getItemPropertyDescriptor(mainSetting);
if (itemPropertyDescriptor != null) {
text = itemPropertyDescriptor.getDisplayName(null);
tooltipText = itemPropertyDescriptor.getDescription(null);
}
final TableViewerColumn column = TableViewerColumnBuilder
.create()
.setText(text)
.setToolTipText(tooltipText)
.setResizable(false)
.setMoveable(false)
.setStyle(SWT.NONE)
.build(tableViewer);
column.getColumn().addSelectionListener(
getSelectionAdapter(tableViewer, comparator, column.getColumn(), 0));
tableViewer.setLabelProvider(labelProvider);
tableViewer.setContentProvider(cp);
final IObservableList list = EMFEditObservables.observeList(getEditingDomain(mainSetting),
mainSetting.getEObject(), mainSetting.getEStructuralFeature());
tableViewer.setInput(list);
final TableColumnLayout layout = new TableColumnLayout();
composite.setLayout(layout);
layout.setColumnData(column.getColumn(), new ColumnWeightData(1, false));
tableViewer.addDoubleClickListener(new IDoubleClickListener() {
@Override
public void doubleClick(DoubleClickEvent event) {
final EObject selectedObject = (EObject) IStructuredSelection.class.cast(event.getSelection())
.getFirstElement();
handleDoubleClick(selectedObject);
}
});
}
private SelectionAdapter getSelectionAdapter(final TableViewer tableViewer,
final ECPTableViewerComparator comparator, final TableColumn column,
final int index) {
final SelectionAdapter selectionAdapter = new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
comparator.setColumn(index);
final int dir = comparator.getDirection();
tableViewer.getTable().setSortDirection(dir);
tableViewer.getTable().setSortColumn(column);
tableViewer.refresh();
}
};
return selectionAdapter;
}
/**
* Method for handling a double click.
*
* @param selectedObject the selected {@link EObject}
*/
protected void handleDoubleClick(EObject selectedObject) {
final ReferenceService referenceService = getViewModelContext().getService(ReferenceService.class);
referenceService.openInNewContext(selectedObject);
}
/**
* Method for adding an existing element.
*
* @param tableViewer the {@link TableViewer}
* @param setting the {@link Setting} to add to
*/
protected void handleAddExisting(TableViewer tableViewer, Setting setting) {
final ReferenceService referenceService = getViewModelContext().getService(ReferenceService.class);
referenceService.addExistingModelElements(setting.getEObject(), (EReference) setting.getEStructuralFeature());
referenceService.openInNewContext(setting.getEObject());
}
/**
* Method for adding a new element.
*
* @param tableViewer the {@link TableViewer}
* @param setting the {@link Setting} to add to
*/
protected void handleAddNew(TableViewer tableViewer, Setting setting) {
final ReferenceService referenceService = getViewModelContext().getService(ReferenceService.class);
referenceService.addNewModelElements(setting.getEObject(),
(EReference) setting.getEStructuralFeature());
}
/**
* Method for deleting elements.
*
* @param tableViewer the {@link TableViewer}
* @param mainSetting the {@link Setting} to delete from
*/
protected void handleDelete(TableViewer tableViewer, Setting setting) {
final DeleteService deleteService = getViewModelContext().getService(DeleteService.class);
if (deleteService == null) {
/*
* #getService(Class<?>) will report to the reportservice if it could not be found
* -> simply return here
*/
return;
}
@SuppressWarnings("unchecked")
final List<Object> deletionList = IStructuredSelection.class.cast(tableViewer.getSelection()).toList();
final EditingDomain editingDomain = getEditingDomain(setting);
/* assured by #isApplicable */
final EReference reference = EReference.class.cast(setting.getEStructuralFeature());
if (reference.isContainment()) {
deleteService.deleteElements(editingDomain, deletionList);
} else {
deleteService.removeElements(editingDomain, setting.getEObject(), reference, deletionList);
}
}
/**
* The {@link ViewerComparator} for this table which allows 3 states for sort order:
* none, up and down.
*
* @author Eugen Neufeld
*
*/
private class ECPTableViewerComparator extends ViewerComparator {
private int propertyIndex;
private static final int NONE = 0;
private int direction = NONE;
public ECPTableViewerComparator() {
propertyIndex = 0;
direction = NONE;
}
public int getDirection() {
switch (direction) {
case 0:
return SWT.NONE;
case 1:
return SWT.UP;
case 2:
return SWT.DOWN;
default:
return SWT.NONE;
}
}
public void setColumn(int column) {
if (column == propertyIndex) {
// Same column as last sort; toggle the direction
direction = (direction + 1) % 3;
} else {
// New column; do an ascending sort
propertyIndex = column;
direction = 1;
}
}
@Override
public int compare(Viewer viewer, Object e1, Object e2) {
if (direction == 0) {
return 0;
}
int rc = 0;
final EObject object1 = (EObject) e1;
final EObject object2 = (EObject) e2;
final EStructuralFeature feat1 = object1.eClass().getEAllStructuralFeatures().get(propertyIndex);
final EStructuralFeature feat2 = object2.eClass().getEAllStructuralFeatures().get(propertyIndex);
final Object value1 = object1.eGet(feat1);
final Object value2 = object2.eGet(feat2);
if (value1 == null) {
rc = 1;
} else if (value2 == null) {
rc = -1;
} else {
rc = value1.toString().compareTo(value2.toString());
}
// If descending order, flip the direction
if (direction == 2) {
rc = -rc;
}
return rc;
}
}
}