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 gnu.java.lang.CPStringBuilder;
042    
043    import java.awt.AWTEvent;
044    import java.awt.BorderLayout;
045    import java.awt.Component;
046    import java.awt.Container;
047    import java.awt.Dimension;
048    import java.awt.Frame;
049    import java.awt.Graphics;
050    import java.awt.GraphicsConfiguration;
051    import java.awt.LayoutManager;
052    import java.awt.event.KeyEvent;
053    import java.awt.event.WindowEvent;
054    
055    import javax.accessibility.Accessible;
056    import 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     */
070    public 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    }