blob: af074586b6c75205ca065e6b4278cc21015373f5 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013, 2020 Dirk Fauth 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:
* Dirk Fauth <dirk.fauth@googlemail.com> - initial API and implementation
*******************************************************************************/
package org.eclipse.nebula.widgets.nattable.examples._400_Configuration;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import org.eclipse.jface.layout.GridDataFactory;
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.data.IDataProvider;
import org.eclipse.nebula.widgets.nattable.data.ListDataProvider;
import org.eclipse.nebula.widgets.nattable.data.convert.DefaultBooleanDisplayConverter;
import org.eclipse.nebula.widgets.nattable.data.convert.DefaultDateDisplayConverter;
import org.eclipse.nebula.widgets.nattable.dataset.person.Person;
import org.eclipse.nebula.widgets.nattable.dataset.person.Person.Gender;
import org.eclipse.nebula.widgets.nattable.dataset.person.PersonService;
import org.eclipse.nebula.widgets.nattable.examples.AbstractNatExample;
import org.eclipse.nebula.widgets.nattable.examples.runner.StandaloneNatExampleRunner;
import org.eclipse.nebula.widgets.nattable.grid.data.DefaultBodyDataProvider;
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.layer.ColumnHeaderLayer;
import org.eclipse.nebula.widgets.nattable.grid.layer.CornerLayer;
import org.eclipse.nebula.widgets.nattable.grid.layer.DefaultColumnHeaderDataLayer;
import org.eclipse.nebula.widgets.nattable.grid.layer.DefaultRowHeaderDataLayer;
import org.eclipse.nebula.widgets.nattable.grid.layer.GridLayer;
import org.eclipse.nebula.widgets.nattable.grid.layer.RowHeaderLayer;
import org.eclipse.nebula.widgets.nattable.hover.HoverLayer;
import org.eclipse.nebula.widgets.nattable.hover.config.ColumnHeaderHoverLayerConfiguration;
import org.eclipse.nebula.widgets.nattable.hover.config.RowHeaderHoverLayerConfiguration;
import org.eclipse.nebula.widgets.nattable.layer.DataLayer;
import org.eclipse.nebula.widgets.nattable.layer.LabelStack;
import org.eclipse.nebula.widgets.nattable.layer.cell.AggregateConfigLabelAccumulator;
import org.eclipse.nebula.widgets.nattable.layer.cell.ColumnLabelAccumulator;
import org.eclipse.nebula.widgets.nattable.layer.cell.IConfigLabelAccumulator;
import org.eclipse.nebula.widgets.nattable.painter.NatTableBorderOverlayPainter;
import org.eclipse.nebula.widgets.nattable.painter.cell.BackgroundImagePainter;
import org.eclipse.nebula.widgets.nattable.painter.cell.CheckBoxPainter;
import org.eclipse.nebula.widgets.nattable.painter.cell.ICellPainter;
import org.eclipse.nebula.widgets.nattable.painter.cell.TextPainter;
import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer;
import org.eclipse.nebula.widgets.nattable.style.CellStyleAttributes;
import org.eclipse.nebula.widgets.nattable.style.DisplayMode;
import org.eclipse.nebula.widgets.nattable.style.IStyle;
import org.eclipse.nebula.widgets.nattable.style.Style;
import org.eclipse.nebula.widgets.nattable.style.theme.DarkNatTableThemeConfiguration;
import org.eclipse.nebula.widgets.nattable.style.theme.DefaultNatTableThemeConfiguration;
import org.eclipse.nebula.widgets.nattable.style.theme.IThemeExtension;
import org.eclipse.nebula.widgets.nattable.style.theme.ModernNatTableThemeConfiguration;
import org.eclipse.nebula.widgets.nattable.style.theme.ThemeConfiguration;
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.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
/**
* Example showing how to use {@link ThemeConfiguration}s in a NatTable. It
* shows how to set and how to switch themes at runtime. Note that there are
* several things that are not controllable via themes like row height, column
* width or ILayerPainter. The later are tight connected to the ILayer
* themselves.
*/
public class _423_ThemeStylingExample extends AbstractNatExample {
public static final String FEMALE_LABEL = "FemaleLabel";
public static final String MALE_LABEL = "MaleLabel";
public static void main(String[] args) throws Exception {
StandaloneNatExampleRunner.run(650, 400, new _423_ThemeStylingExample());
}
@Override
public String getDescription() {
return "This example shows the usage of themes for styling a NatTable and how"
+ " to switch themes at runtime. It also shows how to deal with attributes"
+ " that are not configurable via themes like row heights, column widths and"
+ " ILayerPainter.";
}
@Override
public Control createExampleControl(Composite parent) {
Composite container = new Composite(parent, SWT.NONE);
container.setLayout(new GridLayout());
// property names of the Person class
String[] propertyNames = { "firstName", "lastName", "gender", "married", "birthday" };
// mapping from property to label, needed for column header labels
Map<String, String> propertyToLabelMap = new HashMap<>();
propertyToLabelMap.put("firstName", "Firstname");
propertyToLabelMap.put("lastName", "Lastname");
propertyToLabelMap.put("gender", "Gender");
propertyToLabelMap.put("married", "Married");
propertyToLabelMap.put("birthday", "Birthday");
// build the body layer stack
// Usually you would create a new layer stack by extending
// AbstractIndexLayerTransform and setting the ViewportLayer
// as underlying layer. But in this case using the ViewportLayer
// directly as body layer is also working.
final ListDataProvider<Person> bodyDataProvider =
new DefaultBodyDataProvider<>(PersonService.getPersons(10), propertyNames);
final DataLayer bodyDataLayer = new DataLayer(bodyDataProvider);
HoverLayer bodyHoverLayer = new HoverLayer(bodyDataLayer);
SelectionLayer selectionLayer = new SelectionLayer(bodyHoverLayer);
ViewportLayer viewportLayer = new ViewportLayer(selectionLayer);
// add labels to provider conditional styling
AggregateConfigLabelAccumulator labelAccumulator = new AggregateConfigLabelAccumulator();
labelAccumulator.add(new ColumnLabelAccumulator());
labelAccumulator.add(new IConfigLabelAccumulator() {
@Override
public void accumulateConfigLabels(
LabelStack configLabels, int columnPosition, int rowPosition) {
Person p = bodyDataProvider.getRowObject(rowPosition);
if (p != null) {
configLabels.addLabel(p.getGender().equals(Gender.FEMALE) ? FEMALE_LABEL : MALE_LABEL);
}
}
});
bodyDataLayer.setConfigLabelAccumulator(labelAccumulator);
// build the column header layer
IDataProvider columnHeaderDataProvider =
new DefaultColumnHeaderDataProvider(propertyNames, propertyToLabelMap);
final DataLayer columnHeaderDataLayer =
new DefaultColumnHeaderDataLayer(columnHeaderDataProvider);
HoverLayer columnHoverLayer =
new HoverLayer(columnHeaderDataLayer, false);
final ColumnHeaderLayer columnHeaderLayer =
new ColumnHeaderLayer(columnHoverLayer, viewportLayer, selectionLayer, false);
// add ColumnHeaderHoverLayerConfiguration to ensure that hover styling
// and resizing is working together
columnHeaderLayer.addConfiguration(
new ColumnHeaderHoverLayerConfiguration(columnHoverLayer));
// build the row header layer
IDataProvider rowHeaderDataProvider =
new DefaultRowHeaderDataProvider(bodyDataProvider);
DataLayer rowHeaderDataLayer =
new DefaultRowHeaderDataLayer(rowHeaderDataProvider);
HoverLayer rowHoverLayer =
new HoverLayer(rowHeaderDataLayer, false);
RowHeaderLayer rowHeaderLayer =
new RowHeaderLayer(rowHoverLayer, viewportLayer, selectionLayer, false);
// add RowHeaderHoverLayerConfiguration to ensure that hover styling and
// resizing is working together
rowHeaderLayer.addConfiguration(
new RowHeaderHoverLayerConfiguration(rowHoverLayer));
// build the corner layer
IDataProvider cornerDataProvider =
new DefaultCornerDataProvider(columnHeaderDataProvider, rowHeaderDataProvider);
DataLayer cornerDataLayer =
new DataLayer(cornerDataProvider);
final CornerLayer cornerLayer =
new CornerLayer(cornerDataLayer, rowHeaderLayer, columnHeaderLayer);
// build the grid layer
final GridLayer gridLayer = new GridLayer(
viewportLayer, columnHeaderLayer, rowHeaderLayer, cornerLayer);
final NatTable natTable = new NatTable(container, gridLayer);
GridDataFactory.fillDefaults().grab(true, true).applyTo(natTable);
// adding a full border
natTable.addOverlayPainter(new NatTableBorderOverlayPainter(natTable.getConfigRegistry()));
Composite buttonPanel = new Composite(container, SWT.NONE);
buttonPanel.setLayout(new GridLayout(3, true));
GridDataFactory.fillDefaults().grab(true, false).applyTo(buttonPanel);
final ThemeConfiguration defaultTheme = new DefaultNatTableThemeConfiguration();
final ThemeConfiguration modernTheme = new ModernNatTableThemeConfiguration();
final ThemeConfiguration darkTheme = new DarkNatTableThemeConfiguration();
final ThemeConfiguration conditionalDefaultTheme = new DefaultNatTableThemeConfiguration();
conditionalDefaultTheme.addThemeExtension(new ConditionalStylingThemeExtension());
final ThemeConfiguration conditionalModernTheme = new ModernNatTableThemeConfiguration();
conditionalModernTheme.addThemeExtension(new ConditionalStylingThemeExtension());
final ThemeConfiguration conditionalDarkTheme = new DarkNatTableThemeConfiguration();
conditionalDarkTheme.addThemeExtension(new ConditionalStylingThemeExtension());
final ThemeConfiguration hoverTheme = new HoverThemeConfiguration();
final ThemeConfiguration fontTheme = new FontStylingThemeConfiguration();
Button defaultThemeButton = new Button(buttonPanel, SWT.PUSH);
defaultThemeButton.setText("NatTable Default Theme");
defaultThemeButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
natTable.setTheme(defaultTheme);
// reset to default state
cleanupNonThemeSettings(gridLayer, bodyDataLayer, columnHeaderDataLayer);
}
});
Button modernThemeButton = new Button(buttonPanel, SWT.PUSH);
modernThemeButton.setText("NatTable Modern Theme");
modernThemeButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
natTable.setTheme(modernTheme);
// reset to default state
cleanupNonThemeSettings(gridLayer, bodyDataLayer, columnHeaderDataLayer);
}
});
Button darkThemeButton = new Button(buttonPanel, SWT.PUSH);
darkThemeButton.setText("NatTable Dark Theme");
darkThemeButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
natTable.setTheme(darkTheme);
// reset to default state
cleanupNonThemeSettings(gridLayer, bodyDataLayer, columnHeaderDataLayer);
}
});
Button conditionalThemeButton = new Button(buttonPanel, SWT.PUSH);
conditionalThemeButton.setText("Conditional Default Theme");
conditionalThemeButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
natTable.setTheme(conditionalDefaultTheme);
// reset to default state
cleanupNonThemeSettings(gridLayer, bodyDataLayer, columnHeaderDataLayer);
}
});
Button conditionalModernThemeButton = new Button(buttonPanel, SWT.PUSH);
conditionalModernThemeButton.setText("Conditional Modern Theme");
conditionalModernThemeButton
.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
natTable.setTheme(conditionalModernTheme);
// reset to default state
cleanupNonThemeSettings(gridLayer, bodyDataLayer, columnHeaderDataLayer);
}
});
Button conditionalDarkThemeButton = new Button(buttonPanel, SWT.PUSH);
conditionalDarkThemeButton.setText("Conditional Dark Theme");
conditionalDarkThemeButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
natTable.setTheme(conditionalDarkTheme);
// reset to default state
cleanupNonThemeSettings(gridLayer, bodyDataLayer, columnHeaderDataLayer);
}
});
Button hoverThemeButton = new Button(buttonPanel, SWT.PUSH);
hoverThemeButton.setText("Hover Theme");
hoverThemeButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
natTable.setTheme(hoverTheme);
// reset to default state
cleanupNonThemeSettings(gridLayer, bodyDataLayer, columnHeaderDataLayer);
}
});
Button fontThemeButton = new Button(buttonPanel, SWT.PUSH);
fontThemeButton.setText("Increased Font Theme");
fontThemeButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
natTable.setTheme(fontTheme);
// we are simply increasing the default width and height in this
// example we could also register TextPainters that calculate
// their height by content but they are not able to shrink again
columnHeaderDataLayer.setDefaultRowHeight(30);
columnHeaderDataLayer.setDefaultColumnWidth(130);
bodyDataLayer.setDefaultRowHeight(30);
bodyDataLayer.setDefaultColumnWidth(130);
}
});
return container;
}
/**
* Resets row heights and column widths to default settings.
*/
private void cleanupNonThemeSettings(GridLayer gridLayer,
DataLayer bodyDataLayer, DataLayer columnHeaderDataLayer) {
columnHeaderDataLayer.setDefaultRowHeight(20);
columnHeaderDataLayer.setDefaultColumnWidth(100);
bodyDataLayer.setDefaultRowHeight(20);
bodyDataLayer.setDefaultColumnWidth(100);
}
/**
* ThemeConfiguration that adds hover styling. Note that the stylings are
* only interpreted because the HoverLayer is involved in the layer stacks.
*/
class HoverThemeConfiguration extends DefaultNatTableThemeConfiguration {
{
this.bodyHoverBgColor = GUIHelper.COLOR_YELLOW;
this.bodyHoverSelectionBgColor = GUIHelper.COLOR_GREEN;
this.rHeaderHoverBgColor = GUIHelper.COLOR_RED;
this.rHeaderHoverSelectionBgColor = GUIHelper.COLOR_BLUE;
Image bgImage = GUIHelper.getImageByURL("columnHeaderBg",
getClass().getResource("/org/eclipse/nebula/widgets/nattable/examples/resources/column_header_bg.png"));
Image hoverBgImage = GUIHelper.getImageByURL("hoverColumnHeaderBg",
getClass().getResource("/org/eclipse/nebula/widgets/nattable/examples/resources/hovered_column_header_bg.png"));
Image selectedBgImage = GUIHelper.getImageByURL("selectedColumnHeaderBg",
getClass().getResource("/org/eclipse/nebula/widgets/nattable/examples/resources/selected_column_header_bg.png"));
Image selectedHoveredBgImage = GUIHelper.getImageByURL("selectedHoverColumnHeaderBg",
getClass().getResource("/org/eclipse/nebula/widgets/nattable/examples/resources/selected_hovered_column_header_bg.png"));
TextPainter txtPainter = new TextPainter(false, false);
ICellPainter bgImagePainter =
new BackgroundImagePainter(txtPainter, bgImage);
this.cHeaderCellPainter = bgImagePainter;
this.cornerCellPainter = bgImagePainter;
this.cHeaderSelectionCellPainter =
new BackgroundImagePainter(txtPainter, selectedBgImage);
this.cHeaderHoverCellPainter =
new BackgroundImagePainter(txtPainter, hoverBgImage);
this.cHeaderHoverSelectionCellPainter =
new BackgroundImagePainter(txtPainter, selectedHoveredBgImage);
this.renderCornerGridLines = true;
this.renderColumnHeaderGridLines = true;
}
}
/**
* IThemeExtension that adds conditional styling. As it is implemented as
* theme extension, it can be added to any ThemeConfiguration without the
* need for inheritance.
*/
class ConditionalStylingThemeExtension implements IThemeExtension {
@Override
public void registerStyles(IConfigRegistry configRegistry) {
// add custom styling
IStyle femaleStyle = new Style();
femaleStyle.setAttributeValue(
CellStyleAttributes.BACKGROUND_COLOR,
GUIHelper.COLOR_YELLOW);
femaleStyle.setAttributeValue(
CellStyleAttributes.FOREGROUND_COLOR,
GUIHelper.COLOR_BLACK);
configRegistry.registerConfigAttribute(
CellConfigAttributes.CELL_STYLE,
femaleStyle,
DisplayMode.NORMAL, FEMALE_LABEL);
// add custom painter
configRegistry.registerConfigAttribute(
CellConfigAttributes.CELL_PAINTER,
new CheckBoxPainter(),
DisplayMode.NORMAL,
ColumnLabelAccumulator.COLUMN_LABEL_PREFIX + "3");
// add custom converter
configRegistry.registerConfigAttribute(
CellConfigAttributes.DISPLAY_CONVERTER,
new DefaultBooleanDisplayConverter(),
DisplayMode.NORMAL,
ColumnLabelAccumulator.COLUMN_LABEL_PREFIX + "3");
DateFormat formatter = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.getDefault());
String pattern = ((SimpleDateFormat) formatter).toPattern();
configRegistry.registerConfigAttribute(
CellConfigAttributes.DISPLAY_CONVERTER,
new DefaultDateDisplayConverter(pattern),
DisplayMode.NORMAL,
ColumnLabelAccumulator.COLUMN_LABEL_PREFIX + "4");
}
@Override
public void unregisterStyles(IConfigRegistry configRegistry) {
// unregister custom styling
configRegistry.unregisterConfigAttribute(
CellConfigAttributes.CELL_STYLE,
DisplayMode.NORMAL,
FEMALE_LABEL);
configRegistry.unregisterConfigAttribute(
CellConfigAttributes.CELL_PAINTER,
DisplayMode.NORMAL,
ColumnLabelAccumulator.COLUMN_LABEL_PREFIX + "3");
configRegistry.unregisterConfigAttribute(
CellConfigAttributes.DISPLAY_CONVERTER,
DisplayMode.NORMAL,
ColumnLabelAccumulator.COLUMN_LABEL_PREFIX + "3");
configRegistry.unregisterConfigAttribute(
CellConfigAttributes.DISPLAY_CONVERTER,
DisplayMode.NORMAL,
ColumnLabelAccumulator.COLUMN_LABEL_PREFIX + "4");
}
}
/**
* ThemeConfiguration that sets different fonts which has impact on the row
* heights and columns widths. The automatic resizing is done via specially
* configured TextPainter instances.
*/
class FontStylingThemeConfiguration extends ModernNatTableThemeConfiguration {
{
this.defaultFont = GUIHelper.getFont(new FontData("Arial", 15, SWT.NORMAL));
this.defaultSelectionFont = GUIHelper.getFont(new FontData("Arial", 15, SWT.NORMAL));
this.cHeaderFont = GUIHelper.getFont(new FontData("Arial", 18, SWT.NORMAL));
this.cHeaderSelectionFont = GUIHelper.getFont(new FontData("Arial", 18, SWT.NORMAL));
this.rHeaderFont = GUIHelper.getFont(new FontData("Arial", 18, SWT.NORMAL));
this.rHeaderSelectionFont = GUIHelper.getFont(new FontData("Arial", 18, SWT.NORMAL));
this.renderCornerGridLines = true;
this.renderColumnHeaderGridLines = true;
}
}
}