1 /* JRootPane.java --
2    Copyright (C) 2002, 2004  Free Software Foundation, Inc.
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37 
38 
39 package javax.swing;
40 
41 import java.awt.BorderLayout;
42 import java.awt.Component;
43 import java.awt.Container;
44 import java.awt.Dimension;
45 import java.awt.IllegalComponentStateException;
46 import java.awt.Insets;
47 import java.awt.LayoutManager;
48 import java.awt.LayoutManager2;
49 import java.awt.Rectangle;
50 import java.io.Serializable;
51 
52 import javax.accessibility.Accessible;
53 import javax.accessibility.AccessibleContext;
54 import javax.accessibility.AccessibleRole;
55 import javax.swing.plaf.RootPaneUI;
56 
57 /**
58  * This class is where JComponents are added to. Unlike awt where you could
59  * just say frame.add(), with swing you need to say frame.getRootPane()
60  * (which delivers an instance of this class) and add your components to
61  * that. It is implemented by several 'layers' (pane() should be read as
62  * plane()) each on top of the others where you can add components to.
63  * (getContentPane(), getGlassPane(), getLayeredPane())
64  *
65  * @author Ronald Veldema (rveldema@cs.vu.nl)
66  */
67 public class JRootPane extends JComponent implements Accessible
68 {
69   //  The class used to obtain the accessible role for this object.
70   protected class AccessibleJRootPane extends AccessibleJComponent
71   {
72     /**
73      * For compatability with Sun's JDK
74      */
75     private static final long serialVersionUID = 1082432482784468088L;
76 
77     /**
78      * Creates a new <code>AccessibleJRootPane</code> object.
79      */
AccessibleJRootPane()80     protected AccessibleJRootPane()
81     {
82       // Nothing to do here.
83     }
84 
85     /**
86      * DOCUMENT ME!
87      *
88      * @return DOCUMENT ME!
89      */
getAccessibleRole()90     public AccessibleRole getAccessibleRole()
91     {
92       return AccessibleRole.ROOT_PANE;
93     }
94   }
95 
96   // Custom Layout Manager for JRootPane. It positions contentPane and
97   // menuBar withing its layeredPane.
98   protected class RootLayout implements LayoutManager2, Serializable
99   {
100     /** DOCUMENT ME! */
101     private static final long serialVersionUID = -4100116998559815027L;
102 
103     /**
104      * The cached layout info for the glass pane.
105      */
106     private Rectangle glassPaneBounds;
107 
108     /**
109      * The cached layout info for the layered pane.
110      */
111     private Rectangle layeredPaneBounds;
112 
113     /**
114      * The cached layout info for the content pane.
115      */
116     private Rectangle contentPaneBounds;
117 
118     /**
119      * The cached layout info for the menu bar.
120      */
121     private Rectangle menuBarBounds;
122 
123     /**
124      * Creates a new <code>RootLayout</code> object.
125      */
RootLayout()126     protected RootLayout()
127     {
128       // Nothing to do here.
129     }
130 
131     /**
132      * DOCUMENT ME!
133      *
134      * @param comp DOCUMENT ME!
135      * @param constraints DOCUMENT ME!
136      */
addLayoutComponent(Component comp, Object constraints)137     public void addLayoutComponent(Component comp, Object constraints)
138     {
139       // Nothing to do here.
140     }
141 
142     /**
143      * DOCUMENT ME!
144      *
145      * @param name DOCUMENT ME!
146      * @param comp DOCUMENT ME!
147      */
addLayoutComponent(String name, Component comp)148     public void addLayoutComponent(String name, Component comp)
149     {
150       // Nothing to do here.
151     }
152 
153     /**
154      * DOCUMENT ME!
155      *
156      * @param target DOCUMENT ME!
157      *
158      * @return DOCUMENT ME!
159      */
getLayoutAlignmentX(Container target)160     public float getLayoutAlignmentX(Container target)
161     {
162       return 0.0F;
163     }
164 
165     /**
166      * DOCUMENT ME!
167      *
168      * @param target DOCUMENT ME!
169      *
170      * @return DOCUMENT ME!
171      */
getLayoutAlignmentY(Container target)172     public float getLayoutAlignmentY(Container target)
173     {
174       return 0.0F;
175     }
176 
177     /**
178      * DOCUMENT ME!
179      *
180      * @param target DOCUMENT ME!
181      */
invalidateLayout(Container target)182     public void invalidateLayout(Container target)
183     {
184       synchronized (this)
185         {
186           glassPaneBounds = null;
187           layeredPaneBounds = null;
188           contentPaneBounds = null;
189           menuBarBounds = null;
190         }
191     }
192 
193     /**
194      * DOCUMENT ME!
195      *
196      * @param c DOCUMENT ME!
197      */
layoutContainer(Container c)198     public void layoutContainer(Container c)
199     {
200       if (glassPaneBounds == null || layeredPaneBounds == null
201           || contentPaneBounds == null || menuBarBounds == null)
202         {
203           Insets i = getInsets();
204           int containerWidth = c.getBounds().width - i.left - i.right;
205           int containerHeight = c.getBounds().height - i.top - i.bottom;
206 
207           // 1. the glassPane fills entire viewable region (bounds - insets).
208           // 2. the layeredPane filles entire viewable region.
209           // 3. the menuBar is positioned at the upper edge of layeredPane.
210           // 4. the contentPane fills viewable region minus menuBar, if present.
211 
212 
213           // +-------------------------------+
214           // |  JLayeredPane                 |
215           // |  +--------------------------+ |
216           // |  | menuBar                  | |
217           // |  +--------------------------+ |
218           // |  +--------------------------+ |
219           // |  |contentPane               | |
220           // |  |                          | |
221           // |  |                          | |
222           // |  |                          | |
223           // |  +--------------------------+ |
224           // +-------------------------------+
225 
226           if (menuBar != null)
227             {
228               Dimension menuBarSize = menuBar.getPreferredSize();
229               if (menuBarSize.height > containerHeight)
230                 menuBarSize.height = containerHeight;
231               menuBarBounds = new Rectangle(0, 0, containerWidth,
232                                             menuBarSize.height);
233               contentPaneBounds = new Rectangle(0, menuBarSize.height,
234                                                 containerWidth,
235                                          containerHeight - menuBarSize.height);
236             }
237           else
238             contentPaneBounds = new Rectangle(0, 0, containerWidth,
239                                               containerHeight);
240 
241           glassPaneBounds = new Rectangle(i.left, i.top, containerWidth, containerHeight);
242           layeredPaneBounds = new Rectangle(i.left, i.top, containerWidth, containerHeight);
243         }
244 
245       glassPane.setBounds(glassPaneBounds);
246       layeredPane.setBounds(layeredPaneBounds);
247       if (menuBar != null)
248         menuBar.setBounds(menuBarBounds);
249       getContentPane().setBounds(contentPaneBounds);
250     }
251 
252     /**
253      * DOCUMENT ME!
254      *
255      * @param target DOCUMENT ME!
256      *
257      * @return DOCUMENT ME!
258      */
maximumLayoutSize(Container target)259     public Dimension maximumLayoutSize(Container target)
260     {
261       return preferredLayoutSize(target);
262     }
263 
264     /**
265      * DOCUMENT ME!
266      *
267      * @param target DOCUMENT ME!
268      *
269      * @return DOCUMENT ME!
270      */
minimumLayoutSize(Container target)271     public Dimension minimumLayoutSize(Container target)
272     {
273       return preferredLayoutSize(target);
274     }
275 
276     /**
277      * DOCUMENT ME!
278      *
279      * @param c DOCUMENT ME!
280      *
281      * @return DOCUMENT ME!
282      */
preferredLayoutSize(Container c)283     public Dimension preferredLayoutSize(Container c)
284     {
285       Dimension prefSize = new Dimension();
286       Insets i = getInsets();
287       prefSize = new Dimension(i.left + i.right, i.top + i.bottom);
288       Dimension contentPrefSize = getContentPane().getPreferredSize();
289       prefSize.width += contentPrefSize.width;
290       prefSize.height += contentPrefSize.height;
291       if (menuBar != null)
292         {
293           Dimension menuBarSize = menuBar.getPreferredSize();
294           if (menuBarSize.width > contentPrefSize.width)
295             prefSize.width += menuBarSize.width - contentPrefSize.width;
296           prefSize.height += menuBarSize.height;
297         }
298       return prefSize;
299     }
300 
301     /**
302      * DOCUMENT ME!
303      *
304      * @param comp DOCUMENT ME!
305      */
removeLayoutComponent(Component comp)306     public void removeLayoutComponent(Component comp)
307     {
308       // Nothing to do here.
309     }
310   }
311 
312   /** DOCUMENT ME! */
313   private static final long serialVersionUID = 8690748000348575668L;
314 
315   public static final int NONE = 0;
316   public static final int FRAME = 1;
317   public static final int PLAIN_DIALOG = 2;
318   public static final int INFORMATION_DIALOG = 3;
319   public static final int ERROR_DIALOG = 4;
320   public static final int COLOR_CHOOSER_DIALOG = 5;
321   public static final int FILE_CHOOSER_DIALOG = 6;
322   public static final int QUESTION_DIALOG = 7;
323   public static final int WARNING_DIALOG = 8;
324 
325   /** DOCUMENT ME! */
326   protected Component glassPane;
327 
328   /** DOCUMENT ME! */
329   protected JLayeredPane layeredPane;
330 
331   /** DOCUMENT ME! */
332   protected JMenuBar menuBar;
333 
334   /** DOCUMENT ME! */
335   protected Container contentPane;
336 
337   protected JButton defaultButton;
338 
339   /**
340    * This field is unused since JDK1.3. To override the default action you
341    * should modify the JRootPane's ActionMap.
342    *
343    * @deprecated since JDK1.3
344    *
345    * @specnote the specs indicate that the type of this field is
346    *           a package private inner class
347    *           javax.swing.JRootPane.DefaultAction. I assume that the closest
348    *           public superclass is javax.swing.Action.
349    */
350   protected Action defaultPressAction;
351 
352   /**
353    * This field is unused since JDK1.3. To override the default action you
354    * should modify the JRootPane's ActionMap.
355    *
356    * @deprecated since JDK1.3
357    *
358    * @specnote the specs indicate that the type of this field is
359    *           a package private inner class
360    *           javax.swing.JRootPane.DefaultAction. I assume that the closest
361    *           public superclass is javax.swing.Action.
362    */
363   protected Action defaultReleaseAction;
364 
365   /**
366    * @since 1.4
367    */
368   private int windowDecorationStyle = NONE;
369 
370   /**
371    * DOCUMENT ME!
372    *
373    * @param m DOCUMENT ME!
374    */
setJMenuBar(JMenuBar m)375   public void setJMenuBar(JMenuBar m)
376   {
377     JLayeredPane jlPane = getLayeredPane();
378     if (menuBar != null)
379       jlPane.remove(menuBar);
380     menuBar = m;
381     if (menuBar != null)
382       jlPane.add(menuBar, JLayeredPane.FRAME_CONTENT_LAYER);
383   }
384 
385   /**
386    * @deprecated Replaced by <code>setJMenuBar()</code>
387    */
setMenuBar(JMenuBar m)388   public void setMenuBar(JMenuBar m)
389   {
390     setJMenuBar(m);
391   }
392 
393   /**
394    * DOCUMENT ME!
395    *
396    * @return DOCUMENT ME!
397    */
getJMenuBar()398   public JMenuBar getJMenuBar()
399   {
400     return menuBar;
401   }
402 
403   /**
404    * @deprecated Replaced by <code>getJMenuBar()</code>
405    */
getMenuBar()406   public JMenuBar getMenuBar()
407   {
408     return getJMenuBar();
409   }
410 
411   /**
412    * DOCUMENT ME!
413    *
414    * @return DOCUMENT ME!
415    */
isValidateRoot()416   public boolean isValidateRoot()
417   {
418     return true;
419   }
420 
421   /**
422    * DOCUMENT ME!
423    *
424    * @return DOCUMENT ME!
425    */
getContentPane()426   public Container getContentPane()
427   {
428     if (contentPane == null)
429       setContentPane(createContentPane());
430     return contentPane;
431   }
432 
433   /**
434    * Sets the JRootPane's content pane.  The content pane should typically be
435    * opaque for painting to work properly.  This method also
436    * removes the old content pane from the layered pane.
437    *
438    * @param p the Container that will be the content pane
439    * @throws IllegalComponentStateException if p is null
440    */
setContentPane(Container p)441   public void setContentPane(Container p)
442   {
443     if (p == null)
444       throw new IllegalComponentStateException ("cannot " +
445             "have a null content pane");
446     else
447       {
448         if (contentPane != null && contentPane.getParent() == layeredPane)
449           layeredPane.remove(contentPane);
450         contentPane = p;
451         getLayeredPane().add(contentPane, JLayeredPane.FRAME_CONTENT_LAYER);
452       }
453   }
454 
455   /**
456    * DOCUMENT ME!
457    *
458    * @param comp DOCUMENT ME!
459    * @param constraints DOCUMENT ME!
460    * @param index DOCUMENT ME!
461    */
addImpl(Component comp, Object constraints, int index)462   protected void addImpl(Component comp, Object constraints, int index)
463   {
464     super.addImpl(comp, constraints, index);
465   }
466 
467   /**
468    * DOCUMENT ME!
469    *
470    * @return DOCUMENT ME!
471    */
getGlassPane()472   public Component getGlassPane()
473   {
474     if (glassPane == null)
475       setGlassPane(createGlassPane());
476     return glassPane;
477   }
478 
479   /**
480    * DOCUMENT ME!
481    *
482    * @param f DOCUMENT ME!
483    */
setGlassPane(Component f)484   public void setGlassPane(Component f)
485   {
486     if (glassPane != null)
487       remove(glassPane);
488 
489     glassPane = f;
490 
491     glassPane.setVisible(false);
492     add(glassPane, 0);
493   }
494 
495   /**
496    * DOCUMENT ME!
497    *
498    * @return DOCUMENT ME!
499    */
getLayeredPane()500   public JLayeredPane getLayeredPane()
501   {
502     if (layeredPane == null)
503       setLayeredPane(createLayeredPane());
504     return layeredPane;
505   }
506 
507   /**
508    * Set the layered pane for the root pane.
509    *
510    * @param f The JLayeredPane to be used.
511    *
512    * @throws IllegalComponentStateException if JLayeredPane
513    * parameter is null.
514    */
setLayeredPane(JLayeredPane f)515   public void setLayeredPane(JLayeredPane f)
516   {
517     if (f == null)
518       throw new IllegalComponentStateException();
519 
520     if (layeredPane != null)
521       remove(layeredPane);
522 
523     layeredPane = f;
524     add(f, -1);
525   }
526 
527   /**
528    * Creates a new <code>JRootPane</code> object.
529    */
JRootPane()530   public JRootPane()
531   {
532     setLayout(createRootLayout());
533     getGlassPane();
534     getLayeredPane();
535     getContentPane();
536     setOpaque(true);
537     updateUI();
538   }
539 
540   /**
541    * DOCUMENT ME!
542    *
543    * @return DOCUMENT ME!
544    */
createRootLayout()545   protected LayoutManager createRootLayout()
546   {
547     return new RootLayout();
548   }
549 
550   /**
551    * DOCUMENT ME!
552    *
553    * @return DOCUMENT ME!
554    */
createContentPane()555   protected Container createContentPane()
556   {
557     JPanel p = new JPanel();
558     p.setName(this.getName() + ".contentPane");
559     p.setLayout(new BorderLayout());
560     return p;
561   }
562 
563   /**
564    * DOCUMENT ME!
565    *
566    * @return DOCUMENT ME!
567    */
createGlassPane()568   protected Component createGlassPane()
569   {
570     JPanel p = new JPanel();
571     p.setName(this.getName() + ".glassPane");
572     p.setVisible(false);
573     p.setOpaque(false);
574     return p;
575   }
576 
577   /**
578    * DOCUMENT ME!
579    *
580    * @return DOCUMENT ME!
581    */
createLayeredPane()582   protected JLayeredPane createLayeredPane()
583   {
584     JLayeredPane l = new JLayeredPane();
585     l.setLayout(null);
586     return l;
587   }
588 
589   /**
590    * DOCUMENT ME!
591    *
592    * @return DOCUMENT ME!
593    */
getUI()594   public RootPaneUI getUI()
595   {
596     return (RootPaneUI) ui;
597   }
598 
599   /**
600    * DOCUMENT ME!
601    *
602    * @param ui DOCUMENT ME!
603    */
setUI(RootPaneUI ui)604   public void setUI(RootPaneUI ui)
605   {
606     super.setUI(ui);
607   }
608 
609   /**
610    * DOCUMENT ME!
611    */
updateUI()612   public void updateUI()
613   {
614     setUI((RootPaneUI) UIManager.getUI(this));
615   }
616 
617   /**
618    * DOCUMENT ME!
619    *
620    * @return DOCUMENT ME!
621    */
getUIClassID()622   public String getUIClassID()
623   {
624     return "RootPaneUI";
625   }
626 
getDefaultButton()627   public JButton getDefaultButton()
628   {
629     return defaultButton;
630   }
631 
setDefaultButton(JButton newButton)632   public void setDefaultButton(JButton newButton)
633   {
634     // We only change the default button if the new button is defaultCapable
635     // or null and the old and new button are different objects.
636     if (defaultButton != newButton
637         && (newButton == null || newButton.isDefaultCapable()))
638       {
639         JButton oldButton = defaultButton;
640         defaultButton = newButton;
641         firePropertyChange("defaultButton", oldButton, newButton);
642       }
643   }
644 
645   /**
646    * @since 1.4
647    */
getWindowDecorationStyle()648   public int getWindowDecorationStyle()
649   {
650     return windowDecorationStyle;
651   }
652 
653   /**
654    * @since 1.4
655    */
setWindowDecorationStyle(int style)656   public void setWindowDecorationStyle(int style)
657   {
658     if (style != NONE
659         && style != FRAME
660         && style != INFORMATION_DIALOG
661         && style != ERROR_DIALOG
662         && style != COLOR_CHOOSER_DIALOG
663         && style != FILE_CHOOSER_DIALOG
664         && style != QUESTION_DIALOG
665         && style != WARNING_DIALOG
666         && style != PLAIN_DIALOG)
667       throw new IllegalArgumentException("invalid style");
668 
669     int oldStyle = windowDecorationStyle;
670     windowDecorationStyle = style;
671     firePropertyChange("windowDecorationStyle", oldStyle, style);
672   }
673 
674   /**
675    * This returns <code>true</code> if the <code>glassPane</code> is not
676    * visible because then the root pane can guarantee to tile its children
677    * (the only other direct child is a JLayeredPane which must figure its
678    * <code>optimizeDrawingEnabled</code> state on its own).
679    *
680    * @return <code>true</code> if the <code>glassPane</code> is not
681    *         visible
682    */
isOptimizedDrawingEnable()683   public boolean isOptimizedDrawingEnable()
684   {
685     return ! glassPane.isVisible();
686   }
687 
688   /**
689    * Returns the accessible context for this JRootPane. This will be
690    * an instance of {@link AccessibleJRootPane}.
691    *
692    * @return the accessible context for this JRootPane
693    */
getAccessibleContext()694   public AccessibleContext getAccessibleContext()
695   {
696     if (accessibleContext == null)
697       accessibleContext = new AccessibleJRootPane();
698     return accessibleContext;
699   }
700 }
701