001/* JRootPane.java --
002   Copyright (C) 2002, 2004  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 java.awt.BorderLayout;
042import java.awt.Component;
043import java.awt.Container;
044import java.awt.Dimension;
045import java.awt.IllegalComponentStateException;
046import java.awt.Insets;
047import java.awt.LayoutManager;
048import java.awt.LayoutManager2;
049import java.awt.Rectangle;
050import java.io.Serializable;
051
052import javax.accessibility.Accessible;
053import javax.accessibility.AccessibleContext;
054import javax.accessibility.AccessibleRole;
055import 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 */
067public 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}