| /******************************************************************************* |
| * 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 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: |
| * 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.typed.WidgetProperties; |
| 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; |
| |
| 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 |
| * |
| */ |
| class ECPTableEditingSupport extends EditingSupport { |
| |
| private final CellEditor cellEditor; |
| |
| private final EStructuralFeature cellFeature; |
| |
| /** |
| * @param viewer |
| */ |
| 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 WidgetProperties.text(SWT.FocusOut).observe(cellEditor.getControl()); |
| } |
| |
| @Override |
| protected final void saveCellEditorValue(CellEditor cellEditor, ViewerCell cell) { |
| if (editingState.isUpdateNeeded()) { |
| 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(); |
| } |
| |
| /** |
| * Checks if an update is really needed. |
| * |
| * @return <code>true</code> if update is really needed, <code>false</code> otherwise. |
| */ |
| boolean isUpdateNeeded() { |
| final Object targetValue = target.getValue(); |
| final Object modelValue = model.getValue(); |
| |
| if (targetValue == null) { |
| return modelValue != null; |
| } |
| return !targetValue.equals(modelValue); |
| } |
| } |
| } |
| |
| } |