| /* | |
| * 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 dependent 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 ? menuBar.getWidth() + 5 : - menuBar.getWidth() - 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); | |
| } | |
| } | |
| } |