1 /*
   2  * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javax.swing.plaf.basic;
  27 
  28 import sun.swing.SwingUtilities2;
  29 import java.awt.*;
  30 import java.awt.event.*;
  31 import javax.accessibility.AccessibleContext;
  32 import javax.swing.*;
  33 import javax.swing.plaf.*;
  34 import javax.swing.event.InternalFrameEvent;
  35 import java.beans.PropertyChangeListener;
  36 import java.beans.PropertyChangeEvent;
  37 import java.beans.PropertyVetoException;
  38 import static java.awt.RenderingHints.KEY_TEXT_ANTIALIASING;
  39 import static java.awt.RenderingHints.KEY_TEXT_LCD_CONTRAST;
  40 
  41 import sun.swing.DefaultLookup;
  42 
  43 /**
  44  * The class that manages a basic title bar
  45  * <p>
  46  * <strong>Warning:</strong>
  47  * Serialized objects of this class will not be compatible with
  48  * future Swing releases. The current serialization support is
  49  * appropriate for short term storage or RMI between applications running
  50  * the same version of Swing.  As of 1.4, support for long term storage
  51  * of all JavaBeans
  52  * has been added to the <code>java.beans</code> package.
  53  * Please see {@link java.beans.XMLEncoder}.
  54  *
  55  * @author David Kloba
  56  * @author Steve Wilson
  57  */
  58 @SuppressWarnings("serial") // Same-version serialization only
  59 public class BasicInternalFrameTitlePane extends JComponent
  60 {
  61     /**
  62      * The instance of {@code JMenuBar}.
  63      */
  64     protected JMenuBar menuBar;
  65     /**
  66      * The iconify button.
  67      */
  68     protected JButton iconButton;
  69     /**
  70      * The maximize button.
  71      */
  72     protected JButton maxButton;
  73     /**
  74      * The close button.
  75      */
  76     protected JButton closeButton;
  77 
  78     /**
  79      * The instance of {@code JMenu}.
  80      */
  81     protected JMenu windowMenu;
  82     /**
  83      * The instance of {@code JInternalFrame}.
  84      */
  85     protected JInternalFrame frame;
  86 
  87     /**
  88      * The color of a selected title.
  89      */
  90     protected Color selectedTitleColor;
  91     /**
  92      * The color of a selected text.
  93      */
  94     protected Color selectedTextColor;
  95     /**
  96      * The color of a not selected title.
  97      */
  98     protected Color notSelectedTitleColor;
  99     /**
 100      * The color of a not selected text.
 101      */
 102     protected Color notSelectedTextColor;
 103 
 104     /**
 105      * The maximize icon.
 106      */
 107     protected Icon maxIcon;
 108     /**
 109      * The minimize icon.
 110      */
 111     protected Icon minIcon;
 112     /**
 113      * The iconify icon.
 114      */
 115     protected Icon iconIcon;
 116     /**
 117      * The close icon.
 118      */
 119     protected Icon closeIcon;
 120 
 121     /**
 122      * The instance of a {@code PropertyChangeListener}.
 123      */
 124     protected PropertyChangeListener propertyChangeListener;
 125 
 126     /**
 127      * The instance of a {@code CloseAction}.
 128      */
 129     protected Action closeAction;
 130     /**
 131      * The instance of a {@code MaximizeAction}.
 132      */
 133     protected Action maximizeAction;
 134     /**
 135      * The instance of an {@code IconifyAction}.
 136      */
 137     protected Action iconifyAction;
 138     /**
 139      * The instance of a {@code RestoreAction}.
 140      */
 141     protected Action restoreAction;
 142     /**
 143      * The instance of a {@code MoveAction}.
 144      */
 145     protected Action moveAction;
 146     /**
 147      * The instance of a {@code SizeAction}.
 148      */
 149     protected Action sizeAction;
 150 
 151     // These constants are not used in JDK code
 152     /**
 153      * The close button text property.
 154      */
 155     protected static final String CLOSE_CMD =
 156         UIManager.getString("InternalFrameTitlePane.closeButtonText");
 157     /**
 158      * The minimize button text property.
 159      */
 160     protected static final String ICONIFY_CMD =
 161         UIManager.getString("InternalFrameTitlePane.minimizeButtonText");
 162     /**
 163      * The restore button text property.
 164      */
 165     protected static final String RESTORE_CMD =
 166         UIManager.getString("InternalFrameTitlePane.restoreButtonText");
 167     /**
 168      * The maximize button text property.
 169      */
 170     protected static final String MAXIMIZE_CMD =
 171         UIManager.getString("InternalFrameTitlePane.maximizeButtonText");
 172     /**
 173      * The move button text property.
 174      */
 175     protected static final String MOVE_CMD =
 176         UIManager.getString("InternalFrameTitlePane.moveButtonText");
 177     /**
 178      * The size button text property.
 179      */
 180     protected static final String SIZE_CMD =
 181         UIManager.getString("InternalFrameTitlePane.sizeButtonText");
 182 
 183     private String closeButtonToolTip;
 184     private String iconButtonToolTip;
 185     private String restoreButtonToolTip;
 186     private String maxButtonToolTip;
 187     private Handler handler;
 188 
 189     /**
 190      * Constructs a new instance of {@code BasicInternalFrameTitlePane}.
 191      *
 192      * @param f an instance of {@code JInternalFrame}
 193      */
 194     public BasicInternalFrameTitlePane(JInternalFrame f) {
 195         frame = f;
 196         installTitlePane();
 197     }
 198 
 199     /**
 200      * Installs the title pane.
 201      */
 202     protected void installTitlePane() {
 203         installDefaults();
 204         installListeners();
 205 
 206         createActions();
 207         enableActions();
 208         createActionMap();
 209 
 210         setLayout(createLayout());
 211 
 212         assembleSystemMenu();
 213         createButtons();
 214         addSubComponents();
 215 
 216         updateProperties();
 217     }
 218 
 219     private void updateProperties() {
 220         putClientProperty(KEY_TEXT_ANTIALIASING,
 221                 frame.getClientProperty(KEY_TEXT_ANTIALIASING));
 222         putClientProperty(KEY_TEXT_LCD_CONTRAST,
 223                 frame.getClientProperty(KEY_TEXT_LCD_CONTRAST));
 224     }
 225 
 226     /**
 227      * Adds subcomponents.
 228      */
 229     protected void addSubComponents() {
 230         add(menuBar);
 231         add(iconButton);
 232         add(maxButton);
 233         add(closeButton);
 234     }
 235 
 236     /**
 237      * Creates actions.
 238      */
 239     protected void createActions() {
 240         maximizeAction = new MaximizeAction();
 241         iconifyAction = new IconifyAction();
 242         closeAction = new CloseAction();
 243         restoreAction = new RestoreAction();
 244         moveAction = new MoveAction();
 245         sizeAction = new SizeAction();
 246     }
 247 
 248     ActionMap createActionMap() {
 249         ActionMap map = new ActionMapUIResource();
 250         map.put("showSystemMenu", new ShowSystemMenuAction(true));
 251         map.put("hideSystemMenu", new ShowSystemMenuAction(false));
 252         return map;
 253     }
 254 
 255     /**
 256      * Registers listeners.
 257      */
 258     protected void installListeners() {
 259         if( propertyChangeListener == null ) {
 260             propertyChangeListener = createPropertyChangeListener();
 261         }
 262         frame.addPropertyChangeListener(propertyChangeListener);
 263     }
 264 
 265     /**
 266      * Unregisters listeners.
 267      */
 268     protected void uninstallListeners() {
 269         frame.removePropertyChangeListener(propertyChangeListener);
 270         handler = null;
 271     }
 272 
 273     /**
 274      * Installs default properties.
 275      */
 276     protected void installDefaults() {
 277         maxIcon = UIManager.getIcon("InternalFrame.maximizeIcon");
 278         minIcon = UIManager.getIcon("InternalFrame.minimizeIcon");
 279         iconIcon = UIManager.getIcon("InternalFrame.iconifyIcon");
 280         closeIcon = UIManager.getIcon("InternalFrame.closeIcon");
 281 
 282         selectedTitleColor = UIManager.getColor("InternalFrame.activeTitleBackground");
 283         selectedTextColor = UIManager.getColor("InternalFrame.activeTitleForeground");
 284         notSelectedTitleColor = UIManager.getColor("InternalFrame.inactiveTitleBackground");
 285         notSelectedTextColor = UIManager.getColor("InternalFrame.inactiveTitleForeground");
 286         setFont(UIManager.getFont("InternalFrame.titleFont"));
 287         closeButtonToolTip =
 288                 UIManager.getString("InternalFrame.closeButtonToolTip");
 289         iconButtonToolTip =
 290                 UIManager.getString("InternalFrame.iconButtonToolTip");
 291         restoreButtonToolTip =
 292                 UIManager.getString("InternalFrame.restoreButtonToolTip");
 293         maxButtonToolTip =
 294                 UIManager.getString("InternalFrame.maxButtonToolTip");
 295     }
 296 
 297     /**
 298      * Uninstalls default properties.
 299      */
 300     protected void uninstallDefaults() {
 301     }
 302 
 303     /**
 304      * Creates buttons.
 305      */
 306     protected void createButtons() {
 307         iconButton = new NoFocusButton(
 308                      "InternalFrameTitlePane.iconifyButtonAccessibleName",
 309                      "InternalFrameTitlePane.iconifyButtonOpacity");
 310         iconButton.addActionListener(iconifyAction);
 311         if (iconButtonToolTip != null && iconButtonToolTip.length() != 0) {
 312             iconButton.setToolTipText(iconButtonToolTip);
 313         }
 314 
 315         maxButton = new NoFocusButton(
 316                         "InternalFrameTitlePane.maximizeButtonAccessibleName",
 317                         "InternalFrameTitlePane.maximizeButtonOpacity");
 318         maxButton.addActionListener(maximizeAction);
 319 
 320         closeButton = new NoFocusButton(
 321                       "InternalFrameTitlePane.closeButtonAccessibleName",
 322                       "InternalFrameTitlePane.closeButtonOpacity");
 323         closeButton.addActionListener(closeAction);
 324         if (closeButtonToolTip != null && closeButtonToolTip.length() != 0) {
 325             closeButton.setToolTipText(closeButtonToolTip);
 326         }
 327 
 328         setButtonIcons();
 329     }
 330 
 331     /**
 332      * Sets the button icons.
 333      */
 334     protected void setButtonIcons() {
 335         if(frame.isIcon()) {
 336             if (minIcon != null) {
 337                 iconButton.setIcon(minIcon);
 338             }
 339             if (restoreButtonToolTip != null &&
 340                     restoreButtonToolTip.length() != 0) {
 341                 iconButton.setToolTipText(restoreButtonToolTip);
 342             }
 343             if (maxIcon != null) {
 344                 maxButton.setIcon(maxIcon);
 345             }
 346             if (maxButtonToolTip != null && maxButtonToolTip.length() != 0) {
 347                 maxButton.setToolTipText(maxButtonToolTip);
 348             }
 349         } else if (frame.isMaximum()) {
 350             if (iconIcon != null) {
 351                 iconButton.setIcon(iconIcon);
 352             }
 353             if (iconButtonToolTip != null && iconButtonToolTip.length() != 0) {
 354                 iconButton.setToolTipText(iconButtonToolTip);
 355             }
 356             if (minIcon != null) {
 357                 maxButton.setIcon(minIcon);
 358             }
 359             if (restoreButtonToolTip != null &&
 360                     restoreButtonToolTip.length() != 0) {
 361                 maxButton.setToolTipText(restoreButtonToolTip);
 362             }
 363         } else {
 364             if (iconIcon != null) {
 365                 iconButton.setIcon(iconIcon);
 366             }
 367             if (iconButtonToolTip != null && iconButtonToolTip.length() != 0) {
 368                 iconButton.setToolTipText(iconButtonToolTip);
 369             }
 370             if (maxIcon != null) {
 371                 maxButton.setIcon(maxIcon);
 372             }
 373             if (maxButtonToolTip != null && maxButtonToolTip.length() != 0) {
 374                 maxButton.setToolTipText(maxButtonToolTip);
 375             }
 376         }
 377         if (closeIcon != null) {
 378             closeButton.setIcon(closeIcon);
 379         }
 380     }
 381 
 382     /**
 383      * Assembles system menu.
 384      */
 385     protected void assembleSystemMenu() {
 386         menuBar = createSystemMenuBar();
 387         windowMenu = createSystemMenu();
 388         menuBar.add(windowMenu);
 389         addSystemMenuItems(windowMenu);
 390         enableActions();
 391     }
 392 
 393     /**
 394      * Adds system menu items to {@code systemMenu}.
 395      *
 396      * @param systemMenu an instance of {@code JMenu}
 397      */
 398     protected void addSystemMenuItems(JMenu systemMenu) {
 399         JMenuItem mi = systemMenu.add(restoreAction);
 400         mi.setMnemonic(getButtonMnemonic("restore"));
 401         mi = systemMenu.add(moveAction);
 402         mi.setMnemonic(getButtonMnemonic("move"));
 403         mi = systemMenu.add(sizeAction);
 404         mi.setMnemonic(getButtonMnemonic("size"));
 405         mi = systemMenu.add(iconifyAction);
 406         mi.setMnemonic(getButtonMnemonic("minimize"));
 407         mi = systemMenu.add(maximizeAction);
 408         mi.setMnemonic(getButtonMnemonic("maximize"));
 409         systemMenu.add(new JSeparator());
 410         mi = systemMenu.add(closeAction);
 411         mi.setMnemonic(getButtonMnemonic("close"));
 412     }
 413 
 414     private static int getButtonMnemonic(String button) {
 415         try {
 416             return Integer.parseInt(UIManager.getString(
 417                     "InternalFrameTitlePane." + button + "Button.mnemonic"));
 418         } catch (NumberFormatException e) {
 419             return -1;
 420         }
 421     }
 422 
 423     /**
 424      * Returns a new instance of {@code JMenu}.
 425      *
 426      * @return a new instance of {@code JMenu}
 427      */
 428     protected JMenu createSystemMenu() {
 429         return new JMenu("    ");
 430     }
 431 
 432     /**
 433      * Returns a new instance of {@code JMenuBar}.
 434      *
 435      * @return a new instance of {@code JMenuBar}
 436      */
 437     protected JMenuBar createSystemMenuBar() {
 438         menuBar = new SystemMenuBar();
 439         menuBar.setBorderPainted(false);
 440         return menuBar;
 441     }
 442 
 443     /**
 444      * Shows system menu.
 445      */
 446     protected void showSystemMenu(){
 447         //      windowMenu.setPopupMenuVisible(true);
 448       //      windowMenu.setVisible(true);
 449       windowMenu.doClick();
 450     }
 451 
 452     public void paintComponent(Graphics g)  {
 453         paintTitleBackground(g);
 454 
 455         if(frame.getTitle() != null) {
 456             boolean isSelected = frame.isSelected();
 457             Font f = g.getFont();
 458             g.setFont(getFont());
 459             if(isSelected)
 460                 g.setColor(selectedTextColor);
 461             else
 462                 g.setColor(notSelectedTextColor);
 463 
 464             // Center text vertically.
 465             FontMetrics fm = SwingUtilities2.getFontMetrics(frame, g);
 466             int baseline = (getHeight() + fm.getAscent() - fm.getLeading() -
 467                     fm.getDescent()) / 2;
 468 
 469             int titleX;
 470             Rectangle r = new Rectangle(0, 0, 0, 0);
 471             if (frame.isIconifiable())  r = iconButton.getBounds();
 472             else if (frame.isMaximizable())  r = maxButton.getBounds();
 473             else if (frame.isClosable())  r = closeButton.getBounds();
 474             int titleW;
 475 
 476             String title = frame.getTitle();
 477             if( BasicGraphicsUtils.isLeftToRight(frame) ) {
 478               if (r.x == 0)  r.x = frame.getWidth()-frame.getInsets().right;
 479               titleX = menuBar.getX() + menuBar.getWidth() + 2;
 480               titleW = r.x - titleX - 3;
 481               title = getTitle(frame.getTitle(), fm, titleW);
 482             } else {
 483                 titleX = menuBar.getX() - 2
 484                          - SwingUtilities2.stringWidth(frame,fm,title);
 485             }
 486 
 487             SwingUtilities2.drawString(frame, g, title, titleX, baseline);
 488             g.setFont(f);
 489         }
 490     }
 491 
 492    /**
 493     * Invoked from paintComponent.
 494     * Paints the background of the titlepane.  All text and icons will
 495     * then be rendered on top of this background.
 496     * @param g the graphics to use to render the background
 497     * @since 1.4
 498     */
 499     protected void paintTitleBackground(Graphics g) {
 500         boolean isSelected = frame.isSelected();
 501 
 502         if(isSelected)
 503             g.setColor(selectedTitleColor);
 504         else
 505             g.setColor(notSelectedTitleColor);
 506         g.fillRect(0, 0, getWidth(), getHeight());
 507     }
 508 
 509     /**
 510      * Returns the title.
 511      *
 512      * @param text a text
 513      * @param fm an instance of {@code FontMetrics}
 514      * @param availTextWidth an available text width
 515      * @return the title.
 516      */
 517     protected String getTitle(String text, FontMetrics fm, int availTextWidth) {
 518         return SwingUtilities2.clipStringIfNecessary(
 519                            frame, fm, text, availTextWidth);
 520     }
 521 
 522     /**
 523      * Post a WINDOW_CLOSING-like event to the frame, so that it can
 524      * be treated like a regular {@code Frame}.
 525      *
 526      * @param frame an instance of {@code JInternalFrame}
 527      */
 528     protected void postClosingEvent(JInternalFrame frame) {
 529         InternalFrameEvent e = new InternalFrameEvent(
 530             frame, InternalFrameEvent.INTERNAL_FRAME_CLOSING);
 531         // Try posting event, unless there's a SecurityManager.
 532         try {
 533             Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(e);
 534         } catch (SecurityException se) {
 535             frame.dispatchEvent(e);
 536         }
 537     }
 538 
 539     /**
 540      * Enables actions.
 541      */
 542     protected void enableActions() {
 543         restoreAction.setEnabled(frame.isMaximum() || frame.isIcon());
 544         maximizeAction.setEnabled(
 545             (frame.isMaximizable() && !frame.isMaximum() && !frame.isIcon()) ||
 546             (frame.isMaximizable() && frame.isIcon()));
 547         iconifyAction.setEnabled(frame.isIconifiable() && !frame.isIcon());
 548         closeAction.setEnabled(frame.isClosable());
 549         sizeAction.setEnabled(false);
 550         moveAction.setEnabled(false);
 551     }
 552 
 553     private Handler getHandler() {
 554         if (handler == null) {
 555             handler = new Handler();
 556         }
 557         return handler;
 558     }
 559 
 560     /**
 561      * Returns an instance of {@code PropertyChangeListener}.
 562      *
 563      * @return an instance of {@code PropertyChangeListener}
 564      */
 565     protected PropertyChangeListener createPropertyChangeListener() {
 566         return getHandler();
 567     }
 568 
 569     /**
 570      * Returns a layout manager.
 571      *
 572      * @return a layout manager
 573      */
 574     protected LayoutManager createLayout() {
 575         return getHandler();
 576     }
 577 
 578 
 579     private class Handler implements LayoutManager, PropertyChangeListener {
 580         //
 581         // PropertyChangeListener
 582         //
 583         public void propertyChange(PropertyChangeEvent evt) {
 584             String prop = evt.getPropertyName();
 585 
 586             if (prop == JInternalFrame.IS_SELECTED_PROPERTY) {
 587                 repaint();
 588                 return;
 589             }
 590 
 591             if (prop == JInternalFrame.IS_ICON_PROPERTY ||
 592                     prop == JInternalFrame.IS_MAXIMUM_PROPERTY) {
 593                 setButtonIcons();
 594                 enableActions();
 595                 return;
 596             }
 597 
 598             if ("closable" == prop) {
 599                 if (evt.getNewValue() == Boolean.TRUE) {
 600                     add(closeButton);
 601                 } else {
 602                     remove(closeButton);
 603                 }
 604             } else if ("maximizable" == prop) {
 605                 if (evt.getNewValue() == Boolean.TRUE) {
 606                     add(maxButton);
 607                 } else {
 608                     remove(maxButton);
 609                 }
 610             } else if ("iconable" == prop) {
 611                 if (evt.getNewValue() == Boolean.TRUE) {
 612                     add(iconButton);
 613                 } else {
 614                     remove(iconButton);
 615                 }
 616             }
 617             enableActions();
 618 
 619             revalidate();
 620             repaint();
 621         }
 622 
 623 
 624         //
 625         // LayoutManager
 626         //
 627         public void addLayoutComponent(String name, Component c) {}
 628         public void removeLayoutComponent(Component c) {}
 629         public Dimension preferredLayoutSize(Container c) {
 630             return minimumLayoutSize(c);
 631         }
 632 
 633         public Dimension minimumLayoutSize(Container c) {
 634             // Calculate width.
 635             int width = 22;
 636 
 637             if (frame.isClosable()) {
 638                 width += 19;
 639             }
 640             if (frame.isMaximizable()) {
 641                 width += 19;
 642             }
 643             if (frame.isIconifiable()) {
 644                 width += 19;
 645             }
 646 
 647             FontMetrics fm = frame.getFontMetrics(getFont());
 648             String frameTitle = frame.getTitle();
 649             int title_w = frameTitle != null ? SwingUtilities2.stringWidth(
 650                                frame, fm, frameTitle) : 0;
 651             int title_length = frameTitle != null ? frameTitle.length() : 0;
 652 
 653             // Leave room for three characters in the title.
 654             if (title_length > 3) {
 655                 int subtitle_w = SwingUtilities2.stringWidth(
 656                     frame, fm, frameTitle.substring(0, 3) + "...");
 657                 width += (title_w < subtitle_w) ? title_w : subtitle_w;
 658             } else {
 659                 width += title_w;
 660             }
 661 
 662             // Calculate height.
 663             Icon icon = frame.getFrameIcon();
 664             int fontHeight = fm.getHeight();
 665             fontHeight += 2;
 666             int iconHeight = 0;
 667             if (icon != null) {
 668                 // SystemMenuBar forces the icon to be 16x16 or less.
 669                 iconHeight = Math.min(icon.getIconHeight(), 16);
 670             }
 671             iconHeight += 2;
 672 
 673             int height = Math.max( fontHeight, iconHeight );
 674 
 675             Dimension dim = new Dimension(width, height);
 676 
 677             // Take into account the border insets if any.
 678             if (getBorder() != null) {
 679                 Insets insets = getBorder().getBorderInsets(c);
 680                 dim.height += insets.top + insets.bottom;
 681                 dim.width += insets.left + insets.right;
 682             }
 683             return dim;
 684         }
 685 
 686         public void layoutContainer(Container c) {
 687             boolean leftToRight = BasicGraphicsUtils.isLeftToRight(frame);
 688 
 689             int w = getWidth();
 690             int h = getHeight();
 691             int x;
 692 
 693             int buttonHeight = closeButton.getIcon().getIconHeight();
 694 
 695             Icon icon = frame.getFrameIcon();
 696             int iconHeight = 0;
 697             if (icon != null) {
 698                 iconHeight = icon.getIconHeight();
 699             }
 700             x = (leftToRight) ? 2 : w - 16 - 2;
 701             menuBar.setBounds(x, (h - iconHeight) / 2, 16, 16);
 702 
 703             x = (leftToRight) ? w - 16 - 2 : 2;
 704 
 705             if (frame.isClosable()) {
 706                 closeButton.setBounds(x, (h - buttonHeight) / 2, 16, 14);
 707                 x += (leftToRight) ? -(16 + 2) : 16 + 2;
 708             }
 709 
 710             if (frame.isMaximizable()) {
 711                 maxButton.setBounds(x, (h - buttonHeight) / 2, 16, 14);
 712                 x += (leftToRight) ? -(16 + 2) : 16 + 2;
 713             }
 714 
 715             if (frame.isIconifiable()) {
 716                 iconButton.setBounds(x, (h - buttonHeight) / 2, 16, 14);
 717             }
 718         }
 719     }
 720 
 721     /**
 722      * This class should be treated as a &quot;protected&quot; inner class.
 723      * Instantiate it only within subclasses of <code>Foo</code>.
 724      */
 725     public class PropertyChangeHandler implements PropertyChangeListener {
 726         // NOTE: This class exists only for backward compatibility. All
 727         // its functionality has been moved into Handler. If you need to add
 728         // new functionality add it to the Handler, but make sure this
 729         // class calls into the Handler.
 730         public void propertyChange(PropertyChangeEvent evt) {
 731             getHandler().propertyChange(evt);
 732         }
 733     }
 734 
 735     /**
 736      * This class should be treated as a &quot;protected&quot; inner class.
 737      * Instantiate it only within subclasses of <code>Foo</code>.
 738      */
 739     public class TitlePaneLayout implements LayoutManager {
 740         // NOTE: This class exists only for backward compatibility. All
 741         // its functionality has been moved into Handler. If you need to add
 742         // new functionality add it to the Handler, but make sure this
 743         // class calls into the Handler.
 744         public void addLayoutComponent(String name, Component c) {
 745             getHandler().addLayoutComponent(name, c);
 746         }
 747 
 748         public void removeLayoutComponent(Component c) {
 749             getHandler().removeLayoutComponent(c);
 750         }
 751 
 752         public Dimension preferredLayoutSize(Container c)  {
 753             return getHandler().preferredLayoutSize(c);
 754         }
 755 
 756         public Dimension minimumLayoutSize(Container c) {
 757             return getHandler().minimumLayoutSize(c);
 758         }
 759 
 760         public void layoutContainer(Container c) {
 761             getHandler().layoutContainer(c);
 762         }
 763     }
 764 
 765     /**
 766      * This class should be treated as a &quot;protected&quot; inner class.
 767      * Instantiate it only within subclasses of <code>Foo</code>.
 768      */
 769     public class CloseAction extends AbstractAction {
 770         /**
 771          * Constructs a new instance of a {@code CloseAction}.
 772          */
 773         public CloseAction() {
 774             super(UIManager.getString(
 775                     "InternalFrameTitlePane.closeButtonText"));
 776         }
 777 
 778         public void actionPerformed(ActionEvent e) {
 779             if(frame.isClosable()) {
 780                 frame.doDefaultCloseAction();
 781             }
 782         }
 783     } // end CloseAction
 784 
 785     /**
 786      * This class should be treated as a &quot;protected&quot; inner class.
 787      * Instantiate it only within subclasses of <code>Foo</code>.
 788      */
 789     public class MaximizeAction extends AbstractAction {
 790         /**
 791          * Constructs a new instance of a {@code MaximizeAction}.
 792          */
 793         public MaximizeAction() {
 794             super(UIManager.getString(
 795                     "InternalFrameTitlePane.maximizeButtonText"));
 796         }
 797 
 798         public void actionPerformed(ActionEvent evt) {
 799             if (frame.isMaximizable()) {
 800                 if (frame.isMaximum() && frame.isIcon()) {
 801                     try {
 802                         frame.setIcon(false);
 803                     } catch (PropertyVetoException e) { }
 804                 } else if (!frame.isMaximum()) {
 805                     try {
 806                         frame.setMaximum(true);
 807                     } catch (PropertyVetoException e) { }
 808                 } else {
 809                     try {
 810                         frame.setMaximum(false);
 811                     } catch (PropertyVetoException e) { }
 812                 }
 813             }
 814         }
 815     }
 816 
 817     /**
 818      * This class should be treated as a &quot;protected&quot; inner class.
 819      * Instantiate it only within subclasses of <code>Foo</code>.
 820      */
 821     public class IconifyAction extends AbstractAction {
 822         /**
 823          * Constructs a new instance of an {@code IconifyAction}.
 824          */
 825         public IconifyAction() {
 826             super(UIManager.getString(
 827                     "InternalFrameTitlePane.minimizeButtonText"));
 828         }
 829 
 830         public void actionPerformed(ActionEvent e) {
 831             if(frame.isIconifiable()) {
 832               if(!frame.isIcon()) {
 833                 try { frame.setIcon(true); } catch (PropertyVetoException e1) { }
 834               } else{
 835                 try { frame.setIcon(false); } catch (PropertyVetoException e1) { }
 836               }
 837             }
 838         }
 839     } // end IconifyAction
 840 
 841     /**
 842      * This class should be treated as a &quot;protected&quot; inner class.
 843      * Instantiate it only within subclasses of <code>Foo</code>.
 844      */
 845     public class RestoreAction extends AbstractAction {
 846         /**
 847          * Constructs a new instance of a {@code RestoreAction}.
 848          */
 849         public RestoreAction() {
 850             super(UIManager.getString(
 851                     "InternalFrameTitlePane.restoreButtonText"));
 852         }
 853 
 854         public void actionPerformed(ActionEvent evt) {
 855             if (frame.isMaximizable() && frame.isMaximum() && frame.isIcon()) {
 856                 try {
 857                     frame.setIcon(false);
 858                 } catch (PropertyVetoException e) { }
 859             } else if (frame.isMaximizable() && frame.isMaximum()) {
 860                 try {
 861                     frame.setMaximum(false);
 862                 } catch (PropertyVetoException e) { }
 863             } else if (frame.isIconifiable() && frame.isIcon()) {
 864                 try {
 865                     frame.setIcon(false);
 866                 } catch (PropertyVetoException e) { }
 867             }
 868         }
 869     }
 870 
 871     /**
 872      * This class should be treated as a &quot;protected&quot; inner class.
 873      * Instantiate it only within subclasses of <code>Foo</code>.
 874      */
 875     public class MoveAction extends AbstractAction {
 876         /**
 877          * Constructs a new instance of a {@code MoveAction}.
 878          */
 879         public MoveAction() {
 880             super(UIManager.getString(
 881                     "InternalFrameTitlePane.moveButtonText"));
 882         }
 883 
 884         public void actionPerformed(ActionEvent e) {
 885             // This action is currently undefined
 886         }
 887     } // end MoveAction
 888 
 889     /*
 890      * Handles showing and hiding the system menu.
 891      */
 892     private class ShowSystemMenuAction extends AbstractAction {
 893         private boolean show;   // whether to show the menu
 894 
 895         public ShowSystemMenuAction(boolean show) {
 896             this.show = show;
 897         }
 898 
 899         public void actionPerformed(ActionEvent e) {
 900             if (show) {
 901                 windowMenu.doClick();
 902             } else {
 903                 windowMenu.setVisible(false);
 904             }
 905         }
 906     }
 907 
 908     /**
 909      * This class should be treated as a &quot;protected&quot; inner class.
 910      * Instantiate it only within subclasses of <code>Foo</code>.
 911      */
 912     public class SizeAction extends AbstractAction {
 913         /**
 914          * Constructs a new instance of a {@code SizeAction}.
 915          */
 916         public SizeAction() {
 917             super(UIManager.getString(
 918                     "InternalFrameTitlePane.sizeButtonText"));
 919         }
 920 
 921         public void actionPerformed(ActionEvent e) {
 922             // This action is currently undefined
 923         }
 924     } // end SizeAction
 925 
 926 
 927     /**
 928      * This class should be treated as a &quot;protected&quot; inner class.
 929      * Instantiate it only within subclasses of <code>Foo</code>.
 930      */
 931     @SuppressWarnings("deprecation")
 932     public class SystemMenuBar extends JMenuBar {
 933         public boolean isFocusTraversable() { return false; }
 934         public void requestFocus() {}
 935         public void paint(Graphics g) {
 936             Icon icon = frame.getFrameIcon();
 937             if (icon == null) {
 938               icon = (Icon)DefaultLookup.get(frame, frame.getUI(),
 939                       "InternalFrame.icon");
 940             }
 941             if (icon != null) {
 942                 // Resize to 16x16 if necessary.
 943                 if (icon instanceof ImageIcon && (icon.getIconWidth() > 16 || icon.getIconHeight() > 16)) {
 944                     Image img = ((ImageIcon)icon).getImage();
 945                     ((ImageIcon)icon).setImage(img.getScaledInstance(16, 16, Image.SCALE_SMOOTH));
 946                 }
 947                 icon.paintIcon(this, g, 0, 0);
 948             }
 949         }
 950 
 951         public boolean isOpaque() {
 952             return true;
 953         }
 954     } // end SystemMenuBar
 955 
 956 
 957     private class NoFocusButton extends JButton {
 958         private String uiKey;
 959         public NoFocusButton(String uiKey, String opacityKey) {
 960             setFocusPainted(false);
 961             setMargin(new Insets(0,0,0,0));
 962             this.uiKey = uiKey;
 963 
 964             Object opacity = UIManager.get(opacityKey);
 965             if (opacity instanceof Boolean) {
 966                 setOpaque(((Boolean)opacity).booleanValue());
 967             }
 968         }
 969         @SuppressWarnings("deprecation")
 970         public boolean isFocusTraversable() { return false; }
 971         public void requestFocus() {}
 972         public AccessibleContext getAccessibleContext() {
 973             AccessibleContext ac = super.getAccessibleContext();
 974             if (uiKey != null) {
 975                 ac.setAccessibleName(UIManager.getString(uiKey));
 976                 uiKey = null;
 977             }
 978             return ac;
 979         }
 980     }  // end NoFocusButton
 981 
 982 }   // End Title Pane Class