User Tools

Site Tools


eclipse:nattable

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
eclipse:nattable [2015/11/21 13:50] – [Styling] skipeclipse:nattable [2023/11/01 07:15] (current) – ↷ Page moved from camunda:eclipse:nattable to eclipse:nattable skipidar
Line 1: Line 1:
 +====== 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 
 +<sxh java>
 +      // 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,
 +</sxh>
 +  * 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:<WRAP>
 +
 +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:
 +
 +<code>
 + 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
 +</code>
 +</WRAP>
 +
 +Switching between Position and INdex is possible via the nattable
 +
 +<code>
 +// position -> index
 +natTable.getColumnIndexByPosition(columnPosition)
 +natTable.getRowIndexByPosition(rowPosition) 
 +</code>
 +===== 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.
 +
 +<sxh java>
 +//map the labels to attributes names
 +IDataProvider dataProvider = new ListDataProvider<Person>(List<OwnObject> ownObjectList, new ReflectiveColumnPropertyAccessor(propertyNames));
 +</sxh>
 +
 +==== 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: \\ <WRAP><sxh java>
 +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);    
 +</sxh></WRAP>
 +|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. <WRAP><sxh java>
 +//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);
 +</sxh></WRAP>|
 +| 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: \\ <WRAP><sxh java>
 +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());
 +}
 +
 +</sxh></WRAP>
 +
 +
 +
 +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 |<WRAP>  
 +  *  CELL_PAINTER
 +  *  CELL_STYLE
 +  *  DISPLAY_CONVERTER
 +  *  EXPORT_FORMATTER 
 +<sxh java>
 +configRegistry.registerConfigAttribute(CellConfigAttributes.CELL_PAINTER, new CheckBoxPainter(), DisplayMode.NORMAL, CHECK_BOX_CONFIG_LABEL);
 +</sxh>
 +</WRAP>|
 +|EditConfigAttributes|<WRAP>  
 +    CELL_EDITABLE_RULE
 +    CELL_EDITOR
 +    DATA_VALIDATOR
 +    CONVERSION_ERROR_HANDLER
 +    VALIDATION_ERROR_HANDLER
 +    VALIDATION_ERROR_STYLE
 +<sxh java>
 +configRegistry.registerConfigAttribute(EditConfigAttributes.CELL_EDITOR, new CheckBoxCellEditor(), DisplayMode.NORMAL, CHECK_BOX_EDITOR_CONFIG_LABEL);
 +</sxh></WRAP>|
 +|CellConfigAttributes|<WRAP>  
 +    BACKGROUND_COLOR
 +    FOREGROUND_COLOR
 +    GRADIENT_BACKGROUND_COLOR
 +    GRADIENT_FOREGROUND_COLOR
 +    HORIZONTAL_ALIGNMENT
 +    VERTICAL_ALIGNMENT
 +    FONT
 +    IMAGE
 +    BORDER_STYLE
 +    PASSWORD_ECHO_CHAR
 +<sxh java>
 +IStyle cellStyle = new Style();
 +cellStyle.setAttributeValue(CellStyleAttributes.BACKGROUND_COLOR, GUIHelper.COLOR_RED);
 +configRegistry.registerConfigAttribute(CellConfigAttributes.CELL_STYLE, getStyle(), CHECK_BOX_CONFIG_LABEL);
 +</sxh>
 +</WRAP>|
 +
 +
 +===== useful API =====
 +^API ^ Describtion^
 +|ColumnResizeCommand | Can resize a column. <WRAP><sxh java>
 +                ColumnResizeCommand columnCommand = new ColumnResizeCommand(gridLayer, 3, 300);
 +                natTable.doCommand(columnCommand);
 +</sxh></WRAP>|
 +|[[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. <WRAP><sxh java>
 + private IConfigRegistry configRegistry =  natTable.getConfigRegistry();
 +configRegistry.registerConfigAttribute(CellConfigAttributes.DISPLAY_CONVERTER,
 +                        new  DefaultDateDisplayConverter(), DisplayMode.NORMAL, getColumnLabel(columnNumber));
 +</sxh></WRAP>|
 +|[[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. <WRAP><sxh java>
 +
 + 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;
 + }
 + });
 +    }
 +
 +</sxh></WRAP>|
 +|[[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. <WRAP><sxh java>
 +    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;
 + }
 + });
 +    }
 +</sxh></WRAP>|
 +|[[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 . <WRAP><sxh java>
 +
 +    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);
 +        }
 +    }
 + 
 +</sxh></WRAP>|
 +|[[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]]| <WRAP>
 +
 +Commands are passed through all layers top down. 
 +Default commands are handled by handlers, many of them are owned by the GridLayer. 
 +<sxh java>
 +//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
 +
 +</sxh></WRAP>|
 +|<WRAP><sxh java>
 +natTable.getConfigLabelsByPosition(columnPosition, rowPosition)
 +natTable.getDataValueByPosition(columnPosition, rowPosition)
 +natTable.getColumnIndexByPosition(columnPosition)
 +natTable.getRowIndexByPosition(rowPosition) </sxh></WRAP>| Methodsavailable directly in nattable |
 +|[[http://nattable.mecha1.com|Classname]]| Comment. <WRAP><sxh java>
 +
 + 
 +</sxh></WRAP>|
 +===== 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}}
 +
 +
 +<sxh java>
 +
 + /**
 + * 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);
 + }
 +
 +
 +
 +</sxh>
 +
 +
 +
 +
 +===== Styling =====
 +The styling may happen via different mechanisms:
 +=== Style ===
 +The cellStyle may style cells or headers, since headers are cells too.
 +<code>
 +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
 +</code>
 +
 +The cellStyle is registered to different DisplayModes, 
 +may become active when the cell is Selected, Edited or just viewed.
 +
 +<sxh java>
 +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);
 +
 +</sxh>
 +
 +=== Painter ===
 +The Painter may draw BG or forbid to draw bg. \\
 +When renderer forbids t odraw BG - no registered style is used:
 +
 +<sxh java>
 + // 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);
 +</sxh>
 +
 +
 +=== 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: 
 +
 +<sxh java>
 +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());
 +    }
 +</sxh>
 +
 +The important part is the 
 +<code>
 +cell.getConfigLabels().getLabels()
 +</code>
 +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.
 +
 +<sxh java>
 +package org.eclipse.nebula.widgets.nattable.style;
 +
 +class StyleProxy{
 +...
 +    public <T> T getAttributeValue(ConfigAttribute<T> 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;
 +    }
 +</sxh>
 +===== Sorting =====
 +Sorting is implemented via **ISortModel**. It is passed to the **SortHeaderLayer**
 +<code>
 +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);
 +        }
 +</code>
 +
 +
 +Via Configurations you can add some contextmenus to add sort functionality
 +
 +<code>
 +   /**
 +     * 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));
 +            }
 +
 +        };
 +    }
 +</code>
 +
 +
 +=====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**
 +<sxh java>
 +    @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;
 +    }
 +</sxh>
 +
 +
 +== How to contribute a label by a custom layer ==
 +
 +
 +
 +Use method getConfigLabelsByPosition in **ILayer.class**
 +
 +<sxh java>
 +                // 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;
 +                }
 +</sxh>
 +
 +Attach Labels via Regions. Each region becomes a label too.
 +<sxh java>
 +                combinedCheckboxRowheaderLayer = new CompositeLayer(2, 1);
 +                combinedCheckboxRowheaderLayer.setChildLayer(REGIONS.CHECKBOX_LAYER, checkboxesLayer, 0, 0);
 +                combinedCheckboxRowheaderLayer.setChildLayer(REGIONS.ROW_HEADER_LAYER, rowHeaderLayer, 1, 0);
 +</sxh>
 +
 +=====Example Code =====
 +
 +Example of using [[http://www.eclipse.org/nattable/|NatTable]]
 +
 +<sxh java>
 + 
 +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);
 +        }
 +    }
 + 
 +}
 +
 +</sxh>
 +
 +
 +
 +== Rendering a Cell as a Checkbox ==
 +<sxh java>
 +   @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);
 + }
 +</sxh>
 +
 +
 +== Catching Single Clicks on Column ==
 +<sxh java>
 +@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
 + );
 + }
 +</sxh>
 +
 +
 +== Registering Comboboxes on a Cell ==
 +<sxh java>
 +...
 + 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");
 + }
 +
 +</sxh>
 +
 +
 +== Retrieving an ICellEditor from the cell==
 +<sxh java>
 +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());
 +</sxh>
 +
 +== Retrieving an ICellPainter from the cell==
 +<sxh java>
 +ILayerCell cell = natTable.getCellByPosition(natTable.getColumnPositionByX(event.x), natTable.getRowPositionByY(event.y));
 +ICellPainter painter = natTableNew.getCellPainter(colPosition, rowPosition, cell, configRegistry);
 +</sxh>
 +
 +== Rendering an own SWT Widget inside of the table ==
 +<sxh java>
 +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;
 + }
 +};
 +</sxh>
 +===== NatTable Entry-Point =====
 +Here the painting of the table is started:
 +
 +**GridLineCellLayerPainter.class**
 +<sxh java>
 +    @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);
 +    }
 +</sxh>
 +
 +
 +
 +
 +=====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.
 +
 +<sxh java>
 +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<String> 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<String> 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;
 +    }
 +}
 +</sxh>