Package org.eclipse.nebula.widgets.nattable.painter.layer

Source Code of org.eclipse.nebula.widgets.nattable.painter.layer.CellLayerPainter

/*******************************************************************************
* 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.painter.layer;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry;
import org.eclipse.nebula.widgets.nattable.layer.ILayer;
import org.eclipse.nebula.widgets.nattable.layer.cell.ILayerCell;
import org.eclipse.nebula.widgets.nattable.painter.cell.ICellPainter;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Rectangle;

public class CellLayerPainter implements ILayerPainter {

    private ILayer natLayer;
    private Map<Integer, Integer> horizontalPositionToPixelMap;
    private Map<Integer, Integer> verticalPositionToPixelMap;

    private final boolean clipLeft;
    private final boolean clipTop;

    /**
     * Create a default CellLayerPainter with default clipping behaviour.
     */
    public CellLayerPainter() {
        this(false, false);
    }

    /**
     * Create a CellLayerPainter with specified clipping behaviour.
     *
     * @param clipLeft
     *            Configure the rendering behaviour when cells overlap. If set
     *            to <code>true</code> the left cell will be clipped, if set to
     *            <code>false</code> the right cell will be clipped. The default
     *            value is <code>false</code>.
     * @param clipTop
     *            Configure the rendering behaviour when cells overlap. If set
     *            to <code>true</code> the top cell will be clipped, if set to
     *            <code>false</code> the bottom cell will be clipped. The
     *            default value is <code>false</code>.
     */
    public CellLayerPainter(boolean clipLeft, boolean clipTop) {
        this.clipLeft = clipLeft;
        this.clipTop = clipTop;
    }

    @Override
    public void paintLayer(ILayer natLayer, GC gc, int xOffset, int yOffset,
            Rectangle pixelRectangle, IConfigRegistry configRegistry) {
        if (pixelRectangle.width <= 0 || pixelRectangle.height <= 0) {
            return;
        }

        this.natLayer = natLayer;
        Rectangle positionRectangle = getPositionRectangleFromPixelRectangle(
                natLayer, pixelRectangle);

        calculateDimensionInfo(positionRectangle);

        Collection<ILayerCell> spannedCells = new HashSet<ILayerCell>();

        for (int columnPosition = positionRectangle.x; columnPosition < positionRectangle.x
                + positionRectangle.width; columnPosition++) {
            for (int rowPosition = positionRectangle.y; rowPosition < positionRectangle.y
                    + positionRectangle.height; rowPosition++) {
                if (columnPosition == -1 || rowPosition == -1) {
                    continue;
                }
                ILayerCell cell = natLayer.getCellByPosition(columnPosition,
                        rowPosition);
                if (cell != null) {
                    if (cell.isSpannedCell()) {
                        spannedCells.add(cell);
                    } else {
                        paintCell(cell, gc, configRegistry);
                    }
                }
            }
        }

        for (ILayerCell cell : spannedCells) {
            paintCell(cell, gc, configRegistry);
        }
    }

    /**
     * Determines the rendering behavior when two cells overlap. If
     * <code>true</code>, the left cell will be clipped. If <code>false</code>,
     * the right cell will be clipped. Typically this value is changed in
     * conjunction with split viewports.
     *
     * @param position
     *            The column position for which the clipping behaviour is
     *            requested. By default for all columns the same clipping
     *            behaviour is used. Only for special cases like split viewports
     *            with one header, per position a different behaviour may be
     *            needed.
     */
    protected boolean isClipLeft(int position) {
        return this.clipLeft;
    }

    /**
     * Determines the rendering behavior when two cells overlap. If
     * <code>true</code>, the top cell will be clipped. If <code>false</code>,
     * the bottom cell will be clipped. Typically this value is changed in
     * conjunction with split viewports.
     *
     * @param position
     *            The row position for which the clipping behaviour is
     *            requested. By default for all rows the same clipping behaviour
     *            is used. Only for special cases like split viewports with one
     *            header, per position a different behaviour may be needed.
     */
    protected boolean isClipTop(int position) {
        return this.clipTop;
    }

    private void calculateDimensionInfo(Rectangle positionRectangle) {
        {
            horizontalPositionToPixelMap = new HashMap<Integer, Integer>();
            final int startPosition = positionRectangle.x;
            final int endPosition = startPosition + positionRectangle.width;
            int previousEndX = (startPosition > 0) ? natLayer
                    .getStartXOfColumnPosition(startPosition - 1)
                    + natLayer.getColumnWidthByPosition(startPosition - 1)
                    : Integer.MIN_VALUE;
            for (int position = startPosition; position < endPosition; position++) {
                int startX = natLayer.getStartXOfColumnPosition(position);
                horizontalPositionToPixelMap.put(
                        position,
                        isClipLeft(position) ? startX : Math.max(startX,
                                previousEndX));
                previousEndX = startX
                        + natLayer.getColumnWidthByPosition(position);
            }
            if (endPosition < natLayer.getColumnCount()) {
                int startX = natLayer.getStartXOfColumnPosition(endPosition);
                horizontalPositionToPixelMap.put(endPosition,
                        Math.max(startX, previousEndX));
            }
        }
        {
            verticalPositionToPixelMap = new HashMap<Integer, Integer>();
            final int startPosition = positionRectangle.y;
            final int endPosition = startPosition + positionRectangle.height;
            int previousEndY = (startPosition > 0) ? natLayer
                    .getStartYOfRowPosition(startPosition - 1)
                    + natLayer.getRowHeightByPosition(startPosition - 1)
                    : Integer.MIN_VALUE;
            for (int position = startPosition; position < endPosition; position++) {
                int startY = natLayer.getStartYOfRowPosition(position);
                verticalPositionToPixelMap.put(
                        position,
                        isClipTop(position) ? startY : Math.max(startY,
                                previousEndY));
                previousEndY = startY
                        + natLayer.getRowHeightByPosition(position);
            }
            if (endPosition < natLayer.getRowCount()) {
                int startY = natLayer.getStartYOfRowPosition(endPosition);
                verticalPositionToPixelMap.put(endPosition,
                        Math.max(startY, previousEndY));
            }
        }
    }

    @Override
    public Rectangle adjustCellBounds(int columnPosition, int rowPosition,
            Rectangle cellBounds) {
        return cellBounds;
    }

    protected Rectangle getPositionRectangleFromPixelRectangle(ILayer natLayer,
            Rectangle pixelRectangle) {
        int columnPositionOffset = natLayer
                .getColumnPositionByX(pixelRectangle.x);
        int rowPositionOffset = natLayer.getRowPositionByY(pixelRectangle.y);
        int numColumns = natLayer
                .getColumnPositionByX(Math.min(natLayer.getWidth(),
                        pixelRectangle.x + pixelRectangle.width) - 1)
                - columnPositionOffset + 1;
        int numRows = natLayer.getRowPositionByY(Math.min(natLayer.getHeight(),
                pixelRectangle.y + pixelRectangle.height) - 1)
                - rowPositionOffset + 1;

        return new Rectangle(columnPositionOffset, rowPositionOffset,
                numColumns, numRows);
    }

    protected void paintCell(ILayerCell cell, GC gc,
            IConfigRegistry configRegistry) {
        ILayer layer = cell.getLayer();
        int columnPosition = cell.getColumnPosition();
        int rowPosition = cell.getRowPosition();
        ICellPainter cellPainter = layer.getCellPainter(columnPosition,
                rowPosition, cell, configRegistry);
        Rectangle adjustedCellBounds = layer
                .getLayerPainter()
                .adjustCellBounds(columnPosition, rowPosition, cell.getBounds());
        if (cellPainter != null) {
            Rectangle originalClipping = gc.getClipping();

            int startX = getStartXOfColumnPosition(columnPosition);
            int startY = getStartYOfRowPosition(rowPosition);

            int endX = getStartXOfColumnPosition(cell.getOriginColumnPosition()
                    + cell.getColumnSpan());
            int endY = getStartYOfRowPosition(cell.getOriginRowPosition()
                    + cell.getRowSpan());

            Rectangle cellClipBounds = originalClipping
                    .intersection(new Rectangle(startX, startY, endX - startX,
                            endY - startY));
            gc.setClipping(cellClipBounds.intersection(adjustedCellBounds));

            cellPainter.paintCell(cell, gc, adjustedCellBounds, configRegistry);

            gc.setClipping(originalClipping);
        }
    }

    protected int getStartXOfColumnPosition(final int columnPosition) {
        if (columnPosition < natLayer.getColumnCount()) {
            Integer start = horizontalPositionToPixelMap.get(columnPosition);
            if (start == null) {
                start = Integer.valueOf(natLayer
                        .getStartXOfColumnPosition(columnPosition));
                if (columnPosition > 0) {
                    int start2 = natLayer
                            .getStartXOfColumnPosition(columnPosition - 1)
                            + natLayer
                                    .getColumnWidthByPosition(columnPosition - 1);
                    if (start2 > start.intValue()) {
                        start = Integer.valueOf(start2);
                    }
                }
                horizontalPositionToPixelMap.put(columnPosition, start);
            }
            return start.intValue();
        } else {
            return natLayer.getWidth();
        }
    }

    protected int getStartYOfRowPosition(final int rowPosition) {
        if (rowPosition < natLayer.getRowCount()) {
            Integer start = verticalPositionToPixelMap.get(rowPosition);
            if (start == null) {
                start = Integer.valueOf(natLayer
                        .getStartYOfRowPosition(rowPosition));
                if (rowPosition > 0) {
                    int start2 = natLayer
                            .getStartYOfRowPosition(rowPosition - 1)
                            + natLayer.getRowHeightByPosition(rowPosition - 1);
                    if (start2 > start.intValue()) {
                        start = Integer.valueOf(start2);
                    }
                }
                verticalPositionToPixelMap.put(rowPosition, start);
            }
            return start.intValue();
        } else {
            return natLayer.getHeight();
        }
    }

}
TOP

Related Classes of org.eclipse.nebula.widgets.nattable.painter.layer.CellLayerPainter

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.