0001: package org.underworldlabs.swing.plaf.bumpygradient;
0002:
0003: import java.awt.Color;
0004: import java.awt.Component;
0005: import java.awt.Container;
0006: import java.awt.Dialog;
0007: import java.awt.Dimension;
0008: import java.awt.Font;
0009: import java.awt.FontMetrics;
0010: import java.awt.Frame;
0011: import java.awt.Graphics;
0012: import java.awt.Image;
0013: import java.awt.LayoutManager;
0014: import java.awt.Rectangle;
0015: import java.awt.Toolkit;
0016: import java.awt.Window;
0017: import java.awt.event.ActionEvent;
0018: import java.awt.event.WindowAdapter;
0019: import java.awt.event.WindowEvent;
0020: import java.awt.event.WindowListener;
0021:
0022: import java.beans.PropertyChangeEvent;
0023: import java.beans.PropertyChangeListener;
0024:
0025: import java.util.Locale;
0026:
0027: import javax.swing.AbstractAction;
0028: import javax.swing.Action;
0029: import javax.swing.Icon;
0030: import javax.swing.JButton;
0031: import javax.swing.JComponent;
0032: import javax.swing.JMenu;
0033: import javax.swing.JMenuBar;
0034: import javax.swing.JMenuItem;
0035: import javax.swing.JRootPane;
0036: import javax.swing.JSeparator;
0037: import javax.swing.SwingUtilities;
0038: import javax.swing.UIManager;
0039: import javax.swing.border.Border;
0040: import javax.swing.border.EmptyBorder;
0041: import javax.swing.plaf.UIResource;
0042: import org.underworldlabs.swing.plaf.smoothgradient.SmoothGradientUtils;
0043:
0044: /*
0045: * BumpyGradientTitlePane.java
0046: *
0047: * Copyright (C) 2002, 2003, 2004, 2005, 2006 Takis Diakoumis
0048: *
0049: * This program is free software; you can redistribute it and/or
0050: * modify it under the terms of the GNU General Public License
0051: * as published by the Free Software Foundation; either version 2
0052: * of the License, or any later version.
0053: *
0054: * This program is distributed in the hope that it will be useful,
0055: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0056: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0057: * GNU General Public License for more details.
0058: *
0059: * You should have received a copy of the GNU General Public License
0060: * along with this program; if not, write to the Free Software
0061: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
0062: *
0063: */
0064:
0065: /**
0066: *
0067: * @author Takis Diakoumis
0068: * @version $Revision: 1.4 $
0069: * @date $Date: 2006/05/14 06:56:07 $
0070: */
0071: class BumpyGradientTitlePane extends JComponent {
0072:
0073: private static final Border handyEmptyBorder = new EmptyBorder(0,
0074: 0, 0, 0);
0075: private static final int IMAGE_HEIGHT = 16;
0076: private static final int IMAGE_WIDTH = 16;
0077:
0078: /**
0079: * PropertyChangeListener added to the JRootPane.
0080: */
0081: private PropertyChangeListener propertyChangeListener;
0082:
0083: /**
0084: * JMenuBar, typically renders the system menu items.
0085: */
0086: private JMenuBar menuBar;
0087: /**
0088: * Action used to close the Window.
0089: */
0090: private Action closeAction;
0091:
0092: /**
0093: * Action used to iconify the Frame.
0094: */
0095: private Action iconifyAction;
0096:
0097: /**
0098: * Action to restore the Frame size.
0099: */
0100: private Action restoreAction;
0101:
0102: /**
0103: * Action to restore the Frame size.
0104: */
0105: private Action maximizeAction;
0106:
0107: /**
0108: * Button used to maximize or restore the Frame.
0109: */
0110: private JButton toggleButton;
0111:
0112: /**
0113: * Button used to maximize or restore the Frame.
0114: */
0115: private JButton iconifyButton;
0116:
0117: /**
0118: * Button used to maximize or restore the Frame.
0119: */
0120: private JButton closeButton;
0121:
0122: /**
0123: * Icon used for toggleButton when window is normal size.
0124: */
0125: private Icon maximizeIcon;
0126:
0127: /**
0128: * Icon used for toggleButton when window is maximized.
0129: */
0130: private Icon minimizeIcon;
0131:
0132: /**
0133: * Listens for changes in the state of the Window listener to update
0134: * the state of the widgets.
0135: */
0136: private WindowListener windowListener;
0137:
0138: /**
0139: * Window we're currently in.
0140: */
0141: private Window window;
0142:
0143: /**
0144: * JRootPane rendering for.
0145: */
0146: private JRootPane rootPane;
0147:
0148: /**
0149: * Room remaining in title for bumps.
0150: */
0151: private int buttonsWidth;
0152:
0153: /**
0154: * Buffered Frame.state property. As state isn't bound, this is kept
0155: * to determine when to avoid updating widgets.
0156: */
0157: private int state;
0158:
0159: /**
0160: * MetalRootPaneUI that created us.
0161: */
0162: private BumpyGradientRootPaneUI rootPaneUI;
0163:
0164: // Colors
0165: private Color inactiveBackground = UIManager
0166: .getColor("inactiveCaption");
0167: private Color inactiveForeground = UIManager
0168: .getColor("inactiveCaptionText");
0169: private Color inactiveShadow = UIManager
0170: .getColor("inactiveCaptionBorder");
0171: private Color activeBumpsHighlight = BumpyGradientLookAndFeel
0172: .getInternalFrameBumpsHighlight();
0173: private Color activeBumpsShadow = BumpyGradientLookAndFeel
0174: .getPrimaryControlDarkShadow();
0175: private Color activeBackground = null;
0176: private Color activeForeground = null;
0177: private Color activeShadow = null;
0178:
0179: // Bumps
0180: private final BumpyGradientBumps activeBumps = new BumpyGradientBumps(
0181: 0, 0, BumpyGradientLookAndFeel
0182: .getInternalFrameBumpsHighlight(),
0183: BumpyGradientLookAndFeel.getPrimaryControlDarkShadow(),
0184: BumpyGradientLookAndFeel.getPrimaryControl());
0185:
0186: private final BumpyGradientBumps inactiveBumps = new BumpyGradientBumps(
0187: 0, 0, BumpyGradientLookAndFeel.getControlHighlight(),
0188: BumpyGradientLookAndFeel.getControlDarkShadow(),
0189: BumpyGradientLookAndFeel.getControl());
0190:
0191: public BumpyGradientTitlePane(JRootPane root,
0192: BumpyGradientRootPaneUI ui) {
0193: this .rootPane = root;
0194: rootPaneUI = ui;
0195:
0196: state = -1;
0197:
0198: installSubcomponents();
0199: determineColors();
0200: installDefaults();
0201:
0202: setLayout(createLayout());
0203: }
0204:
0205: /**
0206: * Uninstalls the necessary state.
0207: */
0208: private void uninstall() {
0209: uninstallListeners();
0210: window = null;
0211: removeAll();
0212: }
0213:
0214: /**
0215: * Installs the necessary listeners.
0216: */
0217: private void installListeners() {
0218: if (window != null) {
0219: windowListener = createWindowListener();
0220: window.addWindowListener(windowListener);
0221: propertyChangeListener = createWindowPropertyChangeListener();
0222: window.addPropertyChangeListener(propertyChangeListener);
0223: }
0224: }
0225:
0226: /**
0227: * Uninstalls the necessary listeners.
0228: */
0229: private void uninstallListeners() {
0230: if (window != null) {
0231: window.removeWindowListener(windowListener);
0232: window.removePropertyChangeListener(propertyChangeListener);
0233: }
0234: }
0235:
0236: /**
0237: * Returns the <code>WindowListener</code> to add to the
0238: * <code>Window</code>.
0239: */
0240: private WindowListener createWindowListener() {
0241: return new WindowHandler();
0242: }
0243:
0244: /**
0245: * Returns the <code>PropertyChangeListener</code> to install on
0246: * the <code>Window</code>.
0247: */
0248: private PropertyChangeListener createWindowPropertyChangeListener() {
0249: return new PropertyChangeHandler();
0250: }
0251:
0252: /**
0253: * Returns the <code>JRootPane</code> this was created for.
0254: */
0255: public JRootPane getRootPane() {
0256: return rootPane;
0257: }
0258:
0259: /**
0260: * Returns the decoration style of the <code>JRootPane</code>.
0261: */
0262: private int getWindowDecorationStyle() {
0263: return getRootPane().getWindowDecorationStyle();
0264: }
0265:
0266: public void addNotify() {
0267: super .addNotify();
0268:
0269: uninstallListeners();
0270:
0271: window = SwingUtilities.getWindowAncestor(this );
0272: if (window != null) {
0273: if (window instanceof Frame) {
0274: setState(((Frame) window).getExtendedState());
0275: } else {
0276: setState(0);
0277: }
0278: setActive(window.isActive());
0279: installListeners();
0280: }
0281: }
0282:
0283: public void removeNotify() {
0284: super .removeNotify();
0285:
0286: uninstallListeners();
0287: window = null;
0288: }
0289:
0290: /**
0291: * Adds any sub-Components contained in the <code>MetalTitlePane</code>.
0292: */
0293: private void installSubcomponents() {
0294: if (getWindowDecorationStyle() == JRootPane.FRAME) {
0295: createActions();
0296: menuBar = createMenuBar();
0297: add(menuBar);
0298: createButtons();
0299: add(iconifyButton);
0300: add(toggleButton);
0301: add(closeButton);
0302: }
0303: }
0304:
0305: /**
0306: * Determines the Colors to draw with.
0307: */
0308: private void determineColors() {
0309:
0310: Color _activeBumpsHighlight = activeBumpsHighlight;
0311:
0312: switch (getWindowDecorationStyle()) {
0313: case JRootPane.FRAME:
0314: activeBackground = UIManager.getColor("activeCaption");
0315: activeForeground = UIManager.getColor("activeCaptionText");
0316: activeShadow = UIManager.getColor("activeCaptionBorder");
0317: break;
0318: case JRootPane.ERROR_DIALOG:
0319: activeBackground = UIManager
0320: .getColor("OptionPane.errorDialog.titlePane.background");
0321: activeForeground = UIManager
0322: .getColor("OptionPane.errorDialog.titlePane.foreground");
0323: activeShadow = UIManager
0324: .getColor("OptionPane.errorDialog.titlePane.shadow");
0325: break;
0326: case JRootPane.QUESTION_DIALOG:
0327: case JRootPane.COLOR_CHOOSER_DIALOG:
0328: case JRootPane.FILE_CHOOSER_DIALOG:
0329: activeBackground = UIManager
0330: .getColor("OptionPane.questionDialog.titlePane.background");
0331: activeForeground = UIManager
0332: .getColor("OptionPane.questionDialog.titlePane.foreground");
0333: activeShadow = UIManager
0334: .getColor("OptionPane.questionDialog.titlePane.shadow");
0335: break;
0336: case JRootPane.WARNING_DIALOG:
0337: activeBackground = UIManager
0338: .getColor("OptionPane.warningDialog.titlePane.background");
0339: activeForeground = UIManager
0340: .getColor("OptionPane.warningDialog.titlePane.foreground");
0341: activeShadow = UIManager
0342: .getColor("OptionPane.warningDialog.titlePane.shadow");
0343: break;
0344: case JRootPane.PLAIN_DIALOG:
0345: case JRootPane.INFORMATION_DIALOG:
0346: default:
0347: _activeBumpsHighlight = BumpyGradientLookAndFeel
0348: .getInternalFrameBumpsHighlight();
0349: activeBackground = UIManager.getColor("activeCaption");
0350: activeForeground = UIManager.getColor("activeCaptionText");
0351: activeShadow = UIManager.getColor("activeCaptionBorder");
0352: break;
0353: }
0354: activeBumps.setBumpColors(_activeBumpsHighlight,
0355: activeBumpsShadow, activeBackground);
0356: }
0357:
0358: /**
0359: * Installs the fonts and necessary properties on the MetalTitlePane.
0360: */
0361: private void installDefaults() {
0362: setFont(UIManager.getFont("InternalFrame.titleFont",
0363: getLocale()));
0364: }
0365:
0366: /**
0367: * Uninstalls any previously installed UI values.
0368: */
0369: private void uninstallDefaults() {
0370: }
0371:
0372: /**
0373: * Returns the <code>JMenuBar</code> displaying the appropriate
0374: * system menu items.
0375: */
0376: protected JMenuBar createMenuBar() {
0377: menuBar = new SystemMenuBar();
0378: menuBar.setFocusable(false);
0379: menuBar.setBorderPainted(true);
0380: menuBar.add(createMenu());
0381: return menuBar;
0382: }
0383:
0384: /**
0385: * Closes the Window.
0386: */
0387: private void close() {
0388: Window window = getWindow();
0389:
0390: if (window != null) {
0391: window.dispatchEvent(new WindowEvent(window,
0392: WindowEvent.WINDOW_CLOSING));
0393: }
0394: }
0395:
0396: /**
0397: * Iconifies the Frame.
0398: */
0399: private void iconify() {
0400: Frame frame = getFrame();
0401: if (frame != null) {
0402: frame.setExtendedState(state | Frame.ICONIFIED);
0403: }
0404: }
0405:
0406: /**
0407: * Maximizes the Frame.
0408: */
0409: private void maximize() {
0410: Frame frame = getFrame();
0411: if (frame != null) {
0412: frame.setExtendedState(state | Frame.MAXIMIZED_BOTH);
0413: }
0414: }
0415:
0416: /**
0417: * Restores the Frame size.
0418: */
0419: private void restore() {
0420: Frame frame = getFrame();
0421:
0422: if (frame == null) {
0423: return;
0424: }
0425:
0426: if ((state & Frame.ICONIFIED) != 0) {
0427: frame.setExtendedState(state & ~Frame.ICONIFIED);
0428: } else {
0429: frame.setExtendedState(state & ~Frame.MAXIMIZED_BOTH);
0430: }
0431: }
0432:
0433: /**
0434: * Create the <code>Action</code>s that get associated with the
0435: * buttons and menu items.
0436: */
0437: private void createActions() {
0438: closeAction = new CloseAction();
0439: iconifyAction = new IconifyAction();
0440: restoreAction = new RestoreAction();
0441: maximizeAction = new MaximizeAction();
0442: }
0443:
0444: /**
0445: * Returns the <code>JMenu</code> displaying the appropriate menu items
0446: * for manipulating the Frame.
0447: */
0448: private JMenu createMenu() {
0449: JMenu menu = new JMenu("");
0450: if (getWindowDecorationStyle() == JRootPane.FRAME) {
0451: addMenuItems(menu);
0452: }
0453: return menu;
0454: }
0455:
0456: /**
0457: * Adds the necessary <code>JMenuItem</code>s to the passed in menu.
0458: */
0459: private void addMenuItems(JMenu menu) {
0460: Locale locale = getRootPane().getLocale();
0461: JMenuItem mi = menu.add(restoreAction);
0462: int mnemonic = SmoothGradientUtils.getInt(
0463: "MetalTitlePane.restoreMnemonic", -1);
0464:
0465: if (mnemonic != -1) {
0466: mi.setMnemonic(mnemonic);
0467: }
0468:
0469: mi = menu.add(iconifyAction);
0470: mnemonic = SmoothGradientUtils.getInt(
0471: "MetalTitlePane.iconifyMnemonic", -1);
0472: if (mnemonic != -1) {
0473: mi.setMnemonic(mnemonic);
0474: }
0475:
0476: if (Toolkit.getDefaultToolkit().isFrameStateSupported(
0477: Frame.MAXIMIZED_BOTH)) {
0478: mi = menu.add(maximizeAction);
0479: mnemonic = SmoothGradientUtils.getInt(
0480: "MetalTitlePane.maximizeMnemonic", -1);
0481: if (mnemonic != -1) {
0482: mi.setMnemonic(mnemonic);
0483: }
0484: }
0485:
0486: menu.add(new JSeparator());
0487:
0488: mi = menu.add(closeAction);
0489: mnemonic = SmoothGradientUtils.getInt(
0490: "MetalTitlePane.closeMnemonic", -1);
0491: if (mnemonic != -1) {
0492: mi.setMnemonic(mnemonic);
0493: }
0494: }
0495:
0496: /**
0497: * Returns a <code>JButton</code> appropriate for placement on the
0498: * TitlePane.
0499: */
0500: private JButton createTitleButton() {
0501: JButton button = new JButton();
0502:
0503: button.setFocusPainted(false);
0504: button.setFocusable(false);
0505: button.setOpaque(true);
0506: return button;
0507: }
0508:
0509: /**
0510: * Creates the Buttons that will be placed on the TitlePane.
0511: */
0512: private void createButtons() {
0513: maximizeIcon = UIManager.getIcon("InternalFrame.maximizeIcon");
0514: minimizeIcon = UIManager.getIcon("InternalFrame.minimizeIcon");
0515:
0516: closeButton = createTitleButton();
0517: closeButton.setAction(closeAction);
0518: closeButton.setText(null);
0519: closeButton.putClientProperty("paintActive", Boolean.TRUE);
0520: closeButton.setBorder(handyEmptyBorder);
0521: closeButton.getAccessibleContext().setAccessibleName("Close");
0522: closeButton.setIcon(UIManager
0523: .getIcon("InternalFrame.closeIcon"));
0524:
0525: iconifyButton = createTitleButton();
0526: iconifyButton.setAction(iconifyAction);
0527: iconifyButton.setText(null);
0528: iconifyButton.putClientProperty("paintActive", Boolean.TRUE);
0529: iconifyButton.setBorder(handyEmptyBorder);
0530: iconifyButton.getAccessibleContext().setAccessibleName(
0531: "Iconify");
0532: iconifyButton.setIcon(UIManager
0533: .getIcon("InternalFrame.iconifyIcon"));
0534:
0535: toggleButton = createTitleButton();
0536: toggleButton.setAction(restoreAction);
0537: toggleButton.putClientProperty("paintActive", Boolean.TRUE);
0538: toggleButton.setBorder(handyEmptyBorder);
0539: toggleButton.getAccessibleContext().setAccessibleName(
0540: "Maximize");
0541: toggleButton.setIcon(maximizeIcon);
0542: }
0543:
0544: /**
0545: * Returns the <code>LayoutManager</code> that should be installed on
0546: * the <code>MetalTitlePane</code>.
0547: */
0548: private LayoutManager createLayout() {
0549: return new TitlePaneLayout();
0550: }
0551:
0552: /**
0553: * Updates state dependant upon the Window's active state.
0554: */
0555: private void setActive(boolean isActive) {
0556: if (getWindowDecorationStyle() == JRootPane.FRAME) {
0557: Boolean activeB = isActive ? Boolean.TRUE : Boolean.FALSE;
0558:
0559: iconifyButton.putClientProperty("paintActive", activeB);
0560: closeButton.putClientProperty("paintActive", activeB);
0561: toggleButton.putClientProperty("paintActive", activeB);
0562: }
0563: // Repaint the whole thing as the Borders that are used have
0564: // different colors for active vs inactive
0565: getRootPane().repaint();
0566: }
0567:
0568: /**
0569: * Sets the state of the Window.
0570: */
0571: private void setState(int state) {
0572: setState(state, false);
0573: }
0574:
0575: /**
0576: * Sets the state of the window. If <code>updateRegardless</code> is
0577: * true and the state has not changed, this will update anyway.
0578: */
0579: private void setState(int state, boolean updateRegardless) {
0580: Window w = getWindow();
0581:
0582: if (w != null && getWindowDecorationStyle() == JRootPane.FRAME) {
0583: if (this .state == state && !updateRegardless) {
0584: return;
0585: }
0586: Frame frame = getFrame();
0587:
0588: if (frame != null) {
0589: JRootPane rootPane = getRootPane();
0590:
0591: if (((state & Frame.MAXIMIZED_BOTH) != 0)
0592: && (rootPane.getBorder() == null || (rootPane
0593: .getBorder() instanceof UIResource))
0594: && frame.isShowing()) {
0595: rootPane.setBorder(null);
0596: } else if ((state & Frame.MAXIMIZED_BOTH) == 0) {
0597: // This is a croak, if state becomes bound, this can
0598: // be nuked.
0599: // rootPaneUI.installBorder(rootPane);
0600: }
0601: if (frame.isResizable()) {
0602: if ((state & Frame.MAXIMIZED_BOTH) != 0) {
0603: updateToggleButton(restoreAction, minimizeIcon);
0604: maximizeAction.setEnabled(false);
0605: restoreAction.setEnabled(true);
0606: } else {
0607: updateToggleButton(maximizeAction, maximizeIcon);
0608: maximizeAction.setEnabled(true);
0609: restoreAction.setEnabled(false);
0610: }
0611: if (toggleButton.getParent() == null
0612: || iconifyButton.getParent() == null) {
0613: add(toggleButton);
0614: add(iconifyButton);
0615: revalidate();
0616: repaint();
0617: }
0618: toggleButton.setText(null);
0619: } else {
0620: maximizeAction.setEnabled(false);
0621: restoreAction.setEnabled(false);
0622: if (toggleButton.getParent() != null) {
0623: remove(toggleButton);
0624: revalidate();
0625: repaint();
0626: }
0627: }
0628: } else {
0629: // Not contained in a Frame
0630: maximizeAction.setEnabled(false);
0631: restoreAction.setEnabled(false);
0632: iconifyAction.setEnabled(false);
0633: remove(toggleButton);
0634: remove(iconifyButton);
0635: revalidate();
0636: repaint();
0637: }
0638: closeAction.setEnabled(true);
0639: this .state = state;
0640: }
0641: }
0642:
0643: /**
0644: * Updates the toggle button to contain the Icon <code>icon</code>, and
0645: * Action <code>action</code>.
0646: */
0647: private void updateToggleButton(Action action, Icon icon) {
0648: toggleButton.setAction(action);
0649: toggleButton.setIcon(icon);
0650: toggleButton.setText(null);
0651: }
0652:
0653: /**
0654: * Returns the Frame rendering in. This will return null if the
0655: * <code>JRootPane</code> is not contained in a <code>Frame</code>.
0656: */
0657: private Frame getFrame() {
0658: Window window = getWindow();
0659:
0660: if (window instanceof Frame) {
0661: return (Frame) window;
0662: }
0663: return null;
0664: }
0665:
0666: /**
0667: * Returns the <code>Window</code> the <code>JRootPane</code> is
0668: * contained in. This will return null if there is no parent ancestor
0669: * of the <code>JRootPane</code>.
0670: */
0671: private Window getWindow() {
0672: return window;
0673: }
0674:
0675: /**
0676: * Returns the String to display as the title.
0677: */
0678: private String getTitle() {
0679: Window w = getWindow();
0680:
0681: if (w instanceof Frame) {
0682: return ((Frame) w).getTitle();
0683: } else if (w instanceof Dialog) {
0684: return ((Dialog) w).getTitle();
0685: }
0686: return null;
0687: }
0688:
0689: /**
0690: * Renders the TitlePane.
0691: */
0692: public void paintComponent(Graphics g) {
0693: // As state isn't bound, we need a convenience place to check
0694: // if it has changed. Changing the state typically changes the
0695: if (getFrame() != null) {
0696: setState(getFrame().getExtendedState());
0697: }
0698: Window window = getWindow();
0699: boolean leftToRight = (window == null) ? getRootPane()
0700: .getComponentOrientation().isLeftToRight() : window
0701: .getComponentOrientation().isLeftToRight();
0702: boolean isSelected = (window == null) ? true : window
0703: .isActive();
0704: int width = getWidth();
0705: int height = getHeight();
0706:
0707: Color background;
0708: Color foreground;
0709: Color darkShadow;
0710:
0711: BumpyGradientBumps bumps;
0712:
0713: if (isSelected) {
0714: background = activeBackground;
0715: foreground = activeForeground;
0716: darkShadow = activeShadow;
0717: bumps = activeBumps;
0718: } else {
0719: background = inactiveBackground;
0720: foreground = inactiveForeground;
0721: darkShadow = inactiveShadow;
0722: bumps = inactiveBumps;
0723: }
0724:
0725: g.setColor(background);
0726: g.fillRect(0, 0, width, height);
0727:
0728: g.setColor(darkShadow);
0729: g.drawLine(0, height - 1, width, height - 1);
0730: g.drawLine(0, 0, 0, 0);
0731: g.drawLine(width - 1, 0, width - 1, 0);
0732:
0733: int xOffset = leftToRight ? 5 : width - 5;
0734:
0735: if (getWindowDecorationStyle() == JRootPane.FRAME) {
0736: xOffset += leftToRight ? IMAGE_WIDTH + 5 : -IMAGE_WIDTH - 5;
0737: }
0738:
0739: String theTitle = getTitle();
0740: if (theTitle != null) {
0741: Font f = getFont();
0742: FontMetrics fm = g.getFontMetrics();
0743:
0744: g.setColor(foreground);
0745:
0746: int yOffset = ((height - fm.getHeight()) / 2)
0747: + fm.getAscent();
0748:
0749: Rectangle rect = new Rectangle(0, 0, 0, 0);
0750: if (iconifyButton != null
0751: && iconifyButton.getParent() != null) {
0752: rect = iconifyButton.getBounds();
0753: }
0754: int titleW;
0755:
0756: if (leftToRight) {
0757: if (rect.x == 0) {
0758: rect.x = window.getWidth()
0759: - window.getInsets().right - 2;
0760: }
0761: titleW = rect.x - xOffset - 4;
0762: theTitle = clippedText(theTitle, fm, titleW);
0763: } else {
0764: titleW = xOffset - rect.x - rect.width - 4;
0765: theTitle = clippedText(theTitle, fm, titleW);
0766: xOffset -= SwingUtilities.computeStringWidth(fm,
0767: theTitle);
0768: }
0769: int titleLength = SwingUtilities.computeStringWidth(fm,
0770: theTitle);
0771: g.drawString(theTitle, xOffset, yOffset);
0772: xOffset += leftToRight ? titleLength + 5 : -5;
0773: }
0774:
0775: int bumpXOffset;
0776: int bumpLength;
0777: if (leftToRight) {
0778: bumpLength = width - buttonsWidth - xOffset - 5;
0779: bumpXOffset = xOffset;
0780: } else {
0781: bumpLength = xOffset - buttonsWidth - 5;
0782: bumpXOffset = buttonsWidth + 5;
0783: }
0784: int bumpYOffset = 3;
0785: int bumpHeight = getHeight() - (2 * bumpYOffset);
0786: bumps.setBumpArea(bumpLength, bumpHeight);
0787: bumps.paintIcon(this , g, bumpXOffset, bumpYOffset);
0788:
0789: Rectangle r = new Rectangle(1, 0, width, height);
0790: SmoothGradientUtils.addLight3DEffekt(g, r, true);
0791:
0792: }
0793:
0794: /**
0795: * Convenience method to clip the passed in text to the specified
0796: * size.
0797: */
0798: private String clippedText(String text, FontMetrics fm,
0799: int availTextWidth) {
0800: if ((text == null) || (text.equals(""))) {
0801: return "";
0802: }
0803: int textWidth = SwingUtilities.computeStringWidth(fm, text);
0804: String clipString = "...";
0805: if (textWidth > availTextWidth) {
0806: int totalWidth = SwingUtilities.computeStringWidth(fm,
0807: clipString);
0808: int nChars;
0809: for (nChars = 0; nChars < text.length(); nChars++) {
0810: totalWidth += fm.charWidth(text.charAt(nChars));
0811: if (totalWidth > availTextWidth) {
0812: break;
0813: }
0814: }
0815: text = text.substring(0, nChars) + clipString;
0816: }
0817: return text;
0818: }
0819:
0820: /**
0821: * Actions used to <code>close</code> the <code>Window</code>.
0822: */
0823: private class CloseAction extends AbstractAction {
0824: public CloseAction() {
0825: super (UIManager.getString("MetalTitlePane.closeTitle",
0826: getLocale()));
0827: }
0828:
0829: public void actionPerformed(ActionEvent e) {
0830: close();
0831: }
0832: }
0833:
0834: /**
0835: * Actions used to <code>iconfiy</code> the <code>Frame</code>.
0836: */
0837: private class IconifyAction extends AbstractAction {
0838: public IconifyAction() {
0839: super (UIManager.getString("MetalTitlePane.iconifyTitle",
0840: getLocale()));
0841: }
0842:
0843: public void actionPerformed(ActionEvent e) {
0844: iconify();
0845: }
0846: }
0847:
0848: /**
0849: * Actions used to <code>restore</code> the <code>Frame</code>.
0850: */
0851: private class RestoreAction extends AbstractAction {
0852: public RestoreAction() {
0853: super (UIManager.getString("MetalTitlePane.restoreTitle",
0854: getLocale()));
0855: }
0856:
0857: public void actionPerformed(ActionEvent e) {
0858: restore();
0859: }
0860: }
0861:
0862: /**
0863: * Actions used to <code>restore</code> the <code>Frame</code>.
0864: */
0865: private class MaximizeAction extends AbstractAction {
0866: public MaximizeAction() {
0867: super (UIManager.getString("MetalTitlePane.maximizeTitle",
0868: getLocale()));
0869: }
0870:
0871: public void actionPerformed(ActionEvent e) {
0872: maximize();
0873: }
0874: }
0875:
0876: /**
0877: * Class responsible for drawing the system menu. Looks up the
0878: * image to draw from the Frame associated with the
0879: * <code>JRootPane</code>.
0880: */
0881: private class SystemMenuBar extends JMenuBar {
0882: public void paint(Graphics g) {
0883: Frame frame = getFrame();
0884:
0885: if (isOpaque()) {
0886: g.setColor(getBackground());
0887: g.fillRect(0, 0, getWidth(), getHeight());
0888: }
0889: Image image = (frame != null) ? frame.getIconImage() : null;
0890:
0891: if (image != null) {
0892: g.drawImage(image, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT,
0893: null);
0894: } else {
0895: Icon icon = UIManager.getIcon("InternalFrame.icon");
0896:
0897: if (icon != null) {
0898: icon.paintIcon(this , g, 0, 0);
0899: }
0900: }
0901: }
0902:
0903: public Dimension getMinimumSize() {
0904: return getPreferredSize();
0905: }
0906:
0907: public Dimension getPreferredSize() {
0908: Dimension size = super .getPreferredSize();
0909:
0910: return new Dimension(Math.max(IMAGE_WIDTH, size.width),
0911: Math.max(size.height, IMAGE_HEIGHT));
0912: }
0913: }
0914:
0915: /**
0916: * This inner class is marked "public" due to a compiler bug.
0917: * This class should be treated as a "protected" inner class.
0918: * Instantiate it only within subclasses of <Foo>.
0919: */
0920: private class TitlePaneLayout implements LayoutManager {
0921: public void addLayoutComponent(String name, Component c) {
0922: }
0923:
0924: public void removeLayoutComponent(Component c) {
0925: }
0926:
0927: public Dimension preferredLayoutSize(Container c) {
0928: int height = computeHeight();
0929: return new Dimension(height, height);
0930: }
0931:
0932: public Dimension minimumLayoutSize(Container c) {
0933: return preferredLayoutSize(c);
0934: }
0935:
0936: private int computeHeight() {
0937:
0938: FontMetrics fm = getFontMetrics(getFont());
0939: // = Toolkit.getDefaultToolkit().getFontMetrics(getFont());
0940: int fontHeight = fm.getHeight();
0941: fontHeight += 7;
0942: int iconHeight = 0;
0943: if (getWindowDecorationStyle() == JRootPane.FRAME) {
0944: iconHeight = IMAGE_HEIGHT;
0945: }
0946:
0947: int finalHeight = Math.max(fontHeight, iconHeight);
0948: return finalHeight;
0949: }
0950:
0951: public void layoutContainer(Container c) {
0952: if (getWindowDecorationStyle() != JRootPane.FRAME) {
0953: buttonsWidth = 0;
0954: return;
0955: }
0956: boolean leftToRight = (window == null) ? getRootPane()
0957: .getComponentOrientation().isLeftToRight() : window
0958: .getComponentOrientation().isLeftToRight();
0959:
0960: int w = getWidth();
0961: int x;
0962: int y = 3;
0963: int spacing;
0964: int buttonHeight;
0965: int buttonWidth;
0966:
0967: if (closeButton != null && closeButton.getIcon() != null) {
0968: buttonHeight = closeButton.getIcon().getIconHeight();
0969: buttonWidth = closeButton.getIcon().getIconWidth();
0970: } else {
0971: buttonHeight = IMAGE_HEIGHT;
0972: buttonWidth = IMAGE_WIDTH;
0973: }
0974:
0975: // assumes all buttons have the same dimensions
0976: // these dimensions include the borders
0977:
0978: x = leftToRight ? w : 0;
0979:
0980: spacing = 5;
0981: x = leftToRight ? spacing : w - buttonWidth - spacing;
0982: menuBar.setBounds(x, y, buttonWidth, buttonHeight);
0983:
0984: x = leftToRight ? w : 0;
0985: spacing = 4;
0986: x += leftToRight ? -spacing - buttonWidth : spacing;
0987: if (closeButton != null) {
0988: closeButton.setBounds(x, y, buttonWidth, buttonHeight);
0989: }
0990:
0991: if (!leftToRight)
0992: x += buttonWidth;
0993:
0994: if (Toolkit.getDefaultToolkit().isFrameStateSupported(
0995: Frame.MAXIMIZED_BOTH)) {
0996: if (toggleButton.getParent() != null) {
0997: spacing = 1;//10
0998: x += leftToRight ? -spacing - buttonWidth : spacing;
0999: toggleButton.setBounds(x, y, buttonWidth,
1000: buttonHeight);
1001: if (!leftToRight) {
1002: x += buttonWidth;
1003: }
1004: }
1005: }
1006:
1007: if (iconifyButton != null
1008: && iconifyButton.getParent() != null) {
1009: spacing = 1;
1010: x += leftToRight ? -spacing - buttonWidth : spacing;
1011: iconifyButton
1012: .setBounds(x, y, buttonWidth, buttonHeight);
1013: if (!leftToRight) {
1014: x += buttonWidth;
1015: }
1016: }
1017: buttonsWidth = leftToRight ? w - x : x;
1018: }
1019: }
1020:
1021: /**
1022: * PropertyChangeListener installed on the Window. Updates the necessary
1023: * state as the state of the Window changes.
1024: */
1025: private class PropertyChangeHandler implements
1026: PropertyChangeListener {
1027: public void propertyChange(PropertyChangeEvent pce) {
1028: String name = pce.getPropertyName();
1029:
1030: // Frame.state isn't currently bound.
1031: if ("resizable".equals(name) || "state".equals(name)) {
1032: Frame frame = getFrame();
1033:
1034: if (frame != null) {
1035: setState(frame.getExtendedState(), true);
1036: }
1037: if ("resizable".equals(name)) {
1038: getRootPane().repaint();
1039: }
1040: } else if ("title".equals(name)) {
1041: repaint();
1042: } else if ("componentOrientation".equals(name)) {
1043: revalidate();
1044: repaint();
1045: }
1046: }
1047: }
1048:
1049: /**
1050: * WindowListener installed on the Window, updates the state as necessary.
1051: */
1052: private class WindowHandler extends WindowAdapter {
1053: public void windowActivated(WindowEvent ev) {
1054: setActive(true);
1055: }
1056:
1057: public void windowDeactivated(WindowEvent ev) {
1058: setActive(false);
1059: }
1060: }
1061:
1062: }
|