| /* |
| * Copyright 2008 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.user.client.DOM; |
| import com.google.gwt.user.client.Event; |
| |
| /** |
| * A type of widget that can wrap another widget, hiding the wrapped widget's |
| * methods. When added to a panel, a composite behaves exactly as if the widget |
| * it wraps had been added. |
| * |
| * <p> |
| * The composite is useful for creating a single widget out of an aggregate of |
| * multiple other widgets contained in a single panel. |
| * </p> |
| * |
| * <p> |
| * <h3>Example</h3> |
| * {@example com.google.gwt.examples.CompositeExample} |
| * </p> |
| */ |
| public abstract class Composite extends Widget { |
| |
| private Widget widget; |
| |
| @Override |
| public boolean isAttached() { |
| if (widget != null) { |
| return widget.isAttached(); |
| } |
| return false; |
| } |
| |
| @Override |
| public void onBrowserEvent(Event event) { |
| // Fire any handler added to the composite itself. |
| super.onBrowserEvent(event); |
| |
| // Delegate events to the widget. |
| widget.onBrowserEvent(event); |
| } |
| |
| /** |
| * Provides subclasses access to the topmost widget that defines this |
| * composite. |
| * |
| * @return the widget |
| */ |
| protected Widget getWidget() { |
| return widget; |
| } |
| |
| /** |
| * Sets the widget to be wrapped by the composite. The wrapped widget must be |
| * set before calling any {@link Widget} methods on this object, or adding it |
| * to a panel. This method may only be called once for a given composite. |
| * |
| * @param widget the widget to be wrapped |
| */ |
| protected void initWidget(Widget widget) { |
| // Validate. Make sure the widget is not being set twice. |
| if (this.widget != null) { |
| throw new IllegalStateException("Composite.initWidget() may only be " |
| + "called once."); |
| } |
| |
| // Detach the new child. |
| widget.removeFromParent(); |
| |
| // Use the contained widget's element as the composite's element, |
| // effectively merging them within the DOM. |
| setElement(widget.getElement()); |
| |
| // Logical attach. |
| this.widget = widget; |
| |
| // Adopt. |
| widget.setParent(this); |
| } |
| |
| @Override |
| protected void onAttach() { |
| if (!isOrWasAttached()) { |
| widget.sinkEvents(eventsToSink); |
| eventsToSink = -1; |
| } |
| |
| widget.onAttach(); |
| |
| // Clobber the widget's call to setEventListener(), causing all events to |
| // be routed to this composite, which will delegate back to the widget by |
| // default (note: it's not necessary to clear this in onDetach(), because |
| // the widget's onDetach will do so). |
| DOM.setEventListener(getElement(), this); |
| |
| // Call onLoad() directly, because we're not calling super.onAttach(). |
| onLoad(); |
| } |
| |
| @Override |
| protected void onDetach() { |
| try { |
| onUnload(); |
| } finally { |
| // We don't want an exception in user code to keep us from calling the |
| // super implementation (or event listeners won't get cleaned up and |
| // the attached flag will be wrong). |
| widget.onDetach(); |
| } |
| } |
| |
| /** |
| * This method was for initializing the Widget to be wrapped by this |
| * Composite, but has been deprecated in favor of {@link #initWidget(Widget)}. |
| * |
| * @deprecated Use {@link #initWidget(Widget)} instead |
| */ |
| @Deprecated |
| protected void setWidget(Widget widget) { |
| initWidget(widget); |
| } |
| } |