com.google.gwt.user.client.ui.ComplexPanel.java Source code

Java tutorial

Introduction

Here is the source code for com.google.gwt.user.client.ui.ComplexPanel.java

Source

/*
 * Copyright 2007 Google Inc.
 * 
 * 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.google.gwt.user.client.ui;

import java.util.Iterator;

import com.google.gwt.dom.client.Element;
import com.google.gwt.user.client.DOM;

/**
 * Abstract base class for panels that can contain multiple child widgets.
 */
public abstract class ComplexPanel extends Panel implements IndexedPanel.ForIsWidget {
    private WidgetCollection children = new WidgetCollection(this);

    /**
     * The command used to orphan children.
     */
    private AttachDetachException.Command orphanCommand;

    public Widget getWidget(int index) {
        return getChildren().get(index);
    }

    public int getWidgetCount() {
        return getChildren().size();
    }

    public int getWidgetIndex(IsWidget child) {
        return getWidgetIndex(asWidgetOrNull(child));
    }

    public int getWidgetIndex(Widget child) {
        return getChildren().indexOf(child);
    }

    public Iterator<Widget> iterator() {
        return getChildren().iterator();
    }

    public boolean remove(int index) {
        return remove(getWidget(index));
    }

    @Override
    public boolean remove(Widget w) {
        // Validate.
        if (w.getParent() != this) {
            return false;
        }
        // Orphan.
        try {
            orphan(w);
        } finally {
            // Physical detach.
            Element elem = w.getElement();
            if (DOM.getParent(elem) == null) {
                // FIXME - localdom
            } else {
                DOM.getParent(elem).removeChild(elem);
            }
            // Logical detach.
            getChildren().remove(w);
        }
        return true;
    }

    /**
     * Adds a new child widget to the panel, attaching its Element to the
     * specified container Element.
     * 
     * @param child
     *            the child widget to be added
     * @param container
     *            the element within which the child will be contained
     */
    protected void add(Widget child, Element container) {
        // Detach new child.
        child.removeFromParent();
        // Logical attach.
        getChildren().add(child);
        // Physical attach.
        DOM.appendChild(container, child.getElement());
        // Adopt.
        adopt(child);
    }

    /**
     * Adjusts beforeIndex to account for the possibility that the given widget
     * is already a child of this panel.
     * 
     * @param child
     *            the widget that might be an existing child
     * @param beforeIndex
     *            the index at which it will be added to this panel
     * @return the modified index
     */
    protected int adjustIndex(Widget child, int beforeIndex) {
        checkIndexBoundsForInsertion(beforeIndex);
        // Check to see if this widget is already a direct child.
        if (child.getParent() == this) {
            // If the Widget's previous position was left of the desired new
            // position
            // shift the desired position left to reflect the removal
            int idx = getWidgetIndex(child);
            if (idx < beforeIndex) {
                beforeIndex--;
            }
        }
        return beforeIndex;
    }

    /**
     * Checks that <code>index</code> is in the range [0, getWidgetCount()),
     * which is the valid range on accessible indexes.
     * 
     * @param index
     *            the index being accessed
     */
    protected void checkIndexBoundsForAccess(int index) {
        if (index < 0 || index >= getWidgetCount()) {
            throw new IndexOutOfBoundsException();
        }
    }

    /**
     * Checks that <code>index</code> is in the range [0, getWidgetCount()],
     * which is the valid range for indexes on an insertion.
     * 
     * @param index
     *            the index where insertion will occur
     */
    protected void checkIndexBoundsForInsertion(int index) {
        if (index < 0 || index > getWidgetCount()) {
            throw new IndexOutOfBoundsException();
        }
    }

    /**
     * Gets the list of children contained in this panel.
     * 
     * @return a collection of child widgets
     */
    protected WidgetCollection getChildren() {
        return children;
    }

    /**
     * Insert a new child Widget into this Panel at a specified index, attaching
     * its Element to the specified container Element. The child Element will
     * either be attached to the container at the same index, or simply appended
     * to the container, depending on the value of <code>domInsert</code>.
     * 
     * @param child
     *            the child Widget to be added
     * @param container
     *            the Element within which <code>child</code> will be contained
     * @param beforeIndex
     *            the index before which <code>child</code> will be inserted
     * @param domInsert
     *            if <code>true</code>, insert <code>child</code> into
     *            <code>container</code> at <code>beforeIndex</code>; otherwise
     *            append <code>child</code> to the end of <code>container</code>
     *            .
     */
    protected void insert(Widget child, Element container, int beforeIndex, boolean domInsert) {
        // Validate index; adjust if the widget is already a child of this
        // panel.
        beforeIndex = adjustIndex(child, beforeIndex);
        // Detach new child.
        child.removeFromParent();
        // Logical attach.
        getChildren().insert(child, beforeIndex);
        // Physical attach.
        if (domInsert) {
            DOM.insertChild(container, child.getElement(), beforeIndex);
        } else {
            DOM.appendChild(container, child.getElement());
        }
        // Adopt.
        adopt(child);
    }

    void doLogicalClear() {
        // TODO(jgw): When Layout work has landed, deprecate FlowPanel (the only
        // caller of this method in our code), and deprecate this method with an
        // eye
        // to making it private down the road.
        // Only use one orphan command per panel to avoid object creation.
        if (orphanCommand == null) {
            orphanCommand = new AttachDetachException.Command() {
                public void execute(Widget w) {
                    orphan(w);
                }
            };
        }
        try {
            AttachDetachException.tryCommand(this, orphanCommand);
        } finally {
            children = new WidgetCollection(this);
        }
    }
}