Michael
Michael

Reputation: 4351

Resize every column header to the maximum content size - NatTable

I have a VerticalTextPainter for my column headers.

I would like to set the column header height to the maximum of all column heights.

If I set setCalculateByTextHeight(true) and setCalculateByTextLength(true) it will resize the columns as I scroll to the maximum of what is currently displayed. Instead I would like it to resize to the maximum of all columns and allow the user to change the widths/heights after.

Is it possible to get the maximum height of all column headers?

Update I've tried removing calculating using text height/lengths and adding InitializeAutoResizeColumnsCommand. This makes the column header height be very small and only show "...".

this is the NatTable.

for (int i = 0; i < getColumnCount(); i++) {
    InitializeAutoResizeColumnsCommand columnCommand = new InitializeAutoResizeColumnsCommand(this, i,
        getConfigRegistry(), new GCFactory(this));
    doCommand(columnCommand);
}

for (int i = 0; i < getRowCount(); i++) {
    InitializeAutoResizeRowsCommand rowCommand = new InitializeAutoResizeRowsCommand(this, i,
        getConfigRegistry(), new GCFactory(this));
    doCommand(rowCommand);
}

Full Example (With a composite layer for columns)

I've created an example with a VerticalTextPainter for the column headers. I added a listener to resize the columns when the table is first painted.

import org.eclipse.nebula.widgets.nattable.NatTable;
import org.eclipse.nebula.widgets.nattable.config.AbstractRegistryConfiguration;
import org.eclipse.nebula.widgets.nattable.config.CellConfigAttributes;
import org.eclipse.nebula.widgets.nattable.config.ConfigRegistry;
import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry;
import org.eclipse.nebula.widgets.nattable.data.IDataProvider;
import org.eclipse.nebula.widgets.nattable.data.convert.DefaultDisplayConverter;
import org.eclipse.nebula.widgets.nattable.grid.GridRegion;
import org.eclipse.nebula.widgets.nattable.grid.data.DefaultColumnHeaderDataProvider;
import org.eclipse.nebula.widgets.nattable.grid.data.DefaultCornerDataProvider;
import org.eclipse.nebula.widgets.nattable.grid.data.DefaultRowHeaderDataProvider;
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.CompositeLayer;
import org.eclipse.nebula.widgets.nattable.layer.DataLayer;
import org.eclipse.nebula.widgets.nattable.layer.LabelStack;
import org.eclipse.nebula.widgets.nattable.layer.cell.IConfigLabelAccumulator;
import org.eclipse.nebula.widgets.nattable.painter.cell.CellPainterWrapper;
import org.eclipse.nebula.widgets.nattable.painter.cell.ICellPainter;
import org.eclipse.nebula.widgets.nattable.painter.cell.TextPainter;
import org.eclipse.nebula.widgets.nattable.painter.cell.VerticalTextPainter;
import org.eclipse.nebula.widgets.nattable.painter.cell.decorator.CustomLineBorderDecorator;
import org.eclipse.nebula.widgets.nattable.painter.cell.decorator.LineBorderDecorator;
import org.eclipse.nebula.widgets.nattable.painter.cell.decorator.PaddingDecorator;
import org.eclipse.nebula.widgets.nattable.reorder.ColumnReorderLayer;
import org.eclipse.nebula.widgets.nattable.resize.MaxCellBoundsHelper;
import org.eclipse.nebula.widgets.nattable.resize.command.MultiRowResizeCommand;
import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer;
import org.eclipse.nebula.widgets.nattable.style.BorderStyle;
import org.eclipse.nebula.widgets.nattable.style.CellStyleAttributes;
import org.eclipse.nebula.widgets.nattable.style.DisplayMode;
import org.eclipse.nebula.widgets.nattable.style.HorizontalAlignmentEnum;
import org.eclipse.nebula.widgets.nattable.style.Style;
import org.eclipse.nebula.widgets.nattable.style.VerticalAlignmentEnum;
import org.eclipse.nebula.widgets.nattable.util.GCFactory;
import org.eclipse.nebula.widgets.nattable.util.GUIHelper;
import org.eclipse.nebula.widgets.nattable.viewport.ViewportLayer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;

public class ExampleNatTable {

    private BodyLayerStack bodyLayer;
    private int statusColumn;
    private int statusRejected;
    private int statusInProgress;
    private boolean check = false;
    private NatTable nattable;
    private String[] summaryProperties;
    private String[] properties;
    private static final String FOO_LABEL = "FOO";
    private static final String CELL_LABEL = "Cell_LABEL";

    public static void main(String[] args) {
        new ExampleNatTable();
    }

    public ExampleNatTable() {

        Display display = new Display();
        Shell shell = new Shell(display);
        shell.setLayout(new FillLayout());

        summaryProperties = new String[3];

        for (int i = 0; i < summaryProperties.length; i++) {

            summaryProperties[i] = "s" + i;
        }

        properties = new String[3];

        for (int i = 0; i < properties.length; i++) {

            properties[i] = "Column" + i;
        }

        // Setting the data layout layer
        GridData gridData = new GridData();
        gridData.heightHint = 1;
        gridData.widthHint = 1;

        IConfigRegistry configRegistry = new ConfigRegistry();

        // Body Data Provider
        IDataProvider dataProvider = new DataProvider(properties.length, 55);
        bodyLayer = new BodyLayerStack(dataProvider);
        // datalayer.addConfiguration(new

        // Column Data Provider
        DefaultColumnHeaderDataProvider columnSummaryData = new DefaultColumnHeaderDataProvider(summaryProperties);
        DefaultColumnHeaderDataProvider columnData = new DefaultColumnHeaderDataProvider(properties);
        ColumnHeaderLayerStack columnSummaryLayer = new ColumnHeaderLayerStack(columnSummaryData);
        ColumnHeaderLayerStack columnlayer = new ColumnHeaderLayerStack(columnData);

        /**
         * Composite layer
         */
        final CompositeLayer columnCompositeLayer = new CompositeLayer(1, 2);
        columnCompositeLayer.setChildLayer("SUMMARY_REGION", columnSummaryLayer, 0, 0);
        columnCompositeLayer.setChildLayer("COLUMNS", columnlayer, 0, 1);

        // Row Data Provider
        DefaultRowHeaderDataProvider rowdata = new DefaultRowHeaderDataProvider(dataProvider);
        RowHeaderLayerStack rowlayer = new RowHeaderLayerStack(rowdata);

        // Corner Data Provider
        DefaultCornerDataProvider cornerdata = new DefaultCornerDataProvider(columnData, rowdata);
        DataLayer cornerDataLayer = new DataLayer(cornerdata);
        CornerLayer cornerLayer = new CornerLayer(cornerDataLayer, rowlayer, columnCompositeLayer);

        GridLayer gridlayer = new GridLayer(bodyLayer, columnCompositeLayer, rowlayer, cornerLayer);
        nattable = new NatTable(shell, gridlayer, false);

        // Change for paint
        IConfigLabelAccumulator cellLabelAccumulator = new IConfigLabelAccumulator() {
            // @Override
            @Override
            public void accumulateConfigLabels(LabelStack configLabels, int columnPosition, int rowPosition) {

                int columnIndex = bodyLayer.getColumnIndexByPosition(columnPosition);
                int rowIndex = bodyLayer.getRowIndexByPosition(rowPosition);
                if (columnIndex == 2 && rowIndex == 45) {
                    configLabels.addLabel(FOO_LABEL);
                } else if ((columnIndex == statusColumn) && (rowIndex == statusRejected) && (check == true)) {
                    configLabels.addLabel(CELL_LABEL);
                }
            }
        };
        bodyLayer.setConfigLabelAccumulator(cellLabelAccumulator);

        // nattable.addConfiguration(new DefaultNatTableStyleConfiguration());
        nattable.addConfiguration(new AbstractRegistryConfiguration() {
            // @Override
            @Override
            public void configureRegistry(IConfigRegistry configRegistry) {

                /**
                 * Column Header
                 */
                final Style columnHeaderStyle = new Style();

                columnHeaderStyle.setAttributeValue(CellStyleAttributes.VERTICAL_ALIGNMENT,
                    VerticalAlignmentEnum.BOTTOM);

                columnHeaderStyle.setAttributeValue(CellStyleAttributes.HORIZONTAL_ALIGNMENT,
                    HorizontalAlignmentEnum.CENTER);

                configRegistry.registerConfigAttribute(CellConfigAttributes.CELL_STYLE, columnHeaderStyle,
                    DisplayMode.NORMAL, GridRegion.COLUMN_HEADER);

                final VerticalTextPainter columnHeaderPainter = new VerticalTextPainter(false, true, false);

                Display display = Display.getCurrent();
                Color blue = display.getSystemColor(SWT.COLOR_BLUE);

                final CellPainterWrapper columnHeaderDecorator = new CustomLineBorderDecorator(
                    new PaddingDecorator(columnHeaderPainter, 3, 0, 3, 0),
                    new BorderStyle(1, blue, BorderStyle.LineStyleEnum.SOLID));

                configRegistry.registerConfigAttribute(CellConfigAttributes.CELL_PAINTER, columnHeaderDecorator,
                    DisplayMode.NORMAL, GridRegion.COLUMN_HEADER);

                /**
                 * Cells
                 */
                final Color bgColor = GUIHelper.COLOR_WHITE;
                final Color fgColor = GUIHelper.COLOR_BLACK;
                final Color gradientBgColor = GUIHelper.COLOR_WHITE;
                final Color gradientFgColor = GUIHelper.getColor(136, 212, 215);
                final Font font = GUIHelper.DEFAULT_FONT;
                final HorizontalAlignmentEnum hAlign = HorizontalAlignmentEnum.CENTER;
                final VerticalAlignmentEnum vAlign = VerticalAlignmentEnum.MIDDLE;
                final BorderStyle borderStyle = null;
                final ICellPainter cellPainter = new LineBorderDecorator(new TextPainter(false, true, 5, true));

                configRegistry.registerConfigAttribute(CellConfigAttributes.CELL_PAINTER, cellPainter);

                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.FONT, font);
                cellStyle.setAttributeValue(CellStyleAttributes.HORIZONTAL_ALIGNMENT, hAlign);
                cellStyle.setAttributeValue(CellStyleAttributes.VERTICAL_ALIGNMENT, vAlign);
                cellStyle.setAttributeValue(CellStyleAttributes.BORDER_STYLE, borderStyle);

                configRegistry.registerConfigAttribute(CellConfigAttributes.CELL_STYLE, cellStyle);

                configRegistry.registerConfigAttribute(CellConfigAttributes.DISPLAY_CONVERTER,
                    new DefaultDisplayConverter());
            }
        });

        nattable.setLayoutData(gridData);
        nattable.setConfigRegistry(configRegistry);
        nattable.configure();

        nattable.addListener(SWT.Paint, new Listener() {
            boolean resized = false;

            @Override
            public void handleEvent(Event arg0) {
                if (resized) {
                    return;
                }
                resized = true;

                int[] gridRowHeights = MaxCellBoundsHelper.getPreferredRowHeights(nattable.getConfigRegistry(),
                    new GCFactory(nattable), nattable, new int[] {
                        0
                    });

                if (gridRowHeights != null) {
                    nattable.doCommand(new MultiRowResizeCommand(nattable, new int[] {
                        0
                    }, gridRowHeights));
                    nattable.doCommand(new MultiRowResizeCommand(columnlayer, new int[] {
                        0
                    }, gridRowHeights));
                }
            }
        });

        shell.open();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch())
                display.sleep();
        }
        display.dispose();

    }

    public class DataProvider extends DummyBodyDataProvider {

        public DataProvider(int columnCount, int rowCount) {
            super(columnCount, rowCount);
        }

        @Override
        public int getColumnCount() {
            return properties.length;
        }

        @Override
        public Object getDataValue(int columnIndex, int rowIndex) {

            return new String("" + columnIndex + ":" + rowIndex);

        }

        @Override
        public int getRowCount() {
            return 55;
        }

        @Override
        public void setDataValue(int arg0, int arg1, Object arg2) {

        }
    }

    public class BodyLayerStack extends AbstractLayerTransform {

        private SelectionLayer selectionLayer;

        public BodyLayerStack(IDataProvider dataProvider) {
            DataLayer bodyDataLayer = new DataLayer(dataProvider);
            ColumnReorderLayer columnReorderLayer = new ColumnReorderLayer(bodyDataLayer);
            ColumnHideShowLayer columnHideShowLayer = new ColumnHideShowLayer(columnReorderLayer);
            this.selectionLayer = new SelectionLayer(columnHideShowLayer);
            ViewportLayer viewportLayer = new ViewportLayer(this.selectionLayer);
            setUnderlyingLayer(viewportLayer);
        }

        public SelectionLayer getSelectionLayer() {
            return this.selectionLayer;
        }
    }

    public class ColumnHeaderLayerStack extends AbstractLayerTransform {

        public ColumnHeaderLayerStack(IDataProvider dataProvider) {
            DataLayer dataLayer = new DataLayer(dataProvider);
            ColumnHeaderLayer colHeaderLayer = new ColumnHeaderLayer(dataLayer, ExampleNatTable.this.bodyLayer,
                ExampleNatTable.this.bodyLayer.getSelectionLayer());
            setUnderlyingLayer(colHeaderLayer);
        }
    }

    public class RowHeaderLayerStack extends AbstractLayerTransform {

        public RowHeaderLayerStack(IDataProvider dataProvider) {
            DataLayer dataLayer = new DataLayer(dataProvider, 50, 20);
            RowHeaderLayer rowHeaderLayer = new RowHeaderLayer(dataLayer, ExampleNatTable.this.bodyLayer,
                ExampleNatTable.this.bodyLayer.getSelectionLayer());
            setUnderlyingLayer(rowHeaderLayer);
        }
    }
}

Upvotes: 1

Views: 755

Answers (1)

Dirk Fauth
Dirk Fauth

Reputation: 4231

It sounds like you need an initial auto resize instead of the automatic size configuration.

Have a look at our FAQ section how you can trigger an auto resize. Then of course you need to disable the painter calculate mechanism.

https://www.eclipse.org/nattable/documentation.php?page=faq

For the column header the described mechanism does not work, as the InitializeAutoResizeRowsCommandHandler is registered on the SelectionLayer and for the column header there is no SelectionLayer.

With the 1.6 API you could simply execute this to auto resize the column header row:

this.nattable.doCommand(new AutoResizeRowsCommand(this.nattable, 0));

With an older API you will need to copy the implementation code, as there is no way to avoid the position transformation, and therefore things won't work:

int[] gridRowHeights = MaxCellBoundsHelper.getPreferredRowHeights(
        this.nattable.getConfigRegistry(),
        new GCFactory(this.nattable),
        this.nattable,
        new int[] { 0 });

if (gridRowHeights != null) {
    this.nattable.doCommand(
        new MultiRowResizeCommand(this.nattable, new int[] { 0 }, gridRowHeights, true));
}

In a composition the solution for versions < 1.6 the resize command needs to be calculated and triggered for each row, as the command needs to be transported to the lowest layer in the stack. For the above example it should look like this:

int[] gridRowHeights1 = MaxCellBoundsHelper.getPreferredRowHeights(
        ExampleNatTable.this.nattable.getConfigRegistry(),
        new GCFactory(ExampleNatTable.this.nattable),
        ExampleNatTable.this.nattable,
        new int[] { 0 });
int[] gridRowHeights2 = MaxCellBoundsHelper.getPreferredRowHeights(
        ExampleNatTable.this.nattable.getConfigRegistry(),
        new GCFactory(ExampleNatTable.this.nattable),
        ExampleNatTable.this.nattable,
        new int[] { 1 });

if (gridRowHeights1 != null) {
    ExampleNatTable.this.nattable.doCommand(
            new MultiRowResizeCommand(
                    ExampleNatTable.this.nattable,
                    new int[] { 0 },
                    gridRowHeights1));
}
if (gridRowHeights2 != null) {
    ExampleNatTable.this.nattable.doCommand(
            new MultiRowResizeCommand(
                    ExampleNatTable.this.nattable,
                    new int[] { 1 },
                    gridRowHeights2));
}

Upvotes: 3

Related Questions