UIForAnything.java

package swingtree;

import org.jspecify.annotations.Nullable;
import sprouts.*;
import swingtree.api.Peeker;
import swingtree.style.ComponentExtension;
import swingtree.style.StyleConf;
import swingtree.threading.EventProcessor;

import javax.swing.JComponent;
import java.awt.Component;
import java.lang.ref.WeakReference;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Supplier;

/**
 *  This is the root builder type for all other SwingTree builder subtypes.
 *  It is a generic builder which may wrap any type of Swing component to allow for method chaining
 *  and nesting based building in SwingTree. <br>
 *  Note that a builder is immutable, which means that every method call on a builder
 *  returns a new builder instance with the new state. <br>
 *  The state of the previous builder is disposed of, which means that the wrapped component
 *  is no longer referenced by the previous builder instance and can be garbage collected.<br>
 *  <b>Spent builder nodes may not be reused!</b>
 *
 * @param <I> The type parameter representing the concrete subtype of this abstract class, "I" stands for "Implementation".
 * @param <C> The type parameter representing the concrete component type which this builder is responsible for building.
 * @param <E> The component type parameter which ought to be built in some way.
 */
abstract class UIForAnything<I, C extends E, E extends Component>
{
    /**
     *  The type class of the component managed by this builder.
     *  See documentation for method "build" for more information.
     * @return The type class of the component managed by this builder.
     */
    public final Class<C> getType() {
        return _state().componentType();
    }

    /**
     *  The component managed by this builder.
     *
     *  @throws IllegalStateException if this method is called from a thread other than the EDT
     *                                and this UI is configured to be decoupled from the application thread.
     *                                See {@link UI#use(EventProcessor, Supplier)}.
     *  @return The component managed by this builder.
     * @deprecated Use {@link #get(Class)} instead.
     */
    @Deprecated
    public final C getComponent() {
        boolean isCoupled       = _state().eventProcessor() == EventProcessor.COUPLED;
        boolean isCoupledStrict = _state().eventProcessor() == EventProcessor.COUPLED_STRICT;

        if ( !isCoupled && !isCoupledStrict && !UI.thisIsUIThread() )
            throw new IllegalStateException(
                    "This UI is configured to be decoupled from the application thread, " +
                    "which means that it can only be modified from the EDT. " +
                    "Please use 'UI.run(()->...)' method to execute your modifications on the EDT."
                );
        return _state().component();
    }

    /**
     *  The optional component managed by this builder.
     *
     * @return An {@link OptionalUI} wrapping a component or null.
     *         This optional will throw an exception if the
     *         application has an application thread (see {@link UI#use(EventProcessor, Supplier)})
     *         and this method is called from a thread other than the EDT.
     * @deprecated Use {@link #get(Class)} instead.
     */
    @Deprecated
    public final OptionalUI<C> component() {
        return OptionalUI.ofNullable(_state().component());
    }

    /**
     *  Use this if you wish to access the component wrapped by this builder directly.
     *  This is useful for more fine-grained control, like for example calling
     *  methods like "setName", "setTitle", and so on... <br>
     *  This method accepts a lambda to which the component wrapped by this builder will be supplied.
     *  The lambda can then call said methods or perform other tasks which
     *  might be relevant to the component while also not
     *  breaking the benefits of nesting and method chaining provided by this class...
     *  <br>
     *  The below example shows how this method allows for more fine-grained control over the wrapped component:
     *  <pre>{@code
     *      UI.panel()
     *      peek( panel -> panel.setDebugGraphicsOptions(true) );
     *  }</pre>
     *  <br><br>
     *
     * @param action A Consumer lambda which simply returned the wrapped JComponent type for interacting it.
     * @return This very instance, which enables builder-style method chaining.
     */
    public final I peek( Peeker<C> action ) {
        return _with(action::accept)._this();
    }

    /**
     *  Use this to only build a certain part of the UI if the provided boolean condition is true.
     *  Which is to say, if the condition is false, then the second lambda is ignored, if
     *  on the other hand the condition is true, then the second lambda is executed
     *  with the current builder instance passed to it as a parameter.
     *  Inside the lambda, one can then continue building the UI while also not
     *  breaking the benefits of nesting and method chaining provided by this builder...
     *  <p>
     *  This is in essence a more advanced version of {@link #apply(Consumer)}.
     *  <br>
     *  Here a simple usage example:
     *  <pre>{@code
     *    UI.panel()
     *    .applyIf( userIsLoggedIn, ui -> ui
     *      .add( UI.label("Welcome back!") )
     *      .add( UI.button("Logout")).onClick( () -> logout() )
     *      .add( UI.button("Settings")).onClick( () -> showSettings() )
     *    )
     *    .applyIf( !userIsLoggedIn, ui -> ui
     *      .add( UI.label("Please login to continue.") )
     *      .add( UI.button("Login")).onClick( () -> login() );
     *    );
     *  }</pre>
     *  Here we use theis method to build a panel
     *  with different content depending on whether the user is logged in or not.
     *  <br><br>
     *
     * @param condition The truth value which determines if the second consumer lambda is executed or not.
     * @param building A {@link Consumer} lambda which simply consumes this builder instance.
     * @return This very instance, which enables builder-style method chaining.
     */
    public final I applyIf( boolean condition, Consumer<I> building ) {
        NullUtil.nullArgCheck(building, "building", Consumer.class);

        if ( !condition )
            return _this();

        return _with( thisComponent -> {
                    BuilderState<C> proceduralBuilder =
                        new BuilderState<>(
                                _state().eventProcessor(),
                                BuilderState.Mode.PROCEDURAL_OR_DECLARATIVE,
                                _state().componentType(),
                                ()->thisComponent
                            );
                    building.accept(_newBuilderWithState(proceduralBuilder)._this());
                })
                ._this();
    }


    /**
     *  Allows you to build declarative UI conditionally,
     *  meaning that the UI is only built if the provided {@link Optional} value is present.
     *  If the value is not present, meaning it is null, then the second lambda
     *  (containing UI declarations relevant to the value) is simply ignored.
     *  <p>
     *  Consider the following example:
     *  <pre>{@code
     * // In your view model:
     * public Optional<MySubModel> getM() {
     *   return Optional.ofNullable(this.model);
     * }
     *
     * // In your view:
     * UI.panel()
     * .add(UI.label("Maybe Sub Model:"))
     * .applyIfPresent(vm.getM().map(m->ui->ui
     *   .add(UI.label("Hello Sub Model!"))
     *   .add(UI.label("A:")
     *   .add(UI.textField(m.getA()))
     *   .add(UI.label("B:"))
     *   .add(UI.textField(m.getB()))
     *   // ...
     * ))
     * .add(UI.label("Some other stuff..."));
     * }</pre>
     *
     * The {@code applyIfPresent} method takes an {@code Optional<Consumer<I>>} as parameter,
     * where {@code I} is the type of the UI builder.
     * This allows you to map the optional value to a consumer which is only executed if the value is present.
     * If the optional value is present, the consumer is executed with the
     * current UI builder as a parameter, which allows you to continue building the UI as usual.
     * <br>
     * The {@code m->ui->ui} may look a bit confusing at first, but it is simply a lambda expression
     * which takes the optional value and returns a consumer ({@code ui->ui... }) which takes the UI builder
     * as a parameter.
     * <br>
     * This is in essence a more advanced {@code Optional} centric version of {@link #applyIf(boolean, Consumer)}
     * and {@link #apply(Consumer)}.
     * <br>
     *
     * @param building An optional consumer lambda which simply consumes this builder node.
     * @return This very instance, which enables builder-style method chaining.
     */
    @SuppressWarnings("OptionalUsedAsFieldOrParameterType")
    public final I applyIfPresent( Optional<Consumer<I>> building ) {
        NullUtil.nullArgCheck(building, "building", Optional.class);
        return _with( thisComponent -> {
                    BuilderState<C> proceduralBuilder =
                        new BuilderState<>(
                                _state().eventProcessor(),
                                BuilderState.Mode.PROCEDURAL_OR_DECLARATIVE,
                                _state().componentType(),
                                ()->thisComponent
                            );
                    building.ifPresent( buildingLambda -> {
                        buildingLambda.accept(_newBuilderWithState(proceduralBuilder)._this());
                    });
                })
                ._this();
    }

    /**
     *  Use this to continue building UI inside a provided lambda
     *  if you need to introduce some imperative code in between
     *  the building process. <br>
     *  This is especially useful for when you need to build UI based on loops.
     *  The current builder instance will simply be supplied to the provided {@link Consumer} lambda.
     *  Inside the supplied lambda, you can then continue building the UI while also not
     *  breaking the benefits of nesting and method chaining, effectively preserving
     *  the declarative nature of the builder.
     *  <br><br>
     *  Here is a simple example of how this method can be used to build a panel
     *  with a variable amount of images displayed in a grid:
     *  <pre>{@code
     *      UI.panel("wrap 3")
     *      .apply( ui -> {
     *          for ( String path : imagePaths )
     *              ui.add( UI.label(UI.icon(path)) );
     *      });
     *  }</pre>
     *  <br><br>
     *  Here is another example of how this method can be used to build a panel
     *  with a variable amount of buttons displayed in a grid:
     *  <pre>{@code
     *    UI.panel("wrap 4")
     *    .apply( ui -> {
     *      for ( int i = 0; i < numOfButtons; i++ )
     *          ui.add( UI.button("Button " + i)
     *          .onClick( () -> {...} );
     *    });
     *  }</pre>
     *  <br><br>
     *
     * @param building A Consumer lambda which simply consumes this builder instance.
     * @return This very instance, which enables builder-style method chaining.
     */
    public final I apply( Consumer<I> building ) {
        NullUtil.nullArgCheck(building, "building", Consumer.class);
        return applyIf(true, building);
    }

    /**
     *  This method completes the building process for the wrapped
     *  {@link javax.swing.JComponent} type by returning it.
     *  However, it also expects the user to pass the class of the {@link javax.swing.JComponent}
     *  wrapped by this builder! This is not out of necessity but for better
     *  readability when using the builder in more extensive ways where
     *  the beginning and end of the method chaining and nesting of the builder does
     *  not fit on one screen. <br>
     *  In such cases the expression "{@code .get(MyJComponent.class)}" helps
     *  to identify which type of {@link javax.swing.JComponent} is currently being built on a given
     *  nesting layer... <br><br>
     *  Here is a simple example that demonstrates this technique using
     *  a {@link javax.swing.JPanel} and a {@link javax.swing.JMenuBar}:
     *  <pre>{@code
     *      UI.panel()
     *      .add(
     *          UI.menuBar()
     *          .add( UI.menu("File") )
     *          .add( UI.menuItem("Open") )
     *          .add( UI.menuItem("Save") )
     *          // ...
     *          .add( UI.menuItem("Exit") )
     *          .get(JMenuBar.class)
     *      )
     *      .add( UI.button("Click me!") )
     *      .get(JPanel.class);
     *  }</pre>
     *  As you can see, the expression "{@code .get(JMenuBar.class)}" as well as the expression
     *  "{@code .get(JPanel.class)}" at the end of the builder chain help to identify
     *  which type of {@link javax.swing.JComponent} is currently being built and returned.
     *
     * @param type The type class of the component which this builder wraps.
     * @return The result of the building process, namely: a type of JComponent.
     */
    public final C get( Class<C> type ) {
        if ( type != _state().componentType() && !type.isAssignableFrom(_state().componentType()) )
            throw new IllegalArgumentException(
                    "The type of the component wrapped by this builder is '" + _state().componentType() + "', " +
                    "but the provided type is '" + type + "' which is not assignable from '" + _state().componentType() + "'."
                );
        return getComponent();
    }

    /**
     *  This builder class expects its implementations to be builder types
     *  for anything which can be built in a nested tree-like structure.
     *  Implementations of this abstract method ought to enable support for nested building.
     *  <br><br>
     *
     * @param components An array of component instances which ought to be added to the wrapped component type.
     * @return This very instance, which enables builder-style method chaining.
     */
    @SafeVarargs
    public final I add( E... components ) {
        NullUtil.nullArgCheck(components, "components", Object[].class);
        return _with( thisComponent -> {
                    _addComponentsTo( thisComponent, components );
               })
               ._this();
    }

    /**
     *  Uses the supplied builder to build its component and then add it to the component
     *  that is being built by this builder instance. This directly allows you to nest your
     *  builder based UI declarations in an HTML-like fashion.
     *
     * @param builder A builder for another {@link JComponent} instance which ought to be added to the wrapped component type.
     * @param <T> The type of the {@link JComponent} which is wrapped by the provided builder.
     * @return This very instance, which enables builder-style method chaining.
     */
    public final <T extends JComponent> I add( UIForAnySwing<?, T> builder ) {
        return (I) this.add( new UIForAnything[]{builder} );
    }

    /**
     *  This method provides the same functionality as the other "add" methods.
     *  However, it bypasses the necessity to call the "get" method by
     *  calling it internally for you. <br>
     *  This helps to improve readability, especially when the degree of nesting is very low.
     *
     * @param builders An array of builder instances whose JComponents ought to be added to the one wrapped by this builder.
     * @param <B> The type of the builder instances which are used to configure the components that will be added to the component wrapped by this builder.
     * @return This very instance, which enables builder-style method chaining.
     */
    @SafeVarargs
    @SuppressWarnings("varargs")
    public final <B extends UIForAnything<?, ?, JComponent>> I add( B... builders )
    {
        if ( builders == null )
            throw new IllegalArgumentException("Swing tree builders may not be null!");

        return _with( thisComponent -> {
                    _addBuildersTo( thisComponent, builders );
                })
                ._this();
    }

    /**
     *  This builder class expects its implementations to be builder types
     *  for anything which can be built in a nested tree-like structure.
     *  Implementations of this abstract method ought to enable support for nested building.
     *  <br><br>
     *
     * @param components A list of component instances which ought to be added to the wrapped component type.
     * @return This very instance, which enables builder-style method chaining.
     */
    public final I add( List<E> components ) {
        return _with( thisComponent -> {
                    for ( E component : components )
                        _addBuilderTo(thisComponent, UI.of((JComponent) component), null);
                })
                ._this();
    }

    @SafeVarargs
    protected final <B extends UIForAnything<?, ?, JComponent>> void _addBuildersTo(
        C thisComponent, B... builders
    ) {
        for ( UIForAnything<?, ?, ?> b : builders )
            _addBuilderTo(thisComponent, b, null);
    }

    @SafeVarargs
    protected final void _addComponentsTo( C thisComponent, E... componentsToBeAdded ) {
        for ( E other : componentsToBeAdded )
            _addBuilderTo(thisComponent, UI.of((JComponent) other), null);
    }

    protected final void _addBuilderTo( C thisComponent, UIForAnything<?, ?, ?> builder, @Nullable Object conf )
    {
        NullUtil.nullArgCheck(builder, "builder", UIForAnything.class);

        boolean isCoupled       = _state().eventProcessor() == EventProcessor.COUPLED;
        boolean isCoupledStrict = _state().eventProcessor() == EventProcessor.COUPLED_STRICT;

        if ( !isCoupled && !isCoupledStrict && !UI.thisIsUIThread() )
            throw new IllegalStateException(
                    "This UI is configured to be decoupled from the application thread, " +
                    "which means that it can only be modified from the EDT. " +
                    "Please use 'UI.run(()->...)' method to execute your modifications on the EDT."
                );

        E childComponent = (E) builder.getComponent();

        if ( childComponent instanceof JComponent ) {
            JComponent child = (JComponent) childComponent;

            StyleConf styleConf = ( conf != null ? null : ComponentExtension.from(child).gatherStyle() );
            if ( styleConf != null )
                conf = styleConf.layoutConstraint().orElse(null);

            _addComponentTo(thisComponent, childComponent, conf);

            if ( styleConf != null )
                ComponentExtension.from(child).applyAndInstallStyle(styleConf, true);
            else
                ComponentExtension.from(child).gatherApplyAndInstallStyle(true);
        }
        else
            _addComponentTo(thisComponent, childComponent, conf);

        builder._disposeState(); // The builder may now no longer be used.
    }

    /**
     * This builder class expects its implementations to be builder types
     * for anything which can be built in a nested tree-like structure.
     * Implementations of this abstract method ought to enable support for nested building.
     * <br><br>
     *
     * @param thisComponent  The component which is wrapped by this builder.
     * @param addedComponent A component instance which ought to be added to the wrapped component type.
     * @param constraints    The layout constraint which ought to be used to add the component to the wrapped component type.
     */
    protected abstract void _addComponentTo( C thisComponent, E addedComponent, @Nullable Object constraints );

    /**
     *  Returns the state of the builder, which is a container for the wrapped component
     *  as well as it's type and current {@link EventProcessor}.
     * @return The state of the builder.
     */
    protected abstract BuilderState<C> _state();

    /**
     *  An internal wither method which creates a new builder instance with the provided
     *  {@link BuilderState} stored inside it.
     *
     * @param newState The new state which should be stored inside the new builder instance.
     * @return A new builder instance with the provided state stored inside it.
     */
    protected abstract UIForAnything<I,C, E> _newBuilderWithState( BuilderState<C> newState );

    /**
     *  Creates a new builder with the provided component mutation applied to the wrapped component. <br>
     *  Note that the SwingTree builders are immutable, which means that this method
     *  does not mutate the current builder instance, but instead creates a new builder instance
     *  with a new {@link BuilderState} which contains the provided component mutation (see {@link BuilderState#withMutator(Consumer)}).
     *  Also see {@link #_newBuilderWithState(BuilderState)}.
     *
     * @param componentMutator A consumer lambda which receives the wrapped component and
     *                         is then used to apply some builder action to it.
     * @return A new builder instance with the provided component mutation applied to the wrapped component.
     */
    protected final UIForAnything<I,C,E> _with( Consumer<C> componentMutator ) {
        BuilderState<C> newState = _state().withMutator(componentMutator);
        return _newBuilderWithState(newState);
    }

    /**
     *  A convenient shortcut to the {@link EventProcessor#registerUIEvent(Runnable)} method
     *  to the current {@link EventProcessor} attached to the current {@link BuilderState}.
     *  In practice, this method will ultimately just delegate tasks to the AWT Event Dispatch Thread (EDT).
     *
     * @param action An action which should be executed by the UI thread,
     *               which is determined by implementations of the {@link EventProcessor},
     *               also see {@link UI#use(EventProcessor, Supplier)}. <br>
     *               Usually the UI thread is AWT's Event Dispatch Thread (EDT).
     */
    protected final void _runInUI( Runnable action ) {
        _state().eventProcessor().registerUIEvent( action );
    }

    /**
     *  A convenient delegate to the {@link EventProcessor#registerAppEvent(Runnable)} method,
     *  which allows you to execute an action on the current application thread.
     *  To configure the current {@link EventProcessor} see {@link UI#use(EventProcessor, Supplier)}
     *  or the underlying {@link SwingTree#setEventProcessor(EventProcessor)} method.
     *
     * @param action An action which should be executed by the application thread,
     *               which is determined by implementations of the current {@link EventProcessor},
     *               also see {@link UI#use(EventProcessor, Supplier)}.
     */
    protected final void _runInApp( Runnable action ) {
        _state().eventProcessor().registerAppEvent(action);
    }

    /**
     *  A convenient delegate to the {@link EventProcessor#registerAppEvent(Runnable)} method,
     *  which allows you to execute an action on the current application thread.
     *  Which thread executes these tasks is determined by the current {@link EventProcessor}.
     *  Usually this is the {@link EventProcessor#COUPLED} or {@link EventProcessor#COUPLED_STRICT} event processor.
     *
     * @param value A value which should be captured and then passed to the provided action
     *              on the current application thread (see {@link EventProcessor} and {@link UI#use(EventProcessor, Supplier)}).
     * @param action A consumer lambda which is executed by the application thread
     *               and receives the provided value.
     * @param <T> The type of the value.
     */
    protected final <T> void _runInApp( T value, Consumer<T> action ) {
        _runInApp(()->action.accept(value));
    }

    /**
     *  Use this to register a state change listener for the provided property
     *  which will be executed by the UI thread (see {@link EventProcessor}).
     *
     * @param val A property whose state changes should be listened to on the UI thread.
     * @param thisComponent The component which is wrapped by this builder.
     * @param displayAction A consumer lambda receiving the provided value and
     *                      is then executed by the UI thread.
     * @param <T> The type of the item wrapped by the provided property.
     */
    protected final <T> void _onShow( Val<T> val, C thisComponent, BiConsumer<C, T> displayAction )
    {
        Objects.requireNonNull(val);
        Objects.requireNonNull(displayAction);
        _onShow( new WeakReference<>(val), new WeakReference<>(thisComponent), displayAction );
    }

    protected final <T> UIForAnything<I,C,E> _withOnShow( Val<T> val, BiConsumer<C, T> displayAction )
    {
        Objects.requireNonNull(val);
        Objects.requireNonNull(displayAction);
        return _with( thisComponent -> _onShow( val, thisComponent, displayAction) );
    }

    private <T> void _onShow(
        WeakReference<Val<T>> propertyRef,
        WeakReference<C>      componentRef,
        BiConsumer<C, T>      displayAction
    ) {
        Objects.requireNonNull(propertyRef);
        Objects.requireNonNull(componentRef);
        Objects.requireNonNull(displayAction);
        Action<Val<T>> action = new Action<Val<T>>() {
            @Override
            public void accept( Val<T> value )
            {
                C thisComponent = componentRef.get();
                if ( thisComponent == null ) {
                    /*
                        We make sure that the action is only executed if the component
                        is not disposed. This is important because the action may
                        access the component, and we don't want to get a NPE.
                    */
                    Val<T> property = propertyRef.get();
                    if ( property != null )
                        property.unsubscribe(this);
                        // ^ We unsubscribe from the property because the component is disposed.
                    return;
                }

                T v = value.orElseNull(); // IMPORTANT! We first capture the value and then execute the action in the app thread.
                _runInUI(() ->
                    UI.run( () -> {
                        try {
                            displayAction.accept(thisComponent, v); // Here the captured value is used. This is extremely important!
                            /*
                                 Since this is happening in another thread we are using the captured property item/value.
                                 The property might have changed in the meantime, but we don't care about that,
                                 we want things to happen in the order they were triggered.
                             */
                        } catch ( Exception e ) {
                            throw new RuntimeException(
                                "Failed to apply state of property '" + propertyRef.get() + "' to " +
                                "component '" + thisComponent + "'.",
                                e
                            );
                        }
                    })
                );
            }
        };
        Optional.ofNullable(propertyRef.get()).ifPresent(
            property -> property.onChange(From.ALL, action)
        );
        CustomCleaner
            .getInstance()
            .register(componentRef.get(),
                () -> {
                    Val<T> property = propertyRef.get();
                    if ( property != null )
                        property.unsubscribe(action);
                }
            );
    }

    /**
     *  Use this to register a state change listener for the provided property list
     *  which will be executed by the UI thread (see {@link EventProcessor}).
     *
     * @param vals A property list whose state changes should be listened to on the UI thread.
     * @param c The component which is wrapped by this builder.
     * @param displayAction A consumer lambda receiving the action delegate and
     *                      is then executed by the UI thread.
     * @param <T> The type of the items wrapped by the provided property list.
     */
    protected final <T> void _onShow(
        Vals<T> vals, C c, BiConsumer<C, ValsDelegate<T>> displayAction
    ) {
        Objects.requireNonNull(vals);
        Objects.requireNonNull(displayAction);
        _onShow( vals, new WeakReference<>(c), displayAction );
    }

    protected final <T> UIForAnything<I,C,E> _withOnShow(
        Vals<T> vals, BiConsumer<C, ValsDelegate<T>> displayAction
    ) {
        Objects.requireNonNull(vals);
        Objects.requireNonNull(displayAction);
        return _with( thisComponent -> _onShow( vals, thisComponent, displayAction ) );
    }

    private <T> void _onShow(
        Vals<T> properties, WeakReference<C> ref, BiConsumer<C, ValsDelegate<T>> displayAction
    ) {
        Objects.requireNonNull(properties);
        Objects.requireNonNull(displayAction);
        Action<ValsDelegate<T>> action = new Action<ValsDelegate<T>>() {
            @Override
            public void accept( ValsDelegate<T> delegate ) {
                C thisComponent = ref.get();
                if ( thisComponent == null ) {
                    properties.unsubscribe(this); // We unsubscribe from the property if the component is disposed.
                    return;
                }
                _runInUI(() ->{
                    displayAction.accept(thisComponent, delegate);
                    /*
                        We make sure that the action is only executed if the component
                        is not disposed. This is important because the action may
                        access the component, and we don't want to get a NPE.
                    */
                });
            }
        };
        properties.onChange(action);
        CustomCleaner.getInstance().register(ref.get(), () -> properties.unsubscribe(action));
    }

    /**
     *  Exposes the this-pointer of the builder instance cast to the {@code I} type
     *  parameter of the builder class. <br>
     *  This is done to reduce the amount of type casting
     *  and warnings in the codebase. <br>
     * @return The builder instance itself based on the type parameter {@code <I>}.
     */
    protected final I _this() { return (I) this; }

    /**
     *  This method is used to dispose of the state of the builder,
     *  which means that the builder state disposes of its reference to either
     *  the wrapped component or the wrapped component or the composite of component
     *  factories which are used to build the wrapped component eagerly each time
     *  the wrapped component is accessed. <br>
     *  This is important to avoid memory leaks, as a component is typically
     *  part of a tree of components, and if one component is not garbage collected,
     *  then the whole tree is not garbage collected.
     */
    protected final void _disposeState() { _state().dispose(); }

    @Override
    public final int hashCode() {
        return _state().hashCode();
    }

    @Override
    @SuppressWarnings("EqualsGetClass")
    public final boolean equals( Object obj ) {
        if ( obj == null ) return false;
        if ( obj == this ) return true;
        if ( obj.getClass() != getClass() ) return false;
        UIForAnything<?,?,?> other = (UIForAnything<?,?,?>) obj;
        return _state().equals(other._state());
    }

    @Override
    public final String toString() {
        String componentTypeName = _state().componentType().getName();
        String builderTypeName   = getClass().getSimpleName();
        String asString          = builderTypeName + "[" + componentTypeName + "]";

        if ( _state().isDisposed() ) {
            // We make the whole string strikethrough if the builder is disposed.
            StringBuilder sb = new StringBuilder();
            for ( int i = 0; i < asString.length(); i++ )
                sb.append(asString.charAt(i)).append("\u0336");
            asString = sb.toString();
        }

        return asString;
    }

}