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