All Downloads are FREE. Search and download functionalities are using the official Maven repository.

swingtree.ComponentDelegate Maven / Gradle / Ivy

package swingtree;

import sprouts.Action;

import javax.swing.JComponent;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 *  Instances of this are delegates for a specific components and events that
 *  are passed to user event action handlers (see {@link Action}),
 *  with the purpose of providing useful context information to the action handler.
 *  
* You would typically use this to access and change the state of the component, schedule animations * for the component or query the tree of neighboring components.
* Here a nice usage example where the delegate is used to animate a button: *
{@code
 *      button("I turn green when you hover over me")
 *      .onMouseEnter( it ->
 *          it.animateFor(0.5, TimeUnit.SECONDS, state -> {
 *              double highlight = 1 - state.progress() * 0.5;
 *              it.setBackgroundColor(highlight, 1, highlight);
 *          })
 *      )
 *      .onMouseExit( it ->
 *          it.animateFor(0.5, TimeUnit.SECONDS, state -> {
 *              double highlight = 0.5 + state.progress() * 0.5;
 *              it.setBackgroundColor(highlight, 1, highlight);
 *          })
 *      )
 *  }
* In this example the {@code it} parameter is a {@code ComponentDelegate} * which can be used to access/modify the button, the event, the sibling components... * ...but also exposes a nice API to schedule animations for the button. *

* For some more examples please take a look at the * living swing-tree documentation * where you can browse a large collection of examples demonstrating how to use the API of this class. * * @param The delegate (in most cases origin UI component) type parameter stored by this. * @param The event type parameter of the event stored by this. */ public class ComponentDelegate extends AbstractDelegate { private final E _event; public ComponentDelegate( C component, E event ) { super(false, component, component); _event = Objects.requireNonNull(event); } /** * Exposes the underlying component from which this delegate * and user event actions originate. * This method may only be called by the Swing thread. * If another thread calls this method, an exception will be thrown. * * @return The component for which the current {@link Action} originated. * @throws IllegalStateException If this method is called from a non-Swing thread. */ public final C getComponent() { // We make sure that only the Swing thread can access the component: if ( UI.thisIsUIThread() ) return _component(); else throw new IllegalStateException( "Component can only be accessed by the Swing thread." ); } /** * Use this to access the component of this delegate in the swing thread. * This method will make sure that the passed lambda will * be executed by the Swing thread. *

* @param action The action consuming the component, * which will be executed by the Swing thread. */ public final void forComponent( Consumer action ) { if ( UI.thisIsUIThread() ) action.accept(_component()); else UI.run( () -> action.accept(_component()) ); } public final E getEvent() { return _event; } /** * Exposes the "siblings", which consist of all * the child components of the parent of the delegated component * except the for the delegated component itself. * * @return A list of all siblings excluding the component from which this instance originated. */ public final List getSiblings() { // We make sure that only the Swing thread can access the sibling components: if ( !UI.thisIsUIThread() ) throw new IllegalStateException( "Sibling components can only be accessed by the Swing thread. " + "Please use 'forSiblings(..)' methods instead." ); return _siblingsSource().stream().filter( s -> _component() != s ).collect(Collectors.toList()); } /** * Use this to access the sibling components of this delegate in the swing thread. * This method will make sure that the passed lambda will * be executed by the Swing thread. *

* @param action The action consuming a list of all siblings (excluding the * component from which this instance originated), * which will be executed by the Swing thread. */ public final void forSiblings( Consumer> action ) { if ( UI.thisIsUIThread() ) action.accept(getSiblings()); else UI.run( () -> action.accept(getSiblings()) ); } /** * Allows you to query the sibling components of the delegated component * of the specified type. So a list of all siblings which are of the specified type * will be returned, excluding the currently delegated component itself.
* Note that this method may only be called by the Swing thread. * If another thread calls this method, an exception will be thrown. * Use {@link #forSiblingsOfType(Class, Consumer)} to access the sibling components * of the specified type in a thread-safe way. * * @param type The type class of the sibling components to return. * @param The type of the sibling components to return. * @return A list of all siblings of the specified type, excluding the component from which this instance originated. */ public final List getSiblingsOfType(Class type) { // We make sure that only the Swing thread can access the sibling components: if ( !UI.thisIsUIThread() ) throw new IllegalStateException( "Sibling components can only be accessed by the Swing thread. " + "Please use 'forSiblingsOfType(..)' methods instead." ); return getSiblings() .stream() .filter( s -> type.isAssignableFrom(s.getClass()) ) .map( s -> (T) s ) .collect(Collectors.toList()); } /** * Use this to access the sibling components of this delegate * of the specified type in the swing thread. * This method will make sure that the passed lambda will * be executed by the Swing thread. *

* @param type The type class of the sibling components to return. * @param The {@link JComponent} type of the sibling components to return. * @param action The action consuming a list of all siblings of the specified type, * excluding the component from which this instance originated, * which will be executed by the Swing thread. */ public final void forSiblingsOfType( Class type, Consumer> action ) { if ( UI.thisIsUIThread() ) action.accept(getSiblingsOfType(type)); else UI.run( () -> action.accept(getSiblingsOfType(type)) ); } /** * This method provides a convenient way to access all the children of the parent component * of the component this delegate is for. * Note that this method may only be called by the Swing thread. * If another thread calls this method, an exception will be thrown. * Use {@link #forSiblinghood(Consumer)} to access the sibling components * * @return A list of all siblings including the component from which this instance originated. */ public final List getSiblinghood() { // We make sure that only the Swing thread can access the sibling components: if ( !UI.thisIsUIThread() ) throw new IllegalStateException( "Sibling components can only be accessed by the Swing thread. " + "Please use 'forSiblinghood(..)' methods instead." ); return new ArrayList<>(_siblingsSource()); } /** * Use this to access the sibling components of this delegate in the swing thread. * This method will make sure that the passed lambda will * be executed by the Swing thread. *

* @param action The action consuming a list of all siblings (including the * component from which this instance originated), * which will be executed by the Swing thread. */ public final void forSiblinghood( Consumer> action ) { if ( UI.thisIsUIThread() ) action.accept(getSiblinghood()); else UI.run( () -> action.accept(getSiblinghood()) ); } /** * Allows you to query the sibling components of the delegated component * of the specified type. So a list of all siblings which are of the specified type * will be returned, possibly including the delegated component itself.
* Note that this method may only be called by the Swing thread. * If another thread calls this method, an exception will be thrown. * Use {@link #forSiblinghoodOfType(Class, Consumer)} to access the sibling components * of the specified type in a thread-safe way. * * @param type The type of the sibling components to return. * @param The {@link JComponent} type of the sibling components to return. * @return A list of all siblings of the specified type, including the component from which this instance originated. */ public final List getSiblinghoodOfType(Class type) { // We make sure that only the Swing thread can access the sibling components: if ( !UI.thisIsUIThread() ) throw new IllegalStateException( "Sibling components can only be accessed by the Swing thread. " + "Please use 'forSiblinghoodOfType(..)' methods instead." ); return new ArrayList<>(_siblingsSource()) .stream() .filter( s -> type.isAssignableFrom(s.getClass()) ) .map( s -> (T) s ) .collect(Collectors.toList()); } /** * Use this to access all sibling components (including the one represented by this delegate) * of the specified type in the swing thread. * This method will make sure that the passed lambda will * be executed by the Swing thread. *

* @param type The type of the sibling components to return. * @param The {@link JComponent} type of the sibling components to return. * @param action The action consuming a list of all siblings of the specified type, * including the component from which this instance originated, * which will be executed by the Swing thread. */ public final void forSiblinghoodOfType( Class type, Consumer> action ) { if ( UI.thisIsUIThread() ) action.accept(getSiblinghoodOfType(type)); else UI.run( () -> action.accept(getSiblinghoodOfType(type)) ); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy