001/* JFrame.java --
002   Copyright (C) 2002, 2004, 2005, 2006,  Free Software Foundation, Inc.
003
004This file is part of GNU Classpath.
005
006GNU Classpath is free software; you can redistribute it and/or modify
007it under the terms of the GNU General Public License as published by
008the Free Software Foundation; either version 2, or (at your option)
009any later version.
010
011GNU Classpath is distributed in the hope that it will be useful, but
012WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014General Public License for more details.
015
016You should have received a copy of the GNU General Public License
017along with GNU Classpath; see the file COPYING.  If not, write to the
018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
01902110-1301 USA.
020
021Linking this library statically or dynamically with other modules is
022making a combined work based on this library.  Thus, the terms and
023conditions of the GNU General Public License cover the whole
024combination.
025
026As a special exception, the copyright holders of this library give you
027permission to link this library with independent modules to produce an
028executable, regardless of the license terms of these independent
029modules, and to copy and distribute the resulting executable under
030terms of your choice, provided that you also meet, for each linked
031independent module, the terms and conditions of the license of that
032module.  An independent module is a module which is not derived from
033or based on this library.  If you modify this library, you may extend
034this exception to your version of the library, but you are not
035obligated to do so.  If you do not wish to do so, delete this
036exception statement from your version. */
037
038
039package javax.swing;
040
041import gnu.java.lang.CPStringBuilder;
042
043import java.awt.AWTEvent;
044import java.awt.BorderLayout;
045import java.awt.Component;
046import java.awt.Container;
047import java.awt.Dimension;
048import java.awt.Frame;
049import java.awt.Graphics;
050import java.awt.GraphicsConfiguration;
051import java.awt.LayoutManager;
052import java.awt.event.KeyEvent;
053import java.awt.event.WindowEvent;
054
055import javax.accessibility.Accessible;
056import javax.accessibility.AccessibleContext;
057
058/**
059 * A window that supports window decorations (titlebar and borders).
060 * This is an extension of {@link java.awt.Frame} that provides support
061 * for the Swing architecture. Most importantly it contains a {@link JRootPane}
062 * as it's only top-level child, that manages the content pane, the menu and
063 * a glass pane.
064 *
065 * Also, unlike <code>java.awt.Frame</code>s, JFrames support the
066 * Swing Pluggable Look &amp; Feel architecture.
067 * 
068 * @author Ronald Veldema (rveldema@cs.vu.nl)
069 */
070public class JFrame extends Frame
071  implements WindowConstants, RootPaneContainer, Accessible
072{
073  /**
074   * Provides accessibility support for <code>JFrame</code>s.
075   */
076  protected class AccessibleJFrame extends Frame.AccessibleAWTFrame
077  {
078    /**
079     * Creates a new instance of <code>AccessibleJFrame</code>.
080     */
081    protected AccessibleJFrame()
082    {
083      super();
084      // Nothing to do here.
085    }
086  }
087
088  /**
089   * A flag for {@link #setDefaultCloseOperation(int)}, indicating that the
090   * application should be exited, when this <code>JFrame</code> is closed.
091   * Note that in version 1.4, the equivalent constant has been added to
092   * {@link WindowConstants}.
093   *
094   * @since 1.3
095   */
096  public static final int EXIT_ON_CLOSE = 3;
097
098  private static final long serialVersionUID = -3362141868504252139L;
099  private static boolean defaultLookAndFeelDecorated;
100  private int closeAction = HIDE_ON_CLOSE;
101  protected AccessibleContext accessibleContext;
102  protected JRootPane rootPane;
103  
104  /**
105   * @specnote rootPaneCheckingEnabled is false to comply with J2SE 5.0
106   */
107  protected boolean rootPaneCheckingEnabled = false;
108
109  /**
110   * Creates a new frame with an empty string for the title.
111   */
112  public JFrame()
113  {
114    super("");
115    frameInit();
116  }
117
118  /**
119   * Creates a new <code>JFrame</code> with the specified title.
120   * 
121   * @param title  the frame title (<code>null</code> permitted).
122   */
123  public JFrame(String title)
124  {
125    super(title);
126    frameInit();
127  }
128
129  /**
130   * Creates a new JFrame in the specified {@link GraphicsConfiguration}
131   * and with an empty title.
132   *
133   * @param gc the <code>GraphicsConfiguration</code> that is used for
134   *     the new <code>JFrame</code>
135   *
136   * @see Frame#Frame(GraphicsConfiguration)
137   */
138  public JFrame(GraphicsConfiguration gc)
139  {
140    super(gc);
141    frameInit();
142  }
143
144  /**
145   * Creates a new JFrame in the specified {@link GraphicsConfiguration}
146   * and with the specified title.
147   *
148   * @param title the title for the new <code>JFrame</code>
149   * @param gc the <code>GraphicsConfiguration</code> that is used for
150   *     the new <code>JFrame</code>
151   *
152   * @see Frame#Frame(String, GraphicsConfiguration)
153   */
154  public JFrame(String title, GraphicsConfiguration gc)
155  {
156    super(title, gc);
157    frameInit();
158  }
159
160  protected void frameInit()
161  {
162    // We need to explicitly enable events here so that our processKeyEvent()
163    // and processWindowEvent() gets called.
164    enableEvents(AWTEvent.WINDOW_EVENT_MASK | AWTEvent.KEY_EVENT_MASK);
165
166    super.setLayout(new BorderLayout());
167    setBackground(UIManager.getDefaults().getColor("control"));
168    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
169    getRootPane(); // will do set/create
170
171    // Setup the defaultLookAndFeelDecoration if requested.
172    if (isDefaultLookAndFeelDecorated()
173        && UIManager.getLookAndFeel().getSupportsWindowDecorations())
174      {
175        setUndecorated(true);
176        getRootPane().setWindowDecorationStyle(JRootPane.FRAME);
177      }
178
179    // We're now done the init stage.
180    setRootPaneCheckingEnabled(true);
181  }
182
183  public Dimension getPreferredSize()
184  {
185    return super.getPreferredSize();
186  }
187
188  public JMenuBar getJMenuBar()
189  {
190    return getRootPane().getJMenuBar();
191  }
192
193  public void setJMenuBar(JMenuBar menubar)
194  {
195    getRootPane().setJMenuBar(menubar);
196  }
197
198  public void setLayout(LayoutManager manager)
199  {
200    // Check if we're in initialization stage.  If so, call super.setLayout
201    // otherwise, valid calls go to the content pane.
202    if (isRootPaneCheckingEnabled())
203      getContentPane().setLayout(manager);
204    else
205      super.setLayout(manager);
206  }
207
208  public void setLayeredPane(JLayeredPane layeredPane)
209  {
210    getRootPane().setLayeredPane(layeredPane);
211  }
212
213  public JLayeredPane getLayeredPane()
214  {
215    return getRootPane().getLayeredPane();
216  }
217
218  public JRootPane getRootPane()
219  {
220    if (rootPane == null)
221      setRootPane(createRootPane());
222    return rootPane;
223  }
224
225  protected void setRootPane(JRootPane root)
226  {
227    if (rootPane != null)
228      remove(rootPane);
229
230    rootPane = root;
231    add(rootPane, BorderLayout.CENTER);
232  }
233
234  protected JRootPane createRootPane()
235  {
236    return new JRootPane();
237  }
238
239  public Container getContentPane()
240  {
241    return getRootPane().getContentPane();
242  }
243
244  public void setContentPane(Container contentPane)
245  {
246    getRootPane().setContentPane(contentPane);
247  }
248
249  public Component getGlassPane()
250  {
251    return getRootPane().getGlassPane();
252  }
253
254  public void setGlassPane(Component glassPane)
255  {
256    getRootPane().setGlassPane(glassPane);
257  }
258
259  protected void addImpl(Component comp, Object constraints, int index)
260  {
261    // If we're adding in the initialization stage use super.add.
262    // Otherwise pass the add onto the content pane.
263    if (isRootPaneCheckingEnabled() && comp != rootPane)
264      getContentPane().add(comp,constraints,index);
265    else
266      super.addImpl(comp, constraints, index);
267  }
268
269  public void remove(Component comp)
270  {
271    // If we're removing the root pane, use super.remove. Otherwise
272    // pass it on to the content pane instead.
273    if (comp==rootPane)
274      super.remove(rootPane);
275    else
276      getContentPane().remove(comp);
277  }
278
279  protected boolean isRootPaneCheckingEnabled()
280  {
281    return rootPaneCheckingEnabled;
282  }
283
284  protected void setRootPaneCheckingEnabled(boolean enabled)
285  {
286    rootPaneCheckingEnabled = enabled;
287  }
288
289  public void update(Graphics g)
290  {
291    paint(g);
292  }
293
294  protected void processKeyEvent(KeyEvent e)
295  {
296    super.processKeyEvent(e);
297  }
298
299  public static void setDefaultLookAndFeelDecorated(boolean decorated)
300  {
301    defaultLookAndFeelDecorated = decorated;
302  }
303
304  public static boolean isDefaultLookAndFeelDecorated()
305  {
306    return defaultLookAndFeelDecorated;
307  }
308
309  /**
310   * Returns the object that provides accessibility features for this 
311   * <code>JFrame</code>.
312   *
313   * @return The accessible context (an instance of {@link AccessibleJFrame}).
314   */
315  public AccessibleContext getAccessibleContext()
316  {
317    if (accessibleContext == null)
318      accessibleContext = new AccessibleJFrame();
319    return accessibleContext;
320  }
321
322  /**
323   * Returns a code for the default operation when the frame is closed.  The
324   * default value is {@link WindowConstants#HIDE_ON_CLOSE}.
325   * 
326   * @return One of: {@link WindowConstants#DO_NOTHING_ON_CLOSE},
327   *     {@link WindowConstants#HIDE_ON_CLOSE}, 
328   *     {@link WindowConstants#DISPOSE_ON_CLOSE}, {@link #EXIT_ON_CLOSE}.
329   * 
330   * @see #setDefaultCloseOperation(int)
331   */
332  public int getDefaultCloseOperation()
333  {
334    return closeAction;
335  }
336
337  /**
338   * Returns a string describing the attributes for the <code>JFrame</code>,
339   * for use in debugging.  The return value is guaranteed to be 
340   * non-<code>null</code>, but the format may vary between implementations.
341   * 
342   * @return A string describing the attributes of the <code>JFrame</code>.
343   */
344  protected String paramString()
345  {
346    CPStringBuilder sb = new CPStringBuilder(super.paramString());
347    sb.append(",defaultCloseOperation=");
348    sb.append(SwingUtilities.convertWindowConstantToString(
349        getDefaultCloseOperation()));
350    sb.append(",rootPane=");
351    if (rootPane != null)
352      sb.append(rootPane);
353    sb.append(",rootPaneCheckingEnabled=").append(rootPaneCheckingEnabled);
354    return sb.toString();
355  }
356
357  protected void processWindowEvent(WindowEvent e)
358  {
359    super.processWindowEvent(e);
360    if (e.getID() == WindowEvent.WINDOW_CLOSING)
361      {
362        switch (closeAction)
363          {
364          case EXIT_ON_CLOSE:
365            System.exit(0);
366            break;
367          case DISPOSE_ON_CLOSE:
368            dispose();
369            break;
370          case HIDE_ON_CLOSE:
371            setVisible(false);
372            break;
373          case DO_NOTHING_ON_CLOSE:
374            break;
375          }
376      }
377  }
378
379  /**
380   * Sets the default operation that is performed when this frame is closed.
381   * The default is <code>HIDE_ON_CLOSE</code>.  When 
382   * <code>EXIT_ON_CLOSE</code> is specified this method calls
383   * <code>SecurityManager.checkExit(0)</code> which might throw a
384   * <code>SecurityException</code>.
385   * 
386   * @param operation  a code for the operation (one of: 
387   *     {@link WindowConstants#DO_NOTHING_ON_CLOSE}, 
388   *     {@link WindowConstants#HIDE_ON_CLOSE}, 
389   *     {@link WindowConstants#DISPOSE_ON_CLOSE} and 
390   *     {@link WindowConstants#EXIT_ON_CLOSE}).
391   * 
392   * @throws IllegalArgumentException if <code>operation</code> is not one of
393   *     the specified codes.
394   * 
395   * @see #getDefaultCloseOperation()
396   */
397  public void setDefaultCloseOperation(int operation)
398  {
399    SecurityManager sm = System.getSecurityManager();
400    if (sm != null && operation == EXIT_ON_CLOSE)
401      sm.checkExit(0);
402
403    if (operation != EXIT_ON_CLOSE && operation != DISPOSE_ON_CLOSE
404        && operation != HIDE_ON_CLOSE && operation != DO_NOTHING_ON_CLOSE)
405      throw new IllegalArgumentException("operation must be EXIT_ON_CLOSE, " 
406          + "HIDE_ON_CLOSE, DISPOSE_ON_CLOSE, or DO_NOTHING_ON_CLOSE");
407
408    closeAction = operation;
409  }
410}