com.vaadin.ui.AbstractComponentContainer.java Source code

Java tutorial

Introduction

Here is the source code for com.vaadin.ui.AbstractComponentContainer.java

Source

/*
 * Copyright 2000-2018 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.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;

import com.vaadin.server.ComponentSizeValidator;
import com.vaadin.shared.Registration;
import com.vaadin.shared.ui.AbstractComponentContainerState;

/**
 * Extension to {@link AbstractComponent} that defines the default
 * implementation for the methods in {@link ComponentContainer}. Basic UI
 * components that need to contain other components inherit this class to easily
 * qualify as a component container.
 *
 * @author Vaadin Ltd
 * @since 3.0
 */
@SuppressWarnings("serial")
public abstract class AbstractComponentContainer extends AbstractComponent implements ComponentContainer {

    /**
     * Constructs a new component container.
     */
    public AbstractComponentContainer() {
        super();
    }

    /*
     * (non-Javadoc)
     *
     * @see
     * com.vaadin.ui.ComponentContainer#addComponents(com.vaadin.ui.Component[])
     */
    @Override
    public void addComponents(Component... components) {
        for (Component c : components) {
            addComponent(c);
        }
    }

    /**
     * Removes all components from the container. This should probably be
     * re-implemented in extending classes for a more powerful implementation.
     */
    @Override
    public void removeAllComponents() {
        final LinkedList<Component> l = new LinkedList<>();

        // Adds all components
        for (final Iterator<Component> i = getComponentIterator(); i.hasNext();) {
            l.add(i.next());
        }

        // Removes all component
        for (Component aL : l) {
            removeComponent(aL);
        }
    }

    /*
     * Moves all components from an another container into this container. Don't
     * add a JavaDoc comment here, we use the default documentation from
     * implemented interface.
     */
    @Override
    public void moveComponentsFrom(ComponentContainer source) {
        final LinkedList<Component> components = new LinkedList<>();
        for (final Iterator<Component> i = source.getComponentIterator(); i.hasNext();) {
            components.add(i.next());
        }

        for (final Component c : components) {
            source.removeComponent(c);
            addComponent(c);
        }
    }

    /* documented in interface */
    @Override
    public Registration addComponentAttachListener(ComponentAttachListener listener) {
        return addListener(ComponentAttachEvent.class, listener, ComponentAttachListener.attachMethod);
    }

    /* documented in interface */
    @Override
    @Deprecated
    public void removeComponentAttachListener(ComponentAttachListener listener) {
        removeListener(ComponentAttachEvent.class, listener, ComponentAttachListener.attachMethod);
    }

    /* documented in interface */
    @Override
    public Registration addComponentDetachListener(ComponentDetachListener listener) {
        return addListener(ComponentDetachEvent.class, listener, ComponentDetachListener.detachMethod);
    }

    /* documented in interface */
    @Override
    @Deprecated
    public void removeComponentDetachListener(ComponentDetachListener listener) {
        removeListener(ComponentDetachEvent.class, listener, ComponentDetachListener.detachMethod);
    }

    /**
     * Fires the component attached event. This should be called by the
     * addComponent methods after the component have been added to this
     * container.
     *
     * @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 should be called by the
     * removeComponent methods after the component have been removed from this
     * container.
     *
     * @param component
     *            the component that has been removed from this container.
     */
    protected void fireComponentDetachEvent(Component component) {
        fireEvent(new ComponentDetachEvent(this, component));
    }

    /**
     * This only implements the events and component parent calls. The extending
     * classes must implement component list maintenance and call this method
     * after component list maintenance.
     *
     * @see com.vaadin.ui.ComponentContainer#addComponent(Component)
     */
    @Override
    public void addComponent(Component c) {
        // Make sure we're not adding the component inside it's own content
        if (isOrHasAncestor(c)) {
            throw new IllegalArgumentException("Component cannot be added inside it's own content");
        }

        if (c.getParent() != null) {
            // If the component already has a parent, try to remove it
            AbstractSingleComponentContainer.removeFromParent(c);
        }

        c.setParent(this);
        fireComponentAttachEvent(c);
        markAsDirty();
    }

    /**
     * This only implements the events and component parent calls. The extending
     * classes must implement component list maintenance and call this method
     * before component list maintenance.
     *
     * @see com.vaadin.ui.ComponentContainer#removeComponent(Component)
     */
    @Override
    public void removeComponent(Component c) {
        if (equals(c.getParent())) {
            c.setParent(null);
            fireComponentDetachEvent(c);
            markAsDirty();
        }
    }

    @Override
    public void setWidth(float width, Unit unit) {
        /*
         * child tree repaints may be needed, due to our fall back support for
         * invalid relative sizes
         */
        Collection<Component> dirtyChildren = null;
        boolean childrenMayBecomeUndefined = false;
        if (getWidth() == SIZE_UNDEFINED && width != SIZE_UNDEFINED) {
            // children currently in invalid state may need repaint
            dirtyChildren = getInvalidSizedChildren(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;
            dirtyChildren = getInvalidSizedChildren(false);
        }
        super.setWidth(width, unit);
        repaintChangedChildTrees(dirtyChildren, childrenMayBecomeUndefined, false);
    }

    private void repaintChangedChildTrees(Collection<Component> invalidChildren, boolean childrenMayBecomeUndefined,
            boolean vertical) {
        if (childrenMayBecomeUndefined) {
            Collection<Component> previouslyInvalidComponents = invalidChildren;
            invalidChildren = getInvalidSizedChildren(vertical);
            if (previouslyInvalidComponents != null && invalidChildren != null) {
                for (Iterator<Component> iterator = invalidChildren.iterator(); iterator.hasNext();) {
                    Component component = iterator.next();
                    if (previouslyInvalidComponents.contains(component)) {
                        // still invalid don't repaint
                        iterator.remove();
                    }
                }
            }
        } else if (invalidChildren != null) {
            Collection<Component> stillInvalidChildren = getInvalidSizedChildren(vertical);
            if (stillInvalidChildren != null) {
                for (Component component : stillInvalidChildren) {
                    // didn't become valid
                    invalidChildren.remove(component);
                }
            }
        }
        if (invalidChildren != null) {
            repaintChildTrees(invalidChildren);
        }
    }

    private Collection<Component> getInvalidSizedChildren(final boolean vertical) {
        HashSet<Component> components = null;
        for (Component component : this) {
            boolean valid = vertical ? ComponentSizeValidator.checkHeights(component)
                    : ComponentSizeValidator.checkWidths(component);
            if (!valid) {
                if (components == null) {
                    components = new HashSet<>();
                }
                components.add(component);
            }
        }
        return components;
    }

    private void repaintChildTrees(Collection<Component> dirtyChildren) {
        for (Component c : dirtyChildren) {
            c.markAsDirtyRecursive();
        }
    }

    @Override
    public void setHeight(float height, Unit unit) {
        /*
         * child tree repaints may be needed, due to our fall back support for
         * invalid relative sizes
         */
        Collection<Component> dirtyChildren = null;
        boolean childrenMayBecomeUndefined = false;
        if (getHeight() == SIZE_UNDEFINED && height != SIZE_UNDEFINED) {
            // children currently in invalid state may need repaint
            dirtyChildren = getInvalidSizedChildren(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;
            dirtyChildren = getInvalidSizedChildren(true);
        }
        super.setHeight(height, unit);
        repaintChangedChildTrees(dirtyChildren, childrenMayBecomeUndefined, true);
    }

    /**
     * {@inheritDoc}
     *
     * @deprecated As of 7.0, use {@link #iterator()} instead.
     */
    @Deprecated
    @Override
    public Iterator<Component> getComponentIterator() {
        return iterator();
    }

    @Override
    protected AbstractComponentContainerState getState() {
        return (AbstractComponentContainerState) super.getState();
    }

    @Override
    protected AbstractComponentContainerState getState(boolean markAsDirty) {
        return (AbstractComponentContainerState) super.getState(markAsDirty);
    }
}