diff options
author | Henri Sara <hesara@vaadin.com> | 2012-11-13 18:08:29 +0200 |
---|---|---|
committer | Artur Signell <artur@vaadin.com> | 2012-11-13 18:18:40 +0200 |
commit | 391884746fda1781c55b13bc200dd75373f69141 (patch) | |
tree | 0d5a8dcd9d13c5c39813d81252506e12d72741af /server | |
parent | 4628bcc3062ef19ed9d561f79fe3bfb3696d6e04 (diff) | |
download | vaadin-framework-391884746fda1781c55b13bc200dd75373f69141.tar.gz vaadin-framework-391884746fda1781c55b13bc200dd75373f69141.zip |
UI based on AbstractBasicComponentContainer (#2924)
Change-Id: I1614a3464b8e7a0e9ecdd8c3a76335cdb85bdf87
Diffstat (limited to 'server')
-rw-r--r-- | server/src/com/vaadin/ui/AbstractComponentContainer.java | 75 | ||||
-rw-r--r-- | server/src/com/vaadin/ui/AbstractSingleComponentContainer.java | 281 | ||||
-rw-r--r-- | server/src/com/vaadin/ui/ComponentContainer.java | 147 | ||||
-rw-r--r-- | server/src/com/vaadin/ui/HasComponents.java | 161 | ||||
-rw-r--r-- | server/src/com/vaadin/ui/LegacyWindow.java | 214 | ||||
-rw-r--r-- | server/src/com/vaadin/ui/SingleComponentContainer.java | 63 | ||||
-rw-r--r-- | server/src/com/vaadin/ui/UI.java | 117 | ||||
-rw-r--r-- | server/tests/src/com/vaadin/tests/server/component/abstractcomponentcontainer/TestAbstractComponentContainerListeners.java | 8 | ||||
-rw-r--r-- | server/tests/src/com/vaadin/tests/server/component/ui/LegacyUIAddRemoveComponents.java (renamed from server/tests/src/com/vaadin/tests/server/component/ui/UIAddRemoveComponents.java) | 12 | ||||
-rw-r--r-- | server/tests/src/com/vaadin/tests/server/components/ComponentAttachDetachListenerTest.java | 34 | ||||
-rw-r--r-- | server/tests/src/com/vaadin/ui/LabelDataSource.java | 2 |
11 files changed, 709 insertions, 405 deletions
diff --git a/server/src/com/vaadin/ui/AbstractComponentContainer.java b/server/src/com/vaadin/ui/AbstractComponentContainer.java index fdc753b57c..c60f312293 100644 --- a/server/src/com/vaadin/ui/AbstractComponentContainer.java +++ b/server/src/com/vaadin/ui/AbstractComponentContainer.java @@ -16,7 +16,6 @@ package com.vaadin.ui; -import java.lang.reflect.Method; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; @@ -83,32 +82,11 @@ public abstract class AbstractComponentContainer extends AbstractComponent } } - /* Events */ - - private static final Method COMPONENT_ATTACHED_METHOD; - - private static final Method COMPONENT_DETACHED_METHOD; - - static { - try { - COMPONENT_ATTACHED_METHOD = ComponentAttachListener.class - .getDeclaredMethod("componentAttachedToContainer", - new Class[] { ComponentAttachEvent.class }); - COMPONENT_DETACHED_METHOD = ComponentDetachListener.class - .getDeclaredMethod("componentDetachedFromContainer", - new Class[] { ComponentDetachEvent.class }); - } catch (final java.lang.NoSuchMethodException e) { - // This should never happen - throw new java.lang.RuntimeException( - "Internal error finding methods in AbstractComponentContainer"); - } - } - /* documented in interface */ @Override public void addComponentAttachListener(ComponentAttachListener listener) { - addListener(ComponentContainer.ComponentAttachEvent.class, listener, - COMPONENT_ATTACHED_METHOD); + addListener(ComponentAttachEvent.class, listener, + ComponentAttachListener.attachMethod); } /** @@ -123,9 +101,9 @@ public abstract class AbstractComponentContainer extends AbstractComponent /* documented in interface */ @Override - public void addComponentDetachListener(ComponentDetachListener listener) { - addListener(ComponentContainer.ComponentDetachEvent.class, listener, - COMPONENT_DETACHED_METHOD); + public void removeComponentAttachListener(ComponentAttachListener listener) { + removeListener(ComponentAttachEvent.class, listener, + ComponentAttachListener.attachMethod); } /** @@ -140,9 +118,9 @@ public abstract class AbstractComponentContainer extends AbstractComponent /* documented in interface */ @Override - public void removeComponentAttachListener(ComponentAttachListener listener) { - removeListener(ComponentContainer.ComponentAttachEvent.class, listener, - COMPONENT_ATTACHED_METHOD); + public void addComponentDetachListener(ComponentDetachListener listener) { + addListener(ComponentDetachEvent.class, listener, + ComponentDetachListener.detachMethod); } /** @@ -158,8 +136,8 @@ public abstract class AbstractComponentContainer extends AbstractComponent /* documented in interface */ @Override public void removeComponentDetachListener(ComponentDetachListener listener) { - removeListener(ComponentContainer.ComponentDetachEvent.class, listener, - COMPONENT_DETACHED_METHOD); + removeListener(ComponentDetachEvent.class, listener, + ComponentDetachListener.detachMethod); } /** @@ -218,9 +196,7 @@ public abstract class AbstractComponentContainer extends AbstractComponent if (c.getParent() != null) { // If the component already has a parent, try to remove it - ComponentContainer oldParent = (ComponentContainer) c.getParent(); - oldParent.removeComponent(c); - + AbstractSingleComponentContainer.removeFromParent(c); } c.setParent(this); @@ -250,7 +226,7 @@ public abstract class AbstractComponentContainer extends AbstractComponent super.setVisible(visible); // If the visibility state is toggled it might affect all children - // aswell, e.g. make container visible should make children visible if + // as well, e.g. make container visible should make children visible if // they were only hidden because the container was hidden. markAsDirtyRecursive(); } @@ -315,30 +291,15 @@ public abstract class AbstractComponentContainer extends AbstractComponent private Collection<Component> getInvalidSizedChildren(final boolean vertical) { HashSet<Component> components = null; - if (this instanceof Panel) { - Panel p = (Panel) this; - ComponentContainer content = p.getContent(); + for (Component component : this) { boolean valid = vertical ? ComponentSizeValidator - .checkHeights(content) : ComponentSizeValidator - .checkWidths(content); - + .checkHeights(component) : ComponentSizeValidator + .checkWidths(component); if (!valid) { - components = new HashSet<Component>(1); - components.add(content); - } - } else { - for (Iterator<Component> componentIterator = getComponentIterator(); componentIterator - .hasNext();) { - Component component = componentIterator.next(); - boolean valid = vertical ? ComponentSizeValidator - .checkHeights(component) : ComponentSizeValidator - .checkWidths(component); - if (!valid) { - if (components == null) { - components = new HashSet<Component>(); - } - components.add(component); + if (components == null) { + components = new HashSet<Component>(); } + components.add(component); } } return components; diff --git a/server/src/com/vaadin/ui/AbstractSingleComponentContainer.java b/server/src/com/vaadin/ui/AbstractSingleComponentContainer.java new file mode 100644 index 0000000000..20660ce955 --- /dev/null +++ b/server/src/com/vaadin/ui/AbstractSingleComponentContainer.java @@ -0,0 +1,281 @@ +/* + * Copyright 2011-2012 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.vaadin.ui; + +import java.util.Collections; +import java.util.Iterator; + +import com.vaadin.server.ComponentSizeValidator; + +/** + * Abstract base class for component containers that have only one child + * component. + * + * For component containers that support multiple children, inherit + * {@link AbstractComponentContainer} instead of this class. + * + * @since 7.0 + */ +public abstract class AbstractSingleComponentContainer extends + AbstractComponent implements SingleComponentContainer { + + private Component content; + + @Override + public int getComponentCount() { + return (content != null) ? 1 : 0; + } + + @Override + public Iterator<Component> iterator() { + if (content != null) { + return Collections.singletonList(content).iterator(); + } else { + return Collections.<Component> emptyList().iterator(); + } + } + + /* documented in interface */ + @Override + public void addComponentAttachListener(ComponentAttachListener listener) { + addListener(ComponentAttachEvent.class, listener, + ComponentAttachListener.attachMethod); + + } + + /* documented in interface */ + @Override + public void removeComponentAttachListener(ComponentAttachListener listener) { + removeListener(ComponentAttachEvent.class, listener, + ComponentAttachListener.attachMethod); + } + + /* documented in interface */ + @Override + public void addComponentDetachListener(ComponentDetachListener listener) { + addListener(ComponentDetachEvent.class, listener, + ComponentDetachListener.detachMethod); + } + + /* documented in interface */ + @Override + public void removeComponentDetachListener(ComponentDetachListener listener) { + removeListener(ComponentDetachEvent.class, listener, + ComponentDetachListener.detachMethod); + } + + /** + * Fires the component attached event. This is called by the + * {@link #setContent(Component)} method after the component has been set as + * the content. + * + * @param component + * the component that has been added to this container. + */ + protected void fireComponentAttachEvent(Component component) { + fireEvent(new ComponentAttachEvent(this, component)); + } + + /** + * Fires the component detached event. This is called by the + * {@link #setContent(Component)} method after the content component has + * been replaced by other content. + * + * @param component + * the component that has been removed from this container. + */ + protected void fireComponentDetachEvent(Component component) { + fireEvent(new ComponentDetachEvent(this, component)); + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.ui.HasComponents#isComponentVisible(com.vaadin.ui.Component) + */ + @Override + public boolean isComponentVisible(Component childComponent) { + return true; + } + + @Override + public void setVisible(boolean visible) { + if (isVisible() == visible) { + return; + } + + super.setVisible(visible); + // If the visibility state is toggled it might affect all children + // aswell, e.g. make container visible should make children visible if + // they were only hidden because the container was hidden. + markAsDirtyRecursive(); + } + + @Override + public Component getContent() { + return content; + } + + /** + * Sets the content of this container. The content is a component that + * serves as the outermost item of the visual contents. + * + * The content must always be set, either with a constructor parameter or by + * calling this method. + * + * Previous versions of Vaadin used a {@link VerticalLayout} with margins + * enabled as the default content but that is no longer the case. + * + * @param content + * a component (typically a layout) to use as content + */ + @Override + public void setContent(Component content) { + Component oldContent = getContent(); + if (oldContent == content) { + // do not set the same content twice + return; + } + if (oldContent != null && oldContent.getParent() == this) { + oldContent.setParent(null); + fireComponentDetachEvent(oldContent); + } + this.content = content; + if (content != null) { + removeFromParent(content); + + content.setParent(this); + fireComponentAttachEvent(content); + } + + markAsDirty(); + } + + /** + * Utility method for removing a component from its parent (if possible). + * + * @param content + * component to remove + */ + // TODO move utility method elsewhere? + public static void removeFromParent(Component content) + throws IllegalArgumentException { + HasComponents parent = content.getParent(); + if (parent instanceof ComponentContainer) { + // If the component already has a parent, try to remove it + ComponentContainer oldParent = (ComponentContainer) parent; + oldParent.removeComponent(content); + } else if (parent instanceof SingleComponentContainer) { + SingleComponentContainer oldParent = (SingleComponentContainer) parent; + if (oldParent.getContent() == content) { + oldParent.setContent(null); + } + } else if (parent != null) { + throw new IllegalArgumentException( + "Content is already attached to another parent"); + } + } + + // the setHeight()/setWidth() methods duplicated and simplified from + // AbstractComponentContainer + + @Override + public void setWidth(float width, Unit unit) { + /* + * child tree repaints may be needed, due to our fall back support for + * invalid relative sizes + */ + boolean dirtyChild = false; + boolean childrenMayBecomeUndefined = false; + if (getWidth() == SIZE_UNDEFINED && width != SIZE_UNDEFINED) { + // children currently in invalid state may need repaint + dirtyChild = getInvalidSizedChild(false); + } else if ((width == SIZE_UNDEFINED && getWidth() != SIZE_UNDEFINED) + || (unit == Unit.PERCENTAGE + && getWidthUnits() != Unit.PERCENTAGE && !ComponentSizeValidator + .parentCanDefineWidth(this))) { + /* + * relative width children may get to invalid state if width becomes + * invalid. Width may also become invalid if units become percentage + * due to the fallback support + */ + childrenMayBecomeUndefined = true; + dirtyChild = getInvalidSizedChild(false); + } + super.setWidth(width, unit); + repaintChangedChildTree(dirtyChild, childrenMayBecomeUndefined, false); + } + + private void repaintChangedChildTree(boolean invalidChild, + boolean childrenMayBecomeUndefined, boolean vertical) { + if (getContent() == null) { + return; + } + boolean needRepaint = false; + if (childrenMayBecomeUndefined) { + // if became invalid now + needRepaint = !invalidChild && getInvalidSizedChild(vertical); + } else if (invalidChild) { + // if not still invalid + needRepaint = !getInvalidSizedChild(vertical); + } + if (needRepaint) { + getContent().markAsDirtyRecursive(); + } + } + + private boolean getInvalidSizedChild(final boolean vertical) { + Component content = getContent(); + if (content == null) { + return false; + } + if (vertical) { + return !ComponentSizeValidator.checkHeights(content); + } else { + return !ComponentSizeValidator.checkWidths(content); + } + } + + @Override + public void setHeight(float height, Unit unit) { + /* + * child tree repaints may be needed, due to our fall back support for + * invalid relative sizes + */ + boolean dirtyChild = false; + boolean childrenMayBecomeUndefined = false; + if (getHeight() == SIZE_UNDEFINED && height != SIZE_UNDEFINED) { + // children currently in invalid state may need repaint + dirtyChild = getInvalidSizedChild(true); + } else if ((height == SIZE_UNDEFINED && getHeight() != SIZE_UNDEFINED) + || (unit == Unit.PERCENTAGE + && getHeightUnits() != Unit.PERCENTAGE && !ComponentSizeValidator + .parentCanDefineHeight(this))) { + /* + * relative height children may get to invalid state if height + * becomes invalid. Height may also become invalid if units become + * percentage due to the fallback support. + */ + childrenMayBecomeUndefined = true; + dirtyChild = getInvalidSizedChild(true); + } + super.setHeight(height, unit); + repaintChangedChildTree(dirtyChild, childrenMayBecomeUndefined, true); + } + +} diff --git a/server/src/com/vaadin/ui/ComponentContainer.java b/server/src/com/vaadin/ui/ComponentContainer.java index 3663134520..5ef41d7cbf 100644 --- a/server/src/com/vaadin/ui/ComponentContainer.java +++ b/server/src/com/vaadin/ui/ComponentContainer.java @@ -16,9 +16,10 @@ package com.vaadin.ui; -import java.io.Serializable; import java.util.Iterator; +import com.vaadin.ui.HasComponents.ComponentAttachDetachNotifier; + /** * Extension to the {@link Component} interface which adds to it the capacity to * contain other components. All UI elements that can have child elements @@ -27,7 +28,8 @@ import java.util.Iterator; * @author Vaadin Ltd. * @since 3.0 */ -public interface ComponentContainer extends HasComponents { +public interface ComponentContainer extends HasComponents, + ComponentAttachDetachNotifier { /** * Adds the component into this container. @@ -102,14 +104,6 @@ public interface ComponentContainer extends HasComponents { public void moveComponentsFrom(ComponentContainer source); /** - * Listens the component attach events. - * - * @param listener - * the listener to add. - */ - public void addComponentAttachListener(ComponentAttachListener listener); - - /** * @deprecated Since 7.0, replaced by * {@link #addComponentAttachListener(ComponentAttachListener)} **/ @@ -117,14 +111,6 @@ public interface ComponentContainer extends HasComponents { public void addListener(ComponentAttachListener listener); /** - * Stops the listening component attach events. - * - * @param listener - * the listener to removed. - */ - public void removeComponentAttachListener(ComponentAttachListener listener); - - /** * @deprecated Since 7.0, replaced by * {@link #removeComponentAttachListener(ComponentAttachListener)} **/ @@ -132,11 +118,6 @@ public interface ComponentContainer extends HasComponents { public void removeListener(ComponentAttachListener listener); /** - * Listens the component detach events. - */ - public void addComponentDetachListener(ComponentDetachListener listener); - - /** * @deprecated Since 7.0, replaced by * {@link #addComponentDetachListener(ComponentDetachListener)} **/ @@ -144,130 +125,10 @@ public interface ComponentContainer extends HasComponents { public void addListener(ComponentDetachListener listener); /** - * Stops the listening component detach events. - */ - public void removeComponentDetachListener(ComponentDetachListener listener); - - /** * @deprecated Since 7.0, replaced by * {@link #removeComponentDetachListener(ComponentDetachListener)} **/ @Deprecated public void removeListener(ComponentDetachListener listener); - /** - * Component attach listener interface. - */ - public interface ComponentAttachListener extends Serializable { - - /** - * A new component is attached to container. - * - * @param event - * the component attach event. - */ - public void componentAttachedToContainer(ComponentAttachEvent event); - } - - /** - * Component detach listener interface. - */ - public interface ComponentDetachListener extends Serializable { - - /** - * A component has been detached from container. - * - * @param event - * the component detach event. - */ - public void componentDetachedFromContainer(ComponentDetachEvent event); - } - - /** - * Component attach event sent when a component is attached to container. - */ - @SuppressWarnings("serial") - public static class ComponentAttachEvent extends Component.Event { - - private final Component component; - - /** - * Creates a new attach event. - * - * @param container - * the component container the component has been detached - * to. - * @param attachedComponent - * the component that has been attached. - */ - public ComponentAttachEvent(ComponentContainer container, - Component attachedComponent) { - super(container); - component = attachedComponent; - } - - /** - * Gets the component container. - * - * @param the - * component container. - */ - public ComponentContainer getContainer() { - return (ComponentContainer) getSource(); - } - - /** - * Gets the attached component. - * - * @param the - * attach component. - */ - public Component getAttachedComponent() { - return component; - } - } - - /** - * Component detach event sent when a component is detached from container. - */ - @SuppressWarnings("serial") - public static class ComponentDetachEvent extends Component.Event { - - private final Component component; - - /** - * Creates a new detach event. - * - * @param container - * the component container the component has been detached - * from. - * @param detachedComponent - * the component that has been detached. - */ - public ComponentDetachEvent(ComponentContainer container, - Component detachedComponent) { - super(container); - component = detachedComponent; - } - - /** - * Gets the component container. - * - * @param the - * component container. - */ - public ComponentContainer getContainer() { - return (ComponentContainer) getSource(); - } - - /** - * Gets the detached component. - * - * @return the detached component. - */ - public Component getDetachedComponent() { - return component; - } - } - } diff --git a/server/src/com/vaadin/ui/HasComponents.java b/server/src/com/vaadin/ui/HasComponents.java index db0aa1ca8e..4f6320f6b2 100644 --- a/server/src/com/vaadin/ui/HasComponents.java +++ b/server/src/com/vaadin/ui/HasComponents.java @@ -15,8 +15,12 @@ */ package com.vaadin.ui; +import java.io.Serializable; +import java.lang.reflect.Method; import java.util.Iterator; +import com.vaadin.util.ReflectTools; + /** * Interface that must be implemented by all {@link Component}s that contain * other {@link Component}s. @@ -55,4 +59,161 @@ public interface HasComponents extends Component, Iterable<Component> { */ public boolean isComponentVisible(Component childComponent); + /** + * Interface for {@link HasComponents} implementations that support sending + * attach and detach events for components. + * + * @since 7.0 + */ + public interface ComponentAttachDetachNotifier extends Serializable { + /** + * Listens the component attach events. + * + * @param listener + * the listener to add. + */ + public void addComponentAttachListener(ComponentAttachListener listener); + + /** + * Stops the listening component attach events. + * + * @param listener + * the listener to removed. + */ + public void removeComponentAttachListener( + ComponentAttachListener listener); + + /** + * Listens the component detach events. + */ + public void addComponentDetachListener(ComponentDetachListener listener); + + /** + * Stops the listening component detach events. + */ + public void removeComponentDetachListener( + ComponentDetachListener listener); + } + + /** + * Component attach listener interface. + */ + public interface ComponentAttachListener extends Serializable { + + public static final Method attachMethod = ReflectTools.findMethod( + ComponentAttachListener.class, "componentAttachedToContainer", + ComponentAttachEvent.class); + + /** + * A new component is attached to container. + * + * @param event + * the component attach event. + */ + public void componentAttachedToContainer(ComponentAttachEvent event); + } + + /** + * Component detach listener interface. + */ + public interface ComponentDetachListener extends Serializable { + + public static final Method detachMethod = ReflectTools.findMethod( + ComponentDetachListener.class, + "componentDetachedFromContainer", ComponentDetachEvent.class); + + /** + * A component has been detached from container. + * + * @param event + * the component detach event. + */ + public void componentDetachedFromContainer(ComponentDetachEvent event); + } + + /** + * Component attach event sent when a component is attached to container. + */ + @SuppressWarnings("serial") + public static class ComponentAttachEvent extends Component.Event { + + private final Component component; + + /** + * Creates a new attach event. + * + * @param container + * the container the component has been detached to. + * @param attachedComponent + * the component that has been attached. + */ + public ComponentAttachEvent(HasComponents container, + Component attachedComponent) { + super(container); + component = attachedComponent; + } + + /** + * Gets the component container. + * + * @param the + * component container. + */ + public HasComponents getContainer() { + return (HasComponents) getSource(); + } + + /** + * Gets the attached component. + * + * @param the + * attach component. + */ + public Component getAttachedComponent() { + return component; + } + } + + /** + * Component detach event sent when a component is detached from container. + */ + @SuppressWarnings("serial") + public static class ComponentDetachEvent extends Component.Event { + + private final Component component; + + /** + * Creates a new detach event. + * + * @param container + * the container the component has been detached from. + * @param detachedComponent + * the component that has been detached. + */ + public ComponentDetachEvent(HasComponents container, + Component detachedComponent) { + super(container); + component = detachedComponent; + } + + /** + * Gets the component container. + * + * @param the + * component container. + */ + public HasComponents getContainer() { + return (HasComponents) getSource(); + } + + /** + * Gets the detached component. + * + * @return the detached component. + */ + public Component getDetachedComponent() { + return component; + } + } + } diff --git a/server/src/com/vaadin/ui/LegacyWindow.java b/server/src/com/vaadin/ui/LegacyWindow.java index 88559af0b5..79d4d0aedb 100644 --- a/server/src/com/vaadin/ui/LegacyWindow.java +++ b/server/src/com/vaadin/ui/LegacyWindow.java @@ -1,6 +1,6 @@ /* @VaadinApache2LicenseForJavaFiles@ -*/ + */ package com.vaadin.ui; @@ -9,16 +9,16 @@ import java.net.URL; import com.vaadin.server.LegacyApplication; import com.vaadin.server.Page; -import com.vaadin.server.Resource; -import com.vaadin.server.VaadinRequest; import com.vaadin.server.Page.BrowserWindowResizeEvent; import com.vaadin.server.Page.BrowserWindowResizeListener; +import com.vaadin.server.Resource; +import com.vaadin.server.VaadinRequest; import com.vaadin.shared.ui.BorderStyle; /** - * Helper class to emulate the main window from Vaadin 6 using UIs. This - * class should be used in the same way as Window used as a browser level - * window in Vaadin 6 with {@link com.vaadin.server.LegacyApplication} + * Helper class to emulate the main window from Vaadin 6 using UIs. This class + * should be used in the same way as Window used as a browser level window in + * Vaadin 6 with {@link com.vaadin.server.LegacyApplication} */ @Deprecated public class LegacyWindow extends UI { @@ -29,7 +29,8 @@ public class LegacyWindow extends UI { * Create a new legacy window */ public LegacyWindow() { - super(); + super(new VerticalLayout()); + ((VerticalLayout) getContent()).setMargin(true); } /** @@ -39,7 +40,8 @@ public class LegacyWindow extends UI { * the caption of the window */ public LegacyWindow(String caption) { - super(); + super(new VerticalLayout()); + ((VerticalLayout) getContent()).setMargin(true); setCaption(caption); } @@ -71,12 +73,11 @@ public class LegacyWindow extends UI { * Gets the unique name of the window. The name of the window is used to * uniquely identify it. * <p> - * The name also determines the URL that can be used for direct access - * to a window. All windows can be accessed through - * {@code http://host:port/app/win} where {@code http://host:port/app} - * is the application URL (as returned by - * {@link LegacyApplication#getURL()} and {@code win} is the window - * name. + * The name also determines the URL that can be used for direct access to a + * window. All windows can be accessed through + * {@code http://host:port/app/win} where {@code http://host:port/app} is + * the application URL (as returned by {@link LegacyApplication#getURL()} + * and {@code win} is the window name. * </p> * <p> * Note! Portlets do not support direct window access through URLs. @@ -92,12 +93,11 @@ public class LegacyWindow extends UI { * Sets the unique name of the window. The name of the window is used to * uniquely identify it inside the application. * <p> - * The name also determines the URL that can be used for direct access - * to a window. All windows can be accessed through - * {@code http://host:port/app/win} where {@code http://host:port/app} - * is the application URL (as returned by - * {@link LegacyApplication#getURL()} and {@code win} is the window - * name. + * The name also determines the URL that can be used for direct access to a + * window. All windows can be accessed through + * {@code http://host:port/app/win} where {@code http://host:port/app} is + * the application URL (as returned by {@link LegacyApplication#getURL()} + * and {@code win} is the window name. * </p> * <p> * This method can only be called before the window is added to an @@ -107,8 +107,8 @@ public class LegacyWindow extends UI { * </p> * * @param name - * the new name for the window or null if the application - * should automatically assign a name to it + * the new name for the window or null if the application should + * automatically assign a name to it * @throws IllegalStateException * if the window is attached to an application */ @@ -124,14 +124,14 @@ public class LegacyWindow extends UI { } /** - * Gets the full URL of the window. The returned URL is window specific - * and can be used to directly refer to the window. + * Gets the full URL of the window. The returned URL is window specific and + * can be used to directly refer to the window. * <p> * Note! This method can not be used for portlets. * </p> * - * @return the URL of the window or null if the window is not attached - * to an application + * @return the URL of the window or null if the window is not attached to an + * application */ public URL getURL() { LegacyApplication application = getApplication(); @@ -148,8 +148,8 @@ public class LegacyWindow extends UI { } /** - * Opens the given resource in this UI. The contents of this UI is - * replaced by the {@code Resource}. + * Opens the given resource in this UI. The contents of this UI is replaced + * by the {@code Resource}. * * @param resource * the resource to show in this UI @@ -167,41 +167,39 @@ public class LegacyWindow extends UI { * Opens the given resource in a window with the given name. * <p> * The supplied {@code windowName} is used as the target name in a - * window.open call in the client. This means that special values such - * as "_blank", "_self", "_top", "_parent" have special meaning. An - * empty or <code>null</code> window name is also a special case. + * window.open call in the client. This means that special values such as + * "_blank", "_self", "_top", "_parent" have special meaning. An empty or + * <code>null</code> window name is also a special case. * </p> * <p> - * "", null and "_self" as {@code windowName} all causes the resource to - * be opened in the current window, replacing any old contents. For + * "", null and "_self" as {@code windowName} all causes the resource to be + * opened in the current window, replacing any old contents. For * downloadable content you should avoid "_self" as "_self" causes the * client to skip rendering of any other changes as it considers them - * irrelevant (the page will be replaced by the resource). This can - * speed up the opening of a resource, but it might also put the client - * side into an inconsistent state if the window content is not - * completely replaced e.g., if the resource is downloaded instead of - * displayed in the browser. + * irrelevant (the page will be replaced by the resource). This can speed up + * the opening of a resource, but it might also put the client side into an + * inconsistent state if the window content is not completely replaced e.g., + * if the resource is downloaded instead of displayed in the browser. * </p> * <p> - * "_blank" as {@code windowName} causes the resource to always be - * opened in a new window or tab (depends on the browser and browser - * settings). + * "_blank" as {@code windowName} causes the resource to always be opened in + * a new window or tab (depends on the browser and browser settings). * </p> * <p> - * "_top" and "_parent" as {@code windowName} works as specified by the - * HTML standard. + * "_top" and "_parent" as {@code windowName} works as specified by the HTML + * standard. * </p> * <p> - * Any other {@code windowName} will open the resource in a window with - * that name, either by opening a new window/tab in the browser or by - * replacing the contents of an existing window with that name. + * Any other {@code windowName} will open the resource in a window with that + * name, either by opening a new window/tab in the browser or by replacing + * the contents of an existing window with that name. * </p> * <p> - * As of Vaadin 7.0.0, the functionality for opening a Resource in a - * Page has been replaced with similar methods based on a String URL. - * This is because the usage of Resource is problematic with memory - * management and with security features in some browsers. Is is - * recommended to instead use {@link Link} for starting downloads. + * As of Vaadin 7.0.0, the functionality for opening a Resource in a Page + * has been replaced with similar methods based on a String URL. This is + * because the usage of Resource is problematic with memory management and + * with security features in some browsers. Is is recommended to instead use + * {@link Link} for starting downloads. * </p> * * @param resource @@ -220,11 +218,11 @@ public class LegacyWindow extends UI { * name. For more information on the meaning of {@code windowName}, see * {@link #open(Resource, String)}. * <p> - * As of Vaadin 7.0.0, the functionality for opening a Resource in a - * Page has been replaced with similar methods based on a String URL. - * This is because the usage of Resource is problematic with memory - * management and with security features in some browsers. Is is - * recommended to instead use {@link Link} for starting downloads. + * As of Vaadin 7.0.0, the functionality for opening a Resource in a Page + * has been replaced with similar methods based on a String URL. This is + * because the usage of Resource is problematic with memory management and + * with security features in some browsers. Is is recommended to instead use + * {@link Link} for starting downloads. * </p> * * @param resource @@ -246,9 +244,9 @@ public class LegacyWindow extends UI { } /** - * Adds a new {@link BrowserWindowResizeListener} to this UI. The - * listener will be notified whenever the browser window within which - * this UI resides is resized. + * Adds a new {@link BrowserWindowResizeListener} to this UI. The listener + * will be notified whenever the browser window within which this UI resides + * is resized. * * @param resizeListener * the listener to add @@ -264,9 +262,8 @@ public class LegacyWindow extends UI { } /** - * Removes a {@link BrowserWindowResizeListener} from this UI. The - * listener will no longer be notified when the browser window is - * resized. + * Removes a {@link BrowserWindowResizeListener} from this UI. The listener + * will no longer be notified when the browser window is resized. * * @param resizeListener * the listener to remove @@ -290,8 +287,7 @@ public class LegacyWindow extends UI { } /** - * Gets the last known width of the browser window in which this UI - * resides. + * Gets the last known width of the browser window in which this UI resides. * * @return the browser window width in pixels * @@ -306,18 +302,17 @@ public class LegacyWindow extends UI { * Executes JavaScript in this window. * * <p> - * This method allows one to inject javascript from the server to - * client. A client implementation is not required to implement this - * functionality, but currently all web-based clients do implement this. + * This method allows one to inject javascript from the server to client. A + * client implementation is not required to implement this functionality, + * but currently all web-based clients do implement this. * </p> * * <p> - * Executing javascript this way often leads to cross-browser - * compatibility issues and regressions that are hard to resolve. Use of - * this method should be avoided and instead it is recommended to create - * new widgets with GWT. For more info on creating own, reusable - * client-side widgets in Java, read the corresponding chapter in Book - * of Vaadin. + * Executing javascript this way often leads to cross-browser compatibility + * issues and regressions that are hard to resolve. Use of this method + * should be avoided and instead it is recommended to create new widgets + * with GWT. For more info on creating own, reusable client-side widgets in + * Java, read the corresponding chapter in Book of Vaadin. * </p> * * @param script @@ -338,4 +333,77 @@ public class LegacyWindow extends UI { getPage().setTitle(caption); } + @Override + public ComponentContainer getContent() { + return (ComponentContainer) super.getContent(); + } + + /** + * Set the content of the window. For a {@link LegacyWindow}, the content + * must be a {@link ComponentContainer}. + * + * @param content + */ + @Override + public void setContent(Component content) { + if (!(content instanceof ComponentContainer)) { + throw new IllegalArgumentException( + "The content of a LegacyWindow must be a ComponentContainer"); + } + super.setContent(content); + } + + /** + * This implementation replaces a component in the content container ( + * {@link #getContent()}) instead of in the actual UI. + * + * This method should only be called when the content is a + * {@link ComponentContainer} (default {@link VerticalLayout} or explicitly + * set). + */ + public void replaceComponent(Component oldComponent, Component newComponent) { + getContent().replaceComponent(oldComponent, newComponent); + } + + /** + * Adds a component to this UI. The component is not added directly to the + * UI, but instead to the content container ({@link #getContent()}). + * + * This method should only be called when the content is a + * {@link ComponentContainer} (default {@link VerticalLayout} or explicitly + * set). + * + * @param component + * the component to add to this UI + * + * @see #getContent() + */ + public void addComponent(Component component) { + getContent().addComponent(component); + } + + /** + * This implementation removes the component from the content container ( + * {@link #getContent()}) instead of from the actual UI. + * + * This method should only be called when the content is a + * {@link ComponentContainer} (default {@link VerticalLayout} or explicitly + * set). + */ + public void removeComponent(Component component) { + getContent().removeComponent(component); + } + + /** + * This implementation removes the components from the content container ( + * {@link #getContent()}) instead of from the actual UI. + * + * This method should only be called when the content is a + * {@link ComponentContainer} (default {@link VerticalLayout} or explicitly + * set). + */ + public void removeAllComponents() { + getContent().removeAllComponents(); + } + }
\ No newline at end of file diff --git a/server/src/com/vaadin/ui/SingleComponentContainer.java b/server/src/com/vaadin/ui/SingleComponentContainer.java new file mode 100644 index 0000000000..deb647e5eb --- /dev/null +++ b/server/src/com/vaadin/ui/SingleComponentContainer.java @@ -0,0 +1,63 @@ +/* + * Copyright 2012 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.vaadin.ui; + +import com.vaadin.ui.HasComponents.ComponentAttachDetachNotifier; + +/** + * Interface for component containers that have one child component and do not + * support adding or removing components. + * + * For component containers that support multiple children, see + * {@link ComponentContainer} instead. + * + * @since 7.0 + */ +public interface SingleComponentContainer extends HasComponents, + ComponentAttachDetachNotifier { + + /** + * Gets the number of children this {@link SingleComponentContainer} has. + * This must be symmetric with what {@link #iterator()} returns and thus + * typically return 1 if the content is set, 0 otherwise. + * + * @return The number of child components this container has. + */ + public int getComponentCount(); + + /** + * Gets the content of this container. The content is a component that + * serves as the outermost item of the visual contents. + * + * @return a component to use as content + * + * @see #setContent(Component) + */ + public Component getContent(); + + /** + * Sets the content of this container. The content is a component that + * serves as the outermost item of the visual contents. + * + * The content should always be set, either as a constructor parameter or by + * calling this method. + * + * @return a component (typically a layout) to use as content + */ + public void setContent(Component content); + +} diff --git a/server/src/com/vaadin/ui/UI.java b/server/src/com/vaadin/ui/UI.java index d2f323e5fe..e4cee9386a 100644 --- a/server/src/com/vaadin/ui/UI.java +++ b/server/src/com/vaadin/ui/UI.java @@ -69,9 +69,9 @@ import com.vaadin.util.ReflectTools; * After a UI has been created by the application, it is initialized using * {@link #init(VaadinRequest)}. This method is intended to be overridden by the * developer to add components to the user interface and initialize - * non-component functionality. The component hierarchy is initialized by - * passing a {@link ComponentContainer} with the main layout of the view to - * {@link #setContent(ComponentContainer)}. + * non-component functionality. The component hierarchy must be initialized by + * passing a {@link Component} with the main layout or other content of the view + * to {@link #setContent(Component)} or to the constructor of the UI. * </p> * * @see #init(VaadinRequest) @@ -79,7 +79,7 @@ import com.vaadin.util.ReflectTools; * * @since 7.0 */ -public abstract class UI extends AbstractComponentContainer implements +public abstract class UI extends AbstractSingleComponentContainer implements Action.Container, Action.Notifier, LegacyComponent { /** @@ -178,22 +178,23 @@ public abstract class UI extends AbstractComponentContainer implements private long lastUidlRequest = System.currentTimeMillis(); /** - * Creates a new empty UI without a caption. This UI will have a - * {@link VerticalLayout} with margins enabled as its content. + * Creates a new empty UI without a caption. The content of the UI must be + * set by calling {@link #setContent(Component)} before using the UI. */ public UI() { - this((ComponentContainer) null); + this(null); } /** - * Creates a new UI with the given component container as its content. + * Creates a new UI with the given component (often a layout) as its + * content. * * @param content - * the content container to use as this UIs content. + * the component to use as this UIs content. * - * @see #setContent(ComponentContainer) + * @see #setContent(Component) */ - public UI(ComponentContainer content) { + public UI(Component content) { registerRpc(rpc); setSizeFull(); setContent(content); @@ -224,15 +225,6 @@ public abstract class UI extends AbstractComponentContainer implements } /** - * This implementation replaces a component in the content container ( - * {@link #getContent()}) instead of in the actual UI. - */ - @Override - public void replaceComponent(Component oldComponent, Component newComponent) { - getContent().replaceComponent(oldComponent, newComponent); - } - - /** * Gets the application object to which the component is attached. * * <p> @@ -330,7 +322,7 @@ public abstract class UI extends AbstractComponentContainer implements /* * (non-Javadoc) * - * @see com.vaadin.ui.ComponentContainer#getComponentIterator() + * @see com.vaadin.ui.HasComponents#iterator() */ @Override public Iterator<Component> iterator() { @@ -541,89 +533,6 @@ public abstract class UI extends AbstractComponentContainer implements } /** - * Gets the content of this UI. The content is a component container that - * serves as the outermost item of the visual contents of this UI. - * - * @return a component container to use as content - * - * @see #setContent(ComponentContainer) - * @see #createDefaultLayout() - */ - public ComponentContainer getContent() { - return (ComponentContainer) getState().content; - } - - /** - * Helper method to create the default content layout that is used if no - * content has not been explicitly defined. - * - * @return a newly created layout - */ - private static VerticalLayout createDefaultLayout() { - VerticalLayout layout = new VerticalLayout(); - layout.setMargin(true); - return layout; - } - - /** - * Sets the content of this UI. The content is a component container that - * serves as the outermost item of the visual contents of this UI. If no - * content has been set, a {@link VerticalLayout} with margins enabled will - * be used by default - see {@link #createDefaultLayout()}. The content can - * also be set in a constructor. - * - * @return a component container to use as content - * - * @see #UI(ComponentContainer) - * @see #createDefaultLayout() - */ - public void setContent(ComponentContainer content) { - if (content == null) { - content = createDefaultLayout(); - } - - if (getState().content != null) { - super.removeComponent((Component) getState().content); - } - getState().content = content; - if (content != null) { - super.addComponent(content); - } - } - - /** - * Adds a component to this UI. The component is not added directly to the - * UI, but instead to the content container ({@link #getContent()}). - * - * @param component - * the component to add to this UI - * - * @see #getContent() - */ - @Override - public void addComponent(Component component) { - getContent().addComponent(component); - } - - /** - * This implementation removes the component from the content container ( - * {@link #getContent()}) instead of from the actual UI. - */ - @Override - public void removeComponent(Component component) { - getContent().removeComponent(component); - } - - /** - * This implementation removes the components from the content container ( - * {@link #getContent()}) instead of from the actual UI. - */ - @Override - public void removeAllComponents() { - getContent().removeAllComponents(); - } - - /** * Internal initialization method, should not be overridden. This method is * not declared as final because that would break compatibility with e.g. * CDI. diff --git a/server/tests/src/com/vaadin/tests/server/component/abstractcomponentcontainer/TestAbstractComponentContainerListeners.java b/server/tests/src/com/vaadin/tests/server/component/abstractcomponentcontainer/TestAbstractComponentContainerListeners.java index f9f170eb2a..9763354b57 100644 --- a/server/tests/src/com/vaadin/tests/server/component/abstractcomponentcontainer/TestAbstractComponentContainerListeners.java +++ b/server/tests/src/com/vaadin/tests/server/component/abstractcomponentcontainer/TestAbstractComponentContainerListeners.java @@ -1,10 +1,10 @@ package com.vaadin.tests.server.component.abstractcomponentcontainer; import com.vaadin.tests.server.component.AbstractListenerMethodsTest; -import com.vaadin.ui.ComponentContainer.ComponentAttachEvent; -import com.vaadin.ui.ComponentContainer.ComponentAttachListener; -import com.vaadin.ui.ComponentContainer.ComponentDetachEvent; -import com.vaadin.ui.ComponentContainer.ComponentDetachListener; +import com.vaadin.ui.HasComponents.ComponentAttachEvent; +import com.vaadin.ui.HasComponents.ComponentAttachListener; +import com.vaadin.ui.HasComponents.ComponentDetachEvent; +import com.vaadin.ui.HasComponents.ComponentDetachListener; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.VerticalLayout; diff --git a/server/tests/src/com/vaadin/tests/server/component/ui/UIAddRemoveComponents.java b/server/tests/src/com/vaadin/tests/server/component/ui/LegacyUIAddRemoveComponents.java index 1b07321605..1a5e19e0da 100644 --- a/server/tests/src/com/vaadin/tests/server/component/ui/UIAddRemoveComponents.java +++ b/server/tests/src/com/vaadin/tests/server/component/ui/LegacyUIAddRemoveComponents.java @@ -9,11 +9,11 @@ import org.junit.Test; import com.vaadin.server.VaadinRequest; import com.vaadin.ui.Component; import com.vaadin.ui.Label; -import com.vaadin.ui.UI; +import com.vaadin.ui.LegacyWindow; -public class UIAddRemoveComponents { +public class LegacyUIAddRemoveComponents { - private static class TestUI extends UI { + private static class TestUI extends LegacyWindow { @Override protected void init(VaadinRequest request) { } @@ -21,7 +21,7 @@ public class UIAddRemoveComponents { @Test public void addComponent() { - UI ui = new TestUI(); + TestUI ui = new TestUI(); Component c = new Label("abc"); ui.addComponent(c); @@ -34,7 +34,7 @@ public class UIAddRemoveComponents { @Test public void removeComponent() { - UI ui = new TestUI(); + TestUI ui = new TestUI(); Component c = new Label("abc"); ui.addComponent(c); @@ -49,7 +49,7 @@ public class UIAddRemoveComponents { @Test public void replaceComponent() { - UI ui = new TestUI(); + TestUI ui = new TestUI(); Component c = new Label("abc"); Component d = new Label("def"); diff --git a/server/tests/src/com/vaadin/tests/server/components/ComponentAttachDetachListenerTest.java b/server/tests/src/com/vaadin/tests/server/components/ComponentAttachDetachListenerTest.java index 3ba1c4c7f1..df515795eb 100644 --- a/server/tests/src/com/vaadin/tests/server/components/ComponentAttachDetachListenerTest.java +++ b/server/tests/src/com/vaadin/tests/server/components/ComponentAttachDetachListenerTest.java @@ -8,14 +8,14 @@ import com.vaadin.ui.AbsoluteLayout; import com.vaadin.ui.AbsoluteLayout.ComponentPosition; import com.vaadin.ui.AbstractOrderedLayout; import com.vaadin.ui.Component; -import com.vaadin.ui.ComponentContainer; -import com.vaadin.ui.ComponentContainer.ComponentAttachEvent; -import com.vaadin.ui.ComponentContainer.ComponentAttachListener; -import com.vaadin.ui.ComponentContainer.ComponentDetachEvent; -import com.vaadin.ui.ComponentContainer.ComponentDetachListener; import com.vaadin.ui.CssLayout; import com.vaadin.ui.GridLayout; import com.vaadin.ui.GridLayout.Area; +import com.vaadin.ui.HasComponents; +import com.vaadin.ui.HasComponents.ComponentAttachEvent; +import com.vaadin.ui.HasComponents.ComponentAttachListener; +import com.vaadin.ui.HasComponents.ComponentDetachEvent; +import com.vaadin.ui.HasComponents.ComponentDetachListener; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; @@ -29,12 +29,12 @@ public class ComponentAttachDetachListenerTest extends TestCase { // General variables private int attachCounter = 0; private Component attachedComponent = null; - private ComponentContainer attachTarget = null; + private HasComponents attachTarget = null; private boolean foundInContainer = false; private int detachCounter = 0; private Component detachedComponent = null; - private ComponentContainer detachedTarget = null; + private HasComponents detachedTarget = null; // Ordered layout specific variables private int indexOfComponent = -1; @@ -53,7 +53,7 @@ public class ComponentAttachDetachListenerTest extends TestCase { attachTarget = event.getContainer(); // Search for component in container (should be found) - Iterator<Component> iter = attachTarget.getComponentIterator(); + Iterator<Component> iter = attachTarget.iterator(); while (iter.hasNext()) { if (iter.next() == attachedComponent) { foundInContainer = true; @@ -83,7 +83,7 @@ public class ComponentAttachDetachListenerTest extends TestCase { detachedTarget = event.getContainer(); // Search for component in container (should NOT be found) - Iterator<Component> iter = detachedTarget.getComponentIterator(); + Iterator<Component> iter = detachedTarget.iterator(); while (iter.hasNext()) { if (iter.next() == detachedComponent) { foundInContainer = true; @@ -129,20 +129,20 @@ public class ComponentAttachDetachListenerTest extends TestCase { super.setUp(); olayout = new HorizontalLayout(); - olayout.addListener(new MyAttachListener()); - olayout.addListener(new MyDetachListener()); + olayout.addComponentAttachListener(new MyAttachListener()); + olayout.addComponentDetachListener(new MyDetachListener()); gridlayout = new GridLayout(); - gridlayout.addListener(new MyAttachListener()); - gridlayout.addListener(new MyDetachListener()); + gridlayout.addComponentAttachListener(new MyAttachListener()); + gridlayout.addComponentDetachListener(new MyDetachListener()); absolutelayout = new AbsoluteLayout(); - absolutelayout.addListener(new MyAttachListener()); - absolutelayout.addListener(new MyDetachListener()); + absolutelayout.addComponentAttachListener(new MyAttachListener()); + absolutelayout.addComponentDetachListener(new MyDetachListener()); csslayout = new CssLayout(); - csslayout.addListener(new MyAttachListener()); - csslayout.addListener(new MyDetachListener()); + csslayout.addComponentAttachListener(new MyAttachListener()); + csslayout.addComponentDetachListener(new MyDetachListener()); } public void testOrderedLayoutAttachListener() { diff --git a/server/tests/src/com/vaadin/ui/LabelDataSource.java b/server/tests/src/com/vaadin/ui/LabelDataSource.java index 506a635814..7ef8d67c2a 100644 --- a/server/tests/src/com/vaadin/ui/LabelDataSource.java +++ b/server/tests/src/com/vaadin/ui/LabelDataSource.java @@ -122,7 +122,7 @@ public class LabelDataSource { label.setPropertyDataSource(integerDataSource); UI ui = new MockUI(); ui.setLocale(Locale.GERMANY); - ui.addComponent(label); + ui.setContent(label); Assert.assertEquals(INTEGER_STRING_VALUE_DE, label.getState().text); } } |