Styler.java

package swingtree.api;

import swingtree.style.ComponentStyleDelegate;
import swingtree.style.StyleConf;

import javax.swing.JComponent;
import java.util.Objects;

/**
 * A {@link Styler} is a function that takes a {@link ComponentStyleDelegate} and then
 * transforms and returns it with some new style properties (see {@link swingtree.UIForAnySwing#withStyle(Styler)}). <br>
 * Note that all of this is done in a functional manner, so the original {@link ComponentStyleDelegate}
 * as well as the delegated {@link StyleConf} object is not modified
 * because {@link ComponentStyleDelegate} is an immutable object. <br>
 * This design makes the underlying style engine of SwingTree very flexible and scalable
 * because it allows for the composition of styles and reuse of style logic across many components
 * (see {@link swingtree.style.StyleSheet} for more advanced usage).
 *
 * @param <C> the type of the {@link JComponent} that the {@link ComponentStyleDelegate} is delegating to.
 */
@FunctionalInterface
public interface Styler<C extends JComponent>
{
    /**
     * A {@link Styler} that does nothing, meaning it simply returns the given {@link ComponentStyleDelegate}
     * without applying any style to it.
     *
     * @param <C> The type of the {@link JComponent} that the {@link ComponentStyleDelegate} is delegating to.
     * @return A {@link Styler} that does nothing.
     */
    static <C extends JComponent> Styler<C> none() {
        return (Styler<C>) Constants.STYLER_NONE;
    }

    /**
     * Applies some style to the given {@link ComponentStyleDelegate} and returns a new {@link ComponentStyleDelegate}
     * that has the style applied (if any).
     * @param delegate The {@link ComponentStyleDelegate} to apply the style to.
     * @return A new {@link ComponentStyleDelegate} that has the style applied.
     */
    ComponentStyleDelegate<C> style( ComponentStyleDelegate<C> delegate );

    /**
     * Returns a new {@link Styler} that applies the style of this {@link Styler} and then applies the style
     * of the given {@link Styler}. <br>
     * This method is conceptually equivalent to the
     * {@link java.util.function.Function#andThen(java.util.function.Function)}.
     *
     * @param other the {@link Styler} to apply after this {@link Styler}.
     * @return a new {@link Styler} that applies the style of this {@link Styler} and then applies the style
     * of the given {@link Styler}.
     */
    default Styler<C> andThen( Styler<C> other ) {
        Objects.requireNonNull(other);
        if ( this == none() )
            return other;
        if ( other == none() )
            return this;

        return delegate -> {
            ComponentStyleDelegate<C> result = delegate;
            try {
                result = style( delegate );
            } catch ( Exception e ) {
                // Exceptions inside a styler should not be fatal.
                Constants.LOG.error(
                    "Error trying to run '"+delegate+"' through styler '"+this+"'.",
                    e
                );
            }
            return other.style( result );
        };
    }
}