blob: d7b79d31ed8fc9de12373ae01c83d7da9e914f87 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012, 2020 Original authors and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Original authors and others - initial API and implementation
******************************************************************************/
package org.eclipse.nebula.widgets.nattable.extension.glazedlists.groupBy;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry;
import org.eclipse.nebula.widgets.nattable.data.IDataProvider;
import org.eclipse.nebula.widgets.nattable.grid.layer.ColumnHeaderLayer;
import org.eclipse.nebula.widgets.nattable.layer.cell.ILayerCell;
import org.eclipse.nebula.widgets.nattable.painter.cell.AbstractCellPainter;
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.nebula.widgets.nattable.util.GUIHelper;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Rectangle;
/**
* The painter that is used to render the groupBy state.
*/
public class GroupByHeaderPainter extends AbstractCellPainter {
private static final int LEFT_INDENT = 2;
private static final int ENDCAP_WIDTH = 8;
private static final int X_PADDING = 4;
private static final int Y_PADDING = 2;
private final GroupByModel groupByModel;
private final IDataProvider columnHeaderDataProvider;
private final ColumnHeaderLayer columnHeaderLayer;
private List<Rectangle> groupByCellBounds = new ArrayList<>();
/**
*
* @param groupByModel
* The {@link GroupByModel} needed to retrieve the groupBy state.
* @param columnHeaderDataProvider
* The {@link IDataProvider} needed to retrieve the column label.
*/
public GroupByHeaderPainter(GroupByModel groupByModel, IDataProvider columnHeaderDataProvider) {
this.groupByModel = groupByModel;
this.columnHeaderDataProvider = columnHeaderDataProvider;
this.columnHeaderLayer = null;
}
/**
* @param groupByModel
* The {@link GroupByModel} needed to retrieve the groupBy state.
* @param columnHeaderDataProvider
* The {@link IDataProvider} needed to retrieve the column label.
* @param columnHeaderLayer
* The {@link ColumnHeaderLayer} needed to retrieve the column
* label in case a user renamed a column.
* @since 1.5
*/
public GroupByHeaderPainter(GroupByModel groupByModel,
IDataProvider columnHeaderDataProvider, ColumnHeaderLayer columnHeaderLayer) {
this.groupByModel = groupByModel;
this.columnHeaderDataProvider = columnHeaderDataProvider;
this.columnHeaderLayer = columnHeaderLayer;
}
@Override
public void paintCell(ILayerCell cell, GC gc, Rectangle bounds, IConfigRegistry configRegistry) {
Color originalBackground = gc.getBackground();
Color originalForeground = gc.getForeground();
Font originalFont = gc.getFont();
// get color for header background
Color headerBgColor = configRegistry.getConfigAttribute(
GroupByConfigAttributes.GROUP_BY_HEADER_BACKGROUND_COLOR,
DisplayMode.NORMAL);
if (headerBgColor != null) {
gc.setBackground(headerBgColor);
}
// Draw background
gc.fillRectangle(bounds);
this.groupByCellBounds.clear();
IStyle cellStyle = CellStyleUtil.getCellStyle(cell, configRegistry);
gc.setBackground(cellStyle.getAttributeValue(CellStyleAttributes.BACKGROUND_COLOR));
gc.setForeground(cellStyle.getAttributeValue(CellStyleAttributes.FOREGROUND_COLOR));
gc.setFont(cellStyle.getAttributeValue(CellStyleAttributes.FONT));
gc.setAntialias(GUIHelper.DEFAULT_ANTIALIAS);
gc.setTextAntialias(GUIHelper.DEFAULT_TEXT_ANTIALIAS);
List<Integer> groupByColumnIndexes = this.groupByModel.getGroupByColumnIndexes();
if (!groupByColumnIndexes.isEmpty()) {
int textHeight = gc.textExtent("X").y; //$NON-NLS-1$
int x0 = bounds.x + LEFT_INDENT;
int y0 = bounds.y + bounds.height / 2 - textHeight / 2 - Y_PADDING;
int yHeight = Y_PADDING + textHeight + Y_PADDING;
// Draw leftmost edge
gc.drawLine(x0, y0, x0, y0 + yHeight);
x0++;
// Draw group by columns
int lastColumnIndex = groupByColumnIndexes.size() - 1;
for (int i = 0; i <= lastColumnIndex; i++) {
int columnIndex = groupByColumnIndexes.get(i);
String columnName = null;
if (this.columnHeaderLayer != null && this.columnHeaderLayer.isColumnRenamed(columnIndex)) {
columnName = this.columnHeaderLayer.getRenamedColumnLabelByIndex(columnIndex);
} else {
columnName = (String) this.columnHeaderDataProvider.getDataValue(columnIndex, 0);
}
int textWidth = gc.textExtent(columnName).x;
this.groupByCellBounds.add(new Rectangle(x0, y0, X_PADDING + textWidth + X_PADDING, yHeight));
gc.fillRectangle(x0, y0, X_PADDING + textWidth + X_PADDING, yHeight);
gc.drawLine(x0, y0, x0 + X_PADDING + textWidth + X_PADDING, y0);
gc.drawLine(x0, y0 + yHeight, x0 + X_PADDING + textWidth + X_PADDING, y0 + yHeight);
gc.drawText(columnName, x0 + X_PADDING, y0 + Y_PADDING);
x0 += X_PADDING + textWidth + X_PADDING;
// Draw end cap
if (i < lastColumnIndex) {
gc.fillRectangle(x0, y0, ENDCAP_WIDTH, yHeight);
gc.drawLine(x0, y0, x0 + ENDCAP_WIDTH, y0);
gc.drawLine(x0, y0 + yHeight, x0 + ENDCAP_WIDTH, y0 + yHeight);
} else {
gc.fillPolygon(new int[] { x0, y0, x0 + ENDCAP_WIDTH, y0 + yHeight / 2, x0, y0 + yHeight });
}
gc.drawLine(x0, y0, x0 + ENDCAP_WIDTH - 1, y0 + yHeight / 2);
gc.drawLine(x0, y0 + yHeight, x0 + ENDCAP_WIDTH - 1, y0 + yHeight / 2);
x0 += ENDCAP_WIDTH;
}
} else {
// if no grouping is applied and a hint is specified via
// configuration, the hint is rendered
String hint = configRegistry.getConfigAttribute(
GroupByConfigAttributes.GROUP_BY_HINT,
DisplayMode.NORMAL);
if (hint != null) {
// check if there is a separate styling configured for the hint
IStyle hintStyle = configRegistry.getConfigAttribute(
GroupByConfigAttributes.GROUP_BY_HINT_STYLE,
DisplayMode.NORMAL);
if (hintStyle != null) {
Color hintBackground = hintStyle.getAttributeValue(CellStyleAttributes.BACKGROUND_COLOR);
gc.setBackground(hintBackground != null ? hintBackground : originalBackground);
Color hintForeground = hintStyle.getAttributeValue(CellStyleAttributes.FOREGROUND_COLOR);
if (hintForeground != null) {
gc.setForeground(hintForeground);
}
Font hintFont = CellStyleUtil.getFont(hintStyle, configRegistry);
if (hintFont != null) {
gc.setFont(hintFont);
}
} else {
// ensure the background is the same as the background of
// the groupby header region
gc.setBackground(originalBackground);
}
int textHeight = gc.textExtent("X").y; //$NON-NLS-1$
int x0 = bounds.x + LEFT_INDENT;
int y0 = bounds.y + bounds.height / 2 - textHeight / 2 - Y_PADDING;
gc.drawText(hint, x0 + X_PADDING, y0);
}
}
gc.setBackground(originalBackground);
gc.setForeground(originalForeground);
gc.setFont(originalFont);
}
@Override
public int getPreferredWidth(ILayerCell cell, GC gc, IConfigRegistry configRegistry) {
return 0;
}
@Override
public int getPreferredHeight(ILayerCell cell, GC gc, IConfigRegistry configRegistry) {
return getPreferredHeight();
}
public int getPreferredHeight() {
return 30;
}
public int getGroupByColumnIndexAtXY(int x, int y) {
for (int i = 0; i < this.groupByCellBounds.size(); i++) {
Rectangle bounds = this.groupByCellBounds.get(i);
if (bounds.contains(x, y)) {
return this.groupByModel.getGroupByColumnIndexes().get(i);
}
}
return -1;
}
}