blob: e75ad15839053c042382319298b5c970c71f5cc8 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011-2019 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:
* jonas - initial API and implementation
* Christian W. Damus - bug 547271
******************************************************************************/
package org.eclipse.emfforms.spi.swt.table;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.emf.databinding.EMFDataBindingContext;
import org.eclipse.emfforms.common.Feature;
import org.eclipse.emfforms.common.Optional;
import org.eclipse.emfforms.internal.swt.table.action.KeyBindingManager;
import org.eclipse.emfforms.spi.swt.table.action.ActionBar;
import org.eclipse.emfforms.spi.swt.table.action.ActionBarProvider;
import org.eclipse.emfforms.spi.swt.table.action.ActionConfiguration;
import org.eclipse.jface.databinding.swt.WidgetProperties;
import org.eclipse.jface.layout.AbstractColumnLayout;
import org.eclipse.jface.viewers.AbstractTableViewer;
import org.eclipse.jface.viewers.ColumnPixelData;
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.ISelectionChangedListener;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.ViewerColumn;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Widget;
/**
* @author Jonas Helming
*
* @param <V> the TableViewer implementation to use
*/
public abstract class AbstractTableViewerComposite<V extends AbstractTableViewer> extends Composite {
private final EMFDataBindingContext emfDatabindingContext;
private Optional<List<Control>> validationControls;
private final Set<Feature> enabledFeatures;
private final Optional<ActionBar<V>> actionBar;
/**
* Default constructor.
*
* @param parent the parent {@link Composite}
* @param style the style bits
* @param inputObject the input object
* @param customization the {@link TableViewerSWTCustomization}
* @param title the title
* @param tooltip the tooltip
*/
protected AbstractTableViewerComposite(
Composite parent,
int style,
Object inputObject,
TableViewerSWTCustomization<V> customization,
IObservableValue title,
IObservableValue tooltip) {
super(parent, style);
emfDatabindingContext = new EMFDataBindingContext();
enabledFeatures = determineEnabledFeatures(customization);
actionBar = customization.getActionBar();
renderControl(this, customization, inputObject, emfDatabindingContext, title, tooltip);
}
/**
* Determine the list of enabled features (both for the table as well as the columns).
*
* @param customization the viewer customization
* @return a set of enabled features
*/
private Set<Feature> determineEnabledFeatures(TableViewerSWTCustomization<V> customization) {
final Set<Feature> enabled = new LinkedHashSet<Feature>();
enabled.addAll(customization.getTableConfiguration().getEnabledFeatures());
for (final ColumnConfiguration columnConfig : customization.getColumnConfigurations()) {
enabled.addAll(columnConfig.getEnabledFeatures());
}
return enabled;
}
/**
* @return the enabledFeatures
*/
public Set<Feature> getEnabledFeatures() {
return enabledFeatures;
}
/**
* If present, returns the {@link ActionBar} configuring actions and corresponding control for this composite's
* viewer.
*
* @return The {@link ActionBar}, if any
*/
public Optional<ActionBar<V>> getActionBar() {
return actionBar;
}
/**
* @return the {@link AbstractTableViewer}
*/
public abstract V getTableViewer();
/**
*
* @return the validation controls, if present
*/
public Optional<List<Control>> getValidationControls() {
return validationControls;
}
/**
* Configures the context menu for the given TableViewer instance.
*
* @param tableViewer the table viewer to configure
*/
protected void configureContextMenu(V tableViewer) {
}
/**
* Configures viewer filters for the given TableViewer instance.
*
* @param tableViewer the table viewer to configure
*/
protected void configureViewerFilters(V tableViewer) {
}
private void renderControl(Composite parent, TableViewerSWTCustomization<V> customization,
Object inputObject, EMFDataBindingContext emfDataBindingContext, IObservableValue title,
IObservableValue tooltip) {
customization.createCompositeLayout(parent);
final Optional<Label> titleLabel = customization.getTitleLabel();
if (titleLabel.isPresent()) {
initTitleLabel(titleLabel.get(), title, tooltip, emfDatabindingContext);
}
validationControls = customization.getValidationControls();
final Composite viewerComposite = customization.getViewerComposite();
final V tableViewer = createTableViewer(customization, viewerComposite);
final TableConfiguration configuration = customization.getTableConfiguration();
if (configuration != null) {
// Pump in the configuration data
configuration.getData().forEach(tableViewer::setData);
}
// If an action configuration was configured, bind key bindings to the viewer
final Optional<ActionConfiguration> actionConfiguration = customization.getActionConfiguration();
if (actionConfiguration.isPresent()) {
final KeyBindingManager keyBindingManager = new KeyBindingManager();
keyBindingManager.applyActionConfiguration(actionConfiguration.get());
keyBindingManager.bindToViewer(tableViewer);
}
final Optional<Composite> buttonComposite = customization.getButtonComposite();
if (buttonComposite.isPresent()) {
initActionBar(buttonComposite.get(), customization, tableViewer);
}
enableTooltipSupport(tableViewer);
final Optional<ViewerComparator> comparator = customization.getComparator();
if (comparator.isPresent()) {
tableViewer.setComparator(comparator.get());
}
tableViewer.setContentProvider(customization.createContentProvider());
addColumns(customization, tableViewer, emfDataBindingContext);
setupDragAndDrop(customization, tableViewer);
configureContextMenu(tableViewer);
configureViewerFilters(tableViewer);
tableViewer.setInput(inputObject);
tableViewer.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
viewerSelectionChanged(event);
}
});
final AbstractColumnLayout layout = createLayout(viewerComposite);
final Widget[] columns = getColumns();
for (int i = 0; i < columns.length; i++) {
final Widget tableColumn = columns[i];
final boolean storedIsResizable = (Boolean) tableColumn.getData(ColumnConfiguration.RESIZABLE);
final Integer storedWeight = (Integer) tableColumn.getData(ColumnConfiguration.WEIGHT);
final Integer storedMinWidth = (Integer) tableColumn.getData(ColumnConfiguration.MIN_WIDTH);
if (storedWeight == ColumnConfiguration.NO_WEIGHT) {
layout.setColumnData(tableColumn, new ColumnPixelData(storedMinWidth, storedIsResizable));
} else if (storedMinWidth > 0) {
layout.setColumnData(tableColumn,
new ColumnWeightData(storedWeight, storedMinWidth, storedIsResizable));
} else {
layout.setColumnData(tableColumn,
new ColumnWeightData(storedWeight, storedIsResizable));
}
}
}
private void setupDragAndDrop(TableViewerSWTCustomization<V> customization, final V tableViewer) {
if (customization.hasDND()) {
tableViewer.addDragSupport(customization.getDragOperations(), customization.getDragTransferTypes(),
customization.getDragListener(tableViewer));
tableViewer.addDropSupport(customization.getDropOperations(), customization.getDropTransferTypes(),
customization.getDropListener(tableViewer));
}
}
/**
* Returns the list of columns of the table viewer.
*
* @return the list of columns
*/
public abstract Widget[] getColumns();
/**
* Sets the layout of the given {@link Composite}.
*
* @param viewerComposite the target composite
*
* @return the applied layout
*
*/
protected abstract AbstractColumnLayout createLayout(Composite viewerComposite);
/**
* Creates the table viewer.
*
* @param customization the {@link TableViewerSWTCustomization} to use
* @param viewerComposite the parent composite
*
* @return the table viewer
*/
protected abstract V createTableViewer(TableViewerSWTCustomization<V> customization,
Composite viewerComposite);
private void addColumns(TableViewerSWTCustomization<V> customization, V tableViewer,
EMFDataBindingContext emfDataBindingContext) {
for (final ColumnConfiguration columnConfiguration : customization.getColumnConfigurations()) {
createColumn(columnConfiguration, emfDataBindingContext, tableViewer);
}
}
/**
* Creates a new {@link ViewerColumn}.
*
* @param columnDescription the column description to use
* @param tableViewer the parent {@link AbstractTableViewer}
* @param emfDataBindingContext the data binding context to use
* @return the viewer column
*/
protected abstract ViewerColumn createColumn(ColumnConfiguration columnDescription,
EMFDataBindingContext emfDataBindingContext, V tableViewer);
/**
* Returns the {@link ColumnConfiguration} of the given widget instance.
*
* @param columnWidget the widget to fetch the column configuration for
* @return the {@link ColumnConfigurationImpl}
*/
public ColumnConfiguration getColumnConfiguration(Widget columnWidget) {
return (ColumnConfiguration) columnWidget.getData(ColumnConfiguration.ID);
}
/**
* This method gets called when the selection on the {@link TableViewer} (see {@link #getTableViewer()}) has
* changed.
* <p>
* If you override this method make sure to call super.
* </p>
*
* @param event the {@link SelectionChangedEvent}
*/
protected void viewerSelectionChanged(SelectionChangedEvent event) {
if (actionBar.isPresent()) {
actionBar.get().updateActionBar();
}
}
/**
* Creates a new {@link ColumnViewerEditorActivationStrategy} for the given table viewer.
*
* @param tableViewer the target table viewer.
*
* @return the ColumnViewerEditorActivationStrategy
*
*/
protected static ColumnViewerEditorActivationStrategy createColumnViewerActivationStrategy(
final AbstractTableViewer tableViewer) {
return 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;
}
};
}
private static void enableTooltipSupport(AbstractTableViewer tableViewer) {
ColumnViewerToolTipSupport.enableFor(tableViewer);
}
private static <T extends AbstractTableViewer> void initActionBar(
Composite composite, ActionBarProvider<T> actionBarProvider, T tableViewer) {
final Optional<ActionBar<T>> actionBar = actionBarProvider.getActionBar();
if (actionBar.isPresent()) {
actionBar.get().fillComposite(composite, tableViewer);
}
}
private static void initTitleLabel(Label label, IObservableValue title, IObservableValue tooltip,
EMFDataBindingContext emfDatabindingContext) {
emfDatabindingContext.bindValue(
WidgetProperties.text().observe(label),
title);
emfDatabindingContext.bindValue(
WidgetProperties.tooltipText().observe(label),
tooltip);
}
@Override
public void dispose() {
emfDatabindingContext.dispose();
super.dispose();
}
/**
* Adds a new {@link ControlListener column listener}.
*
* @param columnlistener the listener to add
*/
public abstract void addColumnListener(ControlListener columnlistener);
/**
* Returns the {@link TableControl}.
*
* @return the table control
*/
public abstract TableControl getTableControl();
/**
* Sets the comparator of the table viewer.
*
* @param comparator the {@link TableViewerComparator} to set
* @param sortableColumns the list of columns that can be sorted
*/
public abstract void setComparator(TableViewerComparator comparator, List<Integer> sortableColumns);
/**
* Allow to set an initial sort.
*
* @param column The column to sort
* @since 1.22
*/
public abstract void setCompareColumn(int column);
}