====== NatTable ======
A table is created as following:
- create a BodyLayerStack. Each layer is based on previous.
- create a RowHeaderLayer - it will provide rownames
- create a ColumnNameLayer - it will provide columnnames
- create a CornerLayer - to add some functionality to the left, upper table corner
- assemble all layers in one GridLayer
The functionality is contributed in BodyLayerStack.
{{http://www.eclipse.org/nattable/images/NatTable_Architecture.png?400}}
{{http://www.eclipse.org/nattable/images/NatTable_Commands_Events.png?400}}
{{http://www.eclipse.org/nattable/images/NatTableSystemDiagram.png?400}}
=====FallPits=====
* Layers are created like SWT Widgets - one is part of another. When creating the Gridlayer - use the bottom layer.
* When creating the Column / row layer - use the bottom Layer either asf
// 1. Use the dataProvider, which is the DataSource
dataLayer = new DataLayer(bodyDataProvider);
// 2.
ColumnReorderLayer columnReorderLayer = new ColumnReorderLayer(dataLayer);
// 3. disables some columns
ColumnHideShowLayer columnHideShowLayer = new ColumnHideShowLayer(dataLayer);
// 4. can handle selection
SelectionLayer selectionLayer = new SelectionLayer(dataLayer);
// 5. draw Scrollbars
ViewportLayer viewportLayer = new ViewportLayer(selectionLayer);
viewportLayer.setRegionName(GridRegion.BODY); // set t
// column names
// DataLayer dataLayerColHeader = new DataLayer(this.columnDataProvider);
// REFLECTIVE column provider
DataLayer dataLayerColHeader = new DataLayer(columnDataProviderExt);
ColumnHeaderLayer columnHeaderLayer = new ColumnHeaderLayer(dataLayerColHeader, viewportLayer, selectionLayer);
// row names.
// DEMO of encapsulating layers and configs in an "AbstractLayerTransform"
RowHeaderLayerStack rowHeaderLayer = new RowHeaderLayerStack(this.rowDatadataProvider, viewportLayer,
* a table can oly have ONE ColumnOverrideLabelAccumulator - setConfigLabelAccumulator() allways overrides the old one!
* Columns and rows in a layer are referenced either by position or index:
The **position** of a column/row in a layer corresponds to the **physical location of the column/row** in the current layer. Positions always start from 0 and increase sequentially.
**Positions reorder Indexes.** \\
The **index of a column/row** in a layer corresponds to the location of the column/row in the lowest level layer in the layer stack. Usually the lowest layer in the layer stack will be the DataLayer. Indexes are not necessarily ordered, and in some cases may not even be unique within a layer.
They correspond to the numbers within data providers.
These concepts are illustrated by the following example:
ColumnHideShowLayer C
0 1 2 3 4 <- column positions
1 0 3 4 5 <- column indexes
ColumnReorderLayer B
0 1 2 3 4 5 <- column positions
2 1 0 3 4 5 <- column indexes
DataLayer A
0 1 2 3 4 5 <- column positions
0 1 2 3 4 5 <- column indexes
Switching between Position and INdex is possible via the nattable
// position -> index
natTable.getColumnIndexByPosition(columnPosition)
natTable.getRowIndexByPosition(rowPosition)
===== Inserting own Data =====
To insert own data into the table - implement IDataProvider.
IDataProvider asks for Data by providing the
- **row**
- **column**
Usualy own Data are stored in a Collection of own Objects.
So the **row**s are mapped to the collection cells, and the right object is retrieved, which should be mapped to cells.
Now somehow the own-object's properties should be mapped to columns:
==Access own DataObject by the Reflection.==
There is a reflective way of accessing the objects, by using ReflectiveColumnPropertyAccessor.
It finds the getter methods on its own, if it gets a list of attributes, to display.
//map the labels to attributes names
IDataProvider dataProvider = new ListDataProvider(List ownObjectList, new ReflectiveColumnPropertyAccessor(propertyNames));
==== Concepts ====
^Subject ^ Describtion^
|IConfigRegistry configRegistry| An object, that is registered to **NatTables**. This Object is passed around and collects the Table Configurations from all Layers. \\ To register the data to a configRegistry use the CellConfigAttributes: \\
configRegistry.registerConfigAttribute(CellConfigAttributes.CELL_PAINTER, new CheckBoxPainter(), DisplayMode.NORMAL, CHECK_BOX_CONFIG_LABEL);
configRegistry.registerConfigAttribute(EditConfigAttributes.CELL_EDITOR, new CheckBoxCellEditor(), DisplayMode.NORMAL, CHECK_BOX_EDITOR_CONFIG_LABEL);
|
|IConfiguration | An object, that is registered to **ILayers**. is is asked to add Configurations like Events, Style etc. to the IConfigRegistry |
|AggregateConfiguration | An IConfiguration that stores many IConfiguration objects. Used to put many Configurations E.g. for Edit, head, print, styling etc. in 1 object. Use addConfiguration() in constructor, when subclass this class. |
|Labels| Labels are registered to **Cells, Columns, Rows**. They allow to map the Configurations from ConfigRegistry to cells, columns, rows.
//associate cellStyle with Label GridRegion.ROW_HEADER
Style cellStyle = new Style();
cellStyle.setAttributeValue(CellStyleAttributes.BACKGROUND_COLOR, bgColor);
cellStyle.setAttributeValue(CellStyleAttributes.FOREGROUND_COLOR, fgColor);
cellStyle.setAttributeValue(CellStyleAttributes.GRADIENT_BACKGROUND_COLOR, gradientBgColor);
cellStyle.setAttributeValue(CellStyleAttributes.GRADIENT_FOREGROUND_COLOR, gradientFgColor);
cellStyle.setAttributeValue(CellStyleAttributes.HORIZONTAL_ALIGNMENT, hAlign);
cellStyle.setAttributeValue(CellStyleAttributes.VERTICAL_ALIGNMENT, vAlign);
cellStyle.setAttributeValue(CellStyleAttributes.BORDER_STYLE, borderStyle);
cellStyle.setAttributeValue(CellStyleAttributes.FONT, font);
configRegistry.registerConfigAttribute(CellConfigAttributes.CELL_STYLE, cellStyle, DisplayMode.NORMAL, GridRegion.ROW_HEADER);
|
| UiBindingRegistry | An object, that is registered to **NatTables**. This Object is passed around, like IConfigRegistry and collects the Mouse events, and other user actions. \\ To register the data to a configRegistry use the Attributes: \\
uiBindingRegistry.registerFirstSingleClickBinding(
new CellPainterMouseEventMatcher(GridRegion.COLUMN_HEADER, MouseEventMatcher.LEFT_BUTTON, columnHeaderCheckBoxPainter),
new ToggleCheckBoxColumnAction(columnHeaderCheckBoxPainter, bodyDataLayer)
);
//enables row resizing
public void configureUiBindings(UiBindingRegistry uiBindingRegistry) {
// Mouse move - Show resize cursor
uiBindingRegistry.registerFirstMouseMoveBinding(new RowResizeEventMatcher(SWT.NONE, 0), new RowResizeCursorAction());
uiBindingRegistry.registerMouseMoveBinding(new MouseEventMatcher(), new ClearCursorAction());
// Row resize
uiBindingRegistry.registerFirstMouseDragMode(new RowResizeEventMatcher(SWT.NONE, 1), new RowResizeDragMode());
uiBindingRegistry.registerDoubleClickBinding(new RowResizeEventMatcher(SWT.NONE, 1), new AutoResizeRowAction());
uiBindingRegistry.registerSingleClickBinding(new RowResizeEventMatcher(SWT.NONE, 1), new NoOpMouseAction());
}
|
CellStyleAttributes - Objects encapsulate the Labels, which are used to register functionality via labels, or otherwise. That objects have a generic parameter and contribute a generic type, so that only objects of the right type may be regitered with the given CellStyleAttribute.
^ CellAttributes collection^ What maay be registered?^
|CellConfigAttributes |
* CELL_PAINTER
* CELL_STYLE
* DISPLAY_CONVERTER
* EXPORT_FORMATTER
configRegistry.registerConfigAttribute(CellConfigAttributes.CELL_PAINTER, new CheckBoxPainter(), DisplayMode.NORMAL, CHECK_BOX_CONFIG_LABEL);
|
|EditConfigAttributes|
* CELL_EDITABLE_RULE
* CELL_EDITOR
* DATA_VALIDATOR
* CONVERSION_ERROR_HANDLER
* VALIDATION_ERROR_HANDLER
* VALIDATION_ERROR_STYLE
configRegistry.registerConfigAttribute(EditConfigAttributes.CELL_EDITOR, new CheckBoxCellEditor(), DisplayMode.NORMAL, CHECK_BOX_EDITOR_CONFIG_LABEL);
|
|CellConfigAttributes|
* BACKGROUND_COLOR
* FOREGROUND_COLOR
* GRADIENT_BACKGROUND_COLOR
* GRADIENT_FOREGROUND_COLOR
* HORIZONTAL_ALIGNMENT
* VERTICAL_ALIGNMENT
* FONT
* IMAGE
* BORDER_STYLE
* PASSWORD_ECHO_CHAR
IStyle cellStyle = new Style();
cellStyle.setAttributeValue(CellStyleAttributes.BACKGROUND_COLOR, GUIHelper.COLOR_RED);
configRegistry.registerConfigAttribute(CellConfigAttributes.CELL_STYLE, getStyle(), CHECK_BOX_CONFIG_LABEL);
|
===== useful API =====
^API ^ Describtion^
|ColumnResizeCommand | Can resize a column.
ColumnResizeCommand columnCommand = new ColumnResizeCommand(gridLayer, 3, 300);
natTable.doCommand(columnCommand);
|
|[[http://nattable.mecha1.com/javadoc/latest/core/apidocs/net/sourceforge/nattable/data/convert/IDisplayConverter.html|IDisplayConverter]]| Can convert one kind of data into another, e.g. technical date into dd,mm,yy format.
private IConfigRegistry configRegistry = natTable.getConfigRegistry();
configRegistry.registerConfigAttribute(CellConfigAttributes.DISPLAY_CONVERTER,
new DefaultDateDisplayConverter(), DisplayMode.NORMAL, getColumnLabel(columnNumber));
|
|[[http://nattable.mecha1.com/javadoc/latest/core/apidocs/net/sourceforge/nattable/layer/CompositeLayer.html|CompositeLayer]]| Can display display two independent table parts near each other. E.g. a Table and near it a vertically dependent table. Used to paint Headers.
ILayer createDependentCompositeLayer(ILayer verticallyDependFrom){
IUniqueIndexLayer baseLayer = getDependedLayer();
CompositeLayer compositeLayer = new CompositeLayer(2, 1);
DimensionallyDependentLayer testLayer = new DimensionallyDependentLayer(baseLayer, baseLayer, verticallyDependFrom);
compositeLayer.setChildLayer("mainContent", verticallyDependFrom, 1, 0);
compositeLayer.setChildLayer("testLayer", testLayer, 0, 0); //$NON-NLS-1$
return compositeLayer;
}
IUniqueIndexLayer getDependedLayer(){
return new DataLayer(new IDataProvider() {
@Override
public void setDataValue(int columnIndex, int rowIndex, Object newValue) {
}
@Override
public int getRowCount() {
// Is never used, because this layer is used to create a vertically depending layer.
// The rowCount is set by the layer, from which the current layer vertically depends.
return 1000000;
}
@Override
public Object getDataValue(int columnIndex, int rowIndex) {
return "depend";
}
@Override
public int getColumnCount() {
return 1;
}
});
}
|
|[[http://nattable.mecha1.com/javadoc/latest/core/apidocs/net/sourceforge/nattable/grid/layer/DimensionallyDependentLayer.html|DimensionallyDependentLayer]]| Can make make the cell amount equal to the cell number of the layer it depends from. Adopts the cell Size too. Adopts the number of Cells too.
IUniqueIndexLayer baseLayer = getDependedLayer();
DimensionallyDependentLayer testLayer = new DimensionallyDependentLayer(baseLayer, baseLayer, verticallyDependFrom);
IUniqueIndexLayer getDependedLayer(){
return new DataLayer(new IDataProvider() {
@Override
public void setDataValue(int columnIndex, int rowIndex, Object newValue) {
}
@Override
public int getRowCount() {
// Is never used, because this layer is used to create a vertically depending layer.
// The rowCount is set by the layer, from which the current layer vertically depends.
return 1000000;
}
@Override
public Object getDataValue(int columnIndex, int rowIndex) {
return "depend";
}
@Override
public int getColumnCount() {
return 1;
}
});
}
|
|[[http://nattable.mecha1.com/javadoc/latest/core/apidocs/net/sourceforge/nattable/layer/AbstractLayerTransform.html|AbstractLayerTransform]]| Can be used to extract a group of layers to an object .
private class RowHeaderLayerStack extends AbstractLayerTransform {
public RowHeaderLayerStack(IDataProvider dataProvider, ILayer bodyDataLayer, SelectionLayer selectionLayer) {
DataLayer dataLayer = new DataLayer(dataProvider, 50, 20);
RowHeaderLayer rowHeaderLayer = new RowHeaderLayer(dataLayer, bodyDataLayer, selectionLayer);
setUnderlyingLayer(rowHeaderLayer);
}
}
|
|[[http://download.eclipse.org/nattable/releases/1.0.0/apidocs/org/eclipse/nebula/widgets/nattable/edit/command/EditCellCommand.html|EditCellCommand]] [[http://download.eclipse.org/nattable/releases/1.0.0/apidocs/org/eclipse/nebula/widgets/nattable/edit/command/EditCellCommandHandler.html|EditCellCommandHandler]]|
Commands are passed through all layers top down.
Default commands are handled by handlers, many of them are owned by the GridLayer.
//Layers can execute commands and pass them to sublayers
Layer.doCommand(ILayerCommand command)
/*
/ EDITING HAPPENS AS FOLLOWING:
*/
//register an Editor to the cell's label
configRegistry.registerConfigAttribute(EditConfigAttributes.CELL_EDITOR, cellEditor,
DisplayMode.EDIT, configLabelForCell);
// make the cell, which we registered an editor for - editable
configRegistry.registerConfigAttribute(EditConfigAttributes.CELL_EDITABLE_RULE, IEditableRule.ALWAYS_EDITABLE, DisplayMode.EDIT, configLabelForCell);
//register a mouse event, which will trigger editing (here it is a the first doubleclick)
uiBindingRegistry.registerFirstDoubleClickBinding(new BodyCellEditorMouseEventMatcher(TextCellEditor.class), new MouseEditAction());
//FIRST DOUBLE CLICK occurs
//ask, whether the event with found editor matches requirements for editing: BodyCellEditorMouseEventMatcher.matches(...)
//if yes - trigger an EditCellCommand
//ask, EditCellCommandHandler in GridLayer to Handle the EditCellCommand
//pass editing to the registered editor in cell
|
|
natTable.getConfigLabelsByPosition(columnPosition, rowPosition)
natTable.getDataValueByPosition(columnPosition, rowPosition)
natTable.getColumnIndexByPosition(columnPosition)
natTable.getRowIndexByPosition(rowPosition) | Methodsavailable directly in nattable |
|[[http://nattable.mecha1.com|Classname]]| Comment.
|
===== Header Size =====
Header-Height depends on the TextPainter height. \\
Header-Width depends on body width. \\
See the diagram below. \\
{{http://i520.photobucket.com/albums/w327/schajtan/2014-03-20_17-05-41_zps5e89a084.png?600}}
/**
* The Column Resizing has to happen AFTER the Column was rendered. For that
* a Paintlistener is used, which will unregister itselfe.
*
* Details: http://www.eclipse.org/nattable/documentation.php?page=faq
*/
private void delayedColumnResize() {
natTable.addListener(SWT.Paint, new Listener() {
@Override
public void handleEvent(Event arg0) {
for (int i = 0; i < natTable.getPreferredColumnCount(); i++) {
InitializeAutoResizeColumnsCommand columnCommand = new InitializeAutoResizeColumnsCommand(
natTable, i, natTable.getConfigRegistry(),
new GCFactory(natTable));
natTable.doCommand(columnCommand);
}
natTable.removeListener(SWT.Paint, this);
}
});
}
private void addNormalModeStyling(IConfigRegistry configRegistry) {
Image bgImage = CommonResourceUtil.getImage(COLUMN_HEADER_BG_PATH);
// Painter of headers
// + Padding
// + make cell as high/wide as content
TextPainter txtPainter = new TextPainter(false, false,
Constants.TABLE_PADDING_COLUMNHEADER, true, true);
// Header BG
ICellPainter bgImagePainter = new BackgroundImagePainter(txtPainter,
bgImage, BG_COLOR);
SortableHeaderTextPainter sortableHeaderTextPainter = new SortableHeaderTextPainter(
bgImagePainter, false, true);
configRegistry.registerConfigAttribute(
CellConfigAttributes.CELL_PAINTER, sortableHeaderTextPainter,
DisplayMode.NORMAL, GridRegion.COLUMN_HEADER);
configRegistry.registerConfigAttribute(
CellConfigAttributes.CELL_PAINTER, sortableHeaderTextPainter,
DisplayMode.NORMAL, GridRegion.CORNER);
// the top filter row in the corner should have the same BG color
configRegistry.registerConfigAttribute(
CellConfigAttributes.CELL_PAINTER, sortableHeaderTextPainter,
DisplayMode.NORMAL, IdsNattable.LABEL_CORNER_ROW0);
}
===== Styling =====
The styling may happen via different mechanisms:
=== Style ===
The cellStyle may style cells or headers, since headers are cells too.
Style cellStyle = new Style();
BACKGROUND_COLOR
FOREGROUND_COLOR
GRADIENT_BACKGROUND_COLOR
GRADIENT_FOREGROUND_COLOR
HORIZONTAL_ALIGNMENT
VERTICAL_ALIGNMENT
FONT
IMAGE
BORDER_STYLE
PASSWORD_ECHO_CHAR
TEXT_DECORATION
The cellStyle is registered to different DisplayModes,
may become active when the cell is Selected, Edited or just viewed.
configRegistry.registerConfigAttribute(CellConfigAttributes.CELL_STYLE,
cellStyle, DisplayMode.NORMAL, GridRegion.COLUMN_HEADER);
configRegistry.registerConfigAttribute(CellConfigAttributes.CELL_STYLE,
cellStyle, DisplayMode.NORMAL, GridRegion.CORNER);
configRegistry.registerConfigAttribute(CellConfigAttributes.CELL_STYLE,
cellStyle, DisplayMode.NORMAL, GridRegion.ROW_HEADER);
=== Painter ===
The Painter may draw BG or forbid to draw bg. \\
When renderer forbids t odraw BG - no registered style is used:
// no wrap
// + DONT draw BG
// + Padding
// + make cell as high/wide as content & spacing
ICellPainter txtPainter = new TextPainter(false, false,
TABLE_PADDING_COLUMNHEADER, true);
// no wrap
// + DRAW BG
// + Padding
// + make cell as high/wide as content & spacing
ICellPainter txtPainter = new TextPainter(false, true,
TABLE_PADDING_COLUMNHEADER, true);
=== Style resolution mechanism ===
Which Style wins, if you register 2 different Styles to different Labels, which are assigned to the same cell?
== DisplayMode Priority ==
The order (and priority in which Labels are evaluated). Definde in **DefaultDisplayModeOrdering**:
|SELECT_HOVER, SELECT, HOVER, NORMAL|
All styles from the current mode up to NORMAL-DisplayMode-Labels registered styles are considered.
E.g.
* If current mode is SELECT - then the NatTable will consider all Styles for modes: SELECT, HOVER, NORMAL.
* It will omit the Styles, registerd for the mode SELECT_HOVER
== Label Priority ==
The mechanism is encapsulated inside:
package org.eclipse.nebula.widgets.nattable.style;
class CellStyleUtil{
...
public static IStyle getCellStyle(ILayerCell cell,
IConfigRegistry configRegistry) {
return new CellStyleProxy(configRegistry, cell.getDisplayMode(), cell.getConfigLabels().getLabels());
}
The important part is the
cell.getConfigLabels().getLabels()
which retrieves the labels in a special **order X**.
This order decides, which Style is chosen.
- The Class StyleProxy iterates all labels, in the given **order X**, when it is asked for a special **Style-Attribute A**. First label, for which there is an instance of **Style-Attribute A** in configRegistry - wins the race.
- if no **Style-Attribute A** for no cell labels, then there is a fallback to a none label request.
package org.eclipse.nebula.widgets.nattable.style;
class StyleProxy{
...
public T getAttributeValue(ConfigAttribute styleAttribute) {
...
for (String displayMode : displayModeOrdering
.getDisplayModeOrdering(this.targetDisplayMode)) {
for (String configLabel : this.configLabels) {
IStyle cellStyle = this.configRegistry.getSpecificConfigAttribute(
this.styleConfigAttribute, displayMode, configLabel);
if (cellStyle != null) {
styleAttributeValue = cellStyle
.getAttributeValue(styleAttribute);
if (styleAttributeValue != null) {
return styleAttributeValue;
}
}
}
// default
IStyle cellStyle = this.configRegistry.getSpecificConfigAttribute(
this.styleConfigAttribute, displayMode, null);
if (cellStyle != null) {
styleAttributeValue = cellStyle
.getAttributeValue(styleAttribute);
if (styleAttributeValue != null) {
return styleAttributeValue;
}
}
}
return null;
}
===== Sorting =====
Sorting is implemented via **ISortModel**. It is passed to the **SortHeaderLayer**
import org.eclipse.nebula.widgets.nattable.sort.ISortModel;
ISortModel tableSorter = new ISortModel{
...
}
public TableHeaderStack() {
// 0. datalayer. stores the headers of columns
dataLayerColHeader = new DataLayer(columnDataProvider);
// 1. column header layer. stores the headers
columnHeaderLayer = new ColumnHeaderLayer(dataLayerColHeader, bodyStack.viewportLayer,
bodyStack.selectionLayer);
// 2. sorting layer handles SortCommands. it is placed below the column header layer.
// it handles the SortCommands by manipulating the ISortModel
// it handles the SortCommands by adding sort labels to sorted columns
sortHeaderLayer = new SortHeaderLayer(columnHeaderLayer, tableSorter, false);
// create filterRow composite - the widget where filter text is entered
filterRowHeaderComposite = createFilterRow(sortHeaderLayer, columnDataProvider);
}
Via Configurations you can add some contextmenus to add sort functionality
/**
* Creates the {@link PopupMenuBuilder} for the column header menu with the menu
* items that should be added to the menu.
*
* @param natTable
* The NatTable where the menu should be attached.
* @return The {@link PopupMenuBuilder} that is used to build the column
* header menu.
*/
protected PopupMenuBuilder createColumnHeaderMenu(NatTable natTable) {
return new PopupMenuBuilder(natTable).withHideColumnMenuItem(Messages.MenuItemProviders_hideColumn)
.withShowAllColumnsMenuItem(Messages.MenuItemProviders_showAllColumns)
.withAutoResizeSelectedColumnsMenuItem(Messages.MenuItemProviders_autoResizeAllSelectedColumns)
.withClearAllFilters(Messages.MenuItemProviders_clearAllFilters)
.withMenuItemProvider(getMenuItemSort());
}
private IMenuItemProvider getMenuItemSort() {
return new IMenuItemProvider() {
@Override
public void addMenuItem(final NatTable natTable, Menu popupMenu) {
/*
* at this place we do not receive the concrete column - so we only can introduce a
* general menu for all columns.
*
* That means we can not display sorting state of the current column,
* we can not disable the menu, if sorting is not allowed on this column.
*
* Introduces a mechanism which would allow to react on the state current sorting
* state.
*/
*
Image iconUp = GUIHelper.getImage("up_0"); //$NON-NLS-1$
Image iconDown = GUIHelper.getImage("down_0"); //$NON-NLS-1$
// group
MenuItem sortMenuGroupItem = new MenuItem(popupMenu, SWT.CASCADE);
/** the hotkey is defined in ConfigurationHeaderActions */
sortMenuGroupItem.setText(Messages.ConfigurationHeaderContextMenu_sorting + MENU_TAB_CHAR + HOTKEY_CTRL
+ PLUS_CHAR + HOTKEY_SEARCH);
sortMenuGroupItem.setImage(iconDown);
sortMenuGroupItem.setEnabled(true);
Menu sortMenuGroup = new Menu(sortMenuGroupItem);
sortMenuGroupItem.setMenu(sortMenuGroup);
// Item sort none
MenuItem sortMenuItemNo = new MenuItem(sortMenuGroup, SWT.PUSH);
sortMenuItemNo.setText(Messages.ConfigurationHeaderContextMenu_noSort);
sortMenuItemNo
.addSelectionListener(getSelectionAdapterSorting(SortDirectionEnum.NONE, sortModel, natTable));
// item sort asc
MenuItem sortMenuItemAsc = new MenuItem(sortMenuGroup, SWT.PUSH);
sortMenuItemAsc.setText(Messages.ConfigurationHeaderContextMenu_ascending);
sortMenuItemAsc.setImage(iconUp);
sortMenuItemAsc
.addSelectionListener(getSelectionAdapterSorting(SortDirectionEnum.ASC, sortModel, natTable));
// Item sort desc
MenuItem sortMenuItemDesc = new MenuItem(sortMenuGroup, SWT.PUSH);
sortMenuItemDesc.setText(Messages.ConfigurationHeaderContextMenu_descending);
sortMenuItemDesc.setImage(iconDown);
sortMenuItemDesc
.addSelectionListener(getSelectionAdapterSorting(SortDirectionEnum.DESC, sortModel, natTable));
// HELPER
private SelectionAdapter getSelectionAdapterSorting(final SortDirectionEnum sortDirectionEnum,
final ISortModel sortModel, final NatTable natTable) {
return new SelectionAdapter() {
@SuppressWarnings("unused")
@Override
public void widgetSelected(SelectionEvent e) {
NatEventData natEventData = MenuItemProviders.getNatEventData(e);
int columnPosition = natEventData.getColumnPosition();
int columnIndex = natTable.getColumnIndexByPosition(columnPosition);
// switch model into the predescessor state. SortColumnCommand will siwtch it into
// the next state
sortModel.sort(columnIndex, TableSorter.getPreviousSortDirection(sortDirectionEnum), false);
// send a command
// the command will switch the model into the next sorting-state
natTable.doCommand(new SortColumnCommand(natTable, columnPosition, false));
}
};
}
=====Example Snippets Repository =====
Are checked in on GitHub: https://github.com/skipidar/NatTableExamples
===== Labels =====
Jede Konfiguration, ob Style, oder Renderer ist mit einem Label assoziiert.
== Where is the place, where Labels are ? ==
In **ILayer.class**
@Override
public LabelStack getConfigLabelsByPosition(int columnPosition, int rowPosition) {
LabelStack configLabels = new LabelStack();
if (this.configLabelAccumulator != null) {
this.configLabelAccumulator.accumulateConfigLabels(configLabels, columnPosition, rowPosition);
}
if (this.regionName != null) {
configLabels.addLabel(this.regionName);
}
return configLabels;
}
== How to contribute a label by a custom layer ==
Use method getConfigLabelsByPosition in **ILayer.class**
// need to contribute a label for the whole layer
// WRONG - layers have no chance to contribute Labels, but only via Regions. Noone asks for registered IConfigLabelAccumulator
// @Override
// public LabelStack getRegionLabelsByXY(int x, int y) {
// LabelStack stack = super.getRegionLabelsByXY(x, y);
// stack.addLabel(GridRegion.ROW_HEADER);
// return stack;
// }
// RIGHT
@Override
public LabelStack getConfigLabelsByPosition(int columnPosition, int rowPosition) {
LabelStack stack = super.getConfigLabelsByPosition(columnPosition, rowPosition);
stack.addLabel(GridRegion.ROW_HEADER);
return stack;
}
Attach Labels via Regions. Each region becomes a label too.
combinedCheckboxRowheaderLayer = new CompositeLayer(2, 1);
combinedCheckboxRowheaderLayer.setChildLayer(REGIONS.CHECKBOX_LAYER, checkboxesLayer, 0, 0);
combinedCheckboxRowheaderLayer.setChildLayer(REGIONS.ROW_HEADER_LAYER, rowHeaderLayer, 1, 0);
=====Example Code =====
Example of using [[http://www.eclipse.org/nattable/|NatTable]]
import org.eclipse.nebula.widgets.nattable.NatTable;
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.grid.GridRegion;
import org.eclipse.nebula.widgets.nattable.grid.data.DefaultCornerDataProvider;
import org.eclipse.nebula.widgets.nattable.grid.data.DummyBodyDataProvider;
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.GridLayer;
import org.eclipse.nebula.widgets.nattable.grid.layer.RowHeaderLayer;
import org.eclipse.nebula.widgets.nattable.hideshow.ColumnHideShowLayer;
import org.eclipse.nebula.widgets.nattable.layer.AbstractLayerTransform;
import org.eclipse.nebula.widgets.nattable.layer.DataLayer;
import org.eclipse.nebula.widgets.nattable.layer.ILayer;
import org.eclipse.nebula.widgets.nattable.layer.cell.ColumnOverrideLabelAccumulator;
import org.eclipse.nebula.widgets.nattable.painter.cell.ButtonCellPainter;
import org.eclipse.nebula.widgets.nattable.painter.cell.ImagePainter;
import org.eclipse.nebula.widgets.nattable.painter.cell.TextPainter;
import org.eclipse.nebula.widgets.nattable.painter.cell.decorator.CellPainterDecorator;
import org.eclipse.nebula.widgets.nattable.reorder.ColumnReorderLayer;
import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer;
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.ui.action.IMouseAction;
import org.eclipse.nebula.widgets.nattable.ui.binding.UiBindingRegistry;
import org.eclipse.nebula.widgets.nattable.ui.matcher.CellLabelMouseEventMatcher;
import org.eclipse.nebula.widgets.nattable.ui.matcher.MouseEventMatcher;
import org.eclipse.nebula.widgets.nattable.ui.util.CellEdgeEnum;
import org.eclipse.nebula.widgets.nattable.util.GUIHelper;
import org.eclipse.nebula.widgets.nattable.viewport.ViewportLayer;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
public class Table {
public static final String CUSTOM_CELL_LABEL = "Cell_LABEL";
public static void main(String[] args) {
Display display = new Display ();
Shell shell = new Shell (display);
shell.setLayout(new GridLayout());
shell.setSize(1000, 600);
new Table(shell);
shell.open ();
while (!shell.isDisposed ()) {
if (!display.readAndDispatch ()) display.sleep ();
}
display.dispose ();
}
public Table(Shell parent) {
parent.setLayout(new FillLayout());
IDataProvider bodyDataProvider = setupBigDataProvider();
//All of the layers, needed for the table
BodyStack bodyStack = new BodyStack(bodyDataProvider);
//column names
IDataProvider dataProviderColHeader = getColumnLabelProvider(bodyDataProvider);
DataLayer dataLayerColHeader = new DataLayer(dataProviderColHeader);
ColumnHeaderLayer columnHeaderLayer = new ColumnHeaderLayer(dataLayerColHeader, bodyStack, bodyStack.selectionLayer); //ACHTUNG: use viewportlayer here
//row names.
//DEMO of encapsulating layers and configs in an "AbstractLayerTransform"
IDataProvider dataProviderRowHeader = getRowLabelProvider(bodyDataProvider);
RowHeaderLayerStack rowHeaderLayer = new RowHeaderLayerStack(dataProviderRowHeader, bodyStack, bodyStack.selectionLayer); //ACHTUNG: use viewportlayer here
//Alternative to creating ColumnHeaderLayer:
//CUSTOM AbstractLayerTransform,
//encapsulates row header creation.
//Can change provide changes to layers beneath.
//(left upper)corner
DefaultCornerDataProvider cornerDataProvider = new DefaultCornerDataProvider(dataProviderColHeader, dataProviderRowHeader);
CornerLayer cornerLayer = new CornerLayer(new DataLayer(cornerDataProvider), rowHeaderLayer, columnHeaderLayer);
//top layer
GridLayer gridLayer = new GridLayer(bodyStack, columnHeaderLayer, rowHeaderLayer, cornerLayer);
NatTable natTable = new NatTable(parent, gridLayer, false); //"autoconfigure" I can apply my own configuration
IConfigRegistry configRegistry = new ConfigRegistry();
// Step 1: Create a label accumulator - adds custom labels to all cells which we
// wish to render differently. In this case render as a button.
ColumnOverrideLabelAccumulator cellLabelAccumulator = new ColumnOverrideLabelAccumulator(bodyStack.bodyDataLayer);
//accumulator will add Label "CUSTOM_CELL_LABEL" to the column 2
cellLabelAccumulator.registerColumnOverrides(2, CUSTOM_CELL_LABEL);
// Step 2: Apply the Accumulator to the column
bodyStack.bodyDataLayer.setConfigLabelAccumulator(cellLabelAccumulator);
//Step 3: Apply the Custom style Painter to the cells, annotated by the Label "CUSTOM_CELL_LABEL"
//3.1 new painter
final ButtonCellPainter buttonPainter = new ButtonCellPainter(
new CellPainterDecorator(
new TextPainter(), CellEdgeEnum.RIGHT, new ImagePainter(GUIHelper.getImage("preferences"))
)
);
//3.2 make painter responsible for drawing CUSTOM_CELL_LABEL annotated cells
configRegistry.registerConfigAttribute(CellConfigAttributes.CELL_PAINTER,
buttonPainter,
DisplayMode.NORMAL,
CUSTOM_CELL_LABEL);
//3.3 Add the listener to the button
buttonPainter.addClickListener(new IMouseAction() {
@Override
public void run(NatTable natTable, MouseEvent event) {
System.out.println("MouseClick");
}
});
//3.4 set the style for the CUSTOM_CELL_LABEL annotated cells
Style style = new Style();
style.setAttributeValue(CellStyleAttributes.BACKGROUND_COLOR, GUIHelper.COLOR_WHITE); // Set the color of the cell. This is picked up by the button painter to style the button
configRegistry.registerConfigAttribute(CellConfigAttributes.CELL_STYLE, style, DisplayMode.NORMAL, CUSTOM_CELL_LABEL);
configRegistry.registerConfigAttribute(CellConfigAttributes.CELL_STYLE, style, DisplayMode.SELECT, CUSTOM_CELL_LABEL);
//3.5 add Mouse listener to use the Painter on Mouse event
natTable.addConfiguration(new AbstractUiBindingConfiguration() {
@Override
public void configureUiBindings(UiBindingRegistry uiBindingRegistry) {
// Match a mouse event on the body, when the left button is clicked
// and the custom cell label is present
CellLabelMouseEventMatcher mouseEventMatcher = new CellLabelMouseEventMatcher(
GridRegion.BODY,
MouseEventMatcher.LEFT_BUTTON,
CUSTOM_CELL_LABEL);
// Inform the button painter of the click.
uiBindingRegistry.registerMouseDownBinding(mouseEventMatcher, buttonPainter);
}
});
//Step 4 now apply the configuration to the NatTable
//apply the style, which will draw the data into the Table
natTable.setConfigRegistry(configRegistry);
natTable.addConfiguration(new DefaultNatTableStyleConfiguration()); // must be done after the setConfigRegistry, because the Configuration is stored in the configRegistry
natTable.configure();
}
//HELPER
private IDataProvider setupBigDataProvider() {
DummyBodyDataProvider data = new DummyBodyDataProvider(500, 100000000);
return data;
}
public class BodyStack extends AbstractLayerTransform {
private DataLayer bodyDataLayer;
private ColumnReorderLayer columnReorderLayer;
private ColumnHideShowLayer columnHideShowLayer;
private SelectionLayer selectionLayer;
private ViewportLayer viewportLayer;
public BodyStack(IDataProvider bodyDataProvider){
bodyDataLayer = new DataLayer(bodyDataProvider);
columnReorderLayer = new ColumnReorderLayer(bodyDataLayer);
columnHideShowLayer = new ColumnHideShowLayer(columnReorderLayer);
selectionLayer = new SelectionLayer(columnHideShowLayer);
viewportLayer = new ViewportLayer(selectionLayer);
// make the bottom layer to the layer, which will be used to extend the stack
setUnderlyingLayer(viewportLayer);
}
}
private IDataProvider getRowLabelProvider(final IDataProvider bodyDataProvider){
return new IDataProvider() {
@Override
public void setDataValue(int columnIndex, int rowIndex, Object newValue) {
//nothing
}
@Override
public int getRowCount() {
return bodyDataProvider.getRowCount();
}
@Override
public Object getDataValue(int columnIndex, int rowIndex) {
//here the name of the row is set
return rowIndex;
}
@Override
public int getColumnCount() {
return 1;
}
};
}
private IDataProvider getColumnLabelProvider(final IDataProvider bodyDataProvider){
return new IDataProvider() {
@Override
public void setDataValue(int columnIndex, int rowIndex, Object newValue) {
//nothing
}
@Override
public int getRowCount() {
return 1;
}
@Override
public Object getDataValue(int columnIndex, int rowIndex) {
//here the name of the row is set
return columnIndex;
}
@Override
public int getColumnCount() {
return bodyDataProvider.getColumnCount();
}
};
}
private class RowHeaderLayerStack extends AbstractLayerTransform {
public RowHeaderLayerStack(IDataProvider dataProvider, ILayer bodyDataLayer, SelectionLayer selectionLayer) {
DataLayer dataLayer = new DataLayer(dataProvider, 50, 20);
RowHeaderLayer rowHeaderLayer = new RowHeaderLayer(dataLayer, bodyDataLayer, selectionLayer);
setUnderlyingLayer(rowHeaderLayer);
}
}
}
== Rendering a Cell as a Checkbox ==
@Override
protected void registerDomainSpecificLabels(
ColumnOverrideLabelAccumulator columnOverrideLabelAccumulator) {
//1. add labels to specific columns
columnOverrideLabelAccumulator.registerColumnOverrides(0, CHECK_BOX_EDITOR_CONFIG_LABEL, CHECK_BOX_CONFIG_LABEL);
columnOverrideLabelAccumulator.registerColumnOverrides(1, CHECK_BOX_EDITOR_CONFIG_LABEL, CHECK_BOX_CONFIG_LABEL);
}
@Override
protected void modifyConfigRegistry(IConfigRegistry configRegistry) {
//2. register painter using labels
configRegistry.registerConfigAttribute(CellConfigAttributes.CELL_PAINTER, checkBoxPainter, DisplayMode.NORMAL, CHECK_BOX_CONFIG_LABEL);
//3. register editor for BOTH modes NORMAL and EDIT using labels
CheckBoxCellEditor checkBoxCellEditor = new CheckBoxCellEditor();
configRegistry.registerConfigAttribute(EditConfigAttributes.CELL_EDITOR, checkBoxCellEditor, DisplayMode.NORMAL, CHECK_BOX_EDITOR_CONFIG_LABEL);
configRegistry.registerConfigAttribute(EditConfigAttributes.CELL_EDITOR, checkBoxCellEditor, DisplayMode.EDIT, CHECK_BOX_EDITOR_CONFIG_LABEL);
//4. when are the cells editable? - always
configRegistry.registerConfigAttribute(EditConfigAttributes.CELL_EDITABLE_RULE, IEditableRule.ALWAYS_EDITABLE, DisplayMode.EDIT, CHECK_BOX_CONFIG_LABEL);
configRegistry.registerConfigAttribute(CellConfigAttributes.DISPLAY_CONVERTER, new DefaultBooleanDisplayConverter(), DisplayMode.NORMAL, CHECK_BOX_CONFIG_LABEL);
}
== Catching Single Clicks on Column ==
@Override
protected void modifyUiBindingRegistry(UiBindingRegistry uiBindingRegistry) {
IMouseEventMatcher mouseEventMatcher = new IMouseEventMatcher() {
@Override
public boolean matches(NatTable natTable, MouseEvent event,
LabelStack regionLabels) {
return true;
}
};
IMouseAction mouseAction = new IMouseAction() {
@Override
public void run(NatTable natTable, MouseEvent event) {
int columnPosition = natTable.getColumnPositionByX(event.x); // only the columns in the
int rowPosition = natTable.getRowPositionByY(event.y);
int columnIndex = natTable.getColumnIndexByPosition(columnPosition);
int rowIndex = natTable.getRowIndexByPosition(rowPosition);
IDataProvider dataProvider = getDataProvider();
boolean val = (boolean) dataProvider.getDataValue(columnIndex, rowIndex);
dataProvider.setDataValue(columnIndex, rowIndex, val ? false : true );
}
};
uiBindingRegistry.registerFirstSingleClickBinding(
mouseEventMatcher,
mouseAction
);
}
== Registering Comboboxes on a Cell ==
...
registerColumnLabels(columnOverrideLabelAccumulator, natTable);
makeColumnsEditable();
registerComboBox(configRegistry);
registerValidators(configRegistry);
}
//RENDERING
// 1. add label to the columns
private void registerColumnLabels(ColumnOverrideLabelAccumulator columnOverrideLabelAccumulator, NatTable natTable){
columnOverrideLabelAccumulator.registerColumnOverrides(0, "LABEL0");
columnOverrideLabelAccumulator.registerColumnOverrides(1, "LABEL1");
columnOverrideLabelAccumulator.registerColumnOverrides(2, "LABEL2");
columnOverrideLabelAccumulator.registerColumnOverrides(3, "LABEL3", "LABEL_editor");
columnOverrideLabelAccumulator.registerColumnOverrides(4, "LABEL4");
}
//2. make cells editable
private void makeColumnsEditable(){
//2. make the cell editable
// configRegistry.registerConfigAttribute(EditConfigAttributes.CELL_EDITABLE_RULE, IEditableRule.ALWAYS_EDITABLE, DisplayMode.EDIT, "LABEL0");
configRegistry.registerConfigAttribute(EditConfigAttributes.CELL_EDITABLE_RULE, IEditableRule.ALWAYS_EDITABLE, DisplayMode.EDIT, "LABEL1");
configRegistry.registerConfigAttribute(EditConfigAttributes.CELL_EDITABLE_RULE, IEditableRule.ALWAYS_EDITABLE, DisplayMode.EDIT, "LABEL2");
configRegistry.registerConfigAttribute(EditConfigAttributes.CELL_EDITABLE_RULE, IEditableRule.ALWAYS_EDITABLE, DisplayMode.EDIT, "LABEL3");
configRegistry.registerConfigAttribute(EditConfigAttributes.CELL_EDITABLE_RULE, IEditableRule.ALWAYS_EDITABLE, DisplayMode.EDIT, "LABEL4");
}
//3. register painter
//4. register editor
private static void registerComboBox(IConfigRegistry configRegistry ) {
String COMBO_BOX_CONFIG_LABEL = "LABEL4";
String FORMAT_PRICING_TYPE_CONFIG_LABEL = "LABEL4";
ICellPainter comboBoxCellPainter = new ComboBoxPainter();
// ICellEditor comboBoxCellEditor = new ComboBoxCellEditor(Arrays.asList(new PricingTypeBean("Manuell"), new PricingTypeBean("Automatic")));
// ICellEditor comboBoxCellEditor = new ComboBoxCellEditor(Arrays.asList("222", "333"));
ICellEditor comboBoxCellEditor = new ComboBoxCellEditor(Arrays.asList(1, 98, 99));
configRegistry.registerConfigAttribute(CellConfigAttributes.CELL_PAINTER, comboBoxCellPainter, DisplayMode.NORMAL, COMBO_BOX_CONFIG_LABEL);
configRegistry.registerConfigAttribute(EditConfigAttributes.CELL_EDITOR, comboBoxCellEditor, DisplayMode.NORMAL, COMBO_BOX_CONFIG_LABEL);
configRegistry.registerConfigAttribute(EditConfigAttributes.CELL_EDITOR, comboBoxCellEditor, DisplayMode.EDIT, COMBO_BOX_CONFIG_LABEL);
// displayed values can be displayed differently
// ACHTUNG: DISPLAY_CONVERTER can't return Integer when using ComboBoxCellEditor
configRegistry.registerConfigAttribute(CellConfigAttributes.DISPLAY_CONVERTER, new NumbersToTextDisplayConverter(), DisplayMode.NORMAL, FORMAT_PRICING_TYPE_CONFIG_LABEL);
}
//5. data validator
private void registerValidators(IConfigRegistry configRegistry){
// configRegistry.registerConfigAttribute(EditConfigAttributes.DATA_VALIDATOR,new IntegerValidator(), DisplayMode.EDIT,"LABEL0");
}
== Retrieving an ICellEditor from the cell==
ILayerCell cell = natTable.getCellByPosition(natTable.getColumnPositionByX(event.x), natTable.getRowPositionByY(event.y));
ICellEditor cellEditor = natTable.getConfigRegistry().getConfigAttribute(EditConfigAttributes.CELL_EDITOR, DisplayMode.EDIT, cell.getConfigLabels().getLabels());
== Retrieving an ICellPainter from the cell==
ILayerCell cell = natTable.getCellByPosition(natTable.getColumnPositionByX(event.x), natTable.getRowPositionByY(event.y));
ICellPainter painter = natTableNew.getCellPainter(colPosition, rowPosition, cell, configRegistry);
== Rendering an own SWT Widget inside of the table ==
Control myControl = new Label(natTable, SWT.NONE);
ICellPainter cellPainter = new AbstractCellPainter() {
public void paintCell(ILayerCell cell, GC gc, Rectangle bounds, IConfigRegistry configRegistry) {
myControl.setBounds(bounds);
}
public int getPreferredWidth(ILayerCell cell, GC gc, IConfigRegistry configRegistry) {
return myControl.getBounds().y;
}
public int getPreferredHeight(ILayerCell cell, GC gc, IConfigRegistry configRegistry) {
return myControl.getBounds().x;
}
};
===== NatTable Entry-Point =====
Here the painting of the table is started:
**GridLineCellLayerPainter.class**
@Override
public void paintLayer(ILayer natLayer, GC gc, int xOffset, int yOffset,
Rectangle rectangle, IConfigRegistry configRegistry) {
Boolean renderConfig = null;
LabelStack stack = natLayer.getRegionLabelsByXY(xOffset, yOffset);
if (stack != null) {
// check if there is a configuration telling to not rendering grid
// lines
renderConfig = configRegistry.getConfigAttribute(
CellConfigAttributes.RENDER_GRID_LINES, DisplayMode.NORMAL,
stack.getLabels());
}
this.renderGridLines = (renderConfig != null) ? renderConfig : true;
// Draw GridLines
if (this.renderGridLines)
drawGridLines(natLayer, gc, rectangle, configRegistry);
super.paintLayer(natLayer, gc, xOffset, yOffset, rectangle,
configRegistry);
}
=====Useful Code =====
====Debugging Table====
For debugging it is really important to know, which settings are saved for each particular cell in table.
This code will echo the configuration for each cell, which the mouse hovers over.
import java.util.Arrays;
import java.util.List;
import org.eclipse.core.runtime.Platform;
import org.eclipse.nebula.widgets.nattable.NatTable;
import org.eclipse.nebula.widgets.nattable.config.CellConfigAttributes;
import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry;
import org.eclipse.nebula.widgets.nattable.data.convert.IDisplayConverter;
import org.eclipse.nebula.widgets.nattable.edit.EditConfigAttributes;
import org.eclipse.nebula.widgets.nattable.edit.editor.ICellEditor;
import org.eclipse.nebula.widgets.nattable.layer.LabelStack;
import org.eclipse.nebula.widgets.nattable.layer.cell.ILayerCell;
import org.eclipse.nebula.widgets.nattable.painter.cell.ICellPainter;
import org.eclipse.nebula.widgets.nattable.style.DisplayMode;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseMoveListener;
public class TableObjectsDebugTrace {
private static final String PARAMETER_FOR_DEBUG_TRACE_IN_NATTABLE = "-nattabletrace";
// init
boolean showCoordinates = true;
boolean showLabels = true;
boolean showCellPainter = true;
boolean showCellEditor = true;
boolean showDisplayConverter = true;
private NatTable natTable;
private IConfigRegistry configRegistry;
public TableObjectsDebugTrace(NatTable nattable) {
this.natTable = nattable;
this.configRegistry = nattable.getConfigRegistry();
// check for my custom runtime configuration parameter
List parameters = Arrays.asList(Platform.getCommandLineArgs());
if (parameters.contains(PARAMETER_FOR_DEBUG_TRACE_IN_NATTABLE)) {
nattable.addMouseMoveListener(getDebugTraceMouseListener());
}
}
private MouseMoveListener getDebugTraceMouseListener() {
MouseMoveListener listener = new MouseMoveListener() {
@Override
public void mouseMove(MouseEvent event) {
int row = natTable.getRowPositionByY(event.y);
int col = natTable.getColumnPositionByX(event.x);
ILayerCell cellTemp = natTable.getCellByPosition(col, row);
if (cellTemp == null) {
// we are pointing to an empty space, ther is no cell
return;
}
LabelStack labelStack = cellTemp.getConfigLabels();
if (labelStack == null) {
return;
}
List listLabels = labelStack.getLabels();
ICellPainter cellPainter = configRegistry.getConfigAttribute(CellConfigAttributes.CELL_PAINTER,
DisplayMode.NORMAL, listLabels);
ICellEditor cellEditor = configRegistry.getConfigAttribute(EditConfigAttributes.CELL_EDITOR,
DisplayMode.EDIT, listLabels);
IDisplayConverter displayConverterNorm = configRegistry.getConfigAttribute(
CellConfigAttributes.DISPLAY_CONVERTER, DisplayMode.NORMAL, listLabels);
IDisplayConverter displayConverterEdit = configRegistry.getConfigAttribute(
CellConfigAttributes.DISPLAY_CONVERTER, DisplayMode.EDIT, listLabels);
StringBuilder stringBuilder = new StringBuilder();
if (showCoordinates) {
stringBuilder.append("PosRow:" + row + " PosCol:" + col);
stringBuilder.append(" ");
}
if (showLabels) {
stringBuilder.append("Labels:" + listLabels);
stringBuilder.append(" ");
}
if (showCellPainter) {
stringBuilder.append("Painter:" + cellPainter.getClass().getSimpleName());
stringBuilder.append(" ");
}
if (showCellEditor) {
stringBuilder.append("Editor:" + cellEditor.getClass().getSimpleName());
stringBuilder.append(" ");
}
if (showDisplayConverter) {
stringBuilder.append("DisplayConverter::");
stringBuilder.append("DMode=NORMAL:" + displayConverterNorm.getClass().getSimpleName());
stringBuilder.append(" ");
stringBuilder.append("DMode=EDIT:" + displayConverterEdit.getClass().getSimpleName());
stringBuilder.append(" ");
}
// echo result
System.out.println(stringBuilder.toString());
}
};
return listener;
}
}