diff options
author | Teemu Suo-Anttila <teemusa@vaadin.com> | 2016-03-10 22:40:51 +0200 |
---|---|---|
committer | Teemu Suo-Anttila <teemusa@vaadin.com> | 2016-03-14 07:59:12 +0200 |
commit | a6653d3fe49e6a97468ac09f7f2f4d621bea1078 (patch) | |
tree | 96c82e20ca6551ee4c14c8877f0258b25c63cddf /server/src/main/java/com/vaadin/ui/AbstractSingleComponentContainer.java | |
parent | f7e57d77ce621ee39167369c31d989edc5633266 (diff) | |
download | vaadin-framework-a6653d3fe49e6a97468ac09f7f2f4d621bea1078.tar.gz vaadin-framework-a6653d3fe49e6a97468ac09f7f2f4d621bea1078.zip |
Migrate vaadin-server build to maven
Change-Id: I5c740f4e9cb28103bab199f9a552153d82277e7e
Diffstat (limited to 'server/src/main/java/com/vaadin/ui/AbstractSingleComponentContainer.java')
-rw-r--r-- | server/src/main/java/com/vaadin/ui/AbstractSingleComponentContainer.java | 346 |
1 files changed, 346 insertions, 0 deletions
diff --git a/server/src/main/java/com/vaadin/ui/AbstractSingleComponentContainer.java b/server/src/main/java/com/vaadin/ui/AbstractSingleComponentContainer.java new file mode 100644 index 0000000000..0854ffe9c2 --- /dev/null +++ b/server/src/main/java/com/vaadin/ui/AbstractSingleComponentContainer.java @@ -0,0 +1,346 @@ +/* + * Copyright 2000-2014 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 org.jsoup.nodes.Element; +import org.jsoup.select.Elements; + +import com.vaadin.server.ComponentSizeValidator; +import com.vaadin.server.VaadinService; +import com.vaadin.server.VaadinSession; +import com.vaadin.ui.declarative.DesignContext; +import com.vaadin.ui.declarative.DesignException; + +/** + * 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)); + } + + @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) { + // Make sure we're not adding the component inside it's own content + if (isOrHasAncestor(content)) { + throw new IllegalArgumentException( + "Component cannot be added inside it's own content"); + } + + Component oldContent = getContent(); + if (oldContent == content) { + // do not set the same content twice + return; + } + if (oldContent != null && equals(oldContent.getParent())) { + 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 { + // Verify the appropriate session is locked + UI parentUI = content.getUI(); + if (parentUI != null) { + VaadinSession parentSession = parentUI.getSession(); + if (parentSession != null && !parentSession.hasLock()) { + String message = "Cannot remove from parent when the session is not locked."; + if (VaadinService.isOtherSessionLocked(parentSession)) { + message += " Furthermore, there is another locked session, indicating that the component might be about to be moved from one session to another."; + } + throw new IllegalStateException(message); + } + } + + 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); + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.ui.AbstractComponent#readDesign(org.jsoup.nodes .Element, + * com.vaadin.ui.declarative.DesignContext) + */ + @Override + public void readDesign(Element design, DesignContext designContext) { + // process default attributes + super.readDesign(design, designContext); + readDesignChildren(design.children(), designContext); + } + + /** + * Reads the content component from the list of child elements of a design. + * The list must be empty or contain a single element; if the design + * contains multiple child elements, a DesignException is thrown. This + * method should be overridden by subclasses whose design may contain + * non-content child elements. + * + * @since 7.5.0 + * + * @param children + * the child elements of the design that is being read + * @param context + * the DesignContext instance used to parse the design + * + * @throws DesignException + * if there are multiple child elements + * @throws DesignException + * if a child element could not be parsed as a Component + */ + protected void readDesignChildren(Elements children, DesignContext context) { + if (children.size() > 1) { + throw new DesignException("The container of type " + + getClass().toString() + + " can have only one child component."); + } else if (children.size() == 1) { + setContent(context.readDesign(children.first())); + } + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.ui.AbstractComponent#writeDesign(org.jsoup.nodes.Element + * , com.vaadin.ui.declarative.DesignContext) + */ + @Override + public void writeDesign(Element design, DesignContext designContext) { + // write default attributes (also clears children and attributes) + super.writeDesign(design, designContext); + AbstractSingleComponentContainer def = designContext + .getDefaultInstance(this); + if (!designContext.shouldWriteChildren(this, def)) { + return; + } + // handle child component + Component child = getContent(); + if (child != null) { + Element childNode = designContext.createElement(child); + design.appendChild(childNode); + } + } +}
\ No newline at end of file |