blob: 02ab116107b12afc1ba3cbafd75e4d5d7c9e27b6 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package javax.swing;
27
28import java.awt.*;
29import sun.awt.ModalExclude;
30
31/**
32 * Popups are used to display a <code>Component</code> to the user, typically
33 * on top of all the other <code>Component</code>s in a particular containment
34 * hierarchy. <code>Popup</code>s have a very small life cycle. Once you
35 * have obtained a <code>Popup</code>, and hidden it (invoked the
36 * <code>hide</code> method), you should no longer
37 * invoke any methods on it. This allows the <code>PopupFactory</code> to cache
38 * <code>Popup</code>s for later use.
39 * <p>
40 * The general contract is that if you need to change the size of the
41 * <code>Component</code>, or location of the <code>Popup</code>, you should
42 * obtain a new <code>Popup</code>.
43 * <p>
44 * <code>Popup</code> does not descend from <code>Component</code>, rather
45 * implementations of <code>Popup</code> are responsible for creating
46 * and maintaining their own <code>Component</code>s to render the
47 * requested <code>Component</code> to the user.
48 * <p>
49 * You typically do not explicitly create an instance of <code>Popup</code>,
50 * instead obtain one from a <code>PopupFactory</code>.
51 *
52 * @see PopupFactory
53 *
54 * @since 1.4
55 */
56public class Popup {
57 /**
58 * The Component representing the Popup.
59 */
60 private Component component;
61
62 /**
63 * Creates a <code>Popup</code> for the Component <code>owner</code>
64 * containing the Component <code>contents</code>. <code>owner</code>
65 * is used to determine which <code>Window</code> the new
66 * <code>Popup</code> will parent the <code>Component</code> the
67 * <code>Popup</code> creates to.
68 * A null <code>owner</code> implies there is no valid parent.
69 * <code>x</code> and
70 * <code>y</code> specify the preferred initial location to place
71 * the <code>Popup</code> at. Based on screen size, or other paramaters,
72 * the <code>Popup</code> may not display at <code>x</code> and
73 * <code>y</code>.
74 *
75 * @param owner Component mouse coordinates are relative to, may be null
76 * @param contents Contents of the Popup
77 * @param x Initial x screen coordinate
78 * @param y Initial y screen coordinate
79 * @exception IllegalArgumentException if contents is null
80 */
81 protected Popup(Component owner, Component contents, int x, int y) {
82 this();
83 if (contents == null) {
84 throw new IllegalArgumentException("Contents must be non-null");
85 }
86 reset(owner, contents, x, y);
87 }
88
89 /**
90 * Creates a <code>Popup</code>. This is provided for subclasses.
91 */
92 protected Popup() {
93 }
94
95 /**
96 * Makes the <code>Popup</code> visible. If the <code>Popup</code> is
97 * currently visible, this has no effect.
98 */
99 public void show() {
100 Component component = getComponent();
101
102 if (component != null) {
103 component.show();
104 }
105 }
106
107 /**
108 * Hides and disposes of the <code>Popup</code>. Once a <code>Popup</code>
109 * has been disposed you should no longer invoke methods on it. A
110 * <code>dispose</code>d <code>Popup</code> may be reclaimed and later used
111 * based on the <code>PopupFactory</code>. As such, if you invoke methods
112 * on a <code>disposed</code> <code>Popup</code>, indeterminate
113 * behavior will result.
114 */
115 public void hide() {
116 Component component = getComponent();
117
118 if (component instanceof JWindow) {
119 component.hide();
120 ((JWindow)component).getContentPane().removeAll();
121 }
122 dispose();
123 }
124
125 /**
126 * Frees any resources the <code>Popup</code> may be holding onto.
127 */
128 void dispose() {
129 Component component = getComponent();
130 Window window = SwingUtilities.getWindowAncestor(component);
131
132 if (component instanceof JWindow) {
133 ((Window)component).dispose();
134 component = null;
135 }
136 // If our parent is a DefaultFrame, we need to dispose it, too.
137 if (window instanceof DefaultFrame) {
138 window.dispose();
139 }
140 }
141
142 /**
143 * Resets the <code>Popup</code> to an initial state.
144 */
145 void reset(Component owner, Component contents, int ownerX, int ownerY) {
146 if (getComponent() == null) {
147 component = createComponent(owner);
148 }
149
150 Component c = getComponent();
151
152 if (c instanceof JWindow) {
153 JWindow component = (JWindow)getComponent();
154
155 component.setLocation(ownerX, ownerY);
156 component.getContentPane().add(contents, BorderLayout.CENTER);
157 contents.invalidate();
158 if(component.isVisible()) {
159 // Do not call pack() if window is not visible to
160 // avoid early native peer creation
161 pack();
162 }
163 }
164 }
165
166
167 /**
168 * Causes the <code>Popup</code> to be sized to fit the preferred size
169 * of the <code>Component</code> it contains.
170 */
171 void pack() {
172 Component component = getComponent();
173
174 if (component instanceof Window) {
175 ((Window)component).pack();
176 }
177 }
178
179 /**
180 * Returns the <code>Window</code> to use as the parent of the
181 * <code>Window</code> created for the <code>Popup</code>. This creates
182 * a new <code>DefaultFrame</code>, if necessary.
183 */
184 private Window getParentWindow(Component owner) {
185 Window window = null;
186
187 if (owner instanceof Window) {
188 window = (Window)owner;
189 }
190 else if (owner != null) {
191 window = SwingUtilities.getWindowAncestor(owner);
192 }
193 if (window == null) {
194 window = new DefaultFrame();
195 }
196 return window;
197 }
198
199 /**
200 * Creates the Component to use as the parent of the <code>Popup</code>.
201 * The default implementation creates a <code>Window</code>, subclasses
202 * should override.
203 */
204 Component createComponent(Component owner) {
205 if (GraphicsEnvironment.isHeadless()) {
206 // Generally not useful, bail.
207 return null;
208 }
209 return new HeavyWeightWindow(getParentWindow(owner));
210 }
211
212 /**
213 * Returns the <code>Component</code> returned from
214 * <code>createComponent</code> that will hold the <code>Popup</code>.
215 */
216 Component getComponent() {
217 return component;
218 }
219
220
221 /**
222 * Component used to house window.
223 */
224 static class HeavyWeightWindow extends JWindow implements ModalExclude {
225 HeavyWeightWindow(Window parent) {
226 super(parent);
227 setFocusableWindowState(false);
228 setName("###overrideRedirect###");
229 // Popups are typically transient and most likely won't benefit
230 // from true double buffering. Turn it off here.
231 getRootPane().setUseTrueDoubleBuffering(false);
232 setAlwaysOnTop(true);
233 }
234
235 public void update(Graphics g) {
236 paint(g);
237 }
238
239 public void show() {
240 this.pack();
241 if (getWidth() > 0 && getHeight() > 0) {
242 super.show();
243 }
244 }
245 }
246
247
248 /**
249 * Used if no valid Window ancestor of the supplied owner is found.
250 * <p>
251 * PopupFactory uses this as a way to know when the Popup shouldn't
252 * be cached based on the Window.
253 */
254 static class DefaultFrame extends Frame {
255 }
256}