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 
  39 import sun.swing.DefaultLookup;
  40 
  41 import static sun.swing.SwingUtilities2.AA_TEXT_PROPERTY_KEY;
  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&trade;
  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         final Object aaTextInfo = frame.getClientProperty(AA_TEXT_PROPERTY_KEY);
 221         putClientProperty(AA_TEXT_PROPERTY_KEY, aaTextInfo);
 222     }
 223 
 224     /**
 225      * Adds subcomponents.
 226      */
 227     protected void addSubComponents() {
 228         add(menuBar);
 229         add(iconButton);
 230         add(maxButton);
 231         add(closeButton);
 232     }
 233 
 234     /**
 235      * Creates actions.
 236      */
 237     protected void createActions() {
 238         maximizeAction = new MaximizeAction();
 239         iconifyAction = new IconifyAction();
 240         closeAction = new CloseAction();
 241         restoreAction = new RestoreAction();
 242         moveAction = new MoveAction();
 243         sizeAction = new SizeAction();
 244     }
 245 
 246     ActionMap createActionMap() {
 247         ActionMap map = new ActionMapUIResource();
 248         map.put("showSystemMenu", new ShowSystemMenuAction(true));
 249         map.put("hideSystemMenu", new ShowSystemMenuAction(false));
 250         return map;
 251     }
 252 
 253     /**
 254      * Registers listeners.
 255      */
 256     protected void installListeners() {
 257         if( propertyChangeListener == null ) {
 258             propertyChangeListener = createPropertyChangeListener();
 259         }
 260         frame.addPropertyChangeListener(propertyChangeListener);
 261     }
 262 
 263     /**
 264      * Unregisters listeners.
 265      */
 266     protected void uninstallListeners() {
 267         frame.removePropertyChangeListener(propertyChangeListener);
 268         handler = null;
 269     }
 270 
 271     /**
 272      * Installs default properties.
 273      */
 274     protected void installDefaults() {
 275         maxIcon = UIManager.getIcon("InternalFrame.maximizeIcon");
 276         minIcon = UIManager.getIcon("InternalFrame.minimizeIcon");
 277         iconIcon = UIManager.getIcon("InternalFrame.iconifyIcon");
 278         closeIcon = UIManager.getIcon("InternalFrame.closeIcon");
 279 
 280         selectedTitleColor = UIManager.getColor("InternalFrame.activeTitleBackground");
 281         selectedTextColor = UIManager.getColor("InternalFrame.activeTitleForeground");
 282         notSelectedTitleColor = UIManager.getColor("InternalFrame.inactiveTitleBackground");
 283         notSelectedTextColor = UIManager.getColor("InternalFrame.inactiveTitleForeground");
 284         setFont(UIManager.getFont("InternalFrame.titleFont"));
 285         closeButtonToolTip =
 286                 UIManager.getString("InternalFrame.closeButtonToolTip");
 287         iconButtonToolTip =
 288                 UIManager.getString("InternalFrame.iconButtonToolTip");
 289         restoreButtonToolTip =
 290                 UIManager.getString("InternalFrame.restoreButtonToolTip");
 291         maxButtonToolTip =
 292                 UIManager.getString("InternalFrame.maxButtonToolTip");
 293     }
 294 
 295     /**
 296      * Uninstalls default properties.
 297      */
 298     protected void uninstallDefaults() {
 299     }
 300 
 301     /**
 302      * Creates buttons.
 303      */
 304     protected void createButtons() {
 305         iconButton = new NoFocusButton(
 306                      "InternalFrameTitlePane.iconifyButtonAccessibleName",
 307                      "InternalFrameTitlePane.iconifyButtonOpacity");
 308         iconButton.addActionListener(iconifyAction);
 309         if (iconButtonToolTip != null && iconButtonToolTip.length() != 0) {
 310             iconButton.setToolTipText(iconButtonToolTip);
 311         }
 312 
 313         maxButton = new NoFocusButton(
 314                         "InternalFrameTitlePane.maximizeButtonAccessibleName",
 315                         "InternalFrameTitlePane.maximizeButtonOpacity");
 316         maxButton.addActionListener(maximizeAction);
 317 
 318         closeButton = new NoFocusButton(
 319                       "InternalFrameTitlePane.closeButtonAccessibleName",
 320                       "InternalFrameTitlePane.closeButtonOpacity");
 321         closeButton.addActionListener(closeAction);
 322         if (closeButtonToolTip != null && closeButtonToolTip.length() != 0) {
 323             closeButton.setToolTipText(closeButtonToolTip);
 324         }
 325 
 326         setButtonIcons();
 327     }
 328 
 329     /**
 330      * Sets the button icons.
 331      */
 332     protected void setButtonIcons() {
 333         if(frame.isIcon()) {
 334             if (minIcon != null) {
 335                 iconButton.setIcon(minIcon);
 336             }
 337             if (restoreButtonToolTip != null &&
 338                     restoreButtonToolTip.length() != 0) {
 339                 iconButton.setToolTipText(restoreButtonToolTip);
 340             }
 341             if (maxIcon != null) {
 342                 maxButton.setIcon(maxIcon);
 343             }
 344             if (maxButtonToolTip != null && maxButtonToolTip.length() != 0) {
 345                 maxButton.setToolTipText(maxButtonToolTip);
 346             }
 347         } else if (frame.isMaximum()) {
 348             if (iconIcon != null) {
 349                 iconButton.setIcon(iconIcon);
 350             }
 351             if (iconButtonToolTip != null && iconButtonToolTip.length() != 0) {
 352                 iconButton.setToolTipText(iconButtonToolTip);
 353             }
 354             if (minIcon != null) {
 355                 maxButton.setIcon(minIcon);
 356             }
 357             if (restoreButtonToolTip != null &&
 358                     restoreButtonToolTip.length() != 0) {
 359                 maxButton.setToolTipText(restoreButtonToolTip);
 360             }
 361         } else {
 362             if (iconIcon != null) {
 363                 iconButton.setIcon(iconIcon);
 364             }
 365             if (iconButtonToolTip != null && iconButtonToolTip.length() != 0) {
 366                 iconButton.setToolTipText(iconButtonToolTip);
 367             }
 368             if (maxIcon != null) {
 369                 maxButton.setIcon(maxIcon);
 370             }
 371             if (maxButtonToolTip != null && maxButtonToolTip.length() != 0) {
 372                 maxButton.setToolTipText(maxButtonToolTip);
 373             }
 374         }
 375         if (closeIcon != null) {
 376             closeButton.setIcon(closeIcon);
 377         }
 378     }
 379 
 380     /**
 381      * Assembles system menu.
 382      */
 383     protected void assembleSystemMenu() {
 384         menuBar = createSystemMenuBar();
 385         windowMenu = createSystemMenu();
 386         menuBar.add(windowMenu);
 387         addSystemMenuItems(windowMenu);
 388         enableActions();
 389     }
 390 
 391     /**
 392      * Adds system menu items to {@code systemMenu}.
 393      *
 394      * @param systemMenu an instance of {@code JMenu}
 395      */
 396     protected void addSystemMenuItems(JMenu systemMenu) {
 397         JMenuItem mi = systemMenu.add(restoreAction);
 398         mi.setMnemonic(getButtonMnemonic("restore"));
 399         mi = systemMenu.add(moveAction);
 400         mi.setMnemonic(getButtonMnemonic("move"));
 401         mi = systemMenu.add(sizeAction);
 402         mi.setMnemonic(getButtonMnemonic("size"));
 403         mi = systemMenu.add(iconifyAction);
 404         mi.setMnemonic(getButtonMnemonic("minimize"));
 405         mi = systemMenu.add(maximizeAction);
 406         mi.setMnemonic(getButtonMnemonic("maximize"));
 407         systemMenu.add(new JSeparator());
 408         mi = systemMenu.add(closeAction);
 409         mi.setMnemonic(getButtonMnemonic("close"));
 410     }
 411 
 412     private static int getButtonMnemonic(String button) {
 413         try {
 414             return Integer.parseInt(UIManager.getString(
 415                     "InternalFrameTitlePane." + button + "Button.mnemonic"));
 416         } catch (NumberFormatException e) {
 417             return -1;
 418         }
 419     }
 420 
 421     /**
 422      * Returns a new instance of {@code JMenu}.
 423      *
 424      * @return a new instance of {@code JMenu}
 425      */
 426     protected JMenu createSystemMenu() {
 427         return new JMenu("    ");
 428     }
 429 
 430     /**
 431      * Returns a new instance of {@code JMenuBar}.
 432      *
 433      * @return a new instance of {@code JMenuBar}
 434      */
 435     protected JMenuBar createSystemMenuBar() {
 436         menuBar = new SystemMenuBar();
 437         menuBar.setBorderPainted(false);
 438         return menuBar;
 439     }
 440 
 441     /**
 442      * Shows system menu.
 443      */
 444     protected void showSystemMenu(){
 445         //      windowMenu.setPopupMenuVisible(true);
 446       //      windowMenu.setVisible(true);
 447       windowMenu.doClick();
 448     }
 449 
 450     public void paintComponent(Graphics g)  {
 451         paintTitleBackground(g);
 452 
 453         if(frame.getTitle() != null) {
 454             boolean isSelected = frame.isSelected();
 455             Font f = g.getFont();
 456             g.setFont(getFont());
 457             if(isSelected)
 458                 g.setColor(selectedTextColor);
 459             else
 460                 g.setColor(notSelectedTextColor);
 461 
 462             // Center text vertically.
 463             FontMetrics fm = SwingUtilities2.getFontMetrics(frame, g);
 464             int baseline = (getHeight() + fm.getAscent() - fm.getLeading() -
 465                     fm.getDescent()) / 2;
 466 
 467             int titleX;
 468             Rectangle r = new Rectangle(0, 0, 0, 0);
 469             if (frame.isIconifiable())  r = iconButton.getBounds();
 470             else if (frame.isMaximizable())  r = maxButton.getBounds();
 471             else if (frame.isClosable())  r = closeButton.getBounds();
 472             int titleW;
 473 
 474             String title = frame.getTitle();
 475             if( BasicGraphicsUtils.isLeftToRight(frame) ) {
 476               if (r.x == 0)  r.x = frame.getWidth()-frame.getInsets().right;
 477               titleX = menuBar.getX() + menuBar.getWidth() + 2;
 478               titleW = r.x - titleX - 3;
 479               title = getTitle(frame.getTitle(), fm, titleW);
 480             } else {
 481                 titleX = menuBar.getX() - 2
 482                          - SwingUtilities2.stringWidth(frame,fm,title);
 483             }
 484 
 485             SwingUtilities2.drawString(frame, g, title, titleX, baseline);
 486             g.setFont(f);
 487         }
 488     }
 489 
 490    /**
 491     * Invoked from paintComponent.
 492     * Paints the background of the titlepane.  All text and icons will
 493     * then be rendered on top of this background.
 494     * @param g the graphics to use to render the background
 495     * @since 1.4
 496     */
 497     protected void paintTitleBackground(Graphics g) {
 498         boolean isSelected = frame.isSelected();
 499 
 500         if(isSelected)
 501             g.setColor(selectedTitleColor);
 502         else
 503             g.setColor(notSelectedTitleColor);
 504         g.fillRect(0, 0, getWidth(), getHeight());
 505     }
 506 
 507     /**
 508      * Returns the title.
 509      *
 510      * @param text a text
 511      * @param fm an instance of {@code FontMetrics}
 512      * @param availTextWidth an available text width
 513      * @return the title.
 514      */
 515     protected String getTitle(String text, FontMetrics fm, int availTextWidth) {
 516         return SwingUtilities2.clipStringIfNecessary(
 517                            frame, fm, text, availTextWidth);
 518     }
 519 
 520     /**
 521      * Post a WINDOW_CLOSING-like event to the frame, so that it can
 522      * be treated like a regular {@code Frame}.
 523      *
 524      * @param frame an instance of {@code JInternalFrame}
 525      */
 526     protected void postClosingEvent(JInternalFrame frame) {
 527         InternalFrameEvent e = new InternalFrameEvent(
 528             frame, InternalFrameEvent.INTERNAL_FRAME_CLOSING);
 529         // Try posting event, unless there's a SecurityManager.
 530         try {
 531             Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(e);
 532         } catch (SecurityException se) {
 533             frame.dispatchEvent(e);
 534         }
 535     }
 536 
 537     /**
 538      * Enables actions.
 539      */
 540     protected void enableActions() {
 541         restoreAction.setEnabled(frame.isMaximum() || frame.isIcon());
 542         maximizeAction.setEnabled(
 543             (frame.isMaximizable() && !frame.isMaximum() && !frame.isIcon()) ||
 544             (frame.isMaximizable() && frame.isIcon()));
 545         iconifyAction.setEnabled(frame.isIconifiable() && !frame.isIcon());
 546         closeAction.setEnabled(frame.isClosable());
 547         sizeAction.setEnabled(false);
 548         moveAction.setEnabled(false);
 549     }
 550 
 551     private Handler getHandler() {
 552         if (handler == null) {
 553             handler = new Handler();
 554         }
 555         return handler;
 556     }
 557 
 558     /**
 559      * Returns an instance of {@code PropertyChangeListener}.
 560      *
 561      * @return an instance of {@code PropertyChangeListener}
 562      */
 563     protected PropertyChangeListener createPropertyChangeListener() {
 564         return getHandler();
 565     }
 566 
 567     /**
 568      * Returns a layout manager.
 569      *
 570      * @return a layout manager
 571      */
 572     protected LayoutManager createLayout() {
 573         return getHandler();
 574     }
 575 
 576 
 577     private class Handler implements LayoutManager, PropertyChangeListener {
 578         //
 579         // PropertyChangeListener
 580         //
 581         public void propertyChange(PropertyChangeEvent evt) {
 582             String prop = evt.getPropertyName();
 583 
 584             if (prop == JInternalFrame.IS_SELECTED_PROPERTY) {
 585                 repaint();
 586                 return;
 587             }
 588 
 589             if (prop == JInternalFrame.IS_ICON_PROPERTY ||
 590                     prop == JInternalFrame.IS_MAXIMUM_PROPERTY) {
 591                 setButtonIcons();
 592                 enableActions();
 593                 return;
 594             }
 595 
 596             if ("closable" == prop) {
 597                 if (evt.getNewValue() == Boolean.TRUE) {
 598                     add(closeButton);
 599                 } else {
 600                     remove(closeButton);
 601                 }
 602             } else if ("maximizable" == prop) {
 603                 if (evt.getNewValue() == Boolean.TRUE) {
 604                     add(maxButton);
 605                 } else {
 606                     remove(maxButton);
 607                 }
 608             } else if ("iconable" == prop) {
 609                 if (evt.getNewValue() == Boolean.TRUE) {
 610                     add(iconButton);
 611                 } else {
 612                     remove(iconButton);
 613                 }
 614             }
 615             enableActions();
 616 
 617             revalidate();
 618             repaint();
 619         }
 620 
 621 
 622         //
 623         // LayoutManager
 624         //
 625         public void addLayoutComponent(String name, Component c) {}
 626         public void removeLayoutComponent(Component c) {}
 627         public Dimension preferredLayoutSize(Container c) {
 628             return minimumLayoutSize(c);
 629         }
 630 
 631         public Dimension minimumLayoutSize(Container c) {
 632             // Calculate width.
 633             int width = 22;
 634 
 635             if (frame.isClosable()) {
 636                 width += 19;
 637             }
 638             if (frame.isMaximizable()) {
 639                 width += 19;
 640             }
 641             if (frame.isIconifiable()) {
 642                 width += 19;
 643             }
 644 
 645             FontMetrics fm = frame.getFontMetrics(getFont());
 646             String frameTitle = frame.getTitle();
 647             int title_w = frameTitle != null ? SwingUtilities2.stringWidth(
 648                                frame, fm, frameTitle) : 0;
 649             int title_length = frameTitle != null ? frameTitle.length() : 0;
 650 
 651             // Leave room for three characters in the title.
 652             if (title_length > 3) {
 653                 int subtitle_w = SwingUtilities2.stringWidth(
 654                     frame, fm, frameTitle.substring(0, 3) + "...");
 655                 width += (title_w < subtitle_w) ? title_w : subtitle_w;
 656             } else {
 657                 width += title_w;
 658             }
 659 
 660             // Calculate height.
 661             Icon icon = frame.getFrameIcon();
 662             int fontHeight = fm.getHeight();
 663             fontHeight += 2;
 664             int iconHeight = 0;
 665             if (icon != null) {
 666                 // SystemMenuBar forces the icon to be 16x16 or less.
 667                 iconHeight = Math.min(icon.getIconHeight(), 16);
 668             }
 669             iconHeight += 2;
 670 
 671             int height = Math.max( fontHeight, iconHeight );
 672 
 673             Dimension dim = new Dimension(width, height);
 674 
 675             // Take into account the border insets if any.
 676             if (getBorder() != null) {
 677                 Insets insets = getBorder().getBorderInsets(c);
 678                 dim.height += insets.top + insets.bottom;
 679                 dim.width += insets.left + insets.right;
 680             }
 681             return dim;
 682         }
 683 
 684         public void layoutContainer(Container c) {
 685             boolean leftToRight = BasicGraphicsUtils.isLeftToRight(frame);
 686 
 687             int w = getWidth();
 688             int h = getHeight();
 689             int x;
 690 
 691             int buttonHeight = closeButton.getIcon().getIconHeight();
 692 
 693             Icon icon = frame.getFrameIcon();
 694             int iconHeight = 0;
 695             if (icon != null) {
 696                 iconHeight = icon.getIconHeight();
 697             }
 698             x = (leftToRight) ? 2 : w - 16 - 2;
 699             menuBar.setBounds(x, (h - iconHeight) / 2, 16, 16);
 700 
 701             x = (leftToRight) ? w - 16 - 2 : 2;
 702 
 703             if (frame.isClosable()) {
 704                 closeButton.setBounds(x, (h - buttonHeight) / 2, 16, 14);
 705                 x += (leftToRight) ? -(16 + 2) : 16 + 2;
 706             }
 707 
 708             if (frame.isMaximizable()) {
 709                 maxButton.setBounds(x, (h - buttonHeight) / 2, 16, 14);
 710                 x += (leftToRight) ? -(16 + 2) : 16 + 2;
 711             }
 712 
 713             if (frame.isIconifiable()) {
 714                 iconButton.setBounds(x, (h - buttonHeight) / 2, 16, 14);
 715             }
 716         }
 717     }
 718 
 719     /**
 720      * This class should be treated as a &quot;protected&quot; inner class.
 721      * Instantiate it only within subclasses of <code>Foo</code>.
 722      */
 723     public class PropertyChangeHandler implements PropertyChangeListener {
 724         // NOTE: This class exists only for backward compatibility. All
 725         // its functionality has been moved into Handler. If you need to add
 726         // new functionality add it to the Handler, but make sure this
 727         // class calls into the Handler.
 728         public void propertyChange(PropertyChangeEvent evt) {
 729             getHandler().propertyChange(evt);
 730         }
 731     }
 732 
 733     /**
 734      * This class should be treated as a &quot;protected&quot; inner class.
 735      * Instantiate it only within subclasses of <code>Foo</code>.
 736      */
 737     public class TitlePaneLayout implements LayoutManager {
 738         // NOTE: This class exists only for backward compatibility. All
 739         // its functionality has been moved into Handler. If you need to add
 740         // new functionality add it to the Handler, but make sure this
 741         // class calls into the Handler.
 742         public void addLayoutComponent(String name, Component c) {
 743             getHandler().addLayoutComponent(name, c);
 744         }
 745 
 746         public void removeLayoutComponent(Component c) {
 747             getHandler().removeLayoutComponent(c);
 748         }
 749 
 750         public Dimension preferredLayoutSize(Container c)  {
 751             return getHandler().preferredLayoutSize(c);
 752         }
 753 
 754         public Dimension minimumLayoutSize(Container c) {
 755             return getHandler().minimumLayoutSize(c);
 756         }
 757 
 758         public void layoutContainer(Container c) {
 759             getHandler().layoutContainer(c);
 760         }
 761     }
 762 
 763     /**
 764      * This class should be treated as a &quot;protected&quot; inner class.
 765      * Instantiate it only within subclasses of <code>Foo</code>.
 766      */
 767     public class CloseAction extends AbstractAction {
 768         /**
 769          * Constructs a new instance of a {@code CloseAction}.
 770          */
 771         public CloseAction() {
 772             super(UIManager.getString(
 773                     "InternalFrameTitlePane.closeButtonText"));
 774         }
 775 
 776         public void actionPerformed(ActionEvent e) {
 777             if(frame.isClosable()) {
 778                 frame.doDefaultCloseAction();
 779             }
 780         }
 781     } // end CloseAction
 782 
 783     /**
 784      * This class should be treated as a &quot;protected&quot; inner class.
 785      * Instantiate it only within subclasses of <code>Foo</code>.
 786      */
 787     public class MaximizeAction extends AbstractAction {
 788         /**
 789          * Constructs a new instance of a {@code MaximizeAction}.
 790          */
 791         public MaximizeAction() {
 792             super(UIManager.getString(
 793                     "InternalFrameTitlePane.maximizeButtonText"));
 794         }
 795 
 796         public void actionPerformed(ActionEvent evt) {
 797             if (frame.isMaximizable()) {
 798                 if (frame.isMaximum() && frame.isIcon()) {
 799                     try {
 800                         frame.setIcon(false);
 801                     } catch (PropertyVetoException e) { }
 802                 } else if (!frame.isMaximum()) {
 803                     try {
 804                         frame.setMaximum(true);
 805                     } catch (PropertyVetoException e) { }
 806                 } else {
 807                     try {
 808                         frame.setMaximum(false);
 809                     } catch (PropertyVetoException e) { }
 810                 }
 811             }
 812         }
 813     }
 814 
 815     /**
 816      * This class should be treated as a &quot;protected&quot; inner class.
 817      * Instantiate it only within subclasses of <code>Foo</code>.
 818      */
 819     public class IconifyAction extends AbstractAction {
 820         /**
 821          * Constructs a new instance of an {@code IconifyAction}.
 822          */
 823         public IconifyAction() {
 824             super(UIManager.getString(
 825                     "InternalFrameTitlePane.minimizeButtonText"));
 826         }
 827 
 828         public void actionPerformed(ActionEvent e) {
 829             if(frame.isIconifiable()) {
 830               if(!frame.isIcon()) {
 831                 try { frame.setIcon(true); } catch (PropertyVetoException e1) { }
 832               } else{
 833                 try { frame.setIcon(false); } catch (PropertyVetoException e1) { }
 834               }
 835             }
 836         }
 837     } // end IconifyAction
 838 
 839     /**
 840      * This class should be treated as a &quot;protected&quot; inner class.
 841      * Instantiate it only within subclasses of <code>Foo</code>.
 842      */
 843     public class RestoreAction extends AbstractAction {
 844         /**
 845          * Constructs a new instance of a {@code RestoreAction}.
 846          */
 847         public RestoreAction() {
 848             super(UIManager.getString(
 849                     "InternalFrameTitlePane.restoreButtonText"));
 850         }
 851 
 852         public void actionPerformed(ActionEvent evt) {
 853             if (frame.isMaximizable() && frame.isMaximum() && frame.isIcon()) {
 854                 try {
 855                     frame.setIcon(false);
 856                 } catch (PropertyVetoException e) { }
 857             } else if (frame.isMaximizable() && frame.isMaximum()) {
 858                 try {
 859                     frame.setMaximum(false);
 860                 } catch (PropertyVetoException e) { }
 861             } else if (frame.isIconifiable() && frame.isIcon()) {
 862                 try {
 863                     frame.setIcon(false);
 864                 } catch (PropertyVetoException e) { }
 865             }
 866         }
 867     }
 868 
 869     /**
 870      * This class should be treated as a &quot;protected&quot; inner class.
 871      * Instantiate it only within subclasses of <code>Foo</code>.
 872      */
 873     public class MoveAction extends AbstractAction {
 874         /**
 875          * Constructs a new instance of a {@code MoveAction}.
 876          */
 877         public MoveAction() {
 878             super(UIManager.getString(
 879                     "InternalFrameTitlePane.moveButtonText"));
 880         }
 881 
 882         public void actionPerformed(ActionEvent e) {
 883             // This action is currently undefined
 884         }
 885     } // end MoveAction
 886 
 887     /*
 888      * Handles showing and hiding the system menu.
 889      */
 890     private class ShowSystemMenuAction extends AbstractAction {
 891         private boolean show;   // whether to show the menu
 892 
 893         public ShowSystemMenuAction(boolean show) {
 894             this.show = show;
 895         }
 896 
 897         public void actionPerformed(ActionEvent e) {
 898             if (show) {
 899                 windowMenu.doClick();
 900             } else {
 901                 windowMenu.setVisible(false);
 902             }
 903         }
 904     }
 905 
 906     /**
 907      * This class should be treated as a &quot;protected&quot; inner class.
 908      * Instantiate it only within subclasses of <code>Foo</code>.
 909      */
 910     public class SizeAction extends AbstractAction {
 911         /**
 912          * Constructs a new instance of a {@code SizeAction}.
 913          */
 914         public SizeAction() {
 915             super(UIManager.getString(
 916                     "InternalFrameTitlePane.sizeButtonText"));
 917         }
 918 
 919         public void actionPerformed(ActionEvent e) {
 920             // This action is currently undefined
 921         }
 922     } // end SizeAction
 923 
 924 
 925     /**
 926      * This class should be treated as a &quot;protected&quot; inner class.
 927      * Instantiate it only within subclasses of <code>Foo</code>.
 928      */
 929     public class SystemMenuBar extends JMenuBar {
 930         public boolean isFocusTraversable() { return false; }
 931         public void requestFocus() {}
 932         public void paint(Graphics g) {
 933             Icon icon = frame.getFrameIcon();
 934             if (icon == null) {
 935               icon = (Icon)DefaultLookup.get(frame, frame.getUI(),
 936                       "InternalFrame.icon");
 937             }
 938             if (icon != null) {
 939                 // Resize to 16x16 if necessary.
 940                 if (icon instanceof ImageIcon && (icon.getIconWidth() > 16 || icon.getIconHeight() > 16)) {
 941                     Image img = ((ImageIcon)icon).getImage();
 942                     ((ImageIcon)icon).setImage(img.getScaledInstance(16, 16, Image.SCALE_SMOOTH));
 943                 }
 944                 icon.paintIcon(this, g, 0, 0);
 945             }
 946         }
 947 
 948         public boolean isOpaque() {
 949             return true;
 950         }
 951     } // end SystemMenuBar
 952 
 953 
 954     private class NoFocusButton extends JButton {
 955         private String uiKey;
 956         public NoFocusButton(String uiKey, String opacityKey) {
 957             setFocusPainted(false);
 958             setMargin(new Insets(0,0,0,0));
 959             this.uiKey = uiKey;
 960 
 961             Object opacity = UIManager.get(opacityKey);
 962             if (opacity instanceof Boolean) {
 963                 setOpaque(((Boolean)opacity).booleanValue());
 964             }
 965         }
 966         public boolean isFocusTraversable() { return false; }
 967         public void requestFocus() {}
 968         public AccessibleContext getAccessibleContext() {
 969             AccessibleContext ac = super.getAccessibleContext();
 970             if (uiKey != null) {
 971                 ac.setAccessibleName(UIManager.getString(uiKey));
 972                 uiKey = null;
 973             }
 974             return ac;
 975         }
 976     }  // end NoFocusButton
 977 
 978 }   // End Title Pane Class