Merge from mainline.
[official-gcc.git] / libjava / classpath / javax / swing / plaf / metal / MetalRootPaneUI.java
blob6cabc7e8691364e0b159a7df66095e4b824bc50a
1 /* MetalRootPaneUI.java
2 Copyright (C) 2005, 2006 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
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.
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.
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.
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.
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. */
39 package javax.swing.plaf.metal;
41 import java.awt.Color;
42 import java.awt.Component;
43 import java.awt.Container;
44 import java.awt.Dimension;
45 import java.awt.Frame;
46 import java.awt.Graphics;
47 import java.awt.Insets;
48 import java.awt.LayoutManager;
49 import java.awt.LayoutManager2;
50 import java.awt.Point;
51 import java.awt.Rectangle;
52 import java.awt.Window;
53 import java.awt.event.ActionEvent;
54 import java.awt.event.MouseEvent;
55 import java.beans.PropertyChangeEvent;
57 import javax.swing.AbstractAction;
58 import javax.swing.Action;
59 import javax.swing.Icon;
60 import javax.swing.JButton;
61 import javax.swing.JComponent;
62 import javax.swing.JDialog;
63 import javax.swing.JFrame;
64 import javax.swing.JLabel;
65 import javax.swing.JLayeredPane;
66 import javax.swing.JMenu;
67 import javax.swing.JMenuBar;
68 import javax.swing.JRootPane;
69 import javax.swing.SwingConstants;
70 import javax.swing.SwingUtilities;
71 import javax.swing.UIManager;
72 import javax.swing.border.AbstractBorder;
73 import javax.swing.event.MouseInputAdapter;
74 import javax.swing.plaf.ComponentUI;
75 import javax.swing.plaf.basic.BasicRootPaneUI;
77 /**
78 * A UI delegate for the {@link JRootPane} component. This implementation
79 * supports the JRootPane <code>windowDecorationStyle</code> property.
81 * @author Roman Kennke (kennke@aicas.com)
83 * @since 1.4
85 public class MetalRootPaneUI
86 extends BasicRootPaneUI
89 /**
90 * The border that is used on JRootPane when the windowDecorationStyle
91 * property of the JRootPane is set to a different value than NONE.
93 * @author Roman Kennke (kennke@aicas.com)
95 private static class MetalFrameBorder
96 extends AbstractBorder
98 /**
99 * Returns the border insets.
101 * @param c the component
102 * @param newInsets the insets to be filled with the return value, may be
103 * <code>null</code> in which case a new object is created
105 * @return the border insets
107 public Insets getBorderInsets(Component c, Insets newInsets)
109 if (newInsets == null)
110 newInsets = new Insets(5, 5, 5, 5);
111 else
113 newInsets.top = 5;
114 newInsets.left = 5;
115 newInsets.bottom = 5;
116 newInsets.right = 5;
118 return newInsets;
122 * Returns the border insets.
124 * @param c the component
126 * @return the border insets
128 public Insets getBorderInsets(Component c)
130 return getBorderInsets(c, null);
134 * Paints the border for the specified component.
136 * @param c the component
137 * @param g the graphics device
138 * @param x the x-coordinate
139 * @param y the y-coordinate
140 * @param w the width
141 * @param h the height
143 public void paintBorder(Component c, Graphics g, int x, int y, int w,
144 int h)
146 JRootPane f = (JRootPane) c;
147 Window frame = SwingUtilities.getWindowAncestor(f);
148 if (frame.isActive())
149 g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow());
150 else
151 g.setColor(MetalLookAndFeel.getControlDarkShadow());
153 // Fill the border background.
154 g.fillRect(x, y, w, 5);
155 g.fillRect(x, y, 5, h);
156 g.fillRect(x + w - 5, y, 5, h);
157 g.fillRect(x, y + h - 5, w, 5);
159 // Draw a dot in each corner.
160 g.setColor(MetalLookAndFeel.getControl());
161 g.fillRect(x, y, 1, 1);
162 g.fillRect(x + w - 1, y, 1, 1);
163 g.fillRect(x + w - 1, y + h - 1, 1, 1);
164 g.fillRect(x, y + h - 1, 1, 1);
166 // Draw the lines.
167 g.setColor(MetalLookAndFeel.getBlack());
168 g.drawLine(x + 14, y + 2, x + w - 15, y + 2);
169 g.drawLine(x + 14, y + h - 3, x + w - 15, y + h - 3);
170 g.drawLine(x + 2, y + 14, x + 2, y + h - 15);
171 g.drawLine(x + w - 3, y + 14, x + w - 3, y + h - 15);
173 // Draw the line highlights.
174 if (frame.isActive())
175 g.setColor(MetalLookAndFeel.getPrimaryControlShadow());
176 else
177 g.setColor(MetalLookAndFeel.getControlShadow());
178 g.drawLine(x + 15, y + 3, x + w - 14, y + 3);
179 g.drawLine(x + 15, y + h - 2, x + w - 14, y + h - 2);
180 g.drawLine(x + 3, y + 15, x + 3, y + h - 14);
181 g.drawLine(x + w - 2, y + 15, x + w - 2, y + h - 14);
186 * The component that renders the title bar for frames. This duplicates
187 * most of {@link MetalInternalFrameTitlePane}. It is not reasonably possible
188 * to reuse that class because that is bound to the JInternalFrame and we
189 * need to handle JFrames/JRootPanes here.
191 * @author Roman Kennke (kennke@aicas.com)
193 private static class MetalTitlePane extends JComponent
197 * Handles dragging of the title pane and moves the window accordingly.
199 private class MouseHandler
200 extends MouseInputAdapter
203 * The point where the dragging started.
205 Point lastDragLocation;
208 * Receives notification when the mouse gets pressed on the title pane.
209 * This updates the lastDragLocation.
211 * @param ev the mouse event
213 public void mousePressed(MouseEvent ev)
215 lastDragLocation = ev.getPoint();
219 * Receives notification when the mouse is dragged on the title pane.
220 * This will move the nearest window accordingly.
222 * @param ev the mouse event
224 public void mouseDragged(MouseEvent ev)
226 Point dragLocation = ev.getPoint();
227 int deltaX = dragLocation.x - lastDragLocation.x;
228 int deltaY = dragLocation.y - lastDragLocation.y;
229 Window window = SwingUtilities.getWindowAncestor(rootPane);
230 Point loc = window.getLocation();
231 window.setLocation(loc.x + deltaX, loc.y + deltaY);
232 // Note that we do not update the lastDragLocation. This is because
233 // we move the underlying window while dragging the component, which
234 // results in having the same lastDragLocation under the mouse while
235 // dragging.
240 * The Action responsible for closing the JInternalFrame.
242 private class CloseAction extends AbstractAction
245 * Creates a new action.
247 public CloseAction()
249 super("Close");
253 * This method is called when something closes the frame.
255 * @param e the ActionEvent
257 public void actionPerformed(ActionEvent e)
259 Window frame = SwingUtilities.getWindowAncestor(rootPane);
260 if (frame instanceof JFrame)
262 JFrame jframe = (JFrame) frame;
263 switch (jframe.getDefaultCloseOperation())
265 case JFrame.EXIT_ON_CLOSE:
266 jframe.setVisible(false);
267 jframe.dispose();
268 System.exit(0);
269 break;
270 case JFrame.DISPOSE_ON_CLOSE:
271 jframe.setVisible(false);
272 jframe.dispose();
273 break;
274 case JFrame.HIDE_ON_CLOSE:
275 jframe.setVisible(false);
276 break;
277 case JFrame.DO_NOTHING_ON_CLOSE:
278 default:
279 break;
282 else if (frame instanceof JDialog)
284 JDialog jdialog = (JDialog) frame;
285 switch (jdialog.getDefaultCloseOperation())
287 case JFrame.DISPOSE_ON_CLOSE:
288 jdialog.setVisible(false);
289 jdialog.dispose();
290 break;
291 case JFrame.HIDE_ON_CLOSE:
292 jdialog.setVisible(false);
293 break;
294 case JFrame.DO_NOTHING_ON_CLOSE:
295 default:
296 break;
303 * This action is performed when the iconify button is pressed.
305 private class IconifyAction
306 extends AbstractAction
309 public void actionPerformed(ActionEvent event)
311 Window w = SwingUtilities.getWindowAncestor(rootPane);
312 if (w instanceof Frame)
314 Frame f = (Frame) w;
315 int state = f.getExtendedState();
316 f.setExtendedState(Frame.ICONIFIED);
323 * This action is performed when the maximize button is pressed.
325 private class MaximizeAction
326 extends AbstractAction
329 public void actionPerformed(ActionEvent event)
331 Window w = SwingUtilities.getWindowAncestor(rootPane);
332 if (w instanceof Frame)
334 Frame f = (Frame) w;
335 int state = f.getExtendedState();
336 f.setExtendedState(Frame.MAXIMIZED_BOTH);
342 * This helper class is used to create the minimize, maximize and close
343 * buttons in the top right corner of the Title Pane. These buttons are
344 * special since they cannot be given focus and have no border.
346 private class PaneButton extends JButton
349 * Creates a new PaneButton object with the given Action.
351 * @param a The Action that the button uses.
353 public PaneButton(Action a)
355 super(a);
356 setMargin(new Insets(0, 0, 0, 0));
360 * This method returns true if the Component can be focused.
362 * @return false.
364 public boolean isFocusable()
366 // These buttons cannot be given focus.
367 return false;
373 * The layout for the JRootPane when the <code>windowDecorationStyle</code>
374 * property is set. In addition to the usual JRootPane.RootLayout behaviour
375 * this lays out the titlePane.
377 * @author Roman Kennke (kennke@aicas.com)
379 private class MetalTitlePaneLayout implements LayoutManager
382 * Creates a new <code>TitlePaneLayout</code> object.
384 public MetalTitlePaneLayout()
386 // Do nothing.
390 * Adds a Component to the Container.
392 * @param name The name to reference the added Component by.
393 * @param c The Component to add.
395 public void addLayoutComponent(String name, Component c)
397 // Do nothing.
401 * This method is called to lay out the children of the Title Pane.
403 * @param c The Container to lay out.
405 public void layoutContainer(Container c)
408 Dimension size = c.getSize();
409 Insets insets = c.getInsets();
410 int width = size.width - insets.left - insets.right;
411 int height = size.height - insets.top - insets.bottom;
413 int loc = width - insets.right - 1;
414 int top = insets.top + 2;
415 int buttonHeight = height - 4;
416 if (closeButton.isVisible())
418 int buttonWidth = closeIcon.getIconWidth();
419 loc -= buttonWidth + 2;
420 closeButton.setBounds(loc, top, buttonWidth, buttonHeight);
421 loc -= 6;
424 if (maxButton.isVisible())
426 int buttonWidth = maxIcon.getIconWidth();
427 loc -= buttonWidth + 4;
428 maxButton.setBounds(loc, top, buttonWidth, buttonHeight);
431 if (iconButton.isVisible())
433 int buttonWidth = minIcon.getIconWidth();
434 loc -= buttonWidth + 4;
435 iconButton.setBounds(loc, top, buttonWidth, buttonHeight);
436 loc -= 2;
439 Dimension titlePreferredSize = title.getPreferredSize();
440 title.setBounds(insets.left + 5, insets.top,
441 Math.min(titlePreferredSize.width, loc - insets.left - 10),
442 height);
447 * This method returns the minimum size of the given Container given the
448 * children that it has.
450 * @param c The Container to get a minimum size for.
452 * @return The minimum size of the Container.
454 public Dimension minimumLayoutSize(Container c)
456 return preferredLayoutSize(c);
460 * Returns the preferred size of the given Container taking
461 * into account the children that it has.
463 * @param c The Container to lay out.
465 * @return The preferred size of the Container.
467 public Dimension preferredLayoutSize(Container c)
469 return new Dimension(22, 22);
473 * Removes a Component from the Container.
475 * @param c The Component to remove.
477 public void removeLayoutComponent(Component c)
479 // Nothing to do here.
483 JRootPane rootPane;
485 /** The button that closes the JInternalFrame. */
486 JButton closeButton;
488 /** The button that iconifies the JInternalFrame. */
489 JButton iconButton;
491 /** The button that maximizes the JInternalFrame. */
492 JButton maxButton;
494 Icon minIcon;
496 /** The icon displayed in the maximize button. */
497 Icon maxIcon;
499 /** The icon displayed in the iconify button. */
500 private Icon iconIcon;
502 /** The icon displayed in the close button. */
503 Icon closeIcon;
506 * The background color of the TitlePane when the JInternalFrame is not
507 * selected.
509 private Color notSelectedTitleColor;
512 * The background color of the TitlePane when the JInternalFrame is
513 * selected.
515 private Color selectedTitleColor;
518 * The label used to display the title. This label is not added to the
519 * TitlePane.
521 JLabel title;
523 /** The action associated with closing the JInternalFrame. */
524 private Action closeAction;
526 /** The action associated with iconifying the JInternalFrame. */
527 private Action iconifyAction;
529 /** The action associated with maximizing the JInternalFrame. */
530 private Action maximizeAction;
532 /** The JMenuBar that is located at the top left of the Title Pane. */
533 private JMenuBar menuBar;
535 /** The JMenu inside the menuBar. */
536 protected JMenu windowMenu;
538 MetalTitlePane(JRootPane rp)
540 rootPane = rp;
541 setLayout(createLayout());
542 title = new JLabel();
543 title.setHorizontalAlignment(SwingConstants.LEFT);
544 title.setHorizontalTextPosition(SwingConstants.LEFT);
545 title.setOpaque(false);
546 installTitlePane();
549 protected LayoutManager createLayout()
551 return new MetalTitlePaneLayout();
555 * This method installs the TitlePane onto the JInternalFrameTitlePane. It
556 * also creates any children components that need to be created and adds
557 * listeners to the appropriate components.
559 protected void installTitlePane()
561 installDefaults();
562 installListeners();
563 createActions();
564 assembleSystemMenu();
565 createButtons();
566 setButtonIcons();
567 addSubComponents();
568 enableActions();
571 private void enableActions()
573 // TODO: Implement this.
576 private void addSubComponents()
578 add(menuBar);
579 add(closeButton);
580 add(iconButton);
581 add(maxButton);
584 private void installListeners()
586 MouseInputAdapter mouseHandler = new MouseHandler();
587 addMouseListener(mouseHandler);
588 addMouseMotionListener(mouseHandler);
591 private void createActions()
593 closeAction = new CloseAction();
594 iconifyAction = new IconifyAction();
595 maximizeAction = new MaximizeAction();
598 private void assembleSystemMenu()
600 menuBar = createSystemMenuBar();
601 windowMenu = createSystemMenu();
602 menuBar.add(windowMenu);
603 addSystemMenuItems(windowMenu);
604 enableActions();
607 protected JMenuBar createSystemMenuBar()
609 if (menuBar == null)
610 menuBar = new JMenuBar();
611 menuBar.removeAll();
612 return menuBar;
615 protected JMenu createSystemMenu()
617 if (windowMenu == null)
618 windowMenu = new JMenu();
619 windowMenu.removeAll();
620 return windowMenu;
623 private void addSystemMenuItems(JMenu menu)
625 // TODO: Implement this.
628 protected void createButtons()
630 closeButton = new PaneButton(closeAction);
631 closeButton.setText(null);
632 iconButton = new PaneButton(iconifyAction);
633 iconButton.setText(null);
634 maxButton = new PaneButton(maximizeAction);
635 maxButton.setText(null);
636 closeButton.setBorderPainted(false);
637 closeButton.setContentAreaFilled(false);
638 iconButton.setBorderPainted(false);
639 iconButton.setContentAreaFilled(false);
640 maxButton.setBorderPainted(false);
641 maxButton.setContentAreaFilled(false);
644 protected void setButtonIcons()
646 if (closeIcon != null && closeButton != null)
647 closeButton.setIcon(closeIcon);
648 if (iconIcon != null && iconButton != null)
649 iconButton.setIcon(iconIcon);
650 if (maxIcon != null && maxButton != null)
651 maxButton.setIcon(maxIcon);
655 * Paints a representation of the current state of the internal frame.
657 * @param g the graphics device.
659 public void paintComponent(Graphics g)
661 Window frame = SwingUtilities.getWindowAncestor(rootPane);
662 Color savedColor = g.getColor();
663 paintTitleBackground(g);
664 paintChildren(g);
665 Dimension d = getSize();
666 if (frame.isActive())
667 g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow());
668 else
669 g.setColor(MetalLookAndFeel.getControlDarkShadow());
671 // put a dot in each of the top corners
672 g.drawLine(0, 0, 0, 0);
673 g.drawLine(d.width - 1, 0, d.width - 1, 0);
675 g.drawLine(0, d.height - 1, d.width - 1, d.height - 1);
677 // draw the metal pattern
678 if (UIManager.get("InternalFrame.activeTitleGradient") != null
679 && frame.isActive())
681 MetalUtils.paintGradient(g, 0, 0, getWidth(), getHeight(),
682 SwingConstants.VERTICAL,
683 "InternalFrame.activeTitleGradient");
686 Rectangle b = title.getBounds();
687 int startX = b.x + b.width + 5;
688 int endX = startX;
689 if (iconButton.isVisible())
690 endX = Math.max(iconButton.getX(), endX);
691 else if (maxButton.isVisible())
692 endX = Math.max(maxButton.getX(), endX);
693 else if (closeButton.isVisible())
694 endX = Math.max(closeButton.getX(), endX);
695 endX -= 7;
696 if (endX > startX)
697 MetalUtils.fillMetalPattern(this, g, startX, 3, endX - startX, getHeight() - 6, Color.white, Color.gray);
698 g.setColor(savedColor);
702 * This method paints the TitlePane's background.
704 * @param g The Graphics object to paint with.
706 protected void paintTitleBackground(Graphics g)
708 Window frame = SwingUtilities.getWindowAncestor(rootPane);
710 if (!isOpaque())
711 return;
713 Color saved = g.getColor();
714 Dimension dims = getSize();
716 Color bg = getBackground();
717 if (frame.isActive())
718 bg = selectedTitleColor;
719 else
720 bg = notSelectedTitleColor;
721 g.setColor(bg);
722 g.fillRect(0, 0, dims.width, dims.height);
723 g.setColor(saved);
727 * This method installs the defaults determined by the look and feel.
729 private void installDefaults()
731 title.setFont(UIManager.getFont("InternalFrame.titleFont"));
732 selectedTitleColor = UIManager.getColor("InternalFrame.activeTitleBackground");
733 notSelectedTitleColor = UIManager.getColor("InternalFrame.inactiveTitleBackground");
734 closeIcon = UIManager.getIcon("InternalFrame.closeIcon");
735 iconIcon = UIManager.getIcon("InternalFrame.iconifyIcon");
736 maxIcon = UIManager.getIcon("InternalFrame.maximizeIcon");
737 minIcon = MetalIconFactory.getInternalFrameAltMaximizeIcon(16);
738 Frame frame = (Frame) SwingUtilities.getWindowAncestor(rootPane);
739 title = new JLabel(frame.getTitle(),
740 MetalIconFactory.getInternalFrameDefaultMenuIcon(),
741 SwingConstants.LEFT);
745 private static class MetalRootLayout
746 implements LayoutManager2
750 * The cached layout info for the glass pane.
752 private Rectangle glassPaneBounds;
755 * The cached layout info for the layered pane.
757 private Rectangle layeredPaneBounds;
760 * The cached layout info for the content pane.
762 private Rectangle contentPaneBounds;
765 * The cached layout info for the menu bar.
767 private Rectangle menuBarBounds;
770 * The cached layout info for the title pane.
772 private Rectangle titlePaneBounds;
775 * The cached preferred size.
777 private Dimension prefSize;
780 * The title pane for l&f decorated frames.
782 private MetalTitlePane titlePane;
785 * Creates a new MetalRootLayout.
787 * @param tp the title pane
789 MetalRootLayout(MetalTitlePane tp)
791 titlePane = tp;
794 public void addLayoutComponent(Component component, Object constraints)
796 // Nothing to do here.
799 public Dimension maximumLayoutSize(Container target)
801 return preferredLayoutSize(target);
804 public float getLayoutAlignmentX(Container target)
806 return 0.0F;
809 public float getLayoutAlignmentY(Container target)
811 return 0.0F;
814 public void invalidateLayout(Container target)
816 synchronized (this)
818 glassPaneBounds = null;
819 layeredPaneBounds = null;
820 contentPaneBounds = null;
821 menuBarBounds = null;
822 titlePaneBounds = null;
823 prefSize = null;
827 public void addLayoutComponent(String name, Component component)
829 // Nothing to do here.
832 public void removeLayoutComponent(Component component)
834 // TODO Auto-generated method stub
838 public Dimension preferredLayoutSize(Container parent)
840 JRootPane rp = (JRootPane) parent;
841 JLayeredPane layeredPane = rp.getLayeredPane();
842 Component contentPane = rp.getContentPane();
843 Component menuBar = rp.getJMenuBar();
845 // We must synchronize here, otherwise we cannot guarantee that the
846 // prefSize is still non-null when returning.
847 synchronized (this)
849 if (prefSize == null)
851 Insets i = parent.getInsets();
852 prefSize = new Dimension(i.left + i.right, i.top + i.bottom);
853 Dimension contentPrefSize = contentPane.getPreferredSize();
854 prefSize.width += contentPrefSize.width;
855 prefSize.height += contentPrefSize.height
856 + titlePane.getPreferredSize().height;
857 if (menuBar != null)
859 Dimension menuBarSize = menuBar.getPreferredSize();
860 if (menuBarSize.width > contentPrefSize.width)
861 prefSize.width += menuBarSize.width - contentPrefSize.width;
862 prefSize.height += menuBarSize.height;
865 // Return a copy here so the cached value won't get trashed by some
866 // other component.
867 return new Dimension(prefSize);
871 public Dimension minimumLayoutSize(Container parent)
873 return preferredLayoutSize(parent);
876 public void layoutContainer(Container parent)
878 JRootPane rp = (JRootPane) parent;
879 JLayeredPane layeredPane = rp.getLayeredPane();
880 Component contentPane = rp.getContentPane();
881 Component menuBar = rp.getJMenuBar();
882 Component glassPane = rp.getGlassPane();
884 if (glassPaneBounds == null || layeredPaneBounds == null
885 || contentPaneBounds == null || menuBarBounds == null)
887 Insets i = rp.getInsets();
888 int containerWidth = parent.getBounds().width - i.left - i.right;
889 int containerHeight = parent.getBounds().height - i.top - i.bottom;
891 // 1. The glassPane fills entire viewable region (bounds - insets).
892 // 2. The layeredPane filles entire viewable region.
893 // 3. The titlePane is placed at the upper edge of the layeredPane.
894 // 4. The menuBar is positioned at the upper edge of layeredPane.
895 // 5. The contentPane fills viewable region minus menuBar minus
896 // titlePane, if present.
898 // +-------------------------------+
899 // | JLayeredPane |
900 // | +--------------------------+ |
901 // | | titlePane + |
902 // | +--------------------------+ |
903 // | +--------------------------+ |
904 // | | menuBar | |
905 // | +--------------------------+ |
906 // | +--------------------------+ |
907 // | |contentPane | |
908 // | | | |
909 // | | | |
910 // | | | |
911 // | +--------------------------+ |
912 // +-------------------------------+
914 // Setup titlePaneBounds.
915 if (titlePaneBounds == null)
916 titlePaneBounds = new Rectangle();
917 titlePaneBounds.width = containerWidth;
918 titlePaneBounds.height = titlePane.getPreferredSize().height;
920 // Setup menuBarBounds.
921 if (menuBarBounds == null)
922 menuBarBounds = new Rectangle();
923 menuBarBounds.setBounds(0,
924 titlePaneBounds.y + titlePaneBounds.height,
925 containerWidth, 0);
926 if (menuBar != null)
928 Dimension menuBarSize = menuBar.getPreferredSize();
929 if (menuBarSize.height > containerHeight)
930 menuBarBounds.height = containerHeight;
931 else
932 menuBarBounds.height = menuBarSize.height;
935 // Setup contentPaneBounds.
936 if (contentPaneBounds == null)
937 contentPaneBounds = new Rectangle();
938 contentPaneBounds.setBounds(0,
939 menuBarBounds.y + menuBarBounds.height,
940 containerWidth,
941 containerHeight - menuBarBounds.y
942 - menuBarBounds.height);
943 glassPaneBounds = new Rectangle(i.left, i.top, containerWidth, containerHeight);
944 layeredPaneBounds = new Rectangle(i.left, i.top, containerWidth, containerHeight);
947 // Layout components.
948 glassPane.setBounds(glassPaneBounds);
949 layeredPane.setBounds(layeredPaneBounds);
950 if (menuBar != null)
951 menuBar.setBounds(menuBarBounds);
952 contentPane.setBounds(contentPaneBounds);
953 titlePane.setBounds(titlePaneBounds);
959 * The shared UI instance for MetalRootPaneUIs.
961 private static MetalRootPaneUI instance = null;
964 * Constructs a shared instance of <code>MetalRootPaneUI</code>.
966 public MetalRootPaneUI()
968 super();
972 * Returns a shared instance of <code>MetalRootPaneUI</code>.
974 * @param component the component for which we return an UI instance
976 * @return A shared instance of <code>MetalRootPaneUI</code>.
978 public static ComponentUI createUI(JComponent component)
980 if (instance == null)
981 instance = new MetalRootPaneUI();
982 return instance;
986 * Installs this UI to the root pane. If the
987 * <code>windowDecorationsStyle</code> property is set on the root pane,
988 * the Metal window decorations are installed on the root pane.
990 * @param c
992 public void installUI(JComponent c)
994 super.installUI(c);
995 JRootPane rp = (JRootPane) c;
996 if (rp.getWindowDecorationStyle() != JRootPane.NONE)
997 installWindowDecorations(rp);
1001 * Uninstalls the UI from the root pane. This performs the superclass
1002 * behaviour and uninstalls the window decorations that have possibly been
1003 * installed by {@link #installUI}.
1005 * @param c the root pane
1007 public void uninstallUI(JComponent c)
1009 JRootPane rp = (JRootPane) c;
1010 if (rp.getWindowDecorationStyle() != JRootPane.NONE)
1011 uninstallWindowDecorations(rp);
1012 super.uninstallUI(c);
1016 * Receives notification if any of the JRootPane's property changes. In
1017 * particular this catches changes to the <code>windowDecorationStyle</code>
1018 * property and installs the window decorations accordingly.
1020 * @param ev the property change event
1022 public void propertyChange(PropertyChangeEvent ev)
1024 super.propertyChange(ev);
1025 String propertyName = ev.getPropertyName();
1026 if (propertyName.equals("windowDecorationStyle"))
1028 JRootPane rp = (JRootPane) ev.getSource();
1029 if (rp.getWindowDecorationStyle() != JRootPane.NONE)
1030 installWindowDecorations(rp);
1031 else
1032 uninstallWindowDecorations(rp);
1037 * Installs the window decorations to the root pane. This sets up a border,
1038 * a title pane and a layout manager that can layout the root pane with that
1039 * title pane.
1041 * @param rp the root pane.
1043 private void installWindowDecorations(JRootPane rp)
1045 rp.setBorder(new MetalFrameBorder());
1046 MetalTitlePane titlePane = new MetalTitlePane(rp);
1047 rp.setLayout(new MetalRootLayout(titlePane));
1048 // We should have a contentPane already.
1049 assert rp.getLayeredPane().getComponentCount() > 0
1050 : "We should have a contentPane already";
1052 rp.getLayeredPane().add(titlePane,
1053 JLayeredPane.FRAME_CONTENT_LAYER, 1);
1057 * Uninstalls the window decorations from the root pane. This should rarely
1058 * be necessary, but we do it anyway.
1060 * @param rp the root pane
1062 private void uninstallWindowDecorations(JRootPane rp)
1064 rp.setBorder(null);
1065 JLayeredPane lp = rp.getLayeredPane();
1066 for (int i = lp.getComponentCount() - 1; i >= 0; --i)
1068 if (lp.getComponent(i) instanceof MetalTitlePane)
1070 lp.remove(i);
1071 break;