blob: 739e40847e7039c2cc65a5c8cd812a432f087585 [file] [log] [blame]
/**
*
* Copyright (c) 2011, 2016 - Loetz GmbH&Co.KG (69115 Heidelberg, Germany)
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Christophe Loetz (Loetz GmbH&Co.KG) - initial implementation
*/
package org.eclipse.osbp.osgi.hybrid.api;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.eclipse.osbp.ui.api.themes.EnumCssClass;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.vaadin.event.FieldEvents.BlurEvent;
import com.vaadin.event.FieldEvents.BlurListener;
import com.vaadin.event.FieldEvents.BlurNotifier;
import com.vaadin.event.FieldEvents.FocusEvent;
import com.vaadin.event.FieldEvents.FocusListener;
import com.vaadin.event.FieldEvents.FocusNotifier;
import com.vaadin.server.AbstractClientConnector;
import com.vaadin.ui.AbstractComponent;
import com.vaadin.ui.AbstractComponentContainer;
import com.vaadin.ui.AbstractLayout;
import com.vaadin.ui.Component;
import com.vaadin.ui.HasComponents;
import com.vaadin.ui.HasComponents.ComponentAttachDetachNotifier;
import com.vaadin.ui.HasComponents.ComponentAttachEvent;
import com.vaadin.ui.HasComponents.ComponentAttachListener;
import com.vaadin.ui.HasComponents.ComponentDetachEvent;
import com.vaadin.ui.HasComponents.ComponentDetachListener;
public class RecursiveFocusBlurListener implements ComponentAttachListener, ComponentDetachListener {
private static final Logger LOGGER = LoggerFactory.getLogger(RecursiveFocusBlurListener.class);
private AbstractComponentContainer fParent;
protected RecursiveFocusBlurListener(AbstractComponentContainer container) {
fParent = container;
}
public static RecursiveFocusBlurListener attachFor(AbstractComponentContainer container) {
RecursiveFocusBlurListener listener = new RecursiveFocusBlurListener(container);
listener.recursiveAddComponentAttachDetachListener(container);
listener.recursiveAddFocusBlurListener(container);
return listener;
}
public void detach() {
recursiveRemoveComponentAttachDetachListener(fParent);
recursiveRemoveFocusBlurListener(fParent);
}
private FocusListener fFocusListener = new FocusListener() {
@Override
public void focus(FocusEvent event) {
if (event.getComponent() instanceof AbstractComponent) {
AbstractComponent component = (AbstractComponent) event.getComponent();
recursiveFocus((AbstractComponent)event.getComponent());
}
}
};
private void recursiveFocus(AbstractComponent component) {
if (component != null) {
component.addStyleName(EnumCssClass.HAS_FOCUS.styleName());
if (!component.equals(fParent) && (component.getParent() instanceof AbstractComponent)) {
recursiveFocus((AbstractComponent)component.getParent());
}
}
}
private BlurListener fBlurListener = new BlurListener() {
@Override
public void blur(BlurEvent event) {
if (event.getComponent() instanceof AbstractComponent) {
AbstractComponent component = (AbstractComponent) event.getComponent();
recursiveBlur((AbstractComponent)event.getComponent());
}
}
};
private void recursiveBlur(AbstractComponent component) {
if (component != null) {
component.removeStyleName(EnumCssClass.HAS_FOCUS.styleName());
if (!component.equals(fParent) && (component.getParent() instanceof AbstractComponent)) {
recursiveBlur((AbstractComponent)component.getParent());
}
}
}
private static final long serialVersionUID = 3497317619845108761L;
@Override
public void componentAttachedToContainer(ComponentAttachEvent event) {
if (event.getAttachedComponent() instanceof ComponentAttachDetachNotifier) {
recursiveAddComponentAttachDetachListener((ComponentAttachDetachNotifier)event.getAttachedComponent());
}
if (event.getAttachedComponent() instanceof AbstractClientConnector) {
recursiveAddFocusBlurListener((AbstractClientConnector)event.getAttachedComponent());
}
}
@Override
public void componentDetachedFromContainer(ComponentDetachEvent event) {
if (event.getDetachedComponent() instanceof ComponentAttachDetachNotifier) {
recursiveRemoveComponentAttachDetachListener((ComponentAttachDetachNotifier)event.getDetachedComponent());
}
if (event.getDetachedComponent() instanceof AbstractComponent) {
recursiveRemoveFocusBlurListener((AbstractComponent)event.getDetachedComponent());
}
}
private void recursiveAddComponentAttachDetachListener(ComponentAttachDetachNotifier container) {
AbstractComponent ccontainer = (AbstractComponent) container;
//ccontainer.setImmediate(true);
Collection<?> attachListeners = ccontainer.getListeners(ComponentAttachEvent.class);
if (!attachListeners.contains(this)) {
container.addComponentAttachListener(this);
}
Collection<?> detachListeners = ccontainer.getListeners(ComponentDetachEvent.class);
if (!detachListeners.contains(this)) {
container.addComponentAttachListener(this);
}
if (container instanceof HasComponents) {
Iterator<Component> iterator = ((HasComponents)container).iterator();
while (iterator.hasNext()) {
Component component = iterator.next();
if (component instanceof ComponentAttachDetachNotifier) {
recursiveAddComponentAttachDetachListener((ComponentAttachDetachNotifier)component);
}
}
}
}
private void recursiveRemoveComponentAttachDetachListener(ComponentAttachDetachNotifier container) {
container.removeComponentAttachListener(this);
container.removeComponentAttachListener(this);
if (container instanceof HasComponents) {
Iterator<Component> iterator = ((HasComponents)container).iterator();
while (iterator.hasNext()) {
Component component = iterator.next();
if (component instanceof AbstractComponentContainer) {
recursiveRemoveComponentAttachDetachListener((AbstractComponentContainer)component);
}
}
}
}
private Map<Class<?>,Method> fAddFocusListenerMethods = new HashMap<>();
private Map<Class<?>,Method> fRemoveFocusListenerMethods = new HashMap<>();
private Map<Class<?>,Method> fAddBlurListenerMethods = new HashMap<>();
private Map<Class<?>,Method> fRemoveBlurListenerMethods = new HashMap<>();
private static Set<String> fFocusListenerLogList = new HashSet<>();
private static Set<String> fBlurListenerLogList = new HashSet<>();
private void addFocusListener(AbstractClientConnector component) {
Method addFocusListenerMethod = fAddFocusListenerMethods.get(component.getClass());
if (addFocusListenerMethod == null) {
try {
addFocusListenerMethod = component.getClass().getDeclaredMethod("addFocusListener", FocusListener.class);
if (addFocusListenerMethod != null) {
fAddFocusListenerMethods.put(component.getClass(), addFocusListenerMethod);
Method removeFocusListenerMethod = component.getClass().getDeclaredMethod("removeFocusListener", FocusListener.class);
if (removeFocusListenerMethod != null) {
fRemoveFocusListenerMethods.put(component.getClass(), removeFocusListenerMethod);
}
}
}
catch (NoSuchMethodException | SecurityException e) {
}
}
String className = component.getClass().getCanonicalName();
if (fFocusListenerLogList.contains(className)) {
className = null;
}
else {
fFocusListenerLogList.add(className);
}
if (addFocusListenerMethod != null) {
try {
addFocusListenerMethod.invoke(component, new Object[] {fFocusListener});
}
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
if ((className != null) && LOGGER.isWarnEnabled()) { LOGGER.warn("focuL: "+className+" could not invoke "+e.getLocalizedMessage()); }
}
}
else {
if (!(component instanceof AbstractLayout)) {
if ((className != null) && LOGGER.isWarnEnabled()) { LOGGER.warn("focuL: "+className+" DOESN'T IMPLEMENT FocusNotifier"); }
}
}
}
private void addBlurListener(AbstractClientConnector component) {
Method addBlurListenerMethod = fAddBlurListenerMethods.get(component.getClass());
if (addBlurListenerMethod == null) {
try {
addBlurListenerMethod = component.getClass().getDeclaredMethod("addBlurListener", BlurListener.class);
if (addBlurListenerMethod != null) {
fAddBlurListenerMethods.put(component.getClass(), addBlurListenerMethod);
Method removeBlurListenerMethod = component.getClass().getDeclaredMethod("removeBlurListener", BlurListener.class);
if (removeBlurListenerMethod != null) {
fRemoveBlurListenerMethods.put(component.getClass(), removeBlurListenerMethod);
}
}
}
catch (NoSuchMethodException | SecurityException e) {
}
}
String className = component.getClass().getCanonicalName();
if (fBlurListenerLogList.contains(className)) {
className = null;
}
else {
fBlurListenerLogList.add(className);
}
if (addBlurListenerMethod != null) {
try {
addBlurListenerMethod.invoke(component, new Object[] {fBlurListener});
}
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
if ((className != null) && LOGGER.isWarnEnabled()) { LOGGER.warn("blurL: "+className+" could not invoke "+e.getLocalizedMessage()); }
}
}
else {
if (!(component instanceof AbstractLayout)) {
if ((className != null) && LOGGER.isWarnEnabled()) { LOGGER.warn("blurL: "+className+" DOESN'T IMPLEMENT BlurNotifier"); }
}
}
}
private void recursiveAddFocusBlurListener(AbstractClientConnector component) {
Collection<?> focusListeners = ((AbstractClientConnector)component).getListeners(FocusEvent.class);
if (!focusListeners.contains(fFocusListener)) {
if (component instanceof FocusNotifier) {
((FocusNotifier) component).addFocusListener(fFocusListener);
}
else {
addFocusListener(component);
}
if (component instanceof BlurNotifier) {
((BlurNotifier) component).addBlurListener(fBlurListener);
}
else {
addBlurListener(component);
}
}
if (component instanceof AbstractComponentContainer) {
Iterator<Component> iterator = ((AbstractComponentContainer)component).iterator();
while (iterator.hasNext()) {
Component child = iterator.next();
if (component instanceof AbstractClientConnector) {
recursiveAddFocusBlurListener((AbstractClientConnector)child);
}
}
}
}
private void recursiveRemoveFocusBlurListener(AbstractClientConnector component) {
if (component instanceof FocusNotifier) {
((FocusNotifier) component).removeFocusListener(fFocusListener);
}
else {
Method removeFocusListenerMethod = fRemoveFocusListenerMethods.get(component.getClass());
if (removeFocusListenerMethod != null) {
try {
removeFocusListenerMethod.invoke(component, new Object[] {fFocusListener});
}
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
}
}
}
if (component instanceof BlurNotifier) {
((BlurNotifier) component).removeBlurListener(fBlurListener);
}
else {
Method removeBlurListenerMethod = fRemoveBlurListenerMethods.get(component.getClass());
if (removeBlurListenerMethod != null) {
try {
removeBlurListenerMethod.invoke(component, new Object[] {fBlurListener});
}
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
}
}
}
if (component instanceof HasComponents) {
Iterator<Component> iterator = ((HasComponents)component).iterator();
while (iterator.hasNext()) {
Component child = iterator.next();
if (component instanceof AbstractComponent) {
recursiveRemoveFocusBlurListener((AbstractComponent)child);
}
}
}
}
}