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