NatTable 1.2.0 - New & Noteworthy
The NatTable 1.2.0 release was mainly made possible by UBS. There were a lot of contributions in form of ideas, bug reports, discussions and even new features like traversal handling, scaling for high resolutions and several more you can find in the following sections. We would like to thank UBS for their commitment and support on developing the 1.2.0 release.
Almost every change in code is tracked via ticket in Bugzilla, so if you are curious about the details and all the bugs that are fixed and enhancements that were added with the 1.2.0 release, have a look here.
Dependencies
- Removed dependency to Apache Commons Lang. It was used internally and caused issues for consumers of NatTable when setting up a target definition with newer versions of the Eclipse Platform.
- Replaced the dependency to org.eclipse.core.runtime bundle with org.eclipse.equinox.common to have a smaller set on dependent plugins. The dependency to the org.eclipse.equinox.common bundle is required by JFace, which is used for several NatTable dialogs.
API changes
- Added
ISortModel#getColumnComparator(int)which is necessary to retrieve theComparatorfor column values in order to be able to sort a tree according to the configured sorting. - Added
ICellEditor#activateOnTraversal(IConfigRegistry, List)to be able to configure if an editor should be activated on traversal or not. Necessary because a checkbox shouldn’t change it’s value when automatically activated after committing a value in an adjacent editor. TheCheckBoxCellEditoralways returnsfalse. The abstract implementations will check the newly introducedEditConfigAttributes#ACTIVATE_EDITOR_ON_TRAVERSALconfiguration attribute or returntruein case there is no such configuration attribute set. - Renamed
AggregrateConfigLabelAccumulatortoAggregateConfigLabelAccumulator. - Renamed
ITreeRowModel#isCollapseable()toITreeRowModel#isCollapsible(). - Added
ITreeRowModel#expandToLevel(int),ITreeRowModel#expandToLevel(int, int)andITreeRowModel#expandToLevel(T, int)to be able to expand a tree to a certain level. - Deprecated
ITreeData#formatDataForDepth(int, int),ITreeData#formatDataForDepth(int, T)andITreeRowModel#getObjectAtIndexAndDepth(int, int)which were used byTreeExportFormatter. Since it now correctly uses the configuredIDisplayConverterto convert the values, these methods are not called from the framework anymore. - Deprecated all expand/collapse related methods in
GlazedListTreeDataand moved them toGlazedListTreeRowModelwhere they should reside correctly. ISelectionModelnow extendsILayerEventHandler<IStructuralChangeEvent>in order to be able to handle structural changes correctly dependent on the internal selection storage.- Deprecated
ColumnGroupMenuItemProvidersand moved the methods to the generalMenuItemProviders. - Changed
MoveSelectionCommandHandlermoveLastSelectedXxx method parameters from int toITraversalStrategy.
Enhancements and new features
-
Scaling support for high resolution displays
IntroducedIDpiConverterandAbstractDpiConverterthat are used in conjunction with the newly introducedConfigureScalingCommandto informILayerandSizeConfiginstances about the scaling calculations that need to be performed. Extended theGUIHelperfor several methods related to scaling calculations and added the support for upscaled images. To add different images for different DPI settings, simply put images whose names are prefixed with the DPI values to the same place as the base image.The following shows how to provide a set of images that are used on scaling. The file checkbox.png will be used for 96 DPI, the others specify their DPI setting in the filename.
- checkbox.png
- checkbox_120_120.png
- checkbox_128_128.png
- checkbox_144_144.png
- checkbox_192_192.png
- checkbox_288_288.png
If no image is found for the current DPI value, the base image will be upscaled.
-
Fixed summary row
Introduced theFixedSummaryRowLayerthat renders a summary row at a fixed position if added to aCompositeLayer. It can be configured for usage within a simple horizontal composition aswell as for usage within a grid.The following code shows how to add a fixed summary row above the viewport of a simple NatTable without column and row header.
// Plug in the FixedSummaryRowLayer FixedSummaryRowLayer summaryRowLayer = new FixedSummaryRowLayer(dataLayer, viewportLayer, configRegistry, false); // configure that the horizontal dimensional dependency // is not a CompositeLayer that adds an additional column summaryRowLayer.setHorizontalCompositeDependency(false); CompositeLayer composite = new CompositeLayer(1, 2); composite.setChildLayer("SUMMARY", summaryRowLayer, 0, 0); composite.setChildLayer(GridRegion.BODY, viewportLayer, 0, 1);The following code shows how to add a fixed summary row at the bottom of a grid.
// create the FixedGridSummaryRowLayer FixedSummaryRowLayer summaryRowLayer = new FixedSummaryRowLayer( gridLayer.getBodyDataLayer(), gridLayer, configRegistry, false); // set the summary label that should be shown in the row header summaryRowLayer.setSummaryRowLabel("\\u2211"); // create a composition that has the grid on top and the summary // row at the bottom CompositeLayer composite = new CompositeLayer(1, 2); composite.setChildLayer("GRID", gridLayer, 0, 0); composite.setChildLayer(SUMMARY\_REGION, summaryRowLayer, 0, 1);In case the
FixedSummaryRowLayershould be shown in a grid on top of the body stack below the column header, the layer composition needs some additional modifications. TheCompositeLayerneeds to be top most layer in the body region (which is typically theViewportLayer). The row header layer needs to be of typeFixedSummaryRowHeaderLayerin order to render the row header cell for the additional summary row on top.You will find examples in the NatTable Examples Application in
Tutorial Examples -> Layers -> SummaryRow
that show in detail how to setup a layer composition with a fixed summary row. -
Traversal strategy
IntroducedITraversalStrategyto be able to configure editing traversal and selection movement details. In short this means that you are able to specify if the selection anchor should cycle if moved over a table border and if the selection/focus should jump over cells.An
ITraversalStrategyspecifies aTraversalScope, if the traversal should cycle, the step count and whether the target is valid. There are four default implementations that are only different forTraversalScopeand cycle configuration. All are configured for step count = 1 and accepting every target cell as valid.ITraversalStrategy#AXIS_TRAVERSAL_STRATEGY
TraversalScope = AXIS
cycle = false
On traversal we only see the current row/column and will stop at a table border. This is the known default behavior in NatTable.ITraversalStrategy#AXIS_CYCLE_TRAVERSAL_STRATEGY
TraversalScope#AXIS
cycle = true
On traversal we only see the current row/column. On moving over a table border, the selection will move to the opposite side. E.g. moving over the last column in row 2 will set the selection to the first column in the same row.ITraversalStrategy#TABLE_TRAVERSAL_STRATEGY
TraversalScope#TABLE
cycle = false
On traversal we see the whole table. On moving over a table border, the selection will move to the opposite side by an additional row/column. E.g. moving to the right over the last column in row 2 will set the selection to the first column in the next row.
Since cycle is set tofalse, the traversal will stop at table borders (last column/last row or first column/first row).ITraversalStrategy#TABLE_CYCLE_TRAVERSAL_STRATEGY
TraversalScope#TABLE
cycle = true
On traversal we see the whole table. On moving over a table border, the selection will move to the opposite side by an additional row/column. E.g. moving to the right over the last column in row 2 will set the selection to the first column in the next row.
Since cycle is set to true, the traversal will jump over the table borders, e.g. on moving over the last column/last row cell in a table, the selection will jump to the first column/first row cell in the table.
To specify a custom
ITraversalStrategya customMoveSelectionCommandHandlerneeds to be registered. By default aMoveSelectionCommandHandlerwithITraversalStrategy#AXIS_TRAVERSAL_STRATEGYis registered for theSelectionLayer. To override that behavior you can either exchange theDefaultSelectionLayerConfigurationor register the command handler on a layer above theSelectionLayer, e.g. theViewportLayer. This will exchange the traversal settings globally.// register a MoveCellSelectionCommandHandler with // TABLE_CYCLE_TRAVERSAL_STRATEGY viewportLayer.registerCommandHandler( new MoveCellSelectionCommandHandler( selectionLayer, ITraversalStrategy.TABLE_CYCLE_TRAVERSAL_STRATEGY));Note that it is even possible to register different
ITraversalStrategyfor horizontal and vertical movements.The global
ITraversalStrategysettings in theMoveSelectionCommandHandlercan be overridden for a single command by executing aMoveSelectionCommandwith customized settings.Via
EditTraversalStrategyyou are able to wrap aITraversalStrategyand add the ability to check for editable state. Using theEditTraversalStrategyin conjunction with edit configurations for opening the adjacent editor on commit or editing traversal, the focus will jump to the next editable cell. -
SelectionModel updates
As already stated in the API changes section,ISelectionModelnow extendsILayerEventHandler<IStructuralChangeEvent>. Doing this we introduced a tight connection between theISelectionModeland the handling of structural changes to update the selection. These two were loosely coupled before, which lead to several issues when exchanging theISelectionModel.Note:
If you used thePreserveSelectionStructuralChangeEventHandlerworkaround in previous versions for not clearing the selection on structural changes, you will notice that this workaround will not work anymore. If you still need that behavior, you are now able to achieve the same by configuring and setting aSelectionModelinstance like this:SelectionModel model = new SelectionModel(selectionLayer); // configure to not clear the selection on structural changes model.setClearSelectionOnChange(false); selectionLayer.setSelectionModel(model);If you expect that the selection should update and move with structural changes (e.g. sorting), try to use the
PreserveSelectionModel. -
PopupMenuBuilder - DisposeListener
ThePopupMenuBuildernow adds the necessaryDisposeListenerto the NatTable on callingPopupMenuBuilder#build(). It is not necessary anymore to register such a listener in a configuration yourself. -
PopupMenuBuilder - MenuManager
ThePopupMenuBuildernow internally uses aMenuManagerfor creating and handling MenuItems. This way it is possible to combine Eclipse popup menus with NatTable configurations in conjunction with using core expressions for visibility. Additionally thePopupMenuActionnow sets theNatEventDatato theMenudata map for the keyMenuItemProviders#NAT_EVENT_DATA_KEY. This change was necessary because the Eclipse 4MenuManagerRendereris setting theMenuManagerreference to theMenudata map without a key. -
PopupMenuBuilder - IMenuItemState
With the internal usage ofMenuManagerit is now also possible to configure visibility and enablement of NatTable menu items. To configure these states theIMenuItemStatewas introduced. It can be registered for an ID that points to a menu item. All default NatTable menu items are now identifiable via ID, which are available as constants inPopupMenuBuilder. The following code creates a menu containing the debug menu item that is only visible for columns at column position > 1.Menu debugMenu = new PopupMenuBuilder(natTable) .withInspectLabelsMenuItem() .withEnabledState( PopupMenuBuilder.INSPECT_LABEL_MENU_ITEM_ID, new IMenuItemState() { @Override public boolean isActive(NatEventData natEventData) { return natEventData.getColumnPosition() > 1; } }) .build(); -
DisplayModeMouseEventMatcher
Introduced theDisplayModeMouseEventMatcherthat allows to register a UI binding for aDisplayMode. Using theDisplayModeMouseEventMatcherfor example allows to register different actions on performing a right click on a selected cell or a non selected cell. -
Tree - identification of tree column (index/position)
TheTreeLayeralways specifies the first column to be the tree column. It is now possible to specify whether the column index or the column position should be used to determine the tree column. The default is to use the column position, which means that reordering another column to become the first column in a grid, will make that column the tree column. Changing the behavior to use the column index for tree column determination, column reordering will lead to also reordering the tree column.
The following code will change the identification of the tree column from column position to column index:treeLayer.setUseTreeColumnIndex(true); -
Tree - expand to level
It is now possible to expand nodes in a tree to a certain level. For this theITreeRowModel.// expand all nodes to level 2 natTable.doCommand(new TreeExpandToLevelCommand(2)); // expand node at index 5 to level 2 natTable.doCommand(new TreeExpandToLevelCommand(5, 2)); -
Tree - expand/collapse by key
It is now possible to expand and collapse tree nodes via key interaction. For this theTreeExpandCollapseKeyActionwas introduced. On registering the defaultTreeLayerExpandCollapseKeyBindingsthis action will be bound to the space key. Note that the binding requires theSelectionLayerand theTreeLayerto work correctly.// adds the key bindings that allows pressing space bar to // expand/collapse tree nodes natTable.addConfiguration( new TreeLayerExpandCollapseKeyBindings( bodyLayerStack.getTreeLayer(), bodyLayerStack.getSelectionLayer())); -
GroupBy feature enhancements/corrections
There were numerous bug reports regarding the groupBy feature. They were mostly related to the usage of the wrongIDisplayConverteror the wrongComparator. To solve the issues regarding theIDisplayConverterissues, theGroupByDisplayConverterwas introduced. It is registered by default viaGroupByDataLayerConfiguration. If you are not using the default configuration, you need to ensure to register it in your custom configuration in order to solve the converter issues.To solve the issues related to sorting, it is necessary to enrich the
GroupByDataLayerwith additional information. TheISortModelis needed to retrieve the correctComparator, theTreeLayeris needed to be able to determine the tree column in order to be able to sort the tree nodes, and theGroupByDataLayerreference is needed to be able to sort by summary values. The necessary references can be set using the newly introduced initialize method.// connect ISortModel, TreeLayer and GroupByDataLayer to the // Comparator to support sorting by groupBy summary values bodyLayerStack.getBodyDataLayer().initializeTreeComparator( sortHeaderLayer.getSortModel(), bodyLayerStack.getTreeLayer(), true);This is also the reason for the API change in
ISortModel. -
Excel Export - Exporter configuration
It is now possible to configure the charset and the sheet name to use when exporting a NatTable using the coreExcelExporter. The following code will for example register anExcelExporterthat exports a NatTable in UTF-8, setting the sheet name of the Excel sheet to My data.ExcelExporter exporter = new ExcelExporter(); exporter.setCharset("UTF-8"); exporter.setSheetname("My data"); configRegistry.registerConfigAttribute( ExportConfigAttributes.EXPORTER, exporter);The
PoiExcelExporterin the Apache POI extension now also allows to set the sheet name. -
The
CalculatedValueCache, that is internally used for the calculation and caching of summary values, is now using theConcurrentHashMapto avoid concurrency issues related to the usage ofHashMap. See here for a more detailed description on that issue.