GuiTraverser.java

package swingtree;

import org.slf4j.Logger;

import java.awt.Component;
import java.awt.Container;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.Stream;

/**
 *  Traverses the component tree starting from a given component and finds all components
 *  that match a supplied predicate and type.
 */
final class GuiTraverser
{
    private static final Logger log = org.slf4j.LoggerFactory.getLogger(GuiTraverser.class);
    private final Component _current;


    GuiTraverser( Component current ) {
        Objects.requireNonNull(current);
        _current = current;
    }

    <C extends Component> Stream<C> find( Class<C> type, Predicate<C> predicate ) {
        return find( c -> {
                   boolean isType = type.isAssignableFrom(c.getClass());
                   if ( !isType ) return false;
                   try {
                       return predicate.test(type.cast(c));
                   } catch (Exception e) {
                       log.error(
                               "An exception occurred while testing " +
                               "a component of type '" + type.getSimpleName() + "'!",
                               e
                           );
                       return false;
                   }
               })
               .map( type::cast );
    }

    Stream<Component> find( Predicate<Component> predicate ) {
        List<Component> roots = traverseUpwardsAndFindAllRoots(_current, new ArrayList<>());
        return roots.stream()
                    .flatMap( c -> _traverseDownwardsAndFind(c, predicate).stream() );
    }

    private List<Component> traverseUpwardsAndFindAllRoots(
        Component component,
        List<Component> roots
    ) {
        Component parent = _findRootParentOf(component);
        roots.add(parent);
        if ( parent.getParent() != null ) {
            return traverseUpwardsAndFindAllRoots(parent.getParent(), roots);
        }
        else
            return roots;
    }

    private Component _findRootParentOf( Component component ) {
        Container parent = component.getParent();
        if ( _acknowledgesParenthood( parent, component ) )
            return _findRootParentOf( parent );
        else
            return component;
    }

    private boolean _acknowledgesParenthood( Component parent, Component child ) {
        if ( parent instanceof Container ) {
            Container container = (Container) parent;
            for ( Component component : container.getComponents() )
                if ( component == child )
                    return true;
        }
        return false;
    }

    private List<Component> _traverseDownwardsAndFind( Component cmp, Predicate<Component> predicate )
    {
        List<Component> found = new ArrayList<>();
        _traverseDownwardsAndFind(cmp, predicate, found);
        return found;
    }

    private void _traverseDownwardsAndFind(
        Component cmp,
        Predicate<Component> predicate,
        List<Component> found
    ) {
        if( cmp == null ) return; // Not a container, return
        // Add this component
        if ( predicate.test(cmp) && !found.contains(cmp) )
            found.add(cmp);

        if ( cmp instanceof Container ) { // A container, let's traverse it.
            Container container = (Container) cmp;
            // Go visit and add all children
            for ( Component subComponent : container.getComponents() )
                _traverseDownwardsAndFind(subComponent, predicate, found);
        }
    }
}