org.waveprotocol.wave.client.widget.common.ImplPanel.java Source code

Java tutorial

Introduction

Here is the source code for org.waveprotocol.wave.client.widget.common.ImplPanel.java

Source

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 org.waveprotocol.wave.client.widget.common;

import com.google.common.base.Preconditions;
import com.google.gwt.dom.client.Element;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.DoubleClickEvent;
import com.google.gwt.event.dom.client.DoubleClickHandler;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.event.dom.client.HasDoubleClickHandlers;
import com.google.gwt.event.dom.client.HasMouseDownHandlers;
import com.google.gwt.event.dom.client.MouseDownEvent;
import com.google.gwt.event.dom.client.MouseDownHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.client.ui.WidgetCollection;

import org.waveprotocol.wave.client.common.util.LogicalPanel;

/**
 * A generic panel for use by UiBinder templates, for widgets that require more
 * powerful control over their DOM and/or child lifecycle.
 *
 * Like {@link HTMLPanel}, its state can be defined in UiBinder using regular
 * HTML, allowing child widgets to be attached statically at arbitrary
 * locations. Unlike HTMLPanel, however, it also exposes the ability to attach
 * child widgets <em>dynamically</em> at arbitrary locations. It also exposes
 * the ability to adopt widgets already in the DOM (and, symmetrically, to
 * orphan them).
 *
 */
public class ImplPanel extends HTMLPanel
        implements LogicalPanel, HasClickHandlers, HasDoubleClickHandlers, HasMouseDownHandlers {

    /**
     * Creates an panel with some initial inner-HTML.
     *
     * @param html initial inner contents
     */
    public ImplPanel(String html) {
        super(html);
    }

    /**
     * Adds a widget to this panel.
     */
    @Override
    public void add(Widget child) {
        add(child, getElement());
    }

    // Expose proteced method.
    @Override
    public void add(Widget child, com.google.gwt.user.client.Element container) {
        super.add(child, container);
    }

    /**
     * Adds a widget, inserting it as the first child in the DOM structure.
     *
     * @param child widget to add
     */
    public void insertFirst(Widget child) {
        insertBefore(child, getElement(), getElement().getFirstChildElement());
    }

    @Override
    protected void insert(Widget child, com.google.gwt.user.client.Element container, int beforeIndex,
            boolean domInsert) {
        // This method is intentionally suppressed, because ComplexPanel's insert()
        // method operates under the assumption that the only HTML contents of this
        // panel's element are the elements of this panel's child widgets (i.e., no
        // HTML decorations or chrome elements). This is not the desired behaviour
        // for ImplPanel.
        throw new UnsupportedOperationException("Index-based insertion is not supported by ImplPanel");
    }

    /**
     * Inserts a widget into this panel, attaching its HTML to a specified
     * location within this panel's HTML.
     * <p>
     * Note that in order for this panel to have arbitrary HTML decorations,
     * rather than none at all, this panel must not care about the logical order
     * of its child widgets (an inherited restriction from ComplexPanel, which
     * assumes logical child index == physical DOM index).
     * <p>
     * Assumes (but does not check) that {@code container} is a descendant of this
     * widget's element, and that {@code reference} is a direct child of {@code
     * container}.
     *
     * @param child
     * @param container
     * @param reference
     */
    public void insertBefore(Widget child, Element container, Element reference) {
        // The implementation below is identical to add(), except the physical DOM
        // insertion is positional.

        // Detach new child.
        child.removeFromParent();

        // Logical attach.
        getChildren().add(child);

        // Physical attach.
        container.insertBefore(child.getElement(), reference);

        // Adopt.
        adopt(child);
    }

    /**
     * Inserts a widget into this panel, attaching its HTML to a specified
     * location within this panel's HTML.
     * <p>
     * Note that in order for this panel to have arbitrary HTML decorations,
     * rather than none at all, this panel must not care about the logical order
     * of its child widgets (an inherited restriction from ComplexPanel, which
     * assumes logical child index == physical DOM index).
     * <p>
     * Assumes (but does not check) that {@code container} is a descendant of this
     * widget's element, and that {@code reference} is a direct child of {@code
     * container}.
     *
     * @param child
     * @param container
     * @param reference
     */
    public void insertAfter(Widget child, Element container, Element reference) {
        // The implementation below is identical to add(), except the physical DOM
        // insertion is positional.

        // Detach new child.
        child.removeFromParent();

        // Logical attach.
        getChildren().add(child);

        // Physical attach.
        if (reference == null) {
            container.insertFirst(child.getElement());
        } else {
            container.insertAfter(child.getElement(), reference);
        }

        // Adopt.
        adopt(child);
    }

    @Override
    public void doAdopt(Widget child) {
        Preconditions.checkArgument(child != null && child.getParent() == null, "Not an orphan");
        getChildren().add(child);
        adopt(child);
    }

    @Override
    public void doOrphan(Widget child) {
        Preconditions.checkArgument(child != null && child.getParent() == this, "Not a child");
        orphan(child);
        getChildren().remove(child);
    }

    /**
     * Narrows an object to a widget, if it is a child of this panel. Otherwise,
     * throws an exception.
     *
     * @param o object to narrow
     * @return {@code o} as a widget
     * @throws IllegalArgumentException if {@code o} is not a child of this panel.
     */
    public Widget narrowChild(Object o) {
        // Note: it is very important that this method can be implemented WITHOUT
        // casting.  This implementation uses casting as an optimization.  However,
        // a non-casting version is provided in comments. Anyone touching this
        // method must ensure that a non-casting possibility exists.
        //
        // for (Widget child : getChildren()) {
        //   if (child == o) {
        //     return child;
        //   }
        // }
        // return null;
        //
        Widget w = o instanceof Widget ? (Widget) o : null;
        if (w != null && w.getParent() == this) {
            return w;
        } else {
            throw new IllegalArgumentException("Not a child");
        }
    }

    @Override
    public HandlerRegistration addClickHandler(ClickHandler handler) {
        return addDomHandler(handler, ClickEvent.getType());
    }

    @Override
    public HandlerRegistration addDoubleClickHandler(DoubleClickHandler handler) {
        return addDomHandler(handler, DoubleClickEvent.getType());
    }

    @Override
    public HandlerRegistration addMouseDownHandler(MouseDownHandler handler) {
        return addDomHandler(handler, MouseDownEvent.getType());
    }

    @Override
    public WidgetCollection getChildren() {
        return super.getChildren();
    }
}