RenderAs.java
package swingtree;
import org.slf4j.LoggerFactory;
import swingtree.api.Configurator;
import javax.swing.JComponent;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Predicate;
/**
* This class models the API of the {@link RenderBuilder} which allows you to
* specify how a cell should be rendered.
* Most likely you will want to call {@link #asText(Function)}
* on this as most cells are rendered as simple texts.
* An example would be a combo box containing enum values, which
* you don't want to render as the enum name (all capital letters), but rather as a
* more human-readable string.
*
* @param <C> The type of the component which is used to render the cell.
* @param <E> The type of the value of the cell.
* @param <T> The type of the value of the cell.
*/
public final class RenderAs<C extends JComponent, E, T extends E>
{
private static final org.slf4j.Logger log = LoggerFactory.getLogger(RenderAs.class);
private final RenderBuilder<C, E> _builder;
private final Class<T> _valueType;
private final Predicate<CellDelegate<C, T>> _valueValidator;
RenderAs(RenderBuilder<C, E> builder, Class<T> valueType, Predicate<CellDelegate<C, T>> valueValidator) {
_builder = builder;
_valueType = valueType;
_valueValidator = valueValidator;
}
/**
* Specify a lambda which receives a {@link CellDelegate} instance
* for you to customize its renderer.
* This is the most generic way to customize the rendering of a cell,
* as you can choose between vastly different ways of rendering:
* <pre>{@code
* .when( MyEnum.class )
* .as( cell -> {
* // do component based rendering:
* cell.setRenderer( new JLabel( "Hello World" ) );
* // or do graphics rendering directly:
* cell.setRenderer( g -> {
* // draw something
* g.drawString( "Hello World", 0, 0 );
* });
* })
* }</pre>
*
* @param valueInterpreter A lambda which customizes the provided cell.
* @return The builder API allowing method chaining.
*/
public RenderBuilder<C, E> as( Configurator<CellDelegate<C, T>> valueInterpreter ) {
NullUtil.nullArgCheck(valueInterpreter, "valueInterpreter", Configurator.class);
_builder._store(_valueType, _valueValidator, valueInterpreter);
return _builder;
}
/**
* Specify a lambda which receives a {@link CellDelegate} instance
* and return a {@link Component} which is then used to render the cell.
* <pre>{@code
* .when( MyEnum.class )
* .asComponent( cell -> new JLabel( "Hello World" ) )
* }</pre>
*
* @param renderer A function which returns a {@link Component} which is then used to render the cell.
* @return The builder API allowing method chaining.
*/
public RenderBuilder<C, E> asComponent( Function<CellDelegate<C ,T>, Component> renderer ) {
return this.as( cell -> cell.withRenderer(renderer.apply(cell)) );
}
/**
* Specify a lambda which receives a {@link CellDelegate} instance
* and return a {@link String} which is then used to render the cell.
* <pre>{@code
* .when( MyEnum.class )
* .asText( cell -> "Hello World" )
* }</pre>
*
* @param renderer A function which returns a {@link String} which is then used to render the cell.
* @return The builder API allowing method chaining.
*/
public RenderBuilder<C, E> asText(Function<CellDelegate<C ,T>, String> renderer ) {
return this.as(RenderBuilder._createDefaultTextRenderer(renderer));
}
/**
* Specify a lambda which receives a {@link CellDelegate} instance as well as a {@link Graphics} instance
* and then renders the cell.
* <pre>{@code
* .when( MyEnum.class )
* .render( (cell, g) -> {
* // draw something
* g.drawString( "Hello World", 0, 0 );
* })
* }</pre>
*
* @param renderer A function which receives a {@link CellDelegate} instance as well as a {@link Graphics} instance and then renders the cell.
* @return The builder API allowing method chaining.
*/
public RenderBuilder<C, E> render(BiConsumer<CellDelegate<C ,T>, Graphics2D> renderer ) {
return this.as( cell -> cell.withRenderer(new JComponent( ){
@Override public void paintComponent(Graphics g) {
try {
renderer.accept(cell, (Graphics2D) g);
} catch (Exception e) {
log.warn("An exception occurred while rendering a cell!", e);
/*
We log as warning because exceptions during rendering are not considered
as harmful as elsewhere!
*/
}
}
}) );
}
}