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 }