--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalTitlePane.java Sun Aug 17 15:54:13 2014 +0100
@@ -0,0 +1,1046 @@
+/*
+ * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.swing.plaf.metal;
+
+import sun.swing.SwingUtilities2;
+import sun.awt.SunToolkit;
+import java.awt.*;
+import java.awt.event.*;
+import java.beans.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.event.InternalFrameEvent;
+import javax.swing.plaf.*;
+import javax.swing.plaf.basic.*;
+import java.util.Locale;
+import javax.accessibility.*;
+
+
+/**
+ * Class that manages a JLF awt.Window-descendant class's title bar.
+ * <p>
+ * This class assumes it will be created with a particular window
+ * decoration style, and that if the style changes, a new one will
+ * be created.
+ *
+ * @author Terry Kellerman
+ * @since 1.4
+ */
+@SuppressWarnings("serial") // Superclass is not serializable across versions
+class MetalTitlePane extends JComponent {
+ private static final Border handyEmptyBorder = new EmptyBorder(0,0,0,0);
+ private static final int IMAGE_HEIGHT = 16;
+ private static final int IMAGE_WIDTH = 16;
+
+ /**
+ * PropertyChangeListener added to the JRootPane.
+ */
+ private PropertyChangeListener propertyChangeListener;
+
+ /**
+ * JMenuBar, typically renders the system menu items.
+ */
+ private JMenuBar menuBar;
+ /**
+ * Action used to close the Window.
+ */
+ private Action closeAction;
+
+ /**
+ * Action used to iconify the Frame.
+ */
+ private Action iconifyAction;
+
+ /**
+ * Action to restore the Frame size.
+ */
+ private Action restoreAction;
+
+ /**
+ * Action to restore the Frame size.
+ */
+ private Action maximizeAction;
+
+ /**
+ * Button used to maximize or restore the Frame.
+ */
+ private JButton toggleButton;
+
+ /**
+ * Button used to maximize or restore the Frame.
+ */
+ private JButton iconifyButton;
+
+ /**
+ * Button used to maximize or restore the Frame.
+ */
+ private JButton closeButton;
+
+ /**
+ * Icon used for toggleButton when window is normal size.
+ */
+ private Icon maximizeIcon;
+
+ /**
+ * Icon used for toggleButton when window is maximized.
+ */
+ private Icon minimizeIcon;
+
+ /**
+ * Image used for the system menu icon
+ */
+ private Image systemIcon;
+
+ /**
+ * Listens for changes in the state of the Window listener to update
+ * the state of the widgets.
+ */
+ private WindowListener windowListener;
+
+ /**
+ * Window we're currently in.
+ */
+ private Window window;
+
+ /**
+ * JRootPane rendering for.
+ */
+ private JRootPane rootPane;
+
+ /**
+ * Room remaining in title for bumps.
+ */
+ private int buttonsWidth;
+
+ /**
+ * Buffered Frame.state property. As state isn't bound, this is kept
+ * to determine when to avoid updating widgets.
+ */
+ private int state;
+
+ /**
+ * MetalRootPaneUI that created us.
+ */
+ private MetalRootPaneUI rootPaneUI;
+
+
+ // Colors
+ private Color inactiveBackground = UIManager.getColor("inactiveCaption");
+ private Color inactiveForeground = UIManager.getColor("inactiveCaptionText");
+ private Color inactiveShadow = UIManager.getColor("inactiveCaptionBorder");
+ private Color activeBumpsHighlight = MetalLookAndFeel.getPrimaryControlHighlight();
+ private Color activeBumpsShadow = MetalLookAndFeel.getPrimaryControlDarkShadow();
+ private Color activeBackground = null;
+ private Color activeForeground = null;
+ private Color activeShadow = null;
+
+ // Bumps
+ private MetalBumps activeBumps
+ = new MetalBumps( 0, 0,
+ activeBumpsHighlight,
+ activeBumpsShadow,
+ MetalLookAndFeel.getPrimaryControl() );
+ private MetalBumps inactiveBumps
+ = new MetalBumps( 0, 0,
+ MetalLookAndFeel.getControlHighlight(),
+ MetalLookAndFeel.getControlDarkShadow(),
+ MetalLookAndFeel.getControl() );
+
+
+ public MetalTitlePane(JRootPane root, MetalRootPaneUI ui) {
+ this.rootPane = root;
+ rootPaneUI = ui;
+
+ state = -1;
+
+ installSubcomponents();
+ determineColors();
+ installDefaults();
+
+ setLayout(createLayout());
+ }
+
+ /**
+ * Uninstalls the necessary state.
+ */
+ private void uninstall() {
+ uninstallListeners();
+ window = null;
+ removeAll();
+ }
+
+ /**
+ * Installs the necessary listeners.
+ */
+ private void installListeners() {
+ if (window != null) {
+ windowListener = createWindowListener();
+ window.addWindowListener(windowListener);
+ propertyChangeListener = createWindowPropertyChangeListener();
+ window.addPropertyChangeListener(propertyChangeListener);
+ }
+ }
+
+ /**
+ * Uninstalls the necessary listeners.
+ */
+ private void uninstallListeners() {
+ if (window != null) {
+ window.removeWindowListener(windowListener);
+ window.removePropertyChangeListener(propertyChangeListener);
+ }
+ }
+
+ /**
+ * Returns the <code>WindowListener</code> to add to the
+ * <code>Window</code>.
+ */
+ private WindowListener createWindowListener() {
+ return new WindowHandler();
+ }
+
+ /**
+ * Returns the <code>PropertyChangeListener</code> to install on
+ * the <code>Window</code>.
+ */
+ private PropertyChangeListener createWindowPropertyChangeListener() {
+ return new PropertyChangeHandler();
+ }
+
+ /**
+ * Returns the <code>JRootPane</code> this was created for.
+ */
+ public JRootPane getRootPane() {
+ return rootPane;
+ }
+
+ /**
+ * Returns the decoration style of the <code>JRootPane</code>.
+ */
+ private int getWindowDecorationStyle() {
+ return getRootPane().getWindowDecorationStyle();
+ }
+
+ public void addNotify() {
+ super.addNotify();
+
+ uninstallListeners();
+
+ window = SwingUtilities.getWindowAncestor(this);
+ if (window != null) {
+ if (window instanceof Frame) {
+ setState(((Frame)window).getExtendedState());
+ }
+ else {
+ setState(0);
+ }
+ setActive(window.isActive());
+ installListeners();
+ updateSystemIcon();
+ }
+ }
+
+ public void removeNotify() {
+ super.removeNotify();
+
+ uninstallListeners();
+ window = null;
+ }
+
+ /**
+ * Adds any sub-Components contained in the <code>MetalTitlePane</code>.
+ */
+ private void installSubcomponents() {
+ int decorationStyle = getWindowDecorationStyle();
+ if (decorationStyle == JRootPane.FRAME) {
+ createActions();
+ menuBar = createMenuBar();
+ add(menuBar);
+ createButtons();
+ add(iconifyButton);
+ add(toggleButton);
+ add(closeButton);
+ } else if (decorationStyle == JRootPane.PLAIN_DIALOG ||
+ decorationStyle == JRootPane.INFORMATION_DIALOG ||
+ decorationStyle == JRootPane.ERROR_DIALOG ||
+ decorationStyle == JRootPane.COLOR_CHOOSER_DIALOG ||
+ decorationStyle == JRootPane.FILE_CHOOSER_DIALOG ||
+ decorationStyle == JRootPane.QUESTION_DIALOG ||
+ decorationStyle == JRootPane.WARNING_DIALOG) {
+ createActions();
+ createButtons();
+ add(closeButton);
+ }
+ }
+
+ /**
+ * Determines the Colors to draw with.
+ */
+ private void determineColors() {
+ switch (getWindowDecorationStyle()) {
+ case JRootPane.FRAME:
+ activeBackground = UIManager.getColor("activeCaption");
+ activeForeground = UIManager.getColor("activeCaptionText");
+ activeShadow = UIManager.getColor("activeCaptionBorder");
+ break;
+ case JRootPane.ERROR_DIALOG:
+ activeBackground = UIManager.getColor(
+ "OptionPane.errorDialog.titlePane.background");
+ activeForeground = UIManager.getColor(
+ "OptionPane.errorDialog.titlePane.foreground");
+ activeShadow = UIManager.getColor(
+ "OptionPane.errorDialog.titlePane.shadow");
+ break;
+ case JRootPane.QUESTION_DIALOG:
+ case JRootPane.COLOR_CHOOSER_DIALOG:
+ case JRootPane.FILE_CHOOSER_DIALOG:
+ activeBackground = UIManager.getColor(
+ "OptionPane.questionDialog.titlePane.background");
+ activeForeground = UIManager.getColor(
+ "OptionPane.questionDialog.titlePane.foreground");
+ activeShadow = UIManager.getColor(
+ "OptionPane.questionDialog.titlePane.shadow");
+ break;
+ case JRootPane.WARNING_DIALOG:
+ activeBackground = UIManager.getColor(
+ "OptionPane.warningDialog.titlePane.background");
+ activeForeground = UIManager.getColor(
+ "OptionPane.warningDialog.titlePane.foreground");
+ activeShadow = UIManager.getColor(
+ "OptionPane.warningDialog.titlePane.shadow");
+ break;
+ case JRootPane.PLAIN_DIALOG:
+ case JRootPane.INFORMATION_DIALOG:
+ default:
+ activeBackground = UIManager.getColor("activeCaption");
+ activeForeground = UIManager.getColor("activeCaptionText");
+ activeShadow = UIManager.getColor("activeCaptionBorder");
+ break;
+ }
+ activeBumps.setBumpColors(activeBumpsHighlight, activeBumpsShadow,
+ activeBackground);
+ }
+
+ /**
+ * Installs the fonts and necessary properties on the MetalTitlePane.
+ */
+ private void installDefaults() {
+ setFont(UIManager.getFont("InternalFrame.titleFont", getLocale()));
+ }
+
+ /**
+ * Uninstalls any previously installed UI values.
+ */
+ private void uninstallDefaults() {
+ }
+
+ /**
+ * Returns the <code>JMenuBar</code> displaying the appropriate
+ * system menu items.
+ */
+ protected JMenuBar createMenuBar() {
+ menuBar = new SystemMenuBar();
+ menuBar.setFocusable(false);
+ menuBar.setBorderPainted(true);
+ menuBar.add(createMenu());
+ return menuBar;
+ }
+
+ /**
+ * Closes the Window.
+ */
+ private void close() {
+ Window window = getWindow();
+
+ if (window != null) {
+ window.dispatchEvent(new WindowEvent(
+ window, WindowEvent.WINDOW_CLOSING));
+ }
+ }
+
+ /**
+ * Iconifies the Frame.
+ */
+ private void iconify() {
+ Frame frame = getFrame();
+ if (frame != null) {
+ frame.setExtendedState(state | Frame.ICONIFIED);
+ }
+ }
+
+ /**
+ * Maximizes the Frame.
+ */
+ private void maximize() {
+ Frame frame = getFrame();
+ if (frame != null) {
+ frame.setExtendedState(state | Frame.MAXIMIZED_BOTH);
+ }
+ }
+
+ /**
+ * Restores the Frame size.
+ */
+ private void restore() {
+ Frame frame = getFrame();
+
+ if (frame == null) {
+ return;
+ }
+
+ if ((state & Frame.ICONIFIED) != 0) {
+ frame.setExtendedState(state & ~Frame.ICONIFIED);
+ } else {
+ frame.setExtendedState(state & ~Frame.MAXIMIZED_BOTH);
+ }
+ }
+
+ /**
+ * Create the <code>Action</code>s that get associated with the
+ * buttons and menu items.
+ */
+ private void createActions() {
+ closeAction = new CloseAction();
+ if (getWindowDecorationStyle() == JRootPane.FRAME) {
+ iconifyAction = new IconifyAction();
+ restoreAction = new RestoreAction();
+ maximizeAction = new MaximizeAction();
+ }
+ }
+
+ /**
+ * Returns the <code>JMenu</code> displaying the appropriate menu items
+ * for manipulating the Frame.
+ */
+ private JMenu createMenu() {
+ JMenu menu = new JMenu("");
+ if (getWindowDecorationStyle() == JRootPane.FRAME) {
+ addMenuItems(menu);
+ }
+ return menu;
+ }
+
+ /**
+ * Adds the necessary <code>JMenuItem</code>s to the passed in menu.
+ */
+ private void addMenuItems(JMenu menu) {
+ Locale locale = getRootPane().getLocale();
+ JMenuItem mi = menu.add(restoreAction);
+ int mnemonic = MetalUtils.getInt("MetalTitlePane.restoreMnemonic", -1);
+
+ if (mnemonic != -1) {
+ mi.setMnemonic(mnemonic);
+ }
+
+ mi = menu.add(iconifyAction);
+ mnemonic = MetalUtils.getInt("MetalTitlePane.iconifyMnemonic", -1);
+ if (mnemonic != -1) {
+ mi.setMnemonic(mnemonic);
+ }
+
+ if (Toolkit.getDefaultToolkit().isFrameStateSupported(
+ Frame.MAXIMIZED_BOTH)) {
+ mi = menu.add(maximizeAction);
+ mnemonic =
+ MetalUtils.getInt("MetalTitlePane.maximizeMnemonic", -1);
+ if (mnemonic != -1) {
+ mi.setMnemonic(mnemonic);
+ }
+ }
+
+ menu.add(new JSeparator());
+
+ mi = menu.add(closeAction);
+ mnemonic = MetalUtils.getInt("MetalTitlePane.closeMnemonic", -1);
+ if (mnemonic != -1) {
+ mi.setMnemonic(mnemonic);
+ }
+ }
+
+ /**
+ * Returns a <code>JButton</code> appropriate for placement on the
+ * TitlePane.
+ */
+ private JButton createTitleButton() {
+ JButton button = new JButton();
+
+ button.setFocusPainted(false);
+ button.setFocusable(false);
+ button.setOpaque(true);
+ return button;
+ }
+
+ /**
+ * Creates the Buttons that will be placed on the TitlePane.
+ */
+ private void createButtons() {
+ closeButton = createTitleButton();
+ closeButton.setAction(closeAction);
+ closeButton.setText(null);
+ closeButton.putClientProperty("paintActive", Boolean.TRUE);
+ closeButton.setBorder(handyEmptyBorder);
+ closeButton.putClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY,
+ "Close");
+ closeButton.setIcon(UIManager.getIcon("InternalFrame.closeIcon"));
+
+ if (getWindowDecorationStyle() == JRootPane.FRAME) {
+ maximizeIcon = UIManager.getIcon("InternalFrame.maximizeIcon");
+ minimizeIcon = UIManager.getIcon("InternalFrame.minimizeIcon");
+
+ iconifyButton = createTitleButton();
+ iconifyButton.setAction(iconifyAction);
+ iconifyButton.setText(null);
+ iconifyButton.putClientProperty("paintActive", Boolean.TRUE);
+ iconifyButton.setBorder(handyEmptyBorder);
+ iconifyButton.putClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY,
+ "Iconify");
+ iconifyButton.setIcon(UIManager.getIcon("InternalFrame.iconifyIcon"));
+
+ toggleButton = createTitleButton();
+ toggleButton.setAction(restoreAction);
+ toggleButton.putClientProperty("paintActive", Boolean.TRUE);
+ toggleButton.setBorder(handyEmptyBorder);
+ toggleButton.putClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY,
+ "Maximize");
+ toggleButton.setIcon(maximizeIcon);
+ }
+ }
+
+ /**
+ * Returns the <code>LayoutManager</code> that should be installed on
+ * the <code>MetalTitlePane</code>.
+ */
+ private LayoutManager createLayout() {
+ return new TitlePaneLayout();
+ }
+
+ /**
+ * Updates state dependant upon the Window's active state.
+ */
+ private void setActive(boolean isActive) {
+ Boolean activeB = isActive ? Boolean.TRUE : Boolean.FALSE;
+
+ closeButton.putClientProperty("paintActive", activeB);
+ if (getWindowDecorationStyle() == JRootPane.FRAME) {
+ iconifyButton.putClientProperty("paintActive", activeB);
+ toggleButton.putClientProperty("paintActive", activeB);
+ }
+ // Repaint the whole thing as the Borders that are used have
+ // different colors for active vs inactive
+ getRootPane().repaint();
+ }
+
+ /**
+ * Sets the state of the Window.
+ */
+ private void setState(int state) {
+ setState(state, false);
+ }
+
+ /**
+ * Sets the state of the window. If <code>updateRegardless</code> is
+ * true and the state has not changed, this will update anyway.
+ */
+ private void setState(int state, boolean updateRegardless) {
+ Window w = getWindow();
+
+ if (w != null && getWindowDecorationStyle() == JRootPane.FRAME) {
+ if (this.state == state && !updateRegardless) {
+ return;
+ }
+ Frame frame = getFrame();
+
+ if (frame != null) {
+ JRootPane rootPane = getRootPane();
+
+ if (((state & Frame.MAXIMIZED_BOTH) != 0) &&
+ (rootPane.getBorder() == null ||
+ (rootPane.getBorder() instanceof UIResource)) &&
+ frame.isShowing()) {
+ rootPane.setBorder(null);
+ }
+ else if ((state & Frame.MAXIMIZED_BOTH) == 0) {
+ // This is a croak, if state becomes bound, this can
+ // be nuked.
+ rootPaneUI.installBorder(rootPane);
+ }
+ if (frame.isResizable()) {
+ if ((state & Frame.MAXIMIZED_BOTH) != 0) {
+ updateToggleButton(restoreAction, minimizeIcon);
+ maximizeAction.setEnabled(false);
+ restoreAction.setEnabled(true);
+ }
+ else {
+ updateToggleButton(maximizeAction, maximizeIcon);
+ maximizeAction.setEnabled(true);
+ restoreAction.setEnabled(false);
+ }
+ if (toggleButton.getParent() == null ||
+ iconifyButton.getParent() == null) {
+ add(toggleButton);
+ add(iconifyButton);
+ revalidate();
+ repaint();
+ }
+ toggleButton.setText(null);
+ }
+ else {
+ maximizeAction.setEnabled(false);
+ restoreAction.setEnabled(false);
+ if (toggleButton.getParent() != null) {
+ remove(toggleButton);
+ revalidate();
+ repaint();
+ }
+ }
+ }
+ else {
+ // Not contained in a Frame
+ maximizeAction.setEnabled(false);
+ restoreAction.setEnabled(false);
+ iconifyAction.setEnabled(false);
+ remove(toggleButton);
+ remove(iconifyButton);
+ revalidate();
+ repaint();
+ }
+ closeAction.setEnabled(true);
+ this.state = state;
+ }
+ }
+
+ /**
+ * Updates the toggle button to contain the Icon <code>icon</code>, and
+ * Action <code>action</code>.
+ */
+ private void updateToggleButton(Action action, Icon icon) {
+ toggleButton.setAction(action);
+ toggleButton.setIcon(icon);
+ toggleButton.setText(null);
+ }
+
+ /**
+ * Returns the Frame rendering in. This will return null if the
+ * <code>JRootPane</code> is not contained in a <code>Frame</code>.
+ */
+ private Frame getFrame() {
+ Window window = getWindow();
+
+ if (window instanceof Frame) {
+ return (Frame)window;
+ }
+ return null;
+ }
+
+ /**
+ * Returns the <code>Window</code> the <code>JRootPane</code> is
+ * contained in. This will return null if there is no parent ancestor
+ * of the <code>JRootPane</code>.
+ */
+ private Window getWindow() {
+ return window;
+ }
+
+ /**
+ * Returns the String to display as the title.
+ */
+ private String getTitle() {
+ Window w = getWindow();
+
+ if (w instanceof Frame) {
+ return ((Frame)w).getTitle();
+ }
+ else if (w instanceof Dialog) {
+ return ((Dialog)w).getTitle();
+ }
+ return null;
+ }
+
+ /**
+ * Renders the TitlePane.
+ */
+ public void paintComponent(Graphics g) {
+ // As state isn't bound, we need a convenience place to check
+ // if it has changed. Changing the state typically changes the
+ if (getFrame() != null) {
+ setState(getFrame().getExtendedState());
+ }
+ JRootPane rootPane = getRootPane();
+ Window window = getWindow();
+ boolean leftToRight = (window == null) ?
+ rootPane.getComponentOrientation().isLeftToRight() :
+ window.getComponentOrientation().isLeftToRight();
+ boolean isSelected = (window == null) ? true : window.isActive();
+ int width = getWidth();
+ int height = getHeight();
+
+ Color background;
+ Color foreground;
+ Color darkShadow;
+
+ MetalBumps bumps;
+
+ if (isSelected) {
+ background = activeBackground;
+ foreground = activeForeground;
+ darkShadow = activeShadow;
+ bumps = activeBumps;
+ } else {
+ background = inactiveBackground;
+ foreground = inactiveForeground;
+ darkShadow = inactiveShadow;
+ bumps = inactiveBumps;
+ }
+
+ g.setColor(background);
+ g.fillRect(0, 0, width, height);
+
+ g.setColor( darkShadow );
+ g.drawLine ( 0, height - 1, width, height -1);
+ g.drawLine ( 0, 0, 0 ,0);
+ g.drawLine ( width - 1, 0 , width -1, 0);
+
+ int xOffset = leftToRight ? 5 : width - 5;
+
+ if (getWindowDecorationStyle() == JRootPane.FRAME) {
+ xOffset += leftToRight ? IMAGE_WIDTH + 5 : - IMAGE_WIDTH - 5;
+ }
+
+ String theTitle = getTitle();
+ if (theTitle != null) {
+ FontMetrics fm = SwingUtilities2.getFontMetrics(rootPane, g);
+
+ g.setColor(foreground);
+
+ int yOffset = ( (height - fm.getHeight() ) / 2 ) + fm.getAscent();
+
+ Rectangle rect = new Rectangle(0, 0, 0, 0);
+ if (iconifyButton != null && iconifyButton.getParent() != null) {
+ rect = iconifyButton.getBounds();
+ }
+ int titleW;
+
+ if( leftToRight ) {
+ if (rect.x == 0) {
+ rect.x = window.getWidth() - window.getInsets().right-2;
+ }
+ titleW = rect.x - xOffset - 4;
+ theTitle = SwingUtilities2.clipStringIfNecessary(
+ rootPane, fm, theTitle, titleW);
+ } else {
+ titleW = xOffset - rect.x - rect.width - 4;
+ theTitle = SwingUtilities2.clipStringIfNecessary(
+ rootPane, fm, theTitle, titleW);
+ xOffset -= SwingUtilities2.stringWidth(rootPane, fm,
+ theTitle);
+ }
+ int titleLength = SwingUtilities2.stringWidth(rootPane, fm,
+ theTitle);
+ SwingUtilities2.drawString(rootPane, g, theTitle, xOffset,
+ yOffset );
+ xOffset += leftToRight ? titleLength + 5 : -5;
+ }
+
+ int bumpXOffset;
+ int bumpLength;
+ if( leftToRight ) {
+ bumpLength = width - buttonsWidth - xOffset - 5;
+ bumpXOffset = xOffset;
+ } else {
+ bumpLength = xOffset - buttonsWidth - 5;
+ bumpXOffset = buttonsWidth + 5;
+ }
+ int bumpYOffset = 3;
+ int bumpHeight = getHeight() - (2 * bumpYOffset);
+ bumps.setBumpArea( bumpLength, bumpHeight );
+ bumps.paintIcon(this, g, bumpXOffset, bumpYOffset);
+ }
+
+ /**
+ * Actions used to <code>close</code> the <code>Window</code>.
+ */
+ @SuppressWarnings("serial") // Superclass is not serializable across versions
+ private class CloseAction extends AbstractAction {
+ public CloseAction() {
+ super(UIManager.getString("MetalTitlePane.closeTitle",
+ getLocale()));
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ close();
+ }
+ }
+
+
+ /**
+ * Actions used to <code>iconfiy</code> the <code>Frame</code>.
+ */
+ @SuppressWarnings("serial") // Superclass is not serializable across versions
+ private class IconifyAction extends AbstractAction {
+ public IconifyAction() {
+ super(UIManager.getString("MetalTitlePane.iconifyTitle",
+ getLocale()));
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ iconify();
+ }
+ }
+
+
+ /**
+ * Actions used to <code>restore</code> the <code>Frame</code>.
+ */
+ @SuppressWarnings("serial") // Superclass is not serializable across versions
+ private class RestoreAction extends AbstractAction {
+ public RestoreAction() {
+ super(UIManager.getString
+ ("MetalTitlePane.restoreTitle", getLocale()));
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ restore();
+ }
+ }
+
+
+ /**
+ * Actions used to <code>restore</code> the <code>Frame</code>.
+ */
+ @SuppressWarnings("serial") // Superclass is not serializable across versions
+ private class MaximizeAction extends AbstractAction {
+ public MaximizeAction() {
+ super(UIManager.getString("MetalTitlePane.maximizeTitle",
+ getLocale()));
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ maximize();
+ }
+ }
+
+
+ /**
+ * Class responsible for drawing the system menu. Looks up the
+ * image to draw from the Frame associated with the
+ * <code>JRootPane</code>.
+ */
+ @SuppressWarnings("serial") // Superclass is not serializable across versions
+ private class SystemMenuBar extends JMenuBar {
+ public void paint(Graphics g) {
+ if (isOpaque()) {
+ g.setColor(getBackground());
+ g.fillRect(0, 0, getWidth(), getHeight());
+ }
+
+ if (systemIcon != null) {
+ g.drawImage(systemIcon, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, null);
+ } else {
+ Icon icon = UIManager.getIcon("InternalFrame.icon");
+
+ if (icon != null) {
+ icon.paintIcon(this, g, 0, 0);
+ }
+ }
+ }
+ public Dimension getMinimumSize() {
+ return getPreferredSize();
+ }
+ public Dimension getPreferredSize() {
+ Dimension size = super.getPreferredSize();
+
+ return new Dimension(Math.max(IMAGE_WIDTH, size.width),
+ Math.max(size.height, IMAGE_HEIGHT));
+ }
+ }
+
+ private class TitlePaneLayout implements LayoutManager {
+ public void addLayoutComponent(String name, Component c) {}
+ public void removeLayoutComponent(Component c) {}
+ public Dimension preferredLayoutSize(Container c) {
+ int height = computeHeight();
+ return new Dimension(height, height);
+ }
+
+ public Dimension minimumLayoutSize(Container c) {
+ return preferredLayoutSize(c);
+ }
+
+ private int computeHeight() {
+ FontMetrics fm = rootPane.getFontMetrics(getFont());
+ int fontHeight = fm.getHeight();
+ fontHeight += 7;
+ int iconHeight = 0;
+ if (getWindowDecorationStyle() == JRootPane.FRAME) {
+ iconHeight = IMAGE_HEIGHT;
+ }
+
+ int finalHeight = Math.max( fontHeight, iconHeight );
+ return finalHeight;
+ }
+
+ public void layoutContainer(Container c) {
+ boolean leftToRight = (window == null) ?
+ getRootPane().getComponentOrientation().isLeftToRight() :
+ window.getComponentOrientation().isLeftToRight();
+
+ int w = getWidth();
+ int x;
+ int y = 3;
+ int spacing;
+ int buttonHeight;
+ int buttonWidth;
+
+ if (closeButton != null && closeButton.getIcon() != null) {
+ buttonHeight = closeButton.getIcon().getIconHeight();
+ buttonWidth = closeButton.getIcon().getIconWidth();
+ }
+ else {
+ buttonHeight = IMAGE_HEIGHT;
+ buttonWidth = IMAGE_WIDTH;
+ }
+
+ // assumes all buttons have the same dimensions
+ // these dimensions include the borders
+
+ x = leftToRight ? w : 0;
+
+ spacing = 5;
+ x = leftToRight ? spacing : w - buttonWidth - spacing;
+ if (menuBar != null) {
+ menuBar.setBounds(x, y, buttonWidth, buttonHeight);
+ }
+
+ x = leftToRight ? w : 0;
+ spacing = 4;
+ x += leftToRight ? -spacing -buttonWidth : spacing;
+ if (closeButton != null) {
+ closeButton.setBounds(x, y, buttonWidth, buttonHeight);
+ }
+
+ if( !leftToRight ) x += buttonWidth;
+
+ if (getWindowDecorationStyle() == JRootPane.FRAME) {
+ if (Toolkit.getDefaultToolkit().isFrameStateSupported(
+ Frame.MAXIMIZED_BOTH)) {
+ if (toggleButton.getParent() != null) {
+ spacing = 10;
+ x += leftToRight ? -spacing -buttonWidth : spacing;
+ toggleButton.setBounds(x, y, buttonWidth, buttonHeight);
+ if (!leftToRight) {
+ x += buttonWidth;
+ }
+ }
+ }
+
+ if (iconifyButton != null && iconifyButton.getParent() != null) {
+ spacing = 2;
+ x += leftToRight ? -spacing -buttonWidth : spacing;
+ iconifyButton.setBounds(x, y, buttonWidth, buttonHeight);
+ if (!leftToRight) {
+ x += buttonWidth;
+ }
+ }
+ }
+ buttonsWidth = leftToRight ? w - x : x;
+ }
+ }
+
+
+
+ /**
+ * PropertyChangeListener installed on the Window. Updates the necessary
+ * state as the state of the Window changes.
+ */
+ private class PropertyChangeHandler implements PropertyChangeListener {
+ public void propertyChange(PropertyChangeEvent pce) {
+ String name = pce.getPropertyName();
+
+ // Frame.state isn't currently bound.
+ if ("resizable".equals(name) || "state".equals(name)) {
+ Frame frame = getFrame();
+
+ if (frame != null) {
+ setState(frame.getExtendedState(), true);
+ }
+ if ("resizable".equals(name)) {
+ getRootPane().repaint();
+ }
+ }
+ else if ("title".equals(name)) {
+ repaint();
+ }
+ else if ("componentOrientation" == name) {
+ revalidate();
+ repaint();
+ }
+ else if ("iconImage" == name) {
+ updateSystemIcon();
+ revalidate();
+ repaint();
+ }
+ }
+ }
+
+ /**
+ * Update the image used for the system icon
+ */
+ private void updateSystemIcon() {
+ Window window = getWindow();
+ if (window == null) {
+ systemIcon = null;
+ return;
+ }
+ java.util.List<Image> icons = window.getIconImages();
+ assert icons != null;
+
+ if (icons.size() == 0) {
+ systemIcon = null;
+ }
+ else if (icons.size() == 1) {
+ systemIcon = icons.get(0);
+ }
+ else {
+ systemIcon = SunToolkit.getScaledIconImage(icons,
+ IMAGE_WIDTH,
+ IMAGE_HEIGHT);
+ }
+ }
+
+
+ /**
+ * WindowListener installed on the Window, updates the state as necessary.
+ */
+ private class WindowHandler extends WindowAdapter {
+ public void windowActivated(WindowEvent ev) {
+ setActive(true);
+ }
+
+ public void windowDeactivated(WindowEvent ev) {
+ setActive(false);
+ }
+ }
+}