/*******************************************************************************
* Copyright (c) 2016 Dirk Fauth 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:
* Dirk Fauth - initial API and implementation
******************************************************************************/
package org.eclipse.nebula.widgets.nattable.examples._300_Data;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.nebula.widgets.nattable.NatTable;
import org.eclipse.nebula.widgets.nattable.command.AbstractRowCommand;
import org.eclipse.nebula.widgets.nattable.command.ILayerCommand;
import org.eclipse.nebula.widgets.nattable.command.ILayerCommandHandler;
import org.eclipse.nebula.widgets.nattable.config.AbstractRegistryConfiguration;
import org.eclipse.nebula.widgets.nattable.config.AbstractUiBindingConfiguration;
import org.eclipse.nebula.widgets.nattable.config.CellConfigAttributes;
import org.eclipse.nebula.widgets.nattable.config.ConfigRegistry;
import org.eclipse.nebula.widgets.nattable.config.DefaultNatTableStyleConfiguration;
import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry;
import org.eclipse.nebula.widgets.nattable.data.IDataProvider;
import org.eclipse.nebula.widgets.nattable.data.ListDataProvider;
import org.eclipse.nebula.widgets.nattable.data.ReflectiveColumnPropertyAccessor;
import org.eclipse.nebula.widgets.nattable.data.convert.DefaultDateDisplayConverter;
import org.eclipse.nebula.widgets.nattable.dataset.person.Person;
import org.eclipse.nebula.widgets.nattable.dataset.person.PersonService;
import org.eclipse.nebula.widgets.nattable.examples.AbstractNatExample;
import org.eclipse.nebula.widgets.nattable.examples.runner.StandaloneNatExampleRunner;
import org.eclipse.nebula.widgets.nattable.grid.GridRegion;
import org.eclipse.nebula.widgets.nattable.grid.data.DefaultColumnHeaderDataProvider;
import org.eclipse.nebula.widgets.nattable.grid.data.DefaultCornerDataProvider;
import org.eclipse.nebula.widgets.nattable.grid.data.DefaultRowHeaderDataProvider;
import org.eclipse.nebula.widgets.nattable.grid.layer.ColumnHeaderLayer;
import org.eclipse.nebula.widgets.nattable.grid.layer.CornerLayer;
import org.eclipse.nebula.widgets.nattable.grid.layer.DefaultRowHeaderDataLayer;
import org.eclipse.nebula.widgets.nattable.grid.layer.GridLayer;
import org.eclipse.nebula.widgets.nattable.grid.layer.RowHeaderLayer;
import org.eclipse.nebula.widgets.nattable.layer.DataLayer;
import org.eclipse.nebula.widgets.nattable.layer.ILayer;
import org.eclipse.nebula.widgets.nattable.layer.LabelStack;
import org.eclipse.nebula.widgets.nattable.layer.cell.IConfigLabelAccumulator;
import org.eclipse.nebula.widgets.nattable.layer.event.RowDeleteEvent;
import org.eclipse.nebula.widgets.nattable.layer.event.RowInsertEvent;
import org.eclipse.nebula.widgets.nattable.layer.stack.DefaultBodyLayerStack;
import org.eclipse.nebula.widgets.nattable.painter.cell.CheckBoxPainter;
import org.eclipse.nebula.widgets.nattable.selection.command.SelectRowsCommand;
import org.eclipse.nebula.widgets.nattable.sort.config.SingleClickSortConfiguration;
import org.eclipse.nebula.widgets.nattable.style.DisplayMode;
import org.eclipse.nebula.widgets.nattable.ui.binding.UiBindingRegistry;
import org.eclipse.nebula.widgets.nattable.ui.matcher.MouseEventMatcher;
import org.eclipse.nebula.widgets.nattable.ui.menu.HeaderMenuConfiguration;
import org.eclipse.nebula.widgets.nattable.ui.menu.IMenuItemProvider;
import org.eclipse.nebula.widgets.nattable.ui.menu.MenuItemProviders;
import org.eclipse.nebula.widgets.nattable.ui.menu.PopupMenuAction;
import org.eclipse.nebula.widgets.nattable.ui.menu.PopupMenuBuilder;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
/**
* Example that shows how to add/remove data from the table at runtime.
*/
public class _308_DataModificationExample extends AbstractNatExample {
public static void main(String[] args) throws Exception {
StandaloneNatExampleRunner.run(600, 650, new _308_DataModificationExample());
}
@Override
public String getDescription() {
return "This example shows how to add and remove data values at runtime. "
+ "Via right-click on a cell it is possible to insert a new row object below the current selected row or to delete the current selected row.";
}
@Override
public Control createExampleControl(Composite parent) {
// set the GridLayout because the FillLayout seems to introduce a
// scrollbar rendering issue on changing the content
parent.setLayout(new GridLayout());
// property names of the Person class
String[] personPropertyNames = {
"firstName",
"lastName",
"gender",
"married",
"birthday" };
// mapping from property to label, needed for column header labels
Map<String, String> personPropertyToLabelMap = new HashMap<>();
personPropertyToLabelMap.put("firstName", "Firstname");
personPropertyToLabelMap.put("lastName", "Lastname");
personPropertyToLabelMap.put("gender", "Gender");
personPropertyToLabelMap.put("married", "Married");
personPropertyToLabelMap.put("birthday", "Birthday");
ListDataProvider<Person> bodyDataProvider = new ListDataProvider<>(
PersonService.getPersons(10),
new ReflectiveColumnPropertyAccessor<Person>(personPropertyNames));
IDataProvider personColumnHeaderDataProvider = new DefaultColumnHeaderDataProvider(personPropertyNames, personPropertyToLabelMap);
IDataProvider personRowHeaderDataProvider = new DefaultRowHeaderDataProvider(bodyDataProvider);
// mapping from property to label, needed for column header labels
Map<String, String> addressPropertyToLabelMap = new HashMap<>();
addressPropertyToLabelMap.put("street", "Street");
addressPropertyToLabelMap.put("housenumber", "Housenumber");
addressPropertyToLabelMap.put("postalCode", "Postal Code");
addressPropertyToLabelMap.put("city", "City");
Composite panel = new Composite(parent, SWT.NONE);
panel.setLayout(new GridLayout());
GridDataFactory.fillDefaults().grab(true, true).applyTo(panel);
Composite gridPanel = new Composite(panel, SWT.NONE);
gridPanel.setLayout(new GridLayout());
GridDataFactory.fillDefaults().grab(true, true).applyTo(gridPanel);
Composite buttonPanel = new Composite(panel, SWT.NONE);
buttonPanel.setLayout(new GridLayout());
GridDataFactory.fillDefaults().grab(true, true).applyTo(buttonPanel);
ConfigRegistry configRegistry = new ConfigRegistry();
// create the body layer stack
DataLayer bodyDataLayer = new DataLayer(bodyDataProvider);
bodyDataLayer.setConfigLabelAccumulator(new IConfigLabelAccumulator() {
@Override
public void accumulateConfigLabels(LabelStack configLabels, int columnPosition, int rowPosition) {
switch (columnPosition) {
case 3:
configLabels.addLabel("MARRIED");
break;
case 4:
configLabels.addLabel("DATE");
break;
}
}
});
DefaultBodyLayerStack bodyLayerStack = new DefaultBodyLayerStack(bodyDataLayer);
bodyDataLayer.registerCommandHandler(
new DeleteRowCommandHandler<>(bodyDataProvider.getList()));
bodyDataLayer.registerCommandHandler(
new InsertRowCommandHandler<>(bodyDataProvider.getList()));
// create the column header layer stack
DataLayer columnHeaderDataLayer = new DataLayer(personColumnHeaderDataProvider);
ILayer columnHeaderLayer = new ColumnHeaderLayer(
columnHeaderDataLayer,
bodyLayerStack.getViewportLayer(),
bodyLayerStack.getSelectionLayer());
// create the row header layer stack
DataLayer rowHeaderDataLayer = new DefaultRowHeaderDataLayer(personRowHeaderDataProvider);
ILayer rowHeaderLayer = new RowHeaderLayer(
rowHeaderDataLayer,
bodyLayerStack.getViewportLayer(),
bodyLayerStack.getSelectionLayer());
// create the corner layer stack
ILayer cornerLayer = new CornerLayer(new DataLayer(
new DefaultCornerDataProvider(
personColumnHeaderDataProvider,
personRowHeaderDataProvider)),
rowHeaderLayer,
columnHeaderLayer);
// create the grid layer composed with the prior created layer stacks
GridLayer gridLayer = new GridLayer(
bodyLayerStack,
columnHeaderLayer,
rowHeaderLayer,
cornerLayer);
final NatTable natTable = new NatTable(gridPanel, gridLayer, false);
natTable.setConfigRegistry(configRegistry);
natTable.addConfiguration(new DefaultNatTableStyleConfiguration());
natTable.addConfiguration(new HeaderMenuConfiguration(natTable));
natTable.addConfiguration(new SingleClickSortConfiguration());
natTable.addConfiguration(new AbstractRegistryConfiguration() {
@Override
public void configureRegistry(IConfigRegistry configRegistry) {
configRegistry.registerConfigAttribute(
CellConfigAttributes.CELL_PAINTER,
new CheckBoxPainter(),
DisplayMode.NORMAL,
"MARRIED");
configRegistry.registerConfigAttribute(
CellConfigAttributes.DISPLAY_CONVERTER,
new DefaultDateDisplayConverter("yyyy-MM-dd"),
DisplayMode.NORMAL,
"DATE");
}
});
natTable.addConfiguration(new AbstractUiBindingConfiguration() {
private final Menu bodyMenu = new PopupMenuBuilder(natTable)
.withMenuItemProvider(new IMenuItemProvider() {
@Override
public void addMenuItem(NatTable natTable, Menu popupMenu) {
MenuItem deleteRow = new MenuItem(popupMenu, SWT.PUSH);
deleteRow.setText("Insert below");
deleteRow.setEnabled(true);
deleteRow.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
int rowPosition = MenuItemProviders.getNatEventData(event).getRowPosition();
natTable.doCommand(new InsertRowCommand<>(bodyDataLayer, rowPosition, PersonService.getPersons(1).get(0)));
}
});
}
})
.withMenuItemProvider(new IMenuItemProvider() {
@Override
public void addMenuItem(NatTable natTable, Menu popupMenu) {
MenuItem deleteRow = new MenuItem(popupMenu, SWT.PUSH);
deleteRow.setText("Delete");
deleteRow.setEnabled(true);
deleteRow.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
int rowPosition = MenuItemProviders.getNatEventData(event).getRowPosition();
natTable.doCommand(new DeleteRowCommand(natTable, rowPosition));
}
});
}
})
.build();
@Override
public void configureUiBindings(UiBindingRegistry uiBindingRegistry) {
uiBindingRegistry.registerMouseDownBinding(
new MouseEventMatcher(
SWT.NONE,
GridRegion.BODY,
MouseEventMatcher.RIGHT_BUTTON),
new PopupMenuAction(this.bodyMenu) {
@Override
public void run(NatTable natTable, MouseEvent event) {
int columnPosition = natTable.getColumnPositionByX(event.x);
int rowPosition = natTable.getRowPositionByY(event.y);
if (!bodyLayerStack.getSelectionLayer().isRowPositionFullySelected(rowPosition)) {
natTable.doCommand(
new SelectRowsCommand(
natTable,
columnPosition,
rowPosition,
false,
false));
}
super.run(natTable, event);
}
});
}
});
natTable.configure();
GridDataFactory.fillDefaults().grab(true, true).applyTo(natTable);
return panel;
}
/**
* Command to insert a row.
*/
class InsertRowCommand<T> extends AbstractRowCommand {
private final T object;
public InsertRowCommand(ILayer layer, int rowPosition, T object) {
super(layer, rowPosition);
this.object = object;
}
protected InsertRowCommand(InsertRowCommand<T> command) {
super(command);
this.object = command.object;
}
@Override
public ILayerCommand cloneCommand() {
return new InsertRowCommand<>(this);
}
public T getObject() {
return this.object;
}
}
/**
* The command handler for inserting a row.
*
* @param <T>
*/
@SuppressWarnings("rawtypes")
class InsertRowCommandHandler<T> implements ILayerCommandHandler<InsertRowCommand> {
private List<T> bodyData;
public InsertRowCommandHandler(List<T> bodyData) {
this.bodyData = bodyData;
}
@Override
public Class<InsertRowCommand> getCommandClass() {
return InsertRowCommand.class;
}
@SuppressWarnings("unchecked")
@Override
public boolean doCommand(ILayer targetLayer, InsertRowCommand command) {
// convert the transported position to the target layer
if (command.convertToTargetLayer(targetLayer)) {
// remove the element
this.bodyData.add(command.getRowPosition(), (T) command.getObject());
// fire the event to refresh
targetLayer.fireLayerEvent(new RowInsertEvent(targetLayer, command.getRowPosition()));
return true;
}
return false;
}
}
/**
* Command to delete a row.
*/
class DeleteRowCommand extends AbstractRowCommand {
public DeleteRowCommand(ILayer layer, int rowPosition) {
super(layer, rowPosition);
}
protected DeleteRowCommand(DeleteRowCommand command) {
super(command);
}
@Override
public ILayerCommand cloneCommand() {
return new DeleteRowCommand(this);
}
}
/**
* The command handler for deleting a row.
*
* @param <T>
*/
class DeleteRowCommandHandler<T> implements ILayerCommandHandler<DeleteRowCommand> {
private List<T> bodyData;
public DeleteRowCommandHandler(List<T> bodyData) {
this.bodyData = bodyData;
}
@Override
public Class<DeleteRowCommand> getCommandClass() {
return DeleteRowCommand.class;
}
@Override
public boolean doCommand(ILayer targetLayer, DeleteRowCommand command) {
// convert the transported position to the target layer
if (command.convertToTargetLayer(targetLayer)) {
// remove the element
this.bodyData.remove(command.getRowPosition());
// fire the event to refresh
targetLayer.fireLayerEvent(new RowDeleteEvent(targetLayer, command.getRowPosition()));
return true;
}
return false;
}
}
}