001: /*
002: * Copyright 2007 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License. You may obtain a copy of
006: * the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013: * License for the specific language governing permissions and limitations under
014: * the License.
015: */
016: package com.google.gwt.user.client.ui;
017:
018: import com.google.gwt.user.client.DOM;
019: import com.google.gwt.user.client.Element;
020: import com.google.gwt.user.client.Window;
021: import com.google.gwt.user.client.WindowCloseListener;
022:
023: import java.util.HashMap;
024:
025: /**
026: * The panel to which all other widgets must ultimately be added. RootPanels are
027: * never created directly. Rather, they are accessed via {@link RootPanel#get()}.
028: *
029: * <p>
030: * Most applications will add widgets to the default root panel in their
031: * {@link com.google.gwt.core.client.EntryPoint#onModuleLoad} methods.
032: * </p>
033: */
034: public class RootPanel extends AbsolutePanel {
035:
036: private static HashMap<String, RootPanel> rootPanels = new HashMap<String, RootPanel>();
037:
038: /**
039: * Gets the default root panel. This panel wraps body of the browser's
040: * document. This root panel can contain any number of widgets, which will be
041: * laid out in their natural HTML ordering. Many applications, however, will
042: * add a single panel to the RootPanel to provide more structure.
043: *
044: * @return the default RootPanel
045: */
046: public static RootPanel get() {
047: return get(null);
048: }
049:
050: /**
051: * Gets the root panel associated with a given browser element. For this to
052: * work, the HTML document into which the application is loaded must have
053: * specified an element with the given id.
054: *
055: * @param id the id of the element to be wrapped with a root panel
056: * @return the root panel, or <code>null</code> if no such element was found
057: */
058: public static RootPanel get(String id) {
059: // See if this RootPanel is already created.
060: RootPanel gwt = rootPanels.get(id);
061: if (gwt != null) {
062: return gwt;
063: }
064: // Find the element that this RootPanel will wrap.
065: Element elem = null;
066: if (id != null) {
067: if (null == (elem = DOM.getElementById(id))) {
068: return null;
069: }
070: }
071:
072: if (rootPanels.size() == 0) {
073: hookWindowClosing();
074: }
075:
076: // Create the panel and put it in the map.
077: rootPanels.put(id, gwt = new RootPanel(elem));
078: return gwt;
079: }
080:
081: /**
082: * Convenience method for getting the document's body element.
083: *
084: * @return the document's body element
085: */
086: public static native Element getBodyElement() /*-{
087: return $doc.body;
088: }-*/;
089:
090: private static void hookWindowClosing() {
091: // Catch the window closing event.
092: Window.addWindowCloseListener(new WindowCloseListener() {
093: public void onWindowClosed() {
094: // When the window is closing, detach all root panels. This will cause
095: // all of their children's event listeners to be unhooked, which will
096: // avoid potential memory leaks.
097: for (RootPanel gwt : rootPanels.values()) {
098: if (gwt.isAttached()) {
099: gwt.onDetach();
100: }
101: }
102: }
103:
104: public String onWindowClosing() {
105: return null;
106: }
107: });
108: }
109:
110: private RootPanel(Element elem) {
111: if (elem == null) {
112: // 'null' means use document's body element.
113: elem = getBodyElement();
114: }
115:
116: setElement(elem);
117: onAttach();
118: }
119: }
|