Package org.eclipse.nebula.widgets.nattable.group

Source Code of org.eclipse.nebula.widgets.nattable.group.ColumnGroupHeaderLayer

/*******************************************************************************
* Copyright (c) 2012, 2013 Original authors and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     Original authors and others - initial API and implementation
******************************************************************************/
package org.eclipse.nebula.widgets.nattable.group;

import java.util.List;
import java.util.Properties;

import org.eclipse.nebula.widgets.nattable.NatTable;
import org.eclipse.nebula.widgets.nattable.grid.GridRegion;
import org.eclipse.nebula.widgets.nattable.group.ColumnGroupModel.ColumnGroup;
import org.eclipse.nebula.widgets.nattable.group.command.ColumnGroupsCommandHandler;
import org.eclipse.nebula.widgets.nattable.group.config.DefaultColumnGroupHeaderLayerConfiguration;
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.LabelStack;
import org.eclipse.nebula.widgets.nattable.layer.SizeConfig;
import org.eclipse.nebula.widgets.nattable.layer.cell.ILayerCell;
import org.eclipse.nebula.widgets.nattable.layer.cell.LayerCell;
import org.eclipse.nebula.widgets.nattable.layer.cell.TransformedLayerCell;
import org.eclipse.nebula.widgets.nattable.layer.event.ColumnStructuralRefreshEvent;
import org.eclipse.nebula.widgets.nattable.layer.event.RowStructuralRefreshEvent;
import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer;
import org.eclipse.nebula.widgets.nattable.style.DisplayMode;

/**
* Adds the Column grouping functionality to the column headers. Also persists
* the state of the column groups when
* {@link NatTable#saveState(String, Properties)} is invoked.
*
* Internally uses the {@link ColumnGroupModel} to track the column groups. See
* ColumnGroupGridExample
*/
public class ColumnGroupHeaderLayer extends AbstractLayerTransform {

    private final SizeConfig rowHeightConfig = new SizeConfig(
            DataLayer.DEFAULT_ROW_HEIGHT);
    private final ColumnGroupModel model;
    private final ILayer columnHeaderLayer;

    /**
     * Flag which is used to tell the ColumnGroupHeaderLayer whether to
     * calculate the height of the layer dependent on column group configuration
     * or not. If it is set to <code>true</code> the column header will check if
     * column groups are configured and if not, the height of the column header
     * will not show the double height for showing column groups.
     */
    private boolean calculateHeight = false;

    /**
     * Listener that will fire a RowStructuralRefreshEvent in case the
     * ColumnGroupModel changes. Is only needed in case the dynamic height
     * calculation is enabled.
     */
    private IColumnGroupModelListener modelChangeListener;

    public ColumnGroupHeaderLayer(ILayer columnHeaderLayer,
            SelectionLayer selectionLayer, ColumnGroupModel columnGroupModel) {
        this(columnHeaderLayer, selectionLayer, columnGroupModel, true);
    }

    public ColumnGroupHeaderLayer(final ILayer columnHeaderLayer,
            SelectionLayer selectionLayer, ColumnGroupModel columnGroupModel,
            boolean useDefaultConfiguration) {
        super(columnHeaderLayer);

        this.columnHeaderLayer = columnHeaderLayer;
        this.model = columnGroupModel;

        registerCommandHandler(new ColumnGroupsCommandHandler(model,
                selectionLayer, this));

        if (useDefaultConfiguration) {
            addConfiguration(new DefaultColumnGroupHeaderLayerConfiguration(
                    columnGroupModel));
        }

        modelChangeListener = new IColumnGroupModelListener() {
            @Override
            public void columnGroupModelChanged() {
                fireLayerEvent(new RowStructuralRefreshEvent(columnHeaderLayer));
            }
        };

        this.model.registerColumnGroupModelListener(modelChangeListener);
    }

    // Persistence

    @Override
    public void saveState(String prefix, Properties properties) {
        super.saveState(prefix, properties);
        model.saveState(prefix, properties);
    }

    @Override
    public void loadState(String prefix, Properties properties) {
        super.loadState(prefix, properties);
        model.loadState(prefix, properties);
        fireLayerEvent(new ColumnStructuralRefreshEvent(this));
    }

    // Vertical features

    // Rows

    @Override
    public int getRowCount() {
        if (!calculateHeight
                || (this.model.getAllIndexesInGroups() != null && this.model
                        .getAllIndexesInGroups().size() > 0)) {
            return columnHeaderLayer.getRowCount() + 1;
        }
        return columnHeaderLayer.getRowCount();
    }

    @Override
    public int getPreferredRowCount() {
        return columnHeaderLayer.getPreferredRowCount() + 1;
    }

    @Override
    public int getRowIndexByPosition(int rowPosition) {
        if (rowPosition == 0) {
            return rowPosition;
        } else {
            return columnHeaderLayer.getRowIndexByPosition(rowPosition - 1);
        }
    }

    @Override
    public int localToUnderlyingRowPosition(int localRowPosition) {
        if (localRowPosition == 0) {
            return localRowPosition;
        }
        return localRowPosition - 1;
    }

    // Height

    @Override
    public int getHeight() {
        if (!calculateHeight
                || (this.model.getAllIndexesInGroups() != null && this.model
                        .getAllIndexesInGroups().size() > 0)) {
            return rowHeightConfig.getAggregateSize(1)
                    + columnHeaderLayer.getHeight();
        }
        return columnHeaderLayer.getHeight();
    }

    @Override
    public int getPreferredHeight() {
        return rowHeightConfig.getAggregateSize(1)
                + columnHeaderLayer.getPreferredHeight();
    }

    @Override
    public int getRowHeightByPosition(int rowPosition) {
        if (rowPosition == 0) {
            return rowHeightConfig.getSize(rowPosition);
        } else {
            return columnHeaderLayer.getRowHeightByPosition(rowPosition - 1);
        }
    }

    public void setRowHeight(int rowHeight) {
        this.rowHeightConfig.setSize(0, rowHeight);
    }

    // Row resize

    @Override
    public boolean isRowPositionResizable(int rowPosition) {
        if (rowPosition == 0) {
            return rowHeightConfig.isPositionResizable(rowPosition);
        } else {
            return columnHeaderLayer.isRowPositionResizable(rowPosition - 1);
        }
    }

    // Y

    @Override
    public int getRowPositionByY(int y) {
        int row0Height = getRowHeightByPosition(0);
        if (y < row0Height) {
            return 0;
        } else {
            return 1 + columnHeaderLayer.getRowPositionByY(y - row0Height);
        }
    }

    @Override
    public int getStartYOfRowPosition(int rowPosition) {
        if (rowPosition == 0) {
            return rowHeightConfig.getAggregateSize(rowPosition);
        } else {
            return getRowHeightByPosition(0)
                    + columnHeaderLayer.getStartYOfRowPosition(rowPosition - 1);
        }
    }

    // Cell features

    /**
     * If a cell belongs to a column group: column position - set to the start
     * position of the group span - set to the width/size of the column group
     *
     * NOTE: gc.setClip() is used in the CompositeLayerPainter to ensure that
     * partially visible Column group header cells are rendered properly.
     */
    @Override
    public ILayerCell getCellByPosition(int columnPosition, int rowPosition) {
        int bodyColumnIndex = getColumnIndexByPosition(columnPosition);

        // Column group header cell
        if (model.isPartOfAGroup(bodyColumnIndex)) {
            if (rowPosition == 0) {
                return new LayerCell(this,
                        getStartPositionOfGroup(columnPosition), rowPosition,
                        columnPosition, rowPosition,
                        getColumnSpan(columnPosition), 1);
            } else {
                return new LayerCell(this, columnPosition, rowPosition);
            }
        } else {
            // render column header w/ rowspan = 2
            // as in this case we ask the column header layer for the cell
            // position
            // and the column header layer asks his data provider for the row
            // count
            // which should always return 1, we ask for row position 0 instead
            // of
            // using getGroupHeaderRowPosition(), if we would use
            // getGroupHeaderRowPosition()
            // the ColumnGroupGroupHeaderLayer wouldn't work anymore
            ILayerCell cell = columnHeaderLayer.getCellByPosition(
                    columnPosition, 0);
            if (cell != null) {
                final int rowSpan;

                if (calculateHeight && model.size() == 0) {
                    rowSpan = 1;
                } else {
                    rowSpan = 2;
                }

                cell = new TransformedLayerCell(cell) {
                    @Override
                    public ILayer getLayer() {
                        return ColumnGroupHeaderLayer.this;
                    }

                    @Override
                    public int getRowSpan() {
                        return rowSpan;
                    }
                };
            }
            return cell;
        }
    }

    /**
     * Calculates the span of a cell in a Column Group. Takes into account
     * collapsing and hidden columns in the group.
     *
     * @param columnPosition
     *            position of any column belonging to the group
     */
    protected int getColumnSpan(int columnPosition) {
        int columnIndex = getColumnIndexByPosition(columnPosition);
        ColumnGroup columnGroup = model.getColumnGroupByIndex(columnIndex);

        int sizeOfGroup = columnGroup.getSize();

        if (columnGroup.isCollapsed()) {
            int sizeOfStaticColumns = columnGroup.getStaticColumnIndexes()
                    .size();
            if (sizeOfStaticColumns == 0) {
                return 1;
            } else {
                sizeOfGroup = sizeOfStaticColumns;
            }
        }

        int startPositionOfGroup = getStartPositionOfGroup(columnPosition);
        int endPositionOfGroup = startPositionOfGroup + sizeOfGroup;
        List<Integer> columnIndexesInGroup = columnGroup.getMembers();

        for (int i = startPositionOfGroup; i < endPositionOfGroup; i++) {
            int index = getColumnIndexByPosition(i);
            if (!columnIndexesInGroup.contains(Integer.valueOf(index))) {
                sizeOfGroup--;
            }
        }
        return sizeOfGroup;
    }

    /**
     * Figures out the start position of the group.
     *
     * @param selectionLayerColumnPosition
     *            of any column belonging to the group
     * @return first position of the column group
     */
    private int getStartPositionOfGroup(int columnPosition) {
        int bodyColumnIndex = getColumnIndexByPosition(columnPosition);
        ColumnGroup columnGroup = model.getColumnGroupByIndex(bodyColumnIndex);

        int leastPossibleStartPositionOfGroup = columnPosition
                - (columnGroup.getSize() - 1);
        int i = 0;
        for (i = leastPossibleStartPositionOfGroup; i < columnPosition; i++) {
            if (ColumnGroupUtils.isInTheSameGroup(getColumnIndexByPosition(i),
                    bodyColumnIndex, model)) {
                break;
            }
        }
        return i;
    }

    @Override
    public String getDisplayModeByPosition(int columnPosition, int rowPosition) {
        int columnIndex = getColumnIndexByPosition(columnPosition);
        if (rowPosition == 0 && model.isPartOfAGroup(columnIndex)) {
            return DisplayMode.NORMAL;
        } else {
            return columnHeaderLayer.getDisplayModeByPosition(columnPosition,
                    rowPosition);
        }
    }

    @Override
    public LabelStack getConfigLabelsByPosition(int columnPosition,
            int rowPosition) {
        int columnIndex = getColumnIndexByPosition(columnPosition);
        if (rowPosition == 0 && model.isPartOfAGroup(columnIndex)) {
            LabelStack stack = new LabelStack(GridRegion.COLUMN_GROUP_HEADER);

            if (model.isPartOfACollapseableGroup(columnIndex)) {
                ColumnGroup group = model.getColumnGroupByIndex(columnIndex);
                if (group.isCollapsed()) {
                    stack.addLabelOnTop(DefaultColumnGroupHeaderLayerConfiguration.GROUP_COLLAPSED_CONFIG_TYPE);
                } else {
                    stack.addLabelOnTop(DefaultColumnGroupHeaderLayerConfiguration.GROUP_EXPANDED_CONFIG_TYPE);
                }
            }

            return stack;
        } else {
            return columnHeaderLayer.getConfigLabelsByPosition(columnPosition,
                    rowPosition);
        }
    }

    @Override
    public Object getDataValueByPosition(int columnPosition, int rowPosition) {
        int columnIndex = getColumnIndexByPosition(columnPosition);
        if (rowPosition == 0 && model.isPartOfAGroup(columnIndex)) {
            return model.getColumnGroupByIndex(columnIndex).getName();
        } else {
            return columnHeaderLayer.getDataValueByPosition(columnPosition, 0);
        }
    }

    @Override
    public LabelStack getRegionLabelsByXY(int x, int y) {
        int columnIndex = getColumnIndexByPosition(getColumnPositionByX(x));
        if (model.isPartOfAGroup(columnIndex) && y < getRowHeightByPosition(0)) {
            return new LabelStack(GridRegion.COLUMN_GROUP_HEADER);
        } else {
            return columnHeaderLayer.getRegionLabelsByXY(x, y
                    - getRowHeightByPosition(0));
        }
    }

    // ColumnGroupModel delegates

    public void addColumnsIndexesToGroup(String colGroupName, int... colIndexes) {
        model.addColumnsIndexesToGroup(colGroupName, colIndexes);
    }

    public void clearAllGroups() {
        model.clear();
    }

    public void setStaticColumnIndexesByGroup(String colGroupName,
            int... staticColumnIndexes) {
        model.setStaticColumnIndexesByGroup(colGroupName, staticColumnIndexes);
    }

    public boolean isColumnInGroup(int bodyColumnIndex) {
        return model.isPartOfAGroup(bodyColumnIndex);
    }

    /**
     * @see ColumnGroup#setUnbreakable(boolean)
     */
    public void setGroupUnbreakable(int columnIndex) {
        ColumnGroup columnGroup = model.getColumnGroupByIndex(columnIndex);
        columnGroup.setUnbreakable(true);
    }

    public void setGroupAsCollapsed(int columnIndex) {
        ColumnGroup columnGroup = model.getColumnGroupByIndex(columnIndex);
        columnGroup.setCollapsed(true);
    }

    public boolean isCalculateHeight() {
        return calculateHeight;
    }

    public void setCalculateHeight(boolean calculateHeight) {
        this.calculateHeight = calculateHeight;

        if (calculateHeight) {
            this.model.registerColumnGroupModelListener(modelChangeListener);
        } else {
            this.model.unregisterColumnGroupModelListener(modelChangeListener);
        }
    }

}
TOP

Related Classes of org.eclipse.nebula.widgets.nattable.group.ColumnGroupHeaderLayer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.