Java tutorial
/******************************************************************************* * Copyright (c) 2011-2015 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.edit.internal.swt.controls; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.eclipse.core.databinding.Binding; import org.eclipse.core.databinding.observable.list.IObservableList; import org.eclipse.core.databinding.observable.map.IObservableMap; import org.eclipse.core.databinding.observable.value.IObservableValue; import org.eclipse.core.runtime.Assert; import org.eclipse.emf.common.notify.AdapterFactory; import org.eclipse.emf.common.util.Diagnostic; import org.eclipse.emf.databinding.EMFProperties; import org.eclipse.emf.databinding.EObjectObservableMap; import org.eclipse.emf.databinding.edit.EMFEditObservables; import org.eclipse.emf.ecore.EClass; 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.Activator; import org.eclipse.emf.ecp.edit.internal.swt.table.TableColumnConfiguration; import org.eclipse.emf.ecp.edit.internal.swt.table.TableControlConfiguration; import org.eclipse.emf.ecp.edit.internal.swt.util.CellEditorFactory; import org.eclipse.emf.ecp.edit.internal.swt.util.SWTControl; import org.eclipse.emf.ecp.edit.internal.swt.util.SWTRenderingHelper; import org.eclipse.emf.ecp.edit.spi.swt.table.ECPCellEditor; import org.eclipse.emf.ecp.edit.spi.swt.util.ECPDialogExecutor; import org.eclipse.emf.ecp.view.spi.model.VDiagnostic; import org.eclipse.emf.ecp.view.spi.renderer.RenderingResultRow; import org.eclipse.emf.edit.command.AddCommand; import org.eclipse.emf.edit.command.RemoveCommand; import org.eclipse.emf.edit.domain.EditingDomain; import org.eclipse.emf.edit.provider.AdapterFactoryItemDelegator; import org.eclipse.emf.edit.provider.ComposedAdapterFactory; import org.eclipse.emf.edit.provider.IItemPropertyDescriptor; import org.eclipse.emf.edit.provider.ReflectiveItemProviderAdapterFactory; import org.eclipse.emfforms.spi.localization.LocalizationServiceHelper; import org.eclipse.jface.databinding.swt.SWTObservables; import org.eclipse.jface.databinding.viewers.ObservableListContentProvider; import org.eclipse.jface.databinding.viewers.ObservableMapCellLabelProvider; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.IDialogLabelKeys; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.GridLayoutFactory; import org.eclipse.jface.layout.TableColumnLayout; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.viewers.CellEditor; import org.eclipse.jface.viewers.CellLabelProvider; import org.eclipse.jface.viewers.ColumnViewer; import org.eclipse.jface.viewers.ColumnViewerEditor; import org.eclipse.jface.viewers.ColumnViewerEditorActivationEvent; import org.eclipse.jface.viewers.ColumnViewerEditorActivationListener; import org.eclipse.jface.viewers.ColumnViewerEditorActivationStrategy; import org.eclipse.jface.viewers.ColumnViewerEditorDeactivationEvent; import org.eclipse.jface.viewers.ColumnViewerToolTipSupport; import org.eclipse.jface.viewers.ColumnWeightData; import org.eclipse.jface.viewers.EditingSupport; import org.eclipse.jface.viewers.IColorProvider; 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.TableViewerFocusCellManager; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerCell; import org.eclipse.jface.viewers.ViewerComparator; import org.eclipse.swt.SWT; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Image; 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; /** * The class describing a table control. * * @author Eugen Neufeld * @author emueller */ // this class is not serialized @Deprecated public class TableControl extends SWTControl { private static final String FIXED_COLUMNS = "org.eclipse.rap.rwt.fixedColumns"; //$NON-NLS-1$ private static final String ICON_ADD = "icons/add.png"; //$NON-NLS-1$ private static final String ICONS_UNSET_REFERENCE = "icons/unset_reference.png"; //$NON-NLS-1$ private static final String ICONS_UNSET_FEATURE = "icons/unset_feature.png"; //$NON-NLS-1$ private TableViewer tableViewer; private ComposedAdapterFactory composedAdapterFactory; private AdapterFactoryItemDelegator adapterFactoryItemDelegator; private Button unsetButton; private EClass clazz; private TableControlConfiguration tableControlConfiguration; private boolean editable = true; private EReference getTableReference() { return (EReference) getFirstStructuralFeature(); } /** * * @param tableControlConfiguration the {@link TableControlConfiguration} to use when creating the table */ public final void setTableControlConfiguration(TableControlConfiguration tableControlConfiguration) { this.tableControlConfiguration = tableControlConfiguration; } @Override protected Binding bindValue() { return null; } /** * * {@inheritDoc} * * @see org.eclipse.emf.ecp.edit.internal.swt.util.ECPControlSWT#createControls(org.eclipse.swt.widgets.Composite) */ @Override public List<RenderingResultRow<Control>> createControls(final Composite parent) { final IItemPropertyDescriptor itemPropertyDescriptor = getItemPropertyDescriptor(getFirstSetting()); if (itemPropertyDescriptor == null) { return null; } parent.addDisposeListener(new DisposeListener() { @Override public void widgetDisposed(DisposeEvent e) { dispose(); } }); final List<RenderingResultRow<Control>> list = Collections.singletonList( SWTRenderingHelper.INSTANCE.getResultRowFactory().createRenderingResultRow(createControl(parent))); applyValidation(getControl().getDiagnostic()); return list; } @Override public Composite createControl(final Composite parent) { mainSetting = getFirstSetting(); composedAdapterFactory = new ComposedAdapterFactory( new AdapterFactory[] { new ReflectiveItemProviderAdapterFactory(), new ComposedAdapterFactory(ComposedAdapterFactory.Descriptor.Registry.INSTANCE) }); adapterFactoryItemDelegator = new AdapterFactoryItemDelegator(composedAdapterFactory); clazz = getTableReference().getEReferenceType(); final Composite composite = new Composite(parent, SWT.NONE); composite.setLayout(new GridLayout(1, false)); composite.setBackground(parent.getBackground()); final Composite titleComposite = new Composite(composite, SWT.NONE); titleComposite.setBackground(parent.getBackground()); GridDataFactory.fillDefaults().grab(true, false).align(SWT.FILL, SWT.BEGINNING).applyTo(titleComposite); GridLayoutFactory.fillDefaults().numColumns(3).equalWidth(false).applyTo(titleComposite); final Label label = new Label(titleComposite, SWT.NONE); label.setBackground(parent.getBackground()); label.setText(getItemPropertyDescriptor(mainSetting).getDisplayName(null)); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.BEGINNING).grab(true, false).applyTo(label); // VALIDATION validationLabel = new Label(titleComposite, SWT.NONE); validationLabel.setBackground(parent.getBackground()); // set the size of the label to the size of the image GridDataFactory.fillDefaults().hint(16, 17).applyTo(validationLabel); boolean createButtons = true; if (tableControlConfiguration != null) { createButtons = !tableControlConfiguration.isAddRemoveDisabled(); } if (createButtons) { // addButtons final Composite buttonComposite = new Composite(titleComposite, SWT.NONE); GridDataFactory.fillDefaults().align(SWT.END, SWT.BEGINNING).grab(true, false).applyTo(buttonComposite); int numButtons = 2; createAddRowButton(clazz, buttonComposite); createRemoveRowButton(clazz, buttonComposite); if (!isEmbedded() && getTableReference().isUnsettable()) { unsetButton = new Button(buttonComposite, SWT.PUSH); unsetButton.setToolTipText(getUnsetButtonTooltip()); unsetButton.setImage(Activator.getImage(ICONS_UNSET_FEATURE)); numButtons++; } GridLayoutFactory.fillDefaults().numColumns(numButtons).equalWidth(true).applyTo(buttonComposite); } final Composite controlComposite = new Composite(composite, SWT.NONE); GridDataFactory.fillDefaults().grab(true, true).align(SWT.FILL, SWT.FILL).applyTo(controlComposite); GridLayoutFactory.fillDefaults().numColumns(1).applyTo(controlComposite); // delegate to super class createContentControl(controlComposite); return composite; } private TableViewer createTableViewer(Composite parent) { final TableViewer tableViewer = new TableViewer(parent, SWT.MULTI | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.BORDER); tableViewer.getTable().setData(CUSTOM_VARIANT, "org_eclipse_emf_ecp_control_table"); //$NON-NLS-1$ tableViewer.getTable().setHeaderVisible(true); tableViewer.getTable().setLinesVisible(true); final TableViewerFocusCellManager focusCellManager = new TableViewerFocusCellManager(tableViewer, new ECPFocusCellDrawHighlighter(tableViewer)); 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, focusCellManager, actSupport, ColumnViewerEditor.TABBING_HORIZONTAL | ColumnViewerEditor.TABBING_MOVE_TO_ROW_NEIGHBOR | ColumnViewerEditor.TABBING_VERTICAL | ColumnViewerEditor.KEYBOARD_ACTIVATION); tableViewer.getTable().setData(FIXED_COLUMNS, new Integer(1)); ColumnViewerToolTipSupport.enableFor(tableViewer); return tableViewer; } private void createFixedValidationStatusColumn(TableViewer tableViewer, final List<EStructuralFeature> structuralFeatures) { final TableViewerColumn column = TableViewerColumnBuilder.create().setMoveable(false) .setText(LocalizationServiceHelper.getString(getClass(), DepricatedControlMessageKeys.TableControl_ValidationStatusColumn)) .setWidth(80).build(tableViewer); column.setLabelProvider(new ValidationStatusCellLabelProvider(structuralFeatures)); } private EObject getInstanceOf(EClass clazz) { return clazz.getEPackage().getEFactoryInstance().create(clazz); } /* * (non-Javadoc) * @see * org.eclipse.emf.ecp.edit.internal.swt.util.SWTControl#fillControlComposite(org.eclipse.swt.widgets.Composite) */ @Override protected void fillControlComposite(Composite parent) { final Composite composite = new Composite(parent, SWT.NONE); GridDataFactory.fillDefaults().grab(true, true).align(SWT.FILL, SWT.FILL).hint(1, 200).applyTo(composite); tableViewer = createTableViewer(composite); final ObservableListContentProvider cp = new ObservableListContentProvider(); final EObject tempInstance = getInstanceOf(clazz); final ECPTableViewerComparator comparator = new ECPTableViewerComparator(); tableViewer.setComparator(comparator); int columnNumber = 0; final Map<EStructuralFeature, Boolean> readOnlyConfig = createReadOnlyConfig(clazz); final List<EStructuralFeature> structuralFeatures = new ArrayList<EStructuralFeature>(); structuralFeatures.addAll(readOnlyConfig.keySet()); if (!getControl().isReadonly()) { createFixedValidationStatusColumn(tableViewer, structuralFeatures); } for (final EStructuralFeature feature : structuralFeatures) { final IItemPropertyDescriptor itemPropertyDescriptor = adapterFactoryItemDelegator .getPropertyDescriptor(tempInstance, feature); if (itemPropertyDescriptor == null) { // if we can't render because no edit information is available, do nothing continue; } final CellEditor cellEditor = createCellEditor(tempInstance, feature); final TableViewerColumn column = TableViewerColumnBuilder.create() .setText(itemPropertyDescriptor.getDisplayName(null)) .setToolTipText(itemPropertyDescriptor.getDescription(null)).setResizable(true) .setMoveable(false).setStyle(noStyle()).setData("width", //$NON-NLS-1$ ECPCellEditor.class.isInstance(cellEditor) ? ECPCellEditor.class.cast(cellEditor).getColumnWidthWeight() : 100) .build(tableViewer); column.setLabelProvider(new ECPCellLabelProvider(feature, cellEditor, feature.isMany() ? new EObjectObservableMap(cp.getKnownElements(), feature) : EMFProperties.value(feature).observeDetail(cp.getKnownElements()))); column.getColumn() .addSelectionListener(getSelectionAdapter(comparator, column.getColumn(), columnNumber)); if (!isReadOnlyFeature(readOnlyConfig, feature)) { // remove if no editing needed final EditingSupport observableSupport = new ECPTableEditingSupport(tableViewer, cellEditor, feature); column.setEditingSupport(observableSupport); } columnNumber++; } tableViewer.setContentProvider(cp); final IObservableList list = EMFEditObservables.observeList(getEditingDomain(mainSetting), mainSetting.getEObject(), mainSetting.getEStructuralFeature()); tableViewer.setInput(list); // IMPORTANT: // - the minimumWidth and (non)resizable settings of the ColumnWeightData are not supported properly // - the layout stops resizing columns that have been resized manually by the user (this could be considered a // feature though) final TableColumnLayout layout = new TableColumnLayout(); composite.setLayout(layout); for (int i = 0; i < tableViewer.getTable().getColumns().length; i++) { final Integer storedValue = (Integer) tableViewer.getTable().getColumns()[i].getData("width"); //$NON-NLS-1$ layout.setColumnData(tableViewer.getTable().getColumns()[i], new ColumnWeightData(storedValue == null ? 50 : storedValue)); } } private CellEditor createCellEditor(final EObject tempInstance, final EStructuralFeature feature) { return CellEditorFactory.INSTANCE.getCellEditor(feature, tempInstance, tableViewer.getTable(), getViewModelContext()); } private static boolean isReadOnlyFeature(Map<EStructuralFeature, Boolean> readOnlyConfig, EStructuralFeature feature) { if (readOnlyConfig != null) { final Boolean isReadOnly = readOnlyConfig.get(feature); if (isReadOnly != null) { return isReadOnly; } } return false; } private Map<EStructuralFeature, Boolean> createReadOnlyConfig(EClass clazz) { final Map<EStructuralFeature, Boolean> readOnlyConfig = new LinkedHashMap<EStructuralFeature, Boolean>(); if (tableControlConfiguration != null) { for (final TableColumnConfiguration tcc : tableControlConfiguration.getColumns()) { readOnlyConfig.put(tcc.getColumnAttribute(), tcc.isReadOnly()); } } else { for (final EStructuralFeature feature : clazz.getEStructuralFeatures()) { readOnlyConfig.put(feature, Boolean.FALSE); } } return readOnlyConfig; } private int noStyle() { return SWT.NONE; } @Override protected Button getCustomUnsetButton() { return unsetButton; } private SelectionAdapter getSelectionAdapter(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; } private Button removeButton; private void createRemoveRowButton(EClass clazz, final Composite buttonComposite) { removeButton = new Button(buttonComposite, SWT.None); final Image image = Activator.getImage(ICONS_UNSET_REFERENCE); removeButton.setImage(image); removeButton.setToolTipText(LocalizationServiceHelper.getString(getClass(), DepricatedControlMessageKeys.TableControl_RemoveSelected) + clazz.getInstanceClass().getSimpleName()); removeButton.addSelectionListener(new SelectionAdapter() { /* * (non-Javadoc) * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent) */ @Override public void widgetSelected(SelectionEvent e) { final IStructuredSelection selection = (IStructuredSelection) tableViewer.getSelection(); if (selection == null || selection.getFirstElement() == null) { return; } final List<EObject> deletionList = new ArrayList<EObject>(); final Iterator<?> iterator = selection.iterator(); while (iterator.hasNext()) { deletionList.add((EObject) iterator.next()); } deleteRowUserConfirmDialog(deletionList); } }); final List<?> containments = (List<?>) mainSetting.get(true); if (containments.size() <= getTableReference().getLowerBound()) { removeButton.setEnabled(false); } } /** * This method shows a user confirmation dialog when the user attempts to delete a row in the table. * * @param deletionList the list of selected EObjects to delete */ protected void deleteRowUserConfirmDialog(final List<EObject> deletionList) { final MessageDialog dialog = new MessageDialog(tableViewer.getTable().getShell(), LocalizationServiceHelper.getString(getClass(), DepricatedControlMessageKeys.TableControl_Delete), null, LocalizationServiceHelper.getString(getClass(), DepricatedControlMessageKeys.TableControl_DeleteAreYouSure), MessageDialog.CONFIRM, new String[] { JFaceResources.getString(IDialogLabelKeys.YES_LABEL_KEY), JFaceResources.getString(IDialogLabelKeys.NO_LABEL_KEY) }, 0); new ECPDialogExecutor(dialog) { @Override public void handleResult(int codeResult) { if (codeResult == IDialogConstants.CANCEL_ID) { return; } deleteRows(deletionList); final List<?> containments = (List<?>) mainSetting.get(true); if (containments.size() < getTableReference().getUpperBound()) { addButton.setEnabled(true); } if (containments.size() <= getTableReference().getLowerBound()) { removeButton.setEnabled(false); } } }.execute(); } /** * This is called by {@link #deleteRowUserConfirmDialog(List)} after the user confirmed to delete the selected * elements. * * @param deletionList the list of {@link EObject EObjects} to delete */ protected void deleteRows(List<EObject> deletionList) { final EditingDomain editingDomain = getEditingDomain(mainSetting); final EObject modelElement = mainSetting.getEObject(); editingDomain.getCommandStack() .execute(RemoveCommand.create(editingDomain, modelElement, getTableReference(), deletionList)); } /** * This method is called to add a new entry in the domain model and thus to create a new row in the table. The * element to create is defined by the provided class. * You can override this method but you have to call super nonetheless. * * @param clazz the {@link EClass} defining the EObject to create */ protected void addRow(EClass clazz) { final EObject modelElement = mainSetting.getEObject(); final EObject instance = clazz.getEPackage().getEFactoryInstance().create(clazz); final EditingDomain editingDomain = getEditingDomain(mainSetting); editingDomain.getCommandStack() .execute(AddCommand.create(editingDomain, modelElement, getTableReference(), instance)); } private Button addButton; private Setting mainSetting; private boolean isDisposing; private void createAddRowButton(final EClass clazz, final Composite buttonComposite) { addButton = new Button(buttonComposite, SWT.None); final Image image = Activator.getImage(ICON_ADD); addButton.setImage(image); addButton.setToolTipText(LocalizationServiceHelper.getString(getClass(), DepricatedControlMessageKeys.TableControl_AddInstanceOf) + clazz.getInstanceClass().getSimpleName()); addButton.addSelectionListener(new SelectionAdapter() { /* * (non-Javadoc) * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent) */ @Override public void widgetSelected(SelectionEvent e) { addRow(clazz); final List<?> containments = (List<?>) mainSetting.get(true); if (getTableReference().getUpperBound() != -1 && containments.size() >= getTableReference().getUpperBound()) { addButton.setEnabled(false); } if (containments.size() > getTableReference().getLowerBound()) { removeButton.setEnabled(true); } } }); final List<?> containments = (List<?>) mainSetting.get(true); if (getTableReference().getUpperBound() != -1 && containments.size() >= getTableReference().getUpperBound()) { addButton.setEnabled(false); } } /** * {@inheritDoc} */ @Override public void dispose() { isDisposing = true; super.dispose(); composedAdapterFactory.dispose(); mainSetting = null; adapterFactoryItemDelegator = null; composedAdapterFactory = null; isDisposing = false; } /** * {@inheritDoc} * * @see org.eclipse.emf.ecp.edit.spi.ECPAbstractControl#applyValidation(org.eclipse.emf.ecp.view.spi.model.VDiagnostic) */ @Override protected void applyValidation(VDiagnostic diagnostic) { if (validationLabel == null || validationLabel.isDisposed()) { return; } if (diagnostic != null) { final Image image = getValidationIcon(diagnostic.getHighestSeverity()); validationLabel.setImage(image); validationLabel.setToolTipText(diagnostic.getMessage()); for (final Object object : (Collection<?>) mainSetting.get(true)) { tableViewer.update(object, null); } } } // /** // * {@inheritDoc} // * // * @deprecated // */ // @Deprecated // @Override // public void resetValidation() { // if (validationLabel == null || validationLabel.isDisposed()) { // return; // } // validationLabel.setToolTipText(""); //$NON-NLS-1$ // validationLabel.setImage(null); // tableViewer.refresh(); // } // /** // * {@inheritDoc} // * // * @deprecated // */ // @Deprecated // @Override // public void handleValidation(Diagnostic diagnostic) { // if (diagnostic.getData().isEmpty()) { // return; // } // final Image image = getValidationIcon(diagnostic.getSeverity()); // validationLabel.setImage(image); // validationLabel.setToolTipText(getTableTooltipMessage(diagnostic)); // final EObject object = (EObject) diagnostic.getData().get(0); // tableViewer.update(object, null); // } /** * Returns the message of the validation tool tip shown in the table header. * * @param diagnostic the {@link Diagnostic} to extract the message from * @return the message */ protected String getTableTooltipMessage(Diagnostic diagnostic) { return diagnostic.getMessage(); } /** * Returns the message of the validation tool tip shown in the row. * * @param vDiagnostic the {@link VDiagnostic} to get the message from * @return the message */ protected String getRowTooltipMessage(VDiagnostic vDiagnostic) { return vDiagnostic.getMessage(); } /** * Returns the message of the validation tool tip shown in the cell. * * @param vDiagnostic the {@link VDiagnostic} to get the message from * @return the message */ protected String getCellTooltipMessage(VDiagnostic vDiagnostic) { if (vDiagnostic == null) { return null; } if (vDiagnostic.getDiagnostics().size() == 0) { return vDiagnostic.getMessage(); } final Diagnostic diagnostic = (Diagnostic) vDiagnostic.getDiagnostics().get(0); Diagnostic reason = diagnostic; if (diagnostic.getChildren() != null && diagnostic.getChildren().size() != 0) { reason = diagnostic.getChildren().get(0); } return reason.getMessage(); } /** * {@inheritDoc} * * @deprecated */ @Deprecated @Override public void setEditable(boolean isEditable) { if (addButton != null) { addButton.setVisible(isEditable); } if (removeButton != null) { removeButton.setVisible(isEditable); } editable = isEditable; } /** * @author Jonas * */ private final class ValidationStatusCellLabelProvider extends CellLabelProvider { private final List<EStructuralFeature> structuralFeatures; /** * @param structuralFeatures */ private ValidationStatusCellLabelProvider(List<EStructuralFeature> structuralFeatures) { this.structuralFeatures = structuralFeatures; } @Override public void update(ViewerCell cell) { Integer mostSevere = Diagnostic.OK; final VDiagnostic vDiagnostic = getControl().getDiagnostic(); // for (final Object diagObject : vDiagnostic.getDiagnostics()) { // final Diagnostic diagnostic = (Diagnostic) diagObject; // if (diagnostic.getData().size() == 0) { // continue; // } // if (diagnostic.getData().get(0).equals(cell.getElement())) { // final int currentSeverity = diagnostic.getSeverity(); // if (currentSeverity > mostSevere) { // mostSevere = currentSeverity; // } // } // } final List<Diagnostic> diagnostics = vDiagnostic.getDiagnostics((EObject) cell.getElement()); if (diagnostics.size() != 0) { mostSevere = diagnostics.get(0).getSeverity(); } cell.setImage(getValidationIcon(mostSevere)); } @Override public String getToolTipText(Object element) { final StringBuffer tooltip = new StringBuffer(); final VDiagnostic vDiagnostic = getControl().getDiagnostic(); // for (final Object diagObject : vDiagnostic.getDiagnostics()) { // final Diagnostic diagnostic = (Diagnostic) diagObject; // if (diagnostic.getData().size() < 2) { // continue; // } // if (diagnostic.getSeverity() == Diagnostic.OK) { // continue; // } // if (diagnostic.getData().get(0).equals(element) // && structuralFeatures.contains(diagnostic.getData().get(1))) { // if (tooltip.length() > 0) { // tooltip.append("\n"); //$NON-NLS-1$ // } // tooltip.append(diagnostic.getMessage()); // } // } final List<Diagnostic> diagnostics = vDiagnostic.getDiagnostics((EObject) element); for (final Diagnostic diagnostic : diagnostics) { if (tooltip.length() > 0) { tooltip.append("\n"); //$NON-NLS-1$ } tooltip.append(diagnostic.getMessage()); } return tooltip.toString(); } } /** * 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; } } /** * ECP specficic cell label provider that does also implement {@link IColorProvider} in * order to correctly. * * @author emueller * */ public class ECPCellLabelProvider extends ObservableMapCellLabelProvider implements IColorProvider { private final EStructuralFeature feature; private final CellEditor cellEditor; /** * Constructor. * * @param feature * the {@link EStructuralFeature} the cell is bound to * @param cellEditor * the {@link CellEditor} instance * @param attributeMap * an {@link IObservableMap} instance that is passed to the {@link ObservableMapCellLabelProvider} */ public ECPCellLabelProvider(EStructuralFeature feature, CellEditor cellEditor, IObservableMap attributeMap) { super(attributeMap); this.feature = feature; this.cellEditor = cellEditor; } /** * {@inheritDoc} * * @see org.eclipse.jface.viewers.CellLabelProvider#getToolTipText(java.lang.Object) */ @Override public String getToolTipText(Object element) { final EObject domainObject = (EObject) element; final StringBuffer tooltip = new StringBuffer(); final VDiagnostic vDiagnostic = getControl().getDiagnostic(); final List<Diagnostic> diagnostics = vDiagnostic.getDiagnostic(domainObject, feature); for (final Diagnostic diagnostic : diagnostics) { if (tooltip.length() > 0) { tooltip.append("\n"); //$NON-NLS-1$ } tooltip.append(diagnostic.getMessage()); } return tooltip.toString(); // final VDiagnostic vDiagnostic = getControl().getDiagnostic(); // for (final Object diagObject : vDiagnostic.getDiagnostics()) { // final Diagnostic diagnostic = (Diagnostic) diagObject; // if (diagnostic.getData().size() < 2) { // continue; // } // if (diagnostic.getData().get(0).equals(element) && diagnostic.getData().get(1).equals(feature)) { // // if (diagnostic.getChildren() != null && diagnostic.getChildren().size() != 0) { // boolean childrenUsefull = false; // for (final Diagnostic diagnostic2 : diagnostic.getChildren()) { // if (diagnostic2.getSeverity() != Diagnostic.OK) { // if (tooltip.length() > 0) { // tooltip.append("\n"); //$NON-NLS-1$ // } // tooltip.append(diagnostic2.getMessage()); // childrenUsefull = true; // } // } // if (!childrenUsefull) { // if (tooltip.length() > 0) { // tooltip.append("\n"); //$NON-NLS-1$ // } // tooltip.append(diagnostic.getMessage()); // } // } else { // if (tooltip.length() > 0) { // tooltip.append("\n"); //$NON-NLS-1$ // } // tooltip.append(diagnostic.getMessage()); // } // } // } // if (tooltip.length() != 0) { // return tooltip.toString(); // } // final Object value = ((EObject) element).eGet(feature); // if (value == null) { // return null; // } // return String.valueOf(value); } @Override public void update(ViewerCell cell) { final EObject element = (EObject) cell.getElement(); final Object value = attributeMaps[0].get(element); if (ECPCellEditor.class.isInstance(cellEditor)) { final ECPCellEditor ecpCellEditor = (ECPCellEditor) cellEditor; final String text = ecpCellEditor.getFormatedString(value); cell.setText(text == null ? "" : text); //$NON-NLS-1$ cell.setImage(ecpCellEditor.getImage(value)); } else { cell.setText(value == null ? "" : value.toString()); //$NON-NLS-1$ cell.getControl().setData(CUSTOM_VARIANT, "org_eclipse_emf_ecp_edit_cellEditor_string"); //$NON-NLS-1$ } cell.setBackground(getBackground(element)); } /** * {@inheritDoc} * * @see org.eclipse.jface.viewers.IColorProvider#getForeground(java.lang.Object) */ @Override public Color getForeground(Object element) { return null; } /** * {@inheritDoc} * * @see org.eclipse.jface.viewers.IColorProvider#getBackground(java.lang.Object) */ @Override public Color getBackground(Object element) { if (isDisposing) { return null; } final Integer mostSevere = Diagnostic.OK; final VDiagnostic vDiagnostic = getControl().getDiagnostic(); // for (final Object diagObject : vDiagnostic.getDiagnostics()) { // final Diagnostic diagnostic = (Diagnostic) diagObject; // if (diagnostic.getData().size() < 2) { // continue; // } // if (diagnostic.getData().get(0).equals(element) && diagnostic.getData().get(1).equals(feature)) { // final int currentSeverity = diagnostic.getSeverity(); // if (currentSeverity > mostSevere) { // mostSevere = currentSeverity; // } // } // } final List<Diagnostic> diagnostic = vDiagnostic.getDiagnostic((EObject) element, feature); return getValidationBackgroundColor( diagnostic.size() == 0 ? Diagnostic.OK : diagnostic.get(0).getSeverity()); } } /* * (non-Javadoc) * @see org.eclipse.emf.ecp.edit.internal.swt.util.SWTControl#getUnsetLabelText() */ @Override protected String getUnsetLabelText() { return LocalizationServiceHelper.getString(getClass(), DepricatedControlMessageKeys.TableControl_NotSetClickToSet); } /* * (non-Javadoc) * @see org.eclipse.emf.ecp.edit.internal.swt.util.SWTControl#getUnsetButtonTooltip() */ @Override protected String getUnsetButtonTooltip() { return LocalizationServiceHelper.getString(getClass(), DepricatedControlMessageKeys.TableControl_Unset); } /* * (non-Javadoc) * @see org.eclipse.emf.ecp.edit.internal.swt.util.SWTControl#getControlForTooltip() */ @Override protected Control[] getControlsForTooltip() { // return new Control[] { tableViewer.getControl() }; return new Control[0]; } /** * {@inheritDoc} * * @deprecated */ @Override @Deprecated public boolean showLabel() { return false; } /** * Implementation of the {@link EditingSupport} for the generic ECP Table. * * @author Eugen Neufeld * */ private class ECPTableEditingSupport extends EditingSupport { private final CellEditor cellEditor; private final EStructuralFeature cellFeature; /** * @param viewer */ public ECPTableEditingSupport(ColumnViewer viewer, CellEditor cellEditor, EStructuralFeature feature) { super(viewer); this.cellEditor = cellEditor; cellFeature = feature; } private EditingState editingState; private final ColumnViewerEditorActivationListenerHelper activationListener = new ColumnViewerEditorActivationListenerHelper(); /** * Default implementation always returns <code>true</code>. * * @see org.eclipse.jface.viewers.EditingSupport#canEdit(java.lang.Object) */ @Override protected boolean canEdit(Object element) { if (ECPCellEditor.class.isInstance(cellEditor)) { ECPCellEditor.class.cast(cellEditor).setEditable(editable); return true; } return editable; } /** * Default implementation always returns <code>null</code> as this will be * handled by the Binding. * * @see org.eclipse.jface.viewers.EditingSupport#getValue(java.lang.Object) */ @Override protected Object getValue(Object element) { // no op return null; } /** * Default implementation does nothing as this will be handled by the * Binding. * * @see org.eclipse.jface.viewers.EditingSupport#setValue(java.lang.Object, java.lang.Object) */ @Override protected void setValue(Object element, Object value) { // no op } /** * Creates a {@link Binding} between the editor and the element to be * edited. Invokes {@link #doCreateCellEditorObservable(CellEditor)}, * {@link #doCreateElementObservable(Object, ViewerCell)}, and then * {@link #createBinding(IObservableValue, IObservableValue)}. */ @Override protected void initializeCellEditorValue(CellEditor cellEditor, ViewerCell cell) { final IObservableValue target = doCreateCellEditorObservable(cellEditor); Assert.isNotNull(target, "doCreateCellEditorObservable(...) did not return an observable"); //$NON-NLS-1$ final IObservableValue model = doCreateElementObservable(cell.getElement(), cell); Assert.isNotNull(model, "doCreateElementObservable(...) did not return an observable"); //$NON-NLS-1$ final Binding binding = createBinding(target, model); Assert.isNotNull(binding, "createBinding(...) did not return a binding"); //$NON-NLS-1$ editingState = new EditingState(binding, target, model); getViewer().getColumnViewerEditor().addEditorActivationListener(activationListener); } @Override protected CellEditor getCellEditor(Object element) { return cellEditor; } protected Binding createBinding(IObservableValue target, IObservableValue model) { if (ECPCellEditor.class.isInstance(cellEditor)) { return getDataBindingContext().bindValue(target, model, ((ECPCellEditor) cellEditor).getTargetToModelStrategy(getDataBindingContext()), ((ECPCellEditor) cellEditor).getModelToTargetStrategy(getDataBindingContext())); } return getDataBindingContext().bindValue(target, model); } protected IObservableValue doCreateElementObservable(Object element, ViewerCell cell) { return EMFEditObservables.observeValue(getEditingDomain(), (EObject) element, cellFeature); } protected IObservableValue doCreateCellEditorObservable(CellEditor cellEditor) { if (ECPCellEditor.class.isInstance(cellEditor)) { return ((ECPCellEditor) cellEditor).getValueProperty().observe(cellEditor); } return SWTObservables.observeText(cellEditor.getControl(), SWT.FocusOut); } @Override protected final void saveCellEditorValue(CellEditor cellEditor, ViewerCell cell) { editingState.binding.updateTargetToModel(); } class ColumnViewerEditorActivationListenerHelper extends ColumnViewerEditorActivationListener { @Override public void afterEditorActivated(ColumnViewerEditorActivationEvent event) { // do nothing } @Override public void afterEditorDeactivated(ColumnViewerEditorDeactivationEvent event) { editingState.dispose(); editingState = null; getViewer().getColumnViewerEditor().removeEditorActivationListener(this); final ViewerCell focusCell = getViewer().getColumnViewerEditor().getFocusCell(); if (focusCell != null) { getViewer().update(focusCell.getElement(), null); } } @Override public void beforeEditorActivated(ColumnViewerEditorActivationEvent event) { // do nothing } @Override public void beforeEditorDeactivated(ColumnViewerEditorDeactivationEvent event) { // do nothing } } /** * Maintains references to objects that only live for the length of the edit * cycle. */ class EditingState { private final IObservableValue target; private final IObservableValue model; private final Binding binding; EditingState(Binding binding, IObservableValue target, IObservableValue model) { this.binding = binding; this.target = target; this.model = model; } void dispose() { binding.dispose(); target.dispose(); model.dispose(); } } } }