KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > google > gwt > user > client > ui > PopupPanel


1 /*
2  * Copyright 2007 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */

16 package com.google.gwt.user.client.ui;
17
18 import com.google.gwt.core.client.GWT;
19 import com.google.gwt.user.client.DOM;
20 import com.google.gwt.user.client.Element;
21 import com.google.gwt.user.client.Event;
22 import com.google.gwt.user.client.EventPreview;
23 import com.google.gwt.user.client.Window;
24 import com.google.gwt.user.client.ui.impl.PopupImpl;
25
26 /**
27  * A panel that can "pop up" over other widgets. It overlays the browser's
28  * client area (and any previously-created popups). <p/> The width and height of
29  * the PopupPanel cannot be explicitly set; they are determined by the
30  * PopupPanel's widget. Calls to {@link #setWidth(String)} and
31  * {@link #setHeight(String)} will call these methods on the PopupPanel's
32  * widget.
33  * <p>
34  * <img class='gallery' SRC='PopupPanel.png'/>
35  * </p>
36  *
37  * <p>
38  * <h3>Example</h3>
39  * {@example com.google.gwt.examples.PopupPanelExample}
40  * </p>
41  */

42 public class PopupPanel extends SimplePanel implements SourcesPopupEvents,
43     EventPreview {
44
45   private static final PopupImpl impl = (PopupImpl) GWT.create(PopupImpl.class);
46
47   private boolean autoHide, modal, showing;
48
49   // Used to track requested size across changing child widgets
50
private String JavaDoc desiredHeight;
51   private String JavaDoc desiredWidth;
52
53   private PopupListenerCollection popupListeners;
54
55   /**
56    * Creates an empty popup panel. A child widget must be added to it before it
57    * is shown.
58    */

59   public PopupPanel() {
60     super(impl.createElement());
61   }
62
63   /**
64    * Creates an empty popup panel, specifying its "auto-hide" property.
65    *
66    * @param autoHide <code>true</code> if the popup should be automatically
67    * hidden when the user clicks outside of it
68    */

69   public PopupPanel(boolean autoHide) {
70     this();
71     this.autoHide = autoHide;
72   }
73
74   /**
75    * Creates an empty popup panel, specifying its "auto-hide" property.
76    *
77    * @param autoHide <code>true</code> if the popup should be automatically
78    * hidden when the user clicks outside of it
79    * @param modal <code>true</code> if keyboard or mouse events that do not
80    * target the PopupPanel or its children should be ignored
81    */

82   public PopupPanel(boolean autoHide, boolean modal) {
83     this(autoHide);
84     this.modal = modal;
85   }
86
87   public void addPopupListener(PopupListener listener) {
88     if (popupListeners == null) {
89       popupListeners = new PopupListenerCollection();
90     }
91     popupListeners.add(listener);
92   }
93
94   /**
95    * Centers the popup in the browser window.
96    *
97    * <p>
98    * Note that the popup must be shown before this method is called.
99    * </p>
100    */

101   public void center() {
102     // Centering will not work properly until the panel is shown, because it
103
// cannot be measured until it is attached to the DOM.
104
if (!showing) {
105       throw new IllegalStateException JavaDoc("PopupPanel must be shown before it may "
106           + "be centered.");
107     }
108
109     int left = (Window.getClientWidth() - getOffsetWidth()) / 2;
110     int top = (Window.getClientHeight() - getOffsetHeight()) / 2;
111     setPopupPosition(Window.getScrollLeft() + left, Window.getScrollTop() + top);
112   }
113
114   /**
115    * Gets the popup's left position relative to the browser's client area.
116    *
117    * @return the popup's left position
118    */

119   public int getPopupLeft() {
120     return DOM.getElementPropertyInt(getElement(), "offsetLeft");
121   }
122
123   /**
124    * Gets the popup's top position relative to the browser's client area.
125    *
126    * @return the popup's top position
127    */

128   public int getPopupTop() {
129     return DOM.getElementPropertyInt(getElement(), "offsetTop");
130   }
131
132   public String JavaDoc getTitle() {
133     return DOM.getElementProperty(getContainerElement(), "title");
134   }
135
136   /**
137    * Hides the popup. This has no effect if it is not currently visible.
138    */

139   public void hide() {
140     hide(false);
141   }
142
143   public boolean onEventPreview(Event event) {
144
145     Element target = DOM.eventGetTarget(event);
146     boolean eventTargetsPopup = DOM.isOrHasChild(getElement(), target);
147
148     int type = DOM.eventGetType(event);
149     switch (type) {
150       case Event.ONKEYDOWN: {
151         if (eventTargetsPopup) {
152           return onKeyDownPreview((char) DOM.eventGetKeyCode(event),
153               KeyboardListenerCollection.getKeyboardModifiers(event));
154         } else {
155           return !modal;
156         }
157       }
158       case Event.ONKEYUP: {
159         if (eventTargetsPopup) {
160           return onKeyUpPreview((char) DOM.eventGetKeyCode(event),
161               KeyboardListenerCollection.getKeyboardModifiers(event));
162         } else {
163           return !modal;
164         }
165       }
166       case Event.ONKEYPRESS: {
167         if (eventTargetsPopup) {
168           return onKeyPressPreview((char) DOM.eventGetKeyCode(event),
169               KeyboardListenerCollection.getKeyboardModifiers(event));
170         } else {
171           return !modal;
172         }
173       }
174
175       case Event.ONMOUSEDOWN:
176       case Event.ONMOUSEUP:
177       case Event.ONMOUSEMOVE:
178       case Event.ONCLICK:
179       case Event.ONDBLCLICK: {
180         // Don't eat events if event capture is enabled, as this can interfere
181
// with dialog dragging, for example.
182
if (DOM.getCaptureElement() != null) {
183           return true;
184         }
185
186         // If it's an outside click and auto-hide is enabled:
187
// hide the popup and _don't_ eat the event. ONMOUSEDOWN is used to
188
// prevent problems with showing a popup in response to a mousedown.
189
if (!eventTargetsPopup && autoHide && (type == Event.ONMOUSEDOWN)) {
190           hide(true);
191           return true;
192         }
193
194         break;
195       }
196
197       case Event.ONFOCUS: {
198         if (modal && !eventTargetsPopup && (target != null)) {
199           blur(target);
200           return false;
201         }
202       }
203     }
204
205     return !modal || eventTargetsPopup;
206   }
207
208   /**
209    * Popups get an opportunity to preview keyboard events before they are passed
210    * to a widget contained by the Popup.
211    *
212    * @param key the key code of the depressed key
213    * @param modifiers keyboard modifiers, as specified in
214    * {@link KeyboardListener}.
215    * @return <code>false</code> to suppress the event
216    */

217   public boolean onKeyDownPreview(char key, int modifiers) {
218     return true;
219   }
220
221   /**
222    * Popups get an opportunity to preview keyboard events before they are passed
223    * to a widget contained by the Popup.
224    *
225    * @param key the unicode character pressed
226    * @param modifiers keyboard modifiers, as specified in
227    * {@link KeyboardListener}.
228    * @return <code>false</code> to suppress the event
229    */

230   public boolean onKeyPressPreview(char key, int modifiers) {
231     return true;
232   }
233
234   /**
235    * Popups get an opportunity to preview keyboard events before they are passed
236    * to a widget contained by the Popup.
237    *
238    * @param key the key code of the released key
239    * @param modifiers keyboard modifiers, as specified in
240    * {@link KeyboardListener}.
241    * @return <code>false</code> to suppress the event
242    */

243   public boolean onKeyUpPreview(char key, int modifiers) {
244     return true;
245   }
246
247   public void removePopupListener(PopupListener listener) {
248     if (popupListeners != null) {
249       popupListeners.remove(listener);
250     }
251   }
252
253   public void setHeight(String JavaDoc height) {
254     desiredHeight = height;
255     maybeUpdateSize();
256     // If the user cleared the size, revert to not trying to control children.
257
if (height.length() == 0) {
258       desiredHeight = null;
259     }
260   }
261
262   /**
263    * Sets the popup's position relative to the browser's client area. The
264    * popup's position may be set before calling {@link #show()}.
265    *
266    * @param left the left position, in pixels
267    * @param top the top position, in pixels
268    */

269   public void setPopupPosition(int left, int top) {
270     // Keep the popup within the browser's client area, so that they can't get
271
// 'lost' and become impossible to interact with. Note that we don't attempt
272
// to keep popups pegged to the bottom and right edges, as they will then
273
// cause scrollbars to appear, so the user can't lose them.
274
if (left < 0) {
275       left = 0;
276     }
277     if (top < 0) {
278       top = 0;
279     }
280
281     // Set the popup's position manually, allowing setPopupPosition() to be
282
// called before show() is called (so a popup can be positioned without it
283
// 'jumping' on the screen).
284
Element elem = getElement();
285     DOM.setStyleAttribute(elem, "left", left + "px");
286     DOM.setStyleAttribute(elem, "top", top + "px");
287   }
288
289   public void setTitle(String JavaDoc title) {
290     Element containerElement = getContainerElement();
291     if (title == null || title.length() == 0) {
292       DOM.removeElementAttribute(containerElement, "title");
293     } else {
294       DOM.setElementAttribute(containerElement, "title", title);
295     }
296   }
297
298   /**
299    * Sets whether this object is visible.
300    *
301    * @param visible <code>true</code> to show the object, <code>false</code>
302    * to hide it
303    */

304   public void setVisible(boolean visible) {
305     // We use visibility here instead of UIObject's default of display
306
// Because the panel is absolutely positioned, this will not create
307
// "holes" in displayed contents and it allows normal layout passes
308
// to occur so the size of the PopupPanel can be reliably determined.
309
DOM.setStyleAttribute(getElement(), "visibility", visible ? "visible"
310         : "hidden");
311
312     // If the PopupImpl creates an iframe shim, it's also necessary to hide it
313
// as well.
314
impl.setVisible(getElement(), visible);
315   }
316
317   public void setWidget(Widget w) {
318     super.setWidget(w);
319     maybeUpdateSize();
320   }
321
322   public void setWidth(String JavaDoc width) {
323     desiredWidth = width;
324     maybeUpdateSize();
325     // If the user cleared the size, revert to not trying to control children.
326
if (width.length() == 0) {
327       desiredWidth = null;
328     }
329   }
330
331   /**
332    * Shows the popup. It must have a child widget before this method is called.
333    */

334   public void show() {
335     if (showing) {
336       return;
337     }
338     showing = true;
339     DOM.addEventPreview(this);
340
341     RootPanel.get().add(this);
342     DOM.setStyleAttribute(getElement(), "position", "absolute");
343     impl.onShow(getElement());
344   }
345
346   protected Element getContainerElement() {
347     return impl.getContainerElement(getElement());
348   }
349
350   protected Element getStyleElement() {
351     return impl.getContainerElement(getElement());
352   }
353
354   /**
355    * This method is called when a widget is detached from the browser's
356    * document. To receive notification before the PopupPanel is removed from the
357    * document, override the {@link Widget#onUnload()} method instead.
358    */

359   protected void onDetach() {
360     DOM.removeEventPreview(this);
361     super.onDetach();
362   }
363
364   /**
365    * Remove focus from an Element.
366    *
367    * @param elt The Element on which <code>blur()</code> will be invoked
368    */

369   private native void blur(Element elt) /*-{
370     if (elt.blur) {
371       elt.blur();
372     }
373   }-*/
;
374
375   private void hide(boolean autoClosed) {
376     if (!showing) {
377       return;
378     }
379     showing = false;
380
381     RootPanel.get().remove(this);
382     impl.onHide(getElement());
383     if (popupListeners != null) {
384       popupListeners.firePopupClosed(this, autoClosed);
385     }
386   }
387
388   /**
389    * We control size by setting our child widget's size. However, if we don't
390    * currently have a child, we record the size the user wanted so that when we
391    * do get a child, we can set it correctly. Until size is explicitly cleared,
392    * any child put into the popup will be given that size.
393    */

394   private void maybeUpdateSize() {
395     Widget w = getWidget();
396     if (w != null) {
397       if (desiredHeight != null) {
398         w.setHeight(desiredHeight);
399       }
400       if (desiredWidth != null) {
401         w.setWidth(desiredWidth);
402       }
403     }
404   }
405 }
406
Popular Tags