blob: c11b7d3b510084477f4dc728397e8b1b0c0327f3 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012 Original authors 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:
* Original authors and others - initial API and implementation
******************************************************************************/
package org.eclipse.nebula.widgets.nattable.extension.builder;
import static org.eclipse.nebula.widgets.nattable.util.ObjectUtils.isNotNull;
import java.util.Comparator;
import org.eclipse.nebula.widgets.nattable.NatTable;
import org.eclipse.nebula.widgets.nattable.columnCategories.ChooseColumnsFromCategoriesCommandHandler;
import org.eclipse.nebula.widgets.nattable.columnChooser.command.DisplayColumnChooserCommandHandler;
import org.eclipse.nebula.widgets.nattable.config.CellConfigAttributes;
import org.eclipse.nebula.widgets.nattable.config.ConfigRegistry;
import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry;
import org.eclipse.nebula.widgets.nattable.config.NullComparator;
import org.eclipse.nebula.widgets.nattable.data.IColumnPropertyAccessor;
import org.eclipse.nebula.widgets.nattable.data.IRowIdAccessor;
import org.eclipse.nebula.widgets.nattable.data.convert.DefaultBooleanDisplayConverter;
import org.eclipse.nebula.widgets.nattable.edit.EditConfigAttributes;
import org.eclipse.nebula.widgets.nattable.edit.editor.TextCellEditor;
import org.eclipse.nebula.widgets.nattable.extension.builder.configuration.GridLayerConfiguration;
import org.eclipse.nebula.widgets.nattable.extension.builder.configuration.RightClickColumnHeaderMenuConfiguration;
import org.eclipse.nebula.widgets.nattable.extension.builder.configuration.RowSelectionUIBindings;
import org.eclipse.nebula.widgets.nattable.extension.builder.configuration.SelectionStyleConfiguration;
import org.eclipse.nebula.widgets.nattable.extension.builder.configuration.TableStyleConfiguration;
import org.eclipse.nebula.widgets.nattable.extension.builder.layers.BodyLayerStack;
import org.eclipse.nebula.widgets.nattable.extension.builder.layers.ColumnHeaderLayerStack;
import org.eclipse.nebula.widgets.nattable.extension.builder.layers.CornerLayerStack;
import org.eclipse.nebula.widgets.nattable.extension.builder.layers.RowHeaderLayerStack;
import org.eclipse.nebula.widgets.nattable.extension.builder.model.ColumnStyle;
import org.eclipse.nebula.widgets.nattable.extension.builder.model.IEditor;
import org.eclipse.nebula.widgets.nattable.extension.builder.model.TableColumn;
import org.eclipse.nebula.widgets.nattable.extension.builder.model.TableModel;
import org.eclipse.nebula.widgets.nattable.extension.builder.model.TableRow;
import org.eclipse.nebula.widgets.nattable.extension.builder.model.TableStyle;
import org.eclipse.nebula.widgets.nattable.extension.builder.util.ColumnAccessor;
import org.eclipse.nebula.widgets.nattable.extension.builder.util.ColumnCategoriesModelAssembler;
import org.eclipse.nebula.widgets.nattable.extension.builder.util.ColumnGroupModelAssembler;
import org.eclipse.nebula.widgets.nattable.filterrow.FilterRowDataLayer;
import org.eclipse.nebula.widgets.nattable.filterrow.config.FilterRowConfigAttributes;
import org.eclipse.nebula.widgets.nattable.grid.GridRegion;
import org.eclipse.nebula.widgets.nattable.grid.layer.GridLayer;
import org.eclipse.nebula.widgets.nattable.layer.cell.CellOverrideLabelAccumulator;
import org.eclipse.nebula.widgets.nattable.layer.cell.ColumnOverrideLabelAccumulator;
import org.eclipse.nebula.widgets.nattable.painter.cell.CheckBoxPainter;
import org.eclipse.nebula.widgets.nattable.painter.cell.ComboBoxPainter;
import org.eclipse.nebula.widgets.nattable.selection.RowSelectionModel;
import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer;
import org.eclipse.nebula.widgets.nattable.selection.config.DefaultSelectionLayerConfiguration;
import org.eclipse.nebula.widgets.nattable.selection.config.RowOnlySelectionConfiguration;
import org.eclipse.nebula.widgets.nattable.sort.SortConfigAttributes;
import org.eclipse.nebula.widgets.nattable.style.CellStyleAttributes;
import org.eclipse.nebula.widgets.nattable.style.DisplayMode;
import org.eclipse.nebula.widgets.nattable.style.Style;
import org.eclipse.nebula.widgets.nattable.style.editor.command.DisplayColumnStyleEditorCommandHandler;
import org.eclipse.nebula.widgets.nattable.ui.menu.DebugMenuConfiguration;
import org.eclipse.nebula.widgets.nattable.util.ObjectUtils;
import org.eclipse.swt.widgets.Composite;
import ca.odell.glazedlists.EventList;
import ca.odell.glazedlists.FilterList;
import ca.odell.glazedlists.GlazedLists;
import ca.odell.glazedlists.SortedList;
/**
* Convenience class to configure the grid with the most commonly used features.
*
* @param <T>
* Type of the object in the underlying list
*/
public class NatTableBuilder<T extends TableRow> {
public static final String COLUMN_HEADER_COLUMN_LABEL_PREFIX = "columnHeaderColumnLabel_";
public static final String BODY_COLUMN_LABEL_PREFIX = "bodyColumnLabel_";
private final TableStyle tableStyle;
private final TableModel tableModel;
private final TableColumn[] columns;
private final IRowIdAccessor<T> rowIdAccessor;
private final Composite parent;
private NatTable natTable;
private final EventList<T> eventList;
private FilterList<T> filterList;
private ColumnOverrideLabelAccumulator columnLabelAccumulator;
private IConfigRegistry configRegistry;
// Layers
private BodyLayerStack<T> bodyLayer;
private ColumnHeaderLayerStack<T> columnHeaderLayer;
private RowHeaderLayerStack<T> rowHeaderLayer;
private CornerLayerStack<T> cornerLayer;
private GridLayer gridLayer;
public NatTableBuilder(Composite parent, TableModel tableModel,
EventList<T> eventList, IRowIdAccessor<T> rowIdAccessor) {
this.parent = parent;
this.tableModel = tableModel;
this.rowIdAccessor = rowIdAccessor;
this.tableStyle = tableModel.tableStyle;
this.columns = tableModel.columnProperties;
this.eventList = GlazedLists.threadSafeList(eventList);
}
public NatTable setupLayerStacks() {
IColumnPropertyAccessor<T> columnAccessor = new ColumnAccessor<T>(
columns);
configRegistry = new ConfigRegistry();
SortedList<T> sortedRows = new SortedList<T>(eventList, null);
filterList = new FilterList<T>(sortedRows);
setUpColumnGroupModel();
setUpColumnCategoriesModel();
// Body
bodyLayer = new BodyLayerStack<T>(tableModel, filterList);
// Column header
columnHeaderLayer = new ColumnHeaderLayerStack<T>(sortedRows,
filterList, tableModel, bodyLayer, columnAccessor,
configRegistry);
// Row header
rowHeaderLayer = new RowHeaderLayerStack<T>(bodyLayer, tableModel);
// Corner
cornerLayer = new CornerLayerStack<T>(columnHeaderLayer, rowHeaderLayer);
// Grid
gridLayer = new GridLayer(bodyLayer, columnHeaderLayer, rowHeaderLayer,
cornerLayer, false);
natTable = new NatTable(parent, gridLayer, false);
natTable.setConfigRegistry(configRegistry);
natTable.setBackground(tableStyle.tableBgColor);
// Configuration
natTable.addConfiguration(new TableStyleConfiguration(tableStyle));
configureColumnProperties();
configureSorting();
configureEditing();
configureFiltering();
configureColumnChooser();
configureCategoriesBasedColumnChooser();
configureColumnStyleCustomization();
configureGridLayer();
configureSelectionStyle();
configureColumnHeaderRightClickMenu();
return natTable;
}
private void setUpColumnGroupModel() {
if (tableModel.enableColumnGroups) {
tableModel.columnGroupModel = ColumnGroupModelAssembler
.setupColumnGroups(tableModel.columnProperties);
}
}
private void setUpColumnCategoriesModel() {
tableModel.columnCategoriesModel = ColumnCategoriesModelAssembler
.setupColumnCategories(tableModel.columnProperties);
}
public NatTable build() {
natTable.configure();
return natTable;
}
protected void configureColumnStyleCustomization() {
if (!tableModel.enableColumnStyleCustomization) {
return;
}
// Register a command handler for the StyleEditorDialog
DisplayColumnStyleEditorCommandHandler styleChooserCommandHandler = new DisplayColumnStyleEditorCommandHandler(
bodyLayer.getSelectionLayer(), columnLabelAccumulator,
configRegistry);
bodyLayer.registerCommandHandler(styleChooserCommandHandler);
// Register the style editor as persistable
// This will persist the style applied to the columns when
// NatTable#saveState is invoked
bodyLayer.registerPersistable(styleChooserCommandHandler);
bodyLayer.registerPersistable(columnLabelAccumulator);
}
protected void configureColumnHeaderRightClickMenu() {
if (tableModel.enableColumnHeaderRightClickMenu) {
natTable.addConfiguration(new RightClickColumnHeaderMenuConfiguration(
natTable, tableModel));
}
natTable.addConfiguration(new DebugMenuConfiguration(natTable));
}
/**
* Set up selection behavior. Select cells vs select rows.
*/
protected void configureSelectionStyle() {
SelectionLayer selectionLayer = bodyLayer.getSelectionLayer();
if (tableModel.enableFullRowSelection) {
selectionLayer
.addConfiguration(new RowOnlySelectionConfiguration<T>());
natTable.addConfiguration(new RowSelectionUIBindings());
selectionLayer
.setSelectionModel(new RowSelectionModel<T>(selectionLayer,
bodyLayer.getDataProvider(), rowIdAccessor));
} else {
selectionLayer
.addConfiguration(new DefaultSelectionLayerConfiguration());
}
natTable.addConfiguration(new SelectionStyleConfiguration(tableStyle));
}
/**
* Configure the Alternate row color
*/
protected void configureGridLayer() {
gridLayer.addConfiguration(new GridLayerConfiguration(gridLayer,
tableStyle));
}
protected void configureColumnChooser() {
bodyLayer
.registerCommandHandler(new DisplayColumnChooserCommandHandler(
bodyLayer.getSelectionLayer(), bodyLayer
.getColumnHideShowLayer(), columnHeaderLayer
.getColumnHeaderLayer(), columnHeaderLayer
.getDataLayer(), columnHeaderLayer
.getColumnGroupHeaderLayer(),
tableModel.columnGroupModel));
}
protected void configureCategoriesBasedColumnChooser() {
if (ObjectUtils.isNull(tableModel.columnCategoriesModel)) {
return;
}
bodyLayer
.registerCommandHandler(new ChooseColumnsFromCategoriesCommandHandler(
bodyLayer.getColumnHideShowLayer(), columnHeaderLayer
.getColumnHeaderLayer(), columnHeaderLayer
.getDataLayer(),
tableModel.columnCategoriesModel));
}
protected void configureColumnProperties() {
columnLabelAccumulator = new ColumnOverrideLabelAccumulator(
bodyLayer.getDataLayer());
bodyLayer.addLabelAccumulator(columnLabelAccumulator);
for (int colIndex = 0; colIndex < columns.length; colIndex++) {
Integer width = columns[colIndex].width;
if (isNotNull(width)) {
bodyLayer.getDataLayer().setColumnWidthByPosition(colIndex,
width);
}
// Register a label on each column
String columnLabel = BODY_COLUMN_LABEL_PREFIX + colIndex;
columnLabelAccumulator.registerColumnOverrides(colIndex,
columnLabel);
// Add the display converter/formatter to the column
configRegistry.registerConfigAttribute(
CellConfigAttributes.DISPLAY_CONVERTER,
columns[colIndex].displayConverter, DisplayMode.NORMAL,
columnLabel);
// Add column visual style
Style style = new Style();
ColumnStyle columnStyle = columns[colIndex].style;
if (ObjectUtils.isNotNull(columnStyle)) {
style.setAttributeValue(CellStyleAttributes.BACKGROUND_COLOR,
columnStyle.bgColor);
style.setAttributeValue(CellStyleAttributes.FOREGROUND_COLOR,
columnStyle.fgColor);
style.setAttributeValue(
CellStyleAttributes.HORIZONTAL_ALIGNMENT,
columnStyle.hAlign);
style.setAttributeValue(CellStyleAttributes.VERTICAL_ALIGNMENT,
columnStyle.vAlign);
style.setAttributeValue(CellStyleAttributes.FONT,
columnStyle.font);
style.setAttributeValue(CellStyleAttributes.BORDER_STYLE,
columnStyle.borderStyle);
configRegistry.registerConfigAttribute(
CellConfigAttributes.CELL_STYLE, style,
DisplayMode.NORMAL, columnLabel);
}
}
}
protected void configureSorting() {
ColumnOverrideLabelAccumulator columnHeaderLabelAccumulator = new ColumnOverrideLabelAccumulator(
columnHeaderLayer.getDataLayer());
columnHeaderLayer.addLabelAccumulator(columnHeaderLabelAccumulator);
for (int colIndex = 0; colIndex < columns.length; colIndex++) {
String columnHeaderLabel = COLUMN_HEADER_COLUMN_LABEL_PREFIX
+ colIndex;
// Register an accumulator on the Column Header layer (since it
// triggers sort)
columnHeaderLabelAccumulator.registerColumnOverrides(colIndex,
columnHeaderLabel);
if (columns[colIndex].isSortable) {
Comparator<?> comparator = columns[colIndex].comparator;
configRegistry.registerConfigAttribute(
SortConfigAttributes.SORT_COMPARATOR, comparator,
DisplayMode.NORMAL, columnHeaderLabel);
} else {
configRegistry.registerConfigAttribute(
SortConfigAttributes.SORT_COMPARATOR,
new NullComparator(), DisplayMode.NORMAL,
columnHeaderLabel);
}
}
}
protected void configureFiltering() {
if (!tableModel.enableFilterRow) {
return;
}
for (int colIndex = 0; colIndex < columns.length; colIndex++) {
String filterRowLabel = FilterRowDataLayer.FILTER_ROW_COLUMN_LABEL_PREFIX
+ colIndex;
TableColumn column = columns[colIndex];
configRegistry.registerConfigAttribute(
FilterRowConfigAttributes.FILTER_COMPARATOR,
column.comparator, DisplayMode.NORMAL, filterRowLabel);
configRegistry.registerConfigAttribute(
FilterRowConfigAttributes.FILTER_DISPLAY_CONVERTER,
column.filterRowDisplayConverter, DisplayMode.NORMAL,
filterRowLabel);
configRegistry.registerConfigAttribute(
EditConfigAttributes.CELL_EDITOR,
column.filterRowEditor.getCellEditor(), DisplayMode.NORMAL,
filterRowLabel);
}
// Filter row style
Style style = new Style();
style.setAttributeValue(CellStyleAttributes.BACKGROUND_COLOR,
tableStyle.filterRowBGColor);
style.setAttributeValue(CellStyleAttributes.FOREGROUND_COLOR,
tableStyle.filterRowFGColor);
style.setAttributeValue(CellStyleAttributes.FONT,
tableStyle.filterRowFont);
configRegistry.registerConfigAttribute(CellConfigAttributes.CELL_STYLE,
style, DisplayMode.NORMAL, GridRegion.FILTER_ROW);
}
protected void configureEditing() {
for (int colIndex = 0; colIndex < columns.length; colIndex++) {
TableColumn column = columns[colIndex];
if (column.isEditable) {
IEditor editor = column.editor;
// Column label has been registered already
String columnLabel = BODY_COLUMN_LABEL_PREFIX + colIndex;
configRegistry
.registerConfigAttribute(
EditConfigAttributes.CELL_EDITABLE_RULE,
editor.getEditableRule(), DisplayMode.EDIT,
columnLabel);
configRegistry.registerConfigAttribute(
EditConfigAttributes.DATA_VALIDATOR,
editor.getValidator(), DisplayMode.EDIT, columnLabel);
switch (editor.getType()) {
case CHECKBOX:
configRegistry.registerConfigAttribute(
CellConfigAttributes.CELL_PAINTER,
new CheckBoxPainter(), DisplayMode.NORMAL,
columnLabel);
configRegistry.registerConfigAttribute(
CellConfigAttributes.DISPLAY_CONVERTER,
new DefaultBooleanDisplayConverter(),
DisplayMode.NORMAL, columnLabel);
configRegistry.registerConfigAttribute(
EditConfigAttributes.CELL_EDITOR,
editor.getCellEditor(), DisplayMode.NORMAL,
columnLabel);
break;
case COMBO:
configRegistry.registerConfigAttribute(
CellConfigAttributes.CELL_PAINTER,
new ComboBoxPainter(), DisplayMode.NORMAL,
columnLabel);
configRegistry.registerConfigAttribute(
EditConfigAttributes.CELL_EDITOR,
editor.getCellEditor(), DisplayMode.NORMAL,
columnLabel);
configRegistry.registerConfigAttribute(
EditConfigAttributes.CELL_EDITOR,
editor.getCellEditor(), DisplayMode.EDIT,
columnLabel);
break;
case TEXT:
configRegistry.registerConfigAttribute(
EditConfigAttributes.CELL_EDITOR,
new TextCellEditor());
break;
default:
break;
}
}
}
}
// Accessors for layers
public BodyLayerStack<T> getBodyLayerStack() {
return bodyLayer;
}
public ColumnHeaderLayerStack<T> getColumnHeaderLayerStack() {
return columnHeaderLayer;
}
public RowHeaderLayerStack<T> getRowHeaderLayer() {
return rowHeaderLayer;
}
public CornerLayerStack<T> getCornerLayer() {
return cornerLayer;
}
public GridLayer getGridLayer() {
return gridLayer;
}
public TableModel getTableModel() {
return tableModel;
}
public EventList<T> getEventList() {
return eventList;
}
public FilterList<T> getFilterList() {
return filterList;
}
public NatTable getNatTable() {
return natTable;
}
public void addCellLabelsToBody(
CellOverrideLabelAccumulator<? extends TableRow> myAccumulator) {
bodyLayer.addLabelAccumulator(myAccumulator);
}
}