nattable

Auto resize row heights while sorting or filtering


I can not handle auto row heights resizing. I tried to use AutomaticRowHeightExample, but without success.

Another inspiration was this question, but also did not worked (see my code example). If I sort/filter, in console output I can see numbers of painted rows i while creating PaintListener, but row heights are not updated.

Creating table:

public class NatTableFactory {
  
  // another code

  private NatTable createTable(Composite parent, List<TableLine> tLines, String[][] propertyNames,
      PropertyToLabels[] propToLabels, TableParams params, TextMatcherEditor<TableLine>editor, boolean openableParts) {
    
    BodyLayerStack bodyLayerStack =
        new BodyLayerStack(
                tLines,
                tLines.get(0).getLength(),
                params.getColumnIndicesForRowHeaders());
    
    DataLayer bodyDataLayer = bodyLayerStack.getBodyDataLayer();
    Integer[] rowHeights = getRowHeights(params);
    if( rowHeights != null && rowHeights.length > 0 ) {
      for( int i = 0; i < rowHeights.length; i++ ) {
        if( rowHeights[i] != null )
          bodyDataLayer.setRowHeightByPosition(i, (int) (rowHeights[i] * ApplicationSizeManager.getRowSizeCoefficient()));
      }
    }
    Integer[] colWidths = getColumnWidths(params);
    if( colWidths != null && colWidths.length > 0 ) {
      for( int i = 0; i < colWidths.length; i++ )
        if( colWidths[i] != null )
          bodyDataLayer.setColumnWidthByPosition(i, colWidths[i]);
    }

    DataLayer columnHeaderDataLayer = null;
    if( propertyNames != null ) {
      IDataProvider columnHeaderDataProvider = 
          new DefaultColumnHeaderDataProvider(propertyNames[0], propToLabels[0].getPropertyToLabels());
      columnHeaderDataLayer =
          new DefaultColumnHeaderDataLayer(columnHeaderDataProvider);
    }

    //copy command: include table headers
    bodyLayerStack.registerCommandHandler(new CustomCopyDataCommandHandler(bodyLayerStack.getSelectionLayer(), columnHeaderDataLayer, null, params.getColumnHeaderGroups()));

    CompositeLayer composite = null;
    if( propertyNames != null ) {
      ColumnHeaderLayer columnHeaderLayer =
          new ColumnHeaderLayer(
              columnHeaderDataLayer,
              bodyLayerStack,
              (SelectionLayer)null);
      columnHeaderLayer.addConfiguration(NatTableLayerConfigurations.getColumnHeaderLayerConfiguration(false));

      SortHeaderLayer<TableLine> sortHeaderLayer =
          new SortHeaderLayer<TableLine>(
              columnHeaderLayer,
              new GlazedListsSortModel<TableLine>(
                  bodyLayerStack.getSortedList(),
                  getSortingColumnPropAccessor(propertyNames[0]),
                  configRegistry,
                  columnHeaderDataLayer));

      Integer[] hrHeights = params.getHeaderRowHeights();
      if( hrHeights != null && hrHeights.length > 0 )
        columnHeaderDataLayer.setRowHeightByPosition(0, (int) (hrHeights[0] * ApplicationSizeManager.getRowSizeCoefficient()));
      
      composite = new CompositeLayer(1, 2);
      composite.setChildLayer(GridRegion.COLUMN_HEADER, sortHeaderLayer, 0, 0);
      composite.setChildLayer(GridRegion.BODY, bodyLayerStack, 0, 1);
    } else {
      composite = new CompositeLayer(1, 1);
      composite.setChildLayer(GridRegion.BODY, bodyLayerStack, 0, 0);
    }
    
    composite.addConfiguration(NatTableLayerConfigurations.getCompoositeLayerConfiguration());
    
    NatTable natTable = new NatTable(parent, composite, false);
    
    if( params.getAutoFitColWidthIndices().size() > 0 )
      registerAutoResizeColCmdHandler(natTable, composite, bodyLayerStack, params.getAutoFitColWidthIndices());
    
    // register AutoResizeRowCommandHandler
    // something wrong here?
    
    registerAutoResizeRowCommandHandler(natTable, composite, bodyLayerStack, params.getAutoFitColWidthIndices());
    
    setNatTableContentTooltip(natTable);
    
    natTable.setConfigRegistry(configRegistry);
   
    natTable.addConfiguration(new SingleClickSortConfiguration());
    
    if(columnHeaderDataLayer!=null)
      natTable.addConfiguration(NatTableLayerConfigurations.getCustomComparatorConfiguration(columnHeaderDataLayer));
    
    natTable.addConfiguration(new DefaultNatTableStyleConfiguration());

    setNatTableContextMenu(natTable, openableParts);
    
    natTable.addConfiguration(NatTableLayerConfigurations.getNatTableConfiguration());
    
    //
    /*
    natTable.addConfiguration(new DefaultNatTableStyleConfiguration()
    {
      {
        cellPainter = new LineBorderDecorator(new AutomaticRowHeightTextPainter(5));
      }
    });*/
   
    natTable.configure();

    editor.setFilterator(new TextFilterator<TableLine>() {

      @Override
      public void getFilterStrings(List<String> baseList, TableLine element) {
        for( int i = 0; i < element.getLength(); i++ )
          baseList.add("" + element.getObjectByColumnForFilter(i));
      }
    });
    editor.setMode(TextMatcherEditor.REGULAR_EXPRESSION);
    bodyLayerStack.getFilterList().setMatcherEditor(editor);

    NatTableContentProvider.addNatTableData(natTable, bodyLayerStack.getSelectionLayer(), bodyLayerStack.getBodyDataProvider());
    
    return natTable;
  }
  
  // another code
}

register AutoResizeRowCommandHandler:

// in class NatTableFactory
private void registerAutoResizeRowCommandHandler(NatTable natTable, ILayer commandLayer, ILayer positionLayer, List<Integer> colPositions)
{
  natTable.registerCommandHandler(new AutoResizeRowCommandHandler(commandLayer, positionLayer));
  PaintListener listener = new PaintListener()
  {
    @Override
    public void paintControl(PaintEvent e)
    {
      System.out.println("paintControl");
      for (int i = 0; i < natTable.getRowCount(); i++)
      {
        System.out.println(i);
        InitializeAutoResizeRowsCommand rowCommand = new InitializeAutoResizeRowsCommand(natTable, i, natTable.getConfigRegistry(), new GCFactory(
              natTable));
        AutoResizeRowsCommand command = new AutoResizeRowsCommand(rowCommand);
        natTable.doCommand(command);
      }
    }
  };
  natTable.addPaintListener(listener);
}

BodyLayerStack:

public BodyLayerStack(List<TableLine> values, int columnCount, Integer[] columnIndicesForRowHeaders)
  {
    EventList<TableLine> eventList = GlazedLists.eventList(values);
    TransformedList<TableLine, TableLine> rowObjectsGlazedList = GlazedLists.threadSafeList(eventList);

    // this.filterList = new FilterList<>(rowObjectsGlazedList); //changed to:
    // use the SortedList constructor with 'null' for the Comparator
    // because the Comparator will be set by configuration
    sortedList = new SortedList<>(rowObjectsGlazedList, null);
    // wrap the SortedList with the FilterList
    filterList = new FilterList<>(sortedList);
    
    bodyDataProvider = new ListDataProvider<TableLine>(filterList, getColumnAccessor(columnCount));
    bodyDataLayer = new DataLayer(bodyDataProvider);

    IConfigLabelAccumulator cellLabelAccumulator = new IConfigLabelAccumulator() {
      
      @Override
      public void accumulateConfigLabels(LabelStack configLabels, int columnPosition, int rowPosition) {
        int columnIndex = bodyDataLayer.getColumnIndexByPosition(columnPosition);
        int rowIndex = bodyDataLayer.getRowIndexByPosition(rowPosition);

        if(isRowHeader(columnIndicesForRowHeaders, columnIndex)) 
          configLabels.addLabel(NatTableFactory.RowHeaderLabel);
        else
        {
          // get dataTypes at actual positions and add/refresh labels
          String label = filterList.get(rowIndex).getObjectTypeByColumn(columnIndex);
          // adjust label according to autoFitWitdh option
          if(filterList.get(rowIndex).isAutoFitColWidth(columnIndex))
            label += "_" + NatTableFactory.AutoFitWidthLabel;
          else
            label += "_" + NatTableFactory.NoAutoFitWidthLabel; 
          configLabels.addLabel(label);
        }
      }
    };
    bodyDataLayer.setConfigLabelAccumulator(cellLabelAccumulator);

    GlazedListsEventLayer<TableLine> glazedListsEventLayer = new GlazedListsEventLayer<>(bodyDataLayer, filterList);
    
    selectionLayer = new SelectionLayer(glazedListsEventLayer, false);
    selectionLayer.setSelectionModel(getSelectionModel());
    selectionLayer.addConfiguration(getSelectionConfiguration());
    //
    viewportLayer = new ViewportLayer(selectionLayer);
    setUnderlyingLayer(new ViewportLayer(selectionLayer));

  }

If I call natTable.doCommand(rowCommand) instead of natTable.doCommand(command) while registering handler, row heights are updated correctly, but table is painted repetitively, scroll bar blinks all the time.

I tried also:

private void registerAutoResizeRowCommandHandler(NatTable natTable, ILayer commandLayer, ILayer positionLayer, List<Integer> colPositions)
  {
    natTable.registerCommandHandler(new AutoResizeRowCommandHandler(commandLayer, positionLayer));
    BodyLayerStack bodyLayerStack = (BodyLayerStack) positionLayer;
    natTable.addPaintListener(
        new AutoResizeRowPaintListener(
            natTable, 
            bodyLayerStack.getViewportLayer(), 
            bodyLayerStack.getBodyDataLayer()));
  }

Any idea what did I miss?


Solution

  • I have got it:

    in NatTableFactory:

    private NatTable createTable(Composite parent, List<TableLine> tLines, String[][] propertyNames,
      PropertyToLabels[] propToLabels, TableParams params, TextMatcherEditor<TableLine>editor, 
      boolean openableParts) 
    {
      // another code
      registerAutoResizeRowCommandHandler(natTable, composite, bodyLayerStack);
      //another code
      return natTable;
    }
    

    and:

    private void registerAutoResizeRowCommandHandler(NatTable natTable, 
      CompositeLayer commandLayer, BodyLayerStack bodyLayerStack)
    {
      natTable.registerCommandHandler(new AutoResizeRowCommandHandler(commandLayer, bodyLayerStack));
    
      natTable.addPaintListener(
        new AutoResizeRowPaintListener(
            natTable, 
            bodyLayerStack.getViewportLayer(), 
            bodyLayerStack.getBodyDataLayer()));
    
    }
    

    My mistake was in BodyLayerStack:

    viewportLayer = new ViewportLayer(selectionLayer);
    setUnderlyingLayer(new ViewportLayer(selectionLayer));
    

    correct is:

    viewportLayer = new ViewportLayer(selectionLayer);
    setUnderlyingLayer(viewportLayer);
    

    Thanks Dirk Fauth!