/* * Copyright (c) 2010, grossmann * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the jo-widgets.org nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL jo-widgets.org BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ package org.jowidgets.impl.base.delegate; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import org.jowidgets.api.controller.IContainerListener; import org.jowidgets.api.controller.IContainerRegistry; import org.jowidgets.api.controller.IDisposeListener; import org.jowidgets.api.controller.IListenerFactory; import org.jowidgets.api.toolkit.Toolkit; import org.jowidgets.api.widgets.IComponent; import org.jowidgets.api.widgets.IContainer; import org.jowidgets.api.widgets.IControl; import org.jowidgets.api.widgets.IPopupMenu; import org.jowidgets.common.widgets.IControlCommon; import org.jowidgets.common.widgets.controller.IComponentListener; import org.jowidgets.common.widgets.controller.IFocusListener; import org.jowidgets.common.widgets.controller.IKeyListener; import org.jowidgets.common.widgets.controller.IMouseListener; import org.jowidgets.common.widgets.controller.IPopupDetectionListener; import org.jowidgets.common.widgets.descriptor.IWidgetDescriptor; import org.jowidgets.common.widgets.factory.ICustomWidgetCreator; import org.jowidgets.impl.base.delegate.RecursiveListenenerManager.IListenerRegistrationDelegate; import org.jowidgets.spi.widgets.IContainerSpi; import org.jowidgets.util.Assert; public class ContainerDelegate extends DisposableDelegate { private final IContainerSpi containerSpi; private final IContainer container; private final List<IControl> children; private final PopupMenuCreationDelegate popupMenuCreationDelegate; private final Set<IContainerListener> containerListeners; private final Set<IContainerRegistry> containerRegistries; private final IContainerRegistry containerRegistry; private final Map<IListenerFactory<?>, RecursiveListenenerManager<?>> listenenerManagers; private boolean onRemoveByDispose; private Runnable layoutRunnable; public ContainerDelegate(final IContainerSpi containerSpi, final IContainer container) { Assert.paramNotNull(containerSpi, "containerWidget"); Assert.paramNotNull(container, "widget"); this.containerSpi = containerSpi; this.container = container; this.children = new LinkedList<IControl>(); this.containerListeners = new LinkedHashSet<IContainerListener>(); this.containerRegistries = new LinkedHashSet<IContainerRegistry>(); this.listenenerManagers = new HashMap<IListenerFactory<?>, RecursiveListenenerManager<?>>(); this.popupMenuCreationDelegate = new PopupMenuCreationDelegate(containerSpi, container); this.onRemoveByDispose = false; this.containerRegistry = new IContainerRegistry() { @Override public void register(final IControl control) { control.addDisposeListener(new DisposeListener(control)); for (final IContainerRegistry registry : containerRegistries) { registry.register(control); } } @Override public void unregister(final IControl control) { for (final IContainerRegistry registry : containerRegistries) { registry.unregister(control); } } }; } public IPopupMenu createPopupMenu() { return popupMenuCreationDelegate.createPopupMenu(); } @Override public void dispose() { if (!isDisposed()) { if (container instanceof IControl && container.getParent() != null && (((IControl) container).getParent()).getChildren().contains(container) && !onRemoveByDispose) { onRemoveByDispose = true; (((IControl) container).getParent()).remove((IControl) container); //this will invoke dispose by the parent container onRemoveByDispose = false; } else { popupMenuCreationDelegate.dispose(); final List<IControl> childrenCopy = new LinkedList<IControl>(children); //clear the children to avoid that children will be removed //unnecessarily from its parent container on dispose invocation children.clear(); for (final IControl child : childrenCopy) { if (child instanceof IContainer) { ((IContainer) child).removeContainerRegistry(containerRegistry); } child.dispose(); } containerRegistries.clear(); containerListeners.clear(); for (final RecursiveListenenerManager<?> listenenerManager : listenenerManagers.values()) { listenenerManager.dispose(); } listenenerManagers.clear(); super.dispose(); } } } public void addContainerListener(final IContainerListener listener) { containerListeners.add(listener); } public void removeContainerListener(final IContainerListener listener) { containerListeners.remove(listener); } public void addContainerRegistry(final IContainerRegistry registry) { Assert.paramNotNull(registry, "registry"); containerRegistries.add(registry); for (final IControl control : new LinkedList<IControl>(children)) { registerCurrentChildrenRecursively(control, registry); } } public void removeContainerRegistry(final IContainerRegistry registry) { containerRegistries.remove(registry); } public void addComponentListenerRecursive(final IListenerFactory<IComponentListener> listenerFactory) { final IListenerRegistrationDelegate<IComponentListener> registrationDelegate; registrationDelegate = new IListenerRegistrationDelegate<IComponentListener>() { @Override public void addListener(final IComponent component, final IComponentListener listener) { component.addComponentListener(listener); } @Override public void removeListener(final IComponent component, final IComponentListener listener) { component.removeComponentListener(listener); } }; addListenerRecursive(listenerFactory, registrationDelegate); } public void removeComponentListenerRecursive(final IListenerFactory<IComponentListener> listenerFactory) { removeListenerRecursive(listenerFactory); } public void addFocusListenerRecursive(final IListenerFactory<IFocusListener> listenerFactory) { final IListenerRegistrationDelegate<IFocusListener> registrationDelegate; registrationDelegate = new IListenerRegistrationDelegate<IFocusListener>() { @Override public void addListener(final IComponent component, final IFocusListener listener) { component.addFocusListener(listener); } @Override public void removeListener(final IComponent component, final IFocusListener listener) { component.removeFocusListener(listener); } }; addListenerRecursive(listenerFactory, registrationDelegate); } public void removeFocusListenerRecursive(final IListenerFactory<IFocusListener> listenerFactory) { removeListenerRecursive(listenerFactory); } public void addKeyListenerRecursive(final IListenerFactory<IKeyListener> listenerFactory) { final IListenerRegistrationDelegate<IKeyListener> registrationDelegate; registrationDelegate = new IListenerRegistrationDelegate<IKeyListener>() { @Override public void addListener(final IComponent component, final IKeyListener listener) { component.addKeyListener(listener); } @Override public void removeListener(final IComponent component, final IKeyListener listener) { component.removeKeyListener(listener); } }; addListenerRecursive(listenerFactory, registrationDelegate); } public void removeKeyListenerRecursive(final IListenerFactory<IKeyListener> listenerFactory) { removeListenerRecursive(listenerFactory); } public void addMouseListenerRecursive(final IListenerFactory<IMouseListener> listenerFactory) { final IListenerRegistrationDelegate<IMouseListener> registrationDelegate; registrationDelegate = new IListenerRegistrationDelegate<IMouseListener>() { @Override public void addListener(final IComponent component, final IMouseListener listener) { component.addMouseListener(listener); } @Override public void removeListener(final IComponent component, final IMouseListener listener) { component.removeMouseListener(listener); } }; addListenerRecursive(listenerFactory, registrationDelegate); } public void removeMouseListenerRecursive(final IListenerFactory<IMouseListener> listenerFactory) { removeListenerRecursive(listenerFactory); } public void addPopupDetectionListenerRecursive(final IListenerFactory<IPopupDetectionListener> listenerFactory) { final IListenerRegistrationDelegate<IPopupDetectionListener> registrationDelegate; registrationDelegate = new IListenerRegistrationDelegate<IPopupDetectionListener>() { @Override public void addListener(final IComponent component, final IPopupDetectionListener listener) { component.addPopupDetectionListener(listener); } @Override public void removeListener(final IComponent component, final IPopupDetectionListener listener) { component.removePopupDetectionListener(listener); } }; addListenerRecursive(listenerFactory, registrationDelegate); } public void removePopupDetectionListenerRecursive(final IListenerFactory<IPopupDetectionListener> listenerFactory) { removeListenerRecursive(listenerFactory); } public void layoutLater() { if (layoutRunnable == null) { layoutRunnable = new Runnable() { @Override public void run() { if (!container.isDisposed()) { container.layout(); } layoutRunnable = null; } }; Toolkit.getUiThreadAccess().invokeLater(layoutRunnable); } } public <WIDGET_TYPE extends IControl> WIDGET_TYPE add( final int index, final IWidgetDescriptor<? extends WIDGET_TYPE> descriptor, final Object layoutConstraints) { return add(Integer.valueOf(index), descriptor, layoutConstraints); } public <WIDGET_TYPE extends IControl> WIDGET_TYPE add( final int index, final IWidgetDescriptor<? extends WIDGET_TYPE> descriptor) { return add(index, descriptor, null); } public <WIDGET_TYPE extends IControl> WIDGET_TYPE add( final int index, final ICustomWidgetCreator<WIDGET_TYPE> creator, final Object layoutConstraints) { return add(Integer.valueOf(index), creator, layoutConstraints); } public <WIDGET_TYPE extends IControl> WIDGET_TYPE add(final int index, final ICustomWidgetCreator<WIDGET_TYPE> creator) { return add(Integer.valueOf(index), creator, null); } public <WIDGET_TYPE extends IControl> WIDGET_TYPE add( final IWidgetDescriptor<? extends WIDGET_TYPE> descriptor, final Object layoutConstraints) { return add(null, descriptor, layoutConstraints); } public <WIDGET_TYPE extends IControl> WIDGET_TYPE add( final ICustomWidgetCreator<WIDGET_TYPE> creator, final Object layoutConstraints) { return add(null, creator, layoutConstraints); } public <WIDGET_TYPE extends IControl> WIDGET_TYPE add(final IWidgetDescriptor<? extends WIDGET_TYPE> descriptor) { return add(descriptor, null); } public <WIDGET_TYPE extends IControl> WIDGET_TYPE add(final ICustomWidgetCreator<WIDGET_TYPE> creator) { return add(creator, null); } public <WIDGET_TYPE extends IControl> WIDGET_TYPE add( final Integer index, final IWidgetDescriptor<? extends WIDGET_TYPE> descriptor, final Object layoutConstraints) { final WIDGET_TYPE result = containerSpi.add(index, descriptor, layoutConstraints); afterAdded(index, result); return result; } public <WIDGET_TYPE extends IControl> WIDGET_TYPE add( final Integer index, final ICustomWidgetCreator<WIDGET_TYPE> creator, final Object layoutConstraints) { final WIDGET_TYPE result = containerSpi.add(index, creator, layoutConstraints); afterAdded(index, result); return result; } public void setTabOrder(final Collection<? extends IControl> tabOrder) { containerSpi.setTabOrder(tabOrder); } public void setTabOrder(final IControl... controls) { if (controls != null) { containerSpi.setTabOrder(Arrays.asList(controls)); } else { final Collection<IControlCommon> emptyList = Collections.emptyList(); containerSpi.setTabOrder(emptyList); } } public List<IControl> getChildren() { return Collections.unmodifiableList(new LinkedList<IControl>(children)); } public void removeAll() { final List<IControl> childrenCopy = new LinkedList<IControl>(children); children.clear(); for (final IControl child : childrenCopy) { fireBeforeRemove(child); child.dispose(); } containerSpi.removeAll(); } public boolean remove(final IControl control) { Assert.paramNotNull(control, "control"); if (children.contains(control)) { fireBeforeRemove(control); boolean removed = children.remove(control); control.dispose(); removed = removed && containerSpi.remove(control); if (removed) { return true; } else { throw new IllegalStateException( "Control could not be removed from spi container. This seems to be a bug. Please report this"); } } else { return false; } } private void afterAdded(final Integer index, final IControl control) { control.setParent(container); if (index != null) { children.add(index.intValue(), control); } else { children.add(control); } fireAfterAdded(control); registerNewCreatedChild(control); } private void registerCurrentChildrenRecursively(final IControl control, final IContainerRegistry registry) { registry.register(control); if (control instanceof IContainer) { for (final IControl childControl : ((IContainer) control).getChildren()) { registerCurrentChildrenRecursively(childControl, registry); } } else if (control.getRoot() instanceof IContainer) { for (final IControl childControl : ((IContainer) control.getRoot()).getChildren()) { registerCurrentChildrenRecursively(childControl, registry); } } } private void registerNewCreatedChild(final IControl control) { for (final IContainerRegistry registry : containerRegistries) { registry.register(control); } if (control instanceof IContainer) { final IContainer childContainer = (IContainer) control; childContainer.addContainerRegistry(containerRegistry); } else if (control.getRoot() instanceof IContainer) { final IContainer childContainer = (IContainer) control.getRoot(); childContainer.addContainerRegistry(containerRegistry); } control.addDisposeListener(new DisposeListener(control)); } private void fireAfterAdded(final IControl control) { for (final IContainerListener listener : new LinkedList<IContainerListener>(containerListeners)) { listener.afterAdded(control); } } private void fireBeforeRemove(final IControl control) { for (final IContainerListener listener : new LinkedList<IContainerListener>(containerListeners)) { listener.beforeRemove(control); } } private <LISTENER_TYPE> void addListenerRecursive( final IListenerFactory<LISTENER_TYPE> listenerFactory, final IListenerRegistrationDelegate<LISTENER_TYPE> registrationDelegate) { Assert.paramNotNull(listenerFactory, "listenerFactory"); if (!listenenerManagers.containsKey(listenerFactory)) { final RecursiveListenenerManager<LISTENER_TYPE> listenenerManager; listenenerManager = new RecursiveListenenerManager<LISTENER_TYPE>(container, listenerFactory, registrationDelegate); listenenerManagers.put(listenerFactory, listenenerManager); } } private void removeListenerRecursive(final IListenerFactory<?> listenerFactory) { Assert.paramNotNull(listenerFactory, "listenerFactory"); final RecursiveListenenerManager<?> listenenerManager = listenenerManagers.remove(listenerFactory); if (listenenerManager != null) { listenenerManager.dispose(); } } private final class DisposeListener implements IDisposeListener { private final IControl control; DisposeListener(final IControl control) { this.control = control; } @Override public void onDispose() { for (final IContainerRegistry registry : containerRegistries) { registry.unregister(control); if (control instanceof IContainer) { ((IContainer) control).removeContainerRegistry(containerRegistry); } else if (control.getRoot() instanceof IContainer) { ((IContainer) control.getRoot()).removeContainerRegistry(containerRegistry); } control.removeDisposeListener(this); } } } }