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

Java tutorial

Introduction

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

Source

/*
 * Copyright 2011 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 com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.dom.client.Style.Overflow;
import com.google.gwt.dom.client.Style.Position;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.FiniteWidgetIterator.WidgetProvider;

import java.util.Iterator;

/**
 * A panel that includes a header (top), footer (bottom), and content (middle)
 * area. The header and footer areas resize naturally. The content area is
 * allocated all of the remaining space between the header and footer area.
 */
public class HeaderPanel extends Panel implements RequiresResize {

    /**
     * The widget provider for this panel.
     * 
     * <p>
     * Widgets are returned in the following order:
     * <ol>
     * <li>Header widget</li>
     * <li>Content widget</li>
     * <li>Footer widget</li>
     * </ol>
     */
    private class WidgetProviderImpl implements WidgetProvider {

        public Widget get(int index) {
            switch (index) {
            case 0:
                return header;
            case 1:
                return content;
            case 2:
                return footer;
            }
            throw new ArrayIndexOutOfBoundsException(index);
        }
    }

    private Widget content;
    private final Element contentContainer;
    private Widget footer;
    private final Element footerContainer;
    private final ResizeLayoutPanel.Impl footerImpl = GWT.create(ResizeLayoutPanel.Impl.class);
    private Widget header;
    private final Element headerContainer;
    private final ResizeLayoutPanel.Impl headerImpl = GWT.create(ResizeLayoutPanel.Impl.class);
    private final ScheduledCommand layoutCmd = new ScheduledCommand() {
        public void execute() {
            layoutScheduled = false;
            forceLayout();
        }
    };
    private boolean layoutScheduled = false;

    public HeaderPanel() {
        // Create the outer element
        Element elem = Document.get().createDivElement().cast();
        elem.getStyle().setPosition(Position.RELATIVE);
        elem.getStyle().setOverflow(Overflow.HIDDEN);
        setElement(elem);

        // Create a delegate to handle resize from the header and footer.
        ResizeLayoutPanel.Impl.Delegate resizeDelegate = new ResizeLayoutPanel.Impl.Delegate() {
            public void onResize() {
                scheduledLayout();
            }
        };

        // Create the header container.
        headerContainer = createContainer();
        headerContainer.getStyle().setTop(0.0, Unit.PX);
        headerImpl.init(headerContainer, resizeDelegate);
        elem.appendChild(headerContainer);

        // Create the footer container.
        footerContainer = createContainer();
        footerContainer.getStyle().setBottom(0.0, Unit.PX);
        footerImpl.init(footerContainer, resizeDelegate);
        elem.appendChild(footerContainer);

        // Create the content container.
        contentContainer = createContainer();
        contentContainer.getStyle().setOverflow(Overflow.HIDDEN);
        contentContainer.getStyle().setTop(0.0, Unit.PX);
        contentContainer.getStyle().setHeight(0.0, Unit.PX);
        elem.appendChild(contentContainer);
    }

    /**
     * Adds a widget to this panel.
     * 
     * @param w the child widget to be added
     */
    @Override
    public void add(Widget w) {
        // Add widgets in the order that they appear.
        if (header == null) {
            setHeaderWidget(w);
        } else if (content == null) {
            setContentWidget(w);
        } else if (footer == null) {
            setFooterWidget(w);
        } else {
            throw new IllegalStateException("HeaderPanel already contains header, content, and footer widgets.");
        }
    }

    /**
     * Get the content widget that appears between the header and footer.
     * 
     * @return the content {@link Widget}
     */
    public Widget getContentWidget() {
        return content;
    }

    /**
     * Get the footer widget at the bottom of the panel.
     * 
     * @return the footer {@link Widget}
     */
    public Widget getFooterWidget() {
        return footer;
    }

    /**
     * Get the header widget at the top of the panel.
     * 
     * @return the header {@link Widget}
     */
    public Widget getHeaderWidget() {
        return header;
    }

    public Iterator<Widget> iterator() {
        return new FiniteWidgetIterator(new WidgetProviderImpl(), 3);
    }

    @Override
    public void onAttach() {
        super.onAttach();
        headerImpl.onAttach();
        footerImpl.onAttach();
        scheduledLayout();
    }

    @Override
    public void onDetach() {
        super.onDetach();
        headerImpl.onDetach();
        footerImpl.onDetach();
    }

    public void onResize() {
        // Handle the outer element resizing.
        scheduledLayout();
    }

    @Override
    public boolean remove(Widget w) {
        // Validate.
        if (w.getParent() != this) {
            return false;
        }
        // Orphan.
        try {
            orphan(w);
        } finally {
            // Physical detach.
            w.getElement().removeFromParent();

            // Logical detach.
            if (w == content) {
                content = null;
                contentContainer.getStyle().setDisplay(Display.NONE);
            } else if (w == header) {
                header = null;
                headerContainer.getStyle().setDisplay(Display.NONE);
            } else if (w == footer) {
                footer = null;
                footerContainer.getStyle().setDisplay(Display.NONE);
            }
        }
        return true;
    }

    /**
     * Set the widget in the content portion between the header and footer.
     * 
     * @param w the widget to use as the content
     */
    public void setContentWidget(Widget w) {
        contentContainer.getStyle().clearDisplay();
        add(w, content, contentContainer);

        // Logical attach.
        content = w;
        scheduledLayout();
    }

    /**
     * Set the widget in the footer portion at the bottom of the panel.
     * 
     * @param w the widget to use as the footer
     */
    public void setFooterWidget(Widget w) {
        footerContainer.getStyle().clearDisplay();
        add(w, footer, footerContainer);

        // Logical attach.
        footer = w;
        scheduledLayout();
    }

    /**
     * Set the widget in the header portion at the top of the panel.
     * 
     * @param w the widget to use as the header
     */
    public void setHeaderWidget(Widget w) {
        headerContainer.getStyle().clearDisplay();
        add(w, header, headerContainer);

        // Logical attach.
        header = w;
        scheduledLayout();
    }

    /**
     * Add a widget to the panel in the specified container. Note that this method
     * does not do the logical attach.
     * 
     * @param w the widget to add
     * @param toReplace the widget to replace
     * @param container the container in which to place the widget
     */
    private void add(Widget w, Widget toReplace, Element container) {
        // Validate.
        if (w == toReplace) {
            return;
        }

        // Detach new child.
        if (w != null) {
            w.removeFromParent();
        }

        // Remove old child.
        if (toReplace != null) {
            remove(toReplace);
        }

        if (w != null) {
            // Physical attach.
            container.appendChild(w.getElement());

            adopt(w);
        }
    }

    private Element createContainer() {
        Element container = Document.get().createDivElement().cast();
        container.getStyle().setPosition(Position.ABSOLUTE);
        container.getStyle().setDisplay(Display.NONE);
        container.getStyle().setLeft(0.0, Unit.PX);
        container.getStyle().setWidth(100.0, Unit.PCT);
        return container;
    }

    /**
     * Update the layout.
     */
    private void forceLayout() {
        // No sense in doing layout if we aren't attached or have no content.
        if (!isAttached() || content == null) {
            return;
        }

        // Resize the content area to fit between the header and footer.
        int remainingHeight = getElement().getClientHeight();
        if (header != null) {
            int height = Math.max(0, headerContainer.getOffsetHeight());
            remainingHeight -= height;
            contentContainer.getStyle().setTop(height, Unit.PX);
        } else {
            contentContainer.getStyle().setTop(0.0, Unit.PX);
        }
        if (footer != null) {
            remainingHeight -= footerContainer.getOffsetHeight();
        }
        contentContainer.getStyle().setHeight(Math.max(0, remainingHeight), Unit.PX);

        // Provide resize to child.
        if (content instanceof RequiresResize) {
            ((RequiresResize) content).onResize();
        }
    }

    /**
     * Schedule layout to adjust the height of the content area.
     */
    private void scheduledLayout() {
        if (isAttached() && !layoutScheduled) {
            layoutScheduled = true;
            Scheduler.get().scheduleDeferred(layoutCmd);
        }
    }
}