/*******************************************************************************
* Copyright (c) 2012, 2015 Dirk Fauth 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:
* Dirk Fauth <dirk.fauth@googlemail.com> - initial API and implementation
******************************************************************************/
package org.eclipse.nebula.widgets.nattable.painter.cell.decorator;
import java.util.List;
import org.eclipse.nebula.widgets.nattable.NatTable;
import org.eclipse.nebula.widgets.nattable.config.CellConfigAttributes;
import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry;
import org.eclipse.nebula.widgets.nattable.layer.cell.ILayerCell;
import org.eclipse.nebula.widgets.nattable.painter.cell.CellPainterWrapper;
import org.eclipse.nebula.widgets.nattable.painter.cell.ICellPainter;
import org.eclipse.nebula.widgets.nattable.style.BorderStyle;
import org.eclipse.nebula.widgets.nattable.style.BorderStyle.LineStyleEnum;
import org.eclipse.nebula.widgets.nattable.style.CellStyleAttributes;
import org.eclipse.nebula.widgets.nattable.style.CellStyleUtil;
import org.eclipse.nebula.widgets.nattable.style.DisplayMode;
import org.eclipse.nebula.widgets.nattable.style.IStyle;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
/**
* {@link NatTable} decorator class which is used to draw borders for cells
* whose LabelStack contains border related labels.
* <p>
* Compared to the LineBorderDecorator which paints a border for every side of a
* cell, with this implementation you are free to choose for which side a border
* should be painted or not.
* </p>
*/
public class CustomLineBorderDecorator extends CellPainterWrapper {
/**
* Label for adding a border at the top of a cell.
*/
public static final String TOP_LINE_BORDER_LABEL = "topLineBorderLabel"; //$NON-NLS-1$
/**
* Label for adding a border at the bottom of a cell.
*/
public static final String BOTTOM_LINE_BORDER_LABEL = "bottomLineBorderLabel"; //$NON-NLS-1$
/**
* Label for adding a border at the left of a cell.
*/
public static final String LEFT_LINE_BORDER_LABEL = "leftLineBorderLabel"; //$NON-NLS-1$
/**
* Label for adding a border at the right of a cell.
*/
public static final String RIGHT_LINE_BORDER_LABEL = "rightLineBorderLabel"; //$NON-NLS-1$
/**
* The default border style which will be used if no border style is
* configured via cell style configuration. Can be <code>null</code> if
* there should be no border rendered by default.
*/
private final BorderStyle defaultBorderStyle;
/**
* Creates a new LabelLineBorderDecorator wrapping the given interior
* painter and no default border style.
*
* @param interiorPainter
* The painter to be wrapped by this decorator.
*/
public CustomLineBorderDecorator(ICellPainter interiorPainter) {
this(interiorPainter, null);
}
/**
* Creates a new LabelLineBorderDecorator wrapping the given interior
* painter using the given BorderStyle as default.
*
* @param interiorPainter
* The painter to be wrapped by this decorator.
* @param defaultBorderStyle
* The BorderStyle to use as default if there is no BorderStyle
* configured via cell styles. Can be <code>null</code>.
*/
public CustomLineBorderDecorator(ICellPainter interiorPainter, BorderStyle defaultBorderStyle) {
super(interiorPainter);
this.defaultBorderStyle = defaultBorderStyle;
}
@Override
public int getPreferredWidth(ILayerCell cell, GC gc, IConfigRegistry configRegistry) {
BorderStyle borderStyle = getBorderStyle(cell, configRegistry);
int borderThickness = borderStyle != null ? borderStyle.getThickness() : 0;
int borderLineCount = 0;
// check how many border lines are configured for that cell
List<String> labels = cell.getConfigLabels().getLabels();
if (labels.contains(RIGHT_LINE_BORDER_LABEL))
borderLineCount++;
if (labels.contains(LEFT_LINE_BORDER_LABEL))
borderLineCount++;
return super.getPreferredWidth(cell, gc, configRegistry) + (borderThickness * borderLineCount);
}
@Override
public int getPreferredHeight(ILayerCell cell, GC gc, IConfigRegistry configRegistry) {
BorderStyle borderStyle = getBorderStyle(cell, configRegistry);
int borderThickness = borderStyle != null ? borderStyle.getThickness() : 0;
int borderLineCount = 0;
// check how many border lines are configured for that cell
List<String> labels = cell.getConfigLabels().getLabels();
if (labels.contains(TOP_LINE_BORDER_LABEL))
borderLineCount++;
if (labels.contains(BOTTOM_LINE_BORDER_LABEL))
borderLineCount++;
return super.getPreferredHeight(cell, gc, configRegistry) + (borderThickness * borderLineCount);
}
private BorderStyle getBorderStyle(ILayerCell cell, IConfigRegistry configRegistry) {
IStyle cellStyle = CellStyleUtil.getCellStyle(cell, configRegistry);
BorderStyle borderStyle = cellStyle.getAttributeValue(CellStyleAttributes.BORDER_STYLE);
if (borderStyle == null) {
borderStyle = this.defaultBorderStyle;
}
return borderStyle;
}
@Override
public void paintCell(ILayerCell cell, GC gc, Rectangle rectangle, IConfigRegistry configRegistry) {
BorderStyle borderStyle = getBorderStyle(cell, configRegistry);
int borderThickness = borderStyle != null ? borderStyle.getThickness() : 0;
// check how many border lines are configured for that cell
List<String> labels = cell.getConfigLabels().getLabels();
int leftBorderThickness = 0;
int rightBorderThickness = 0;
int topBorderThickness = 0;
int bottomBorderThickness = 0;
if (labels.contains(LEFT_LINE_BORDER_LABEL))
leftBorderThickness = borderThickness;
if (labels.contains(RIGHT_LINE_BORDER_LABEL))
rightBorderThickness = borderThickness;
if (labels.contains(TOP_LINE_BORDER_LABEL))
topBorderThickness = borderThickness;
if (labels.contains(BOTTOM_LINE_BORDER_LABEL))
bottomBorderThickness = borderThickness;
Rectangle interiorBounds = new Rectangle(
rectangle.x + leftBorderThickness,
rectangle.y + topBorderThickness,
(rectangle.width - leftBorderThickness - rightBorderThickness),
(rectangle.height - topBorderThickness - bottomBorderThickness));
super.paintCell(cell, gc, interiorBounds, configRegistry);
if (borderStyle == null
|| borderThickness <= 0
|| (leftBorderThickness == 0 && rightBorderThickness == 0
&& topBorderThickness == 0 && bottomBorderThickness == 0)) {
return;
}
// Save GC settings
Color originalForeground = gc.getForeground();
int originalLineWidth = gc.getLineWidth();
int originalLineStyle = gc.getLineStyle();
Integer gridLineWidth = configRegistry.getConfigAttribute(
CellConfigAttributes.GRID_LINE_WIDTH,
DisplayMode.NORMAL,
cell.getConfigLabels().getLabels());
int adjustment = (gridLineWidth == null || gridLineWidth == 1)
? 0 : Math.round(gridLineWidth.floatValue() / 2);
gc.setLineWidth(borderThickness);
Rectangle borderArea = new Rectangle(
rectangle.x,
rectangle.y,
rectangle.width,
rectangle.height);
if (borderThickness >= 1) {
int shift = 0;
int correction = 0;
if ((borderThickness % 2) == 0) {
shift = borderThickness / 2;
} else {
shift = borderThickness / 2;
correction = 1;
}
if (leftBorderThickness >= 1) {
borderArea.x += (shift + adjustment);
borderArea.width -= (shift + adjustment);
}
if (rightBorderThickness >= 1) {
borderArea.width -= shift + correction;
}
if (topBorderThickness >= 1) {
borderArea.y += (shift + adjustment);
borderArea.height -= (shift + adjustment);
}
if (bottomBorderThickness >= 1) {
borderArea.height -= shift + correction;
}
}
gc.setLineStyle(LineStyleEnum.toSWT(borderStyle.getLineStyle()));
gc.setForeground(borderStyle.getColor());
// if all borders are set draw a rectangle
if (leftBorderThickness > 0 && rightBorderThickness > 0
&& topBorderThickness > 0 && bottomBorderThickness > 0) {
gc.drawRectangle(borderArea);
}
// else draw a line for every set border
else {
Point topLeftPos = new Point(borderArea.x, borderArea.y);
Point topRightPos = new Point(borderArea.x + borderArea.width, borderArea.y);
Point bottomLeftPos = new Point(borderArea.x, borderArea.y + borderArea.height);
Point bottomRightPos = new Point(
borderArea.x + borderArea.width,
borderArea.y + borderArea.height);
if (leftBorderThickness > 0) {
gc.drawLine(topLeftPos.x, topLeftPos.y, bottomLeftPos.x, bottomLeftPos.y);
}
if (rightBorderThickness > 0) {
gc.drawLine(topRightPos.x, topRightPos.y, bottomRightPos.x, bottomRightPos.y);
}
if (topBorderThickness > 0) {
gc.drawLine(topLeftPos.x, topLeftPos.y, topRightPos.x, topRightPos.y);
}
if (bottomBorderThickness > 0) {
gc.drawLine(bottomLeftPos.x, bottomLeftPos.y, bottomRightPos.x, bottomRightPos.y);
}
}
// Restore GC settings
gc.setForeground(originalForeground);
gc.setLineWidth(originalLineWidth);
gc.setLineStyle(originalLineStyle);
}
}