001    /* JRootPane.java --
002       Copyright (C) 2002, 2004  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.BorderLayout;
042    import java.awt.Component;
043    import java.awt.Container;
044    import java.awt.Dimension;
045    import java.awt.IllegalComponentStateException;
046    import java.awt.Insets;
047    import java.awt.LayoutManager;
048    import java.awt.LayoutManager2;
049    import java.awt.Rectangle;
050    import java.io.Serializable;
051    
052    import javax.accessibility.Accessible;
053    import javax.accessibility.AccessibleContext;
054    import javax.accessibility.AccessibleRole;
055    import javax.swing.plaf.RootPaneUI;
056    
057    /**
058     * This class is where JComponents are added to. Unlike awt where you could
059     * just say frame.add(), with swing you need to say frame.getRootPane()
060     * (which delivers an instance of this class) and add your components to
061     * that. It is implemented by several 'layers' (pane() should be read as
062     * plane()) each on top of the others where you can add components to.
063     * (getContentPane(), getGlassPane(), getLayeredPane())
064     *
065     * @author Ronald Veldema (rveldema@cs.vu.nl)
066     */
067    public class JRootPane extends JComponent implements Accessible
068    {
069      //  The class used to obtain the accessible role for this object.
070      protected class AccessibleJRootPane extends AccessibleJComponent
071      {
072        /**
073         * For compatability with Sun's JDK
074         */
075        private static final long serialVersionUID = 1082432482784468088L;
076    
077        /**
078         * Creates a new <code>AccessibleJRootPane</code> object.
079         */
080        protected AccessibleJRootPane()
081        {
082          // Nothing to do here.
083        }
084    
085        /**
086         * DOCUMENT ME!
087         *
088         * @return DOCUMENT ME!
089         */
090        public AccessibleRole getAccessibleRole()
091        {
092          return AccessibleRole.ROOT_PANE;
093        }
094      }
095    
096      // Custom Layout Manager for JRootPane. It positions contentPane and
097      // menuBar withing its layeredPane.
098      protected class RootLayout implements LayoutManager2, Serializable
099      {
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         */
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         */
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         */
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         */
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         */
172        public float getLayoutAlignmentY(Container target)
173        {
174          return 0.0F;
175        }
176    
177        /**
178         * DOCUMENT ME!
179         *
180         * @param target DOCUMENT ME!
181         */
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         */
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         */
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         */
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         */
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         */
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       */
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       */
388      public void setMenuBar(JMenuBar m)
389      {
390        setJMenuBar(m);
391      }
392    
393      /**
394       * DOCUMENT ME!
395       *
396       * @return DOCUMENT ME!
397       */
398      public JMenuBar getJMenuBar()
399      {
400        return menuBar;
401      }
402    
403      /**
404       * @deprecated Replaced by <code>getJMenuBar()</code>
405       */
406      public JMenuBar getMenuBar()
407      {
408        return getJMenuBar();
409      }
410    
411      /**
412       * DOCUMENT ME!
413       *
414       * @return DOCUMENT ME!
415       */
416      public boolean isValidateRoot()
417      {
418        return true;
419      }
420    
421      /**
422       * DOCUMENT ME!
423       *
424       * @return DOCUMENT ME!
425       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
545      protected LayoutManager createRootLayout()
546      {
547        return new RootLayout();
548      }
549    
550      /**
551       * DOCUMENT ME!
552       *
553       * @return DOCUMENT ME!
554       */
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       */
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       */
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       */
594      public RootPaneUI getUI()
595      {
596        return (RootPaneUI) ui;
597      }
598    
599      /**
600       * DOCUMENT ME!
601       *
602       * @param ui DOCUMENT ME!
603       */
604      public void setUI(RootPaneUI ui)
605      {
606        super.setUI(ui);
607      }
608    
609      /**
610       * DOCUMENT ME!
611       */
612      public void updateUI()
613      {
614        setUI((RootPaneUI) UIManager.getUI(this));
615      }
616    
617      /**
618       * DOCUMENT ME!
619       *
620       * @return DOCUMENT ME!
621       */
622      public String getUIClassID()
623      {
624        return "RootPaneUI";
625      }
626    
627      public JButton getDefaultButton()
628      {
629        return defaultButton;
630      }
631    
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       */
648      public int getWindowDecorationStyle()
649      {
650        return windowDecorationStyle;
651      }
652    
653      /**
654       * @since 1.4
655       */
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       */
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       */
694      public AccessibleContext getAccessibleContext()
695      {
696        if (accessibleContext == null)
697          accessibleContext = new AccessibleJRootPane();
698        return accessibleContext;
699      }
700    }