aboutsummaryrefslogtreecommitdiffstats
path: root/server/src/main/java/com/vaadin/ui/AbstractSingleComponentContainer.java
diff options
context:
space:
mode:
authorTeemu Suo-Anttila <teemusa@vaadin.com>2016-03-10 22:40:51 +0200
committerTeemu Suo-Anttila <teemusa@vaadin.com>2016-03-14 07:59:12 +0200
commita6653d3fe49e6a97468ac09f7f2f4d621bea1078 (patch)
tree96c82e20ca6551ee4c14c8877f0258b25c63cddf /server/src/main/java/com/vaadin/ui/AbstractSingleComponentContainer.java
parentf7e57d77ce621ee39167369c31d989edc5633266 (diff)
downloadvaadin-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.java346
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