package com.constellio.app.ui.util;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.vaadin.ui.Component;
import com.vaadin.ui.ComponentContainer;
import com.vaadin.ui.CustomComponent;
import com.vaadin.ui.SingleComponentContainer;
/**
* Adapted from https://vaadin.com/forum/#!/thread/217291/217290
*
* @author Vincent
*/
public class ComponentTreeUtils {
@SuppressWarnings("unchecked")
public static <T> T findParent(Component component, Class<T> clazz) {
T match = null;
Component currentParent = component;
while (match == null && currentParent != null) {
if (clazz.isAssignableFrom(currentParent.getClass())) {
match = (T) currentParent;
break;
}
currentParent = currentParent.getParent();
}
return match;
}
public static <T> T getFirstChild(Component component, Class<T> clazz) {
List<T> matches = getChildren(component, clazz);
return !matches.isEmpty() ? matches.get(0) : null;
}
public static <T> List<T> getChildren(Component component, Class<T> clazz) {
final List<T> matches = new ArrayList<T>();
traverse(component, new FindByClass<T>(clazz, matches));
return matches;
}
/**
* Traverse all components under a given component.
*
* @param component
* @param invocation
*/
public static void traverse(Component component, MethodInvoker invocation) {
traverse("Self", component, invocation);
}
private static void traverse(String theCaller, Component component, MethodInvoker invocation) {
// Self
invocation.invokeMethod(theCaller, component);
// Content of Panel and children of Window
if (component instanceof SingleComponentContainer) {
final SingleComponentContainer singleComponentContainer = (SingleComponentContainer) component;
if (singleComponentContainer.getContent() != null) {
traverse(singleComponentContainer.toString(), singleComponentContainer.getContent(), invocation);
}
} else if (component instanceof CustomComponent) {
final CustomComponent customComponent = (CustomComponent) component;
// All the contained components
final Iterator<Component> subComponents = customComponent.iterator();
while (subComponents.hasNext()) {
Component subComponent = subComponents.next();
traverse(component.toString(), subComponent, invocation);
}
} else if (component instanceof ComponentContainer) {
ComponentContainer componentContainer = (ComponentContainer) component;
// All the contained components
final Iterator<Component> subComponents = componentContainer.iterator();
while (subComponents.hasNext()) {
Component subComponent = subComponents.next();
traverse(component.toString(), subComponent, invocation);
}
}
}
/**
* Just invoke any method on a component of the Application graph, just implement the only method
* {@link #invokeMethod(String, Object)}.
*
* @version $Id: ComponentTraverser.java,v 1.11 2010/09/14 19:40:32 tettoni Exp $
*/
public static interface MethodInvoker {
/**
* Invoke a method on theTarget.
*
* @param theCaller
* Only for logging - not functional
* @param theTarget
* The target object to invoke on.
*/
public void invokeMethod(String theCaller, Object theTarget);
}
public static class FindByClass<C> implements MethodInvoker {
private Class<C> clazz;
private List<C> matches;
public FindByClass(Class<C> clazz, List<C> matches) {
this.clazz = clazz;
this.matches = matches;
}
@SuppressWarnings("unchecked")
@Override
public void invokeMethod(String theCaller, Object theTarget) {
if (clazz.isAssignableFrom(theTarget.getClass())) {
matches.add((C) theTarget);
}
}
}
}