jdk/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalTitlePane.java
changeset 25859 3317bb8137f4
parent 23697 e556a715949f
child 47020 2c55106dc37b
equal deleted inserted replaced
25858:836adbf7a2cd 25859:3317bb8137f4
       
     1 /*
       
     2  * Copyright (c) 2000, 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.metal;
       
    27 
       
    28 import sun.swing.SwingUtilities2;
       
    29 import sun.awt.SunToolkit;
       
    30 import java.awt.*;
       
    31 import java.awt.event.*;
       
    32 import java.beans.*;
       
    33 import javax.swing.*;
       
    34 import javax.swing.border.*;
       
    35 import javax.swing.event.InternalFrameEvent;
       
    36 import javax.swing.plaf.*;
       
    37 import javax.swing.plaf.basic.*;
       
    38 import java.util.Locale;
       
    39 import javax.accessibility.*;
       
    40 
       
    41 
       
    42 /**
       
    43  * Class that manages a JLF awt.Window-descendant class's title bar.
       
    44  * <p>
       
    45  * This class assumes it will be created with a particular window
       
    46  * decoration style, and that if the style changes, a new one will
       
    47  * be created.
       
    48  *
       
    49  * @author Terry Kellerman
       
    50  * @since 1.4
       
    51  */
       
    52 @SuppressWarnings("serial") // Superclass is not serializable across versions
       
    53 class MetalTitlePane extends JComponent {
       
    54     private static final Border handyEmptyBorder = new EmptyBorder(0,0,0,0);
       
    55     private static final int IMAGE_HEIGHT = 16;
       
    56     private static final int IMAGE_WIDTH = 16;
       
    57 
       
    58     /**
       
    59      * PropertyChangeListener added to the JRootPane.
       
    60      */
       
    61     private PropertyChangeListener propertyChangeListener;
       
    62 
       
    63     /**
       
    64      * JMenuBar, typically renders the system menu items.
       
    65      */
       
    66     private JMenuBar menuBar;
       
    67     /**
       
    68      * Action used to close the Window.
       
    69      */
       
    70     private Action closeAction;
       
    71 
       
    72     /**
       
    73      * Action used to iconify the Frame.
       
    74      */
       
    75     private Action iconifyAction;
       
    76 
       
    77     /**
       
    78      * Action to restore the Frame size.
       
    79      */
       
    80     private Action restoreAction;
       
    81 
       
    82     /**
       
    83      * Action to restore the Frame size.
       
    84      */
       
    85     private Action maximizeAction;
       
    86 
       
    87     /**
       
    88      * Button used to maximize or restore the Frame.
       
    89      */
       
    90     private JButton toggleButton;
       
    91 
       
    92     /**
       
    93      * Button used to maximize or restore the Frame.
       
    94      */
       
    95     private JButton iconifyButton;
       
    96 
       
    97     /**
       
    98      * Button used to maximize or restore the Frame.
       
    99      */
       
   100     private JButton closeButton;
       
   101 
       
   102     /**
       
   103      * Icon used for toggleButton when window is normal size.
       
   104      */
       
   105     private Icon maximizeIcon;
       
   106 
       
   107     /**
       
   108      * Icon used for toggleButton when window is maximized.
       
   109      */
       
   110     private Icon minimizeIcon;
       
   111 
       
   112     /**
       
   113      * Image used for the system menu icon
       
   114      */
       
   115     private Image systemIcon;
       
   116 
       
   117     /**
       
   118      * Listens for changes in the state of the Window listener to update
       
   119      * the state of the widgets.
       
   120      */
       
   121     private WindowListener windowListener;
       
   122 
       
   123     /**
       
   124      * Window we're currently in.
       
   125      */
       
   126     private Window window;
       
   127 
       
   128     /**
       
   129      * JRootPane rendering for.
       
   130      */
       
   131     private JRootPane rootPane;
       
   132 
       
   133     /**
       
   134      * Room remaining in title for bumps.
       
   135      */
       
   136     private int buttonsWidth;
       
   137 
       
   138     /**
       
   139      * Buffered Frame.state property. As state isn't bound, this is kept
       
   140      * to determine when to avoid updating widgets.
       
   141      */
       
   142     private int state;
       
   143 
       
   144     /**
       
   145      * MetalRootPaneUI that created us.
       
   146      */
       
   147     private MetalRootPaneUI rootPaneUI;
       
   148 
       
   149 
       
   150     // Colors
       
   151     private Color inactiveBackground = UIManager.getColor("inactiveCaption");
       
   152     private Color inactiveForeground = UIManager.getColor("inactiveCaptionText");
       
   153     private Color inactiveShadow = UIManager.getColor("inactiveCaptionBorder");
       
   154     private Color activeBumpsHighlight = MetalLookAndFeel.getPrimaryControlHighlight();
       
   155     private Color activeBumpsShadow = MetalLookAndFeel.getPrimaryControlDarkShadow();
       
   156     private Color activeBackground = null;
       
   157     private Color activeForeground = null;
       
   158     private Color activeShadow = null;
       
   159 
       
   160     // Bumps
       
   161     private MetalBumps activeBumps
       
   162         = new MetalBumps( 0, 0,
       
   163                           activeBumpsHighlight,
       
   164                           activeBumpsShadow,
       
   165                           MetalLookAndFeel.getPrimaryControl() );
       
   166     private MetalBumps inactiveBumps
       
   167         = new MetalBumps( 0, 0,
       
   168                           MetalLookAndFeel.getControlHighlight(),
       
   169                           MetalLookAndFeel.getControlDarkShadow(),
       
   170                           MetalLookAndFeel.getControl() );
       
   171 
       
   172 
       
   173     public MetalTitlePane(JRootPane root, MetalRootPaneUI ui) {
       
   174         this.rootPane = root;
       
   175         rootPaneUI = ui;
       
   176 
       
   177         state = -1;
       
   178 
       
   179         installSubcomponents();
       
   180         determineColors();
       
   181         installDefaults();
       
   182 
       
   183         setLayout(createLayout());
       
   184     }
       
   185 
       
   186     /**
       
   187      * Uninstalls the necessary state.
       
   188      */
       
   189     private void uninstall() {
       
   190         uninstallListeners();
       
   191         window = null;
       
   192         removeAll();
       
   193     }
       
   194 
       
   195     /**
       
   196      * Installs the necessary listeners.
       
   197      */
       
   198     private void installListeners() {
       
   199         if (window != null) {
       
   200             windowListener = createWindowListener();
       
   201             window.addWindowListener(windowListener);
       
   202             propertyChangeListener = createWindowPropertyChangeListener();
       
   203             window.addPropertyChangeListener(propertyChangeListener);
       
   204         }
       
   205     }
       
   206 
       
   207     /**
       
   208      * Uninstalls the necessary listeners.
       
   209      */
       
   210     private void uninstallListeners() {
       
   211         if (window != null) {
       
   212             window.removeWindowListener(windowListener);
       
   213             window.removePropertyChangeListener(propertyChangeListener);
       
   214         }
       
   215     }
       
   216 
       
   217     /**
       
   218      * Returns the <code>WindowListener</code> to add to the
       
   219      * <code>Window</code>.
       
   220      */
       
   221     private WindowListener createWindowListener() {
       
   222         return new WindowHandler();
       
   223     }
       
   224 
       
   225     /**
       
   226      * Returns the <code>PropertyChangeListener</code> to install on
       
   227      * the <code>Window</code>.
       
   228      */
       
   229     private PropertyChangeListener createWindowPropertyChangeListener() {
       
   230         return new PropertyChangeHandler();
       
   231     }
       
   232 
       
   233     /**
       
   234      * Returns the <code>JRootPane</code> this was created for.
       
   235      */
       
   236     public JRootPane getRootPane() {
       
   237         return rootPane;
       
   238     }
       
   239 
       
   240     /**
       
   241      * Returns the decoration style of the <code>JRootPane</code>.
       
   242      */
       
   243     private int getWindowDecorationStyle() {
       
   244         return getRootPane().getWindowDecorationStyle();
       
   245     }
       
   246 
       
   247     public void addNotify() {
       
   248         super.addNotify();
       
   249 
       
   250         uninstallListeners();
       
   251 
       
   252         window = SwingUtilities.getWindowAncestor(this);
       
   253         if (window != null) {
       
   254             if (window instanceof Frame) {
       
   255                 setState(((Frame)window).getExtendedState());
       
   256             }
       
   257             else {
       
   258                 setState(0);
       
   259             }
       
   260             setActive(window.isActive());
       
   261             installListeners();
       
   262             updateSystemIcon();
       
   263         }
       
   264     }
       
   265 
       
   266     public void removeNotify() {
       
   267         super.removeNotify();
       
   268 
       
   269         uninstallListeners();
       
   270         window = null;
       
   271     }
       
   272 
       
   273     /**
       
   274      * Adds any sub-Components contained in the <code>MetalTitlePane</code>.
       
   275      */
       
   276     private void installSubcomponents() {
       
   277         int decorationStyle = getWindowDecorationStyle();
       
   278         if (decorationStyle == JRootPane.FRAME) {
       
   279             createActions();
       
   280             menuBar = createMenuBar();
       
   281             add(menuBar);
       
   282             createButtons();
       
   283             add(iconifyButton);
       
   284             add(toggleButton);
       
   285             add(closeButton);
       
   286         } else if (decorationStyle == JRootPane.PLAIN_DIALOG ||
       
   287                 decorationStyle == JRootPane.INFORMATION_DIALOG ||
       
   288                 decorationStyle == JRootPane.ERROR_DIALOG ||
       
   289                 decorationStyle == JRootPane.COLOR_CHOOSER_DIALOG ||
       
   290                 decorationStyle == JRootPane.FILE_CHOOSER_DIALOG ||
       
   291                 decorationStyle == JRootPane.QUESTION_DIALOG ||
       
   292                 decorationStyle == JRootPane.WARNING_DIALOG) {
       
   293             createActions();
       
   294             createButtons();
       
   295             add(closeButton);
       
   296         }
       
   297     }
       
   298 
       
   299     /**
       
   300      * Determines the Colors to draw with.
       
   301      */
       
   302     private void determineColors() {
       
   303         switch (getWindowDecorationStyle()) {
       
   304         case JRootPane.FRAME:
       
   305             activeBackground = UIManager.getColor("activeCaption");
       
   306             activeForeground = UIManager.getColor("activeCaptionText");
       
   307             activeShadow = UIManager.getColor("activeCaptionBorder");
       
   308             break;
       
   309         case JRootPane.ERROR_DIALOG:
       
   310             activeBackground = UIManager.getColor(
       
   311                 "OptionPane.errorDialog.titlePane.background");
       
   312             activeForeground = UIManager.getColor(
       
   313                 "OptionPane.errorDialog.titlePane.foreground");
       
   314             activeShadow = UIManager.getColor(
       
   315                 "OptionPane.errorDialog.titlePane.shadow");
       
   316             break;
       
   317         case JRootPane.QUESTION_DIALOG:
       
   318         case JRootPane.COLOR_CHOOSER_DIALOG:
       
   319         case JRootPane.FILE_CHOOSER_DIALOG:
       
   320             activeBackground = UIManager.getColor(
       
   321                 "OptionPane.questionDialog.titlePane.background");
       
   322             activeForeground = UIManager.getColor(
       
   323                 "OptionPane.questionDialog.titlePane.foreground");
       
   324             activeShadow = UIManager.getColor(
       
   325                 "OptionPane.questionDialog.titlePane.shadow");
       
   326             break;
       
   327         case JRootPane.WARNING_DIALOG:
       
   328             activeBackground = UIManager.getColor(
       
   329                 "OptionPane.warningDialog.titlePane.background");
       
   330             activeForeground = UIManager.getColor(
       
   331                 "OptionPane.warningDialog.titlePane.foreground");
       
   332             activeShadow = UIManager.getColor(
       
   333                 "OptionPane.warningDialog.titlePane.shadow");
       
   334             break;
       
   335         case JRootPane.PLAIN_DIALOG:
       
   336         case JRootPane.INFORMATION_DIALOG:
       
   337         default:
       
   338             activeBackground = UIManager.getColor("activeCaption");
       
   339             activeForeground = UIManager.getColor("activeCaptionText");
       
   340             activeShadow = UIManager.getColor("activeCaptionBorder");
       
   341             break;
       
   342         }
       
   343         activeBumps.setBumpColors(activeBumpsHighlight, activeBumpsShadow,
       
   344                                   activeBackground);
       
   345     }
       
   346 
       
   347     /**
       
   348      * Installs the fonts and necessary properties on the MetalTitlePane.
       
   349      */
       
   350     private void installDefaults() {
       
   351         setFont(UIManager.getFont("InternalFrame.titleFont", getLocale()));
       
   352     }
       
   353 
       
   354     /**
       
   355      * Uninstalls any previously installed UI values.
       
   356      */
       
   357     private void uninstallDefaults() {
       
   358     }
       
   359 
       
   360     /**
       
   361      * Returns the <code>JMenuBar</code> displaying the appropriate
       
   362      * system menu items.
       
   363      */
       
   364     protected JMenuBar createMenuBar() {
       
   365         menuBar = new SystemMenuBar();
       
   366         menuBar.setFocusable(false);
       
   367         menuBar.setBorderPainted(true);
       
   368         menuBar.add(createMenu());
       
   369         return menuBar;
       
   370     }
       
   371 
       
   372     /**
       
   373      * Closes the Window.
       
   374      */
       
   375     private void close() {
       
   376         Window window = getWindow();
       
   377 
       
   378         if (window != null) {
       
   379             window.dispatchEvent(new WindowEvent(
       
   380                                  window, WindowEvent.WINDOW_CLOSING));
       
   381         }
       
   382     }
       
   383 
       
   384     /**
       
   385      * Iconifies the Frame.
       
   386      */
       
   387     private void iconify() {
       
   388         Frame frame = getFrame();
       
   389         if (frame != null) {
       
   390             frame.setExtendedState(state | Frame.ICONIFIED);
       
   391         }
       
   392     }
       
   393 
       
   394     /**
       
   395      * Maximizes the Frame.
       
   396      */
       
   397     private void maximize() {
       
   398         Frame frame = getFrame();
       
   399         if (frame != null) {
       
   400             frame.setExtendedState(state | Frame.MAXIMIZED_BOTH);
       
   401         }
       
   402     }
       
   403 
       
   404     /**
       
   405      * Restores the Frame size.
       
   406      */
       
   407     private void restore() {
       
   408         Frame frame = getFrame();
       
   409 
       
   410         if (frame == null) {
       
   411             return;
       
   412         }
       
   413 
       
   414         if ((state & Frame.ICONIFIED) != 0) {
       
   415             frame.setExtendedState(state & ~Frame.ICONIFIED);
       
   416         } else {
       
   417             frame.setExtendedState(state & ~Frame.MAXIMIZED_BOTH);
       
   418         }
       
   419     }
       
   420 
       
   421     /**
       
   422      * Create the <code>Action</code>s that get associated with the
       
   423      * buttons and menu items.
       
   424      */
       
   425     private void createActions() {
       
   426         closeAction = new CloseAction();
       
   427         if (getWindowDecorationStyle() == JRootPane.FRAME) {
       
   428             iconifyAction = new IconifyAction();
       
   429             restoreAction = new RestoreAction();
       
   430             maximizeAction = new MaximizeAction();
       
   431         }
       
   432     }
       
   433 
       
   434     /**
       
   435      * Returns the <code>JMenu</code> displaying the appropriate menu items
       
   436      * for manipulating the Frame.
       
   437      */
       
   438     private JMenu createMenu() {
       
   439         JMenu menu = new JMenu("");
       
   440         if (getWindowDecorationStyle() == JRootPane.FRAME) {
       
   441             addMenuItems(menu);
       
   442         }
       
   443         return menu;
       
   444     }
       
   445 
       
   446     /**
       
   447      * Adds the necessary <code>JMenuItem</code>s to the passed in menu.
       
   448      */
       
   449     private void addMenuItems(JMenu menu) {
       
   450         Locale locale = getRootPane().getLocale();
       
   451         JMenuItem mi = menu.add(restoreAction);
       
   452         int mnemonic = MetalUtils.getInt("MetalTitlePane.restoreMnemonic", -1);
       
   453 
       
   454         if (mnemonic != -1) {
       
   455             mi.setMnemonic(mnemonic);
       
   456         }
       
   457 
       
   458         mi = menu.add(iconifyAction);
       
   459         mnemonic = MetalUtils.getInt("MetalTitlePane.iconifyMnemonic", -1);
       
   460         if (mnemonic != -1) {
       
   461             mi.setMnemonic(mnemonic);
       
   462         }
       
   463 
       
   464         if (Toolkit.getDefaultToolkit().isFrameStateSupported(
       
   465                 Frame.MAXIMIZED_BOTH)) {
       
   466             mi = menu.add(maximizeAction);
       
   467             mnemonic =
       
   468                 MetalUtils.getInt("MetalTitlePane.maximizeMnemonic", -1);
       
   469             if (mnemonic != -1) {
       
   470                 mi.setMnemonic(mnemonic);
       
   471             }
       
   472         }
       
   473 
       
   474         menu.add(new JSeparator());
       
   475 
       
   476         mi = menu.add(closeAction);
       
   477         mnemonic = MetalUtils.getInt("MetalTitlePane.closeMnemonic", -1);
       
   478         if (mnemonic != -1) {
       
   479             mi.setMnemonic(mnemonic);
       
   480         }
       
   481     }
       
   482 
       
   483     /**
       
   484      * Returns a <code>JButton</code> appropriate for placement on the
       
   485      * TitlePane.
       
   486      */
       
   487     private JButton createTitleButton() {
       
   488         JButton button = new JButton();
       
   489 
       
   490         button.setFocusPainted(false);
       
   491         button.setFocusable(false);
       
   492         button.setOpaque(true);
       
   493         return button;
       
   494     }
       
   495 
       
   496     /**
       
   497      * Creates the Buttons that will be placed on the TitlePane.
       
   498      */
       
   499     private void createButtons() {
       
   500         closeButton = createTitleButton();
       
   501         closeButton.setAction(closeAction);
       
   502         closeButton.setText(null);
       
   503         closeButton.putClientProperty("paintActive", Boolean.TRUE);
       
   504         closeButton.setBorder(handyEmptyBorder);
       
   505         closeButton.putClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY,
       
   506                                       "Close");
       
   507         closeButton.setIcon(UIManager.getIcon("InternalFrame.closeIcon"));
       
   508 
       
   509         if (getWindowDecorationStyle() == JRootPane.FRAME) {
       
   510             maximizeIcon = UIManager.getIcon("InternalFrame.maximizeIcon");
       
   511             minimizeIcon = UIManager.getIcon("InternalFrame.minimizeIcon");
       
   512 
       
   513             iconifyButton = createTitleButton();
       
   514             iconifyButton.setAction(iconifyAction);
       
   515             iconifyButton.setText(null);
       
   516             iconifyButton.putClientProperty("paintActive", Boolean.TRUE);
       
   517             iconifyButton.setBorder(handyEmptyBorder);
       
   518             iconifyButton.putClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY,
       
   519                                             "Iconify");
       
   520             iconifyButton.setIcon(UIManager.getIcon("InternalFrame.iconifyIcon"));
       
   521 
       
   522             toggleButton = createTitleButton();
       
   523             toggleButton.setAction(restoreAction);
       
   524             toggleButton.putClientProperty("paintActive", Boolean.TRUE);
       
   525             toggleButton.setBorder(handyEmptyBorder);
       
   526             toggleButton.putClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY,
       
   527                                            "Maximize");
       
   528             toggleButton.setIcon(maximizeIcon);
       
   529         }
       
   530     }
       
   531 
       
   532     /**
       
   533      * Returns the <code>LayoutManager</code> that should be installed on
       
   534      * the <code>MetalTitlePane</code>.
       
   535      */
       
   536     private LayoutManager createLayout() {
       
   537         return new TitlePaneLayout();
       
   538     }
       
   539 
       
   540     /**
       
   541      * Updates state dependant upon the Window's active state.
       
   542      */
       
   543     private void setActive(boolean isActive) {
       
   544         Boolean activeB = isActive ? Boolean.TRUE : Boolean.FALSE;
       
   545 
       
   546         closeButton.putClientProperty("paintActive", activeB);
       
   547         if (getWindowDecorationStyle() == JRootPane.FRAME) {
       
   548             iconifyButton.putClientProperty("paintActive", activeB);
       
   549             toggleButton.putClientProperty("paintActive", activeB);
       
   550         }
       
   551         // Repaint the whole thing as the Borders that are used have
       
   552         // different colors for active vs inactive
       
   553         getRootPane().repaint();
       
   554     }
       
   555 
       
   556     /**
       
   557      * Sets the state of the Window.
       
   558      */
       
   559     private void setState(int state) {
       
   560         setState(state, false);
       
   561     }
       
   562 
       
   563     /**
       
   564      * Sets the state of the window. If <code>updateRegardless</code> is
       
   565      * true and the state has not changed, this will update anyway.
       
   566      */
       
   567     private void setState(int state, boolean updateRegardless) {
       
   568         Window w = getWindow();
       
   569 
       
   570         if (w != null && getWindowDecorationStyle() == JRootPane.FRAME) {
       
   571             if (this.state == state && !updateRegardless) {
       
   572                 return;
       
   573             }
       
   574             Frame frame = getFrame();
       
   575 
       
   576             if (frame != null) {
       
   577                 JRootPane rootPane = getRootPane();
       
   578 
       
   579                 if (((state & Frame.MAXIMIZED_BOTH) != 0) &&
       
   580                         (rootPane.getBorder() == null ||
       
   581                         (rootPane.getBorder() instanceof UIResource)) &&
       
   582                             frame.isShowing()) {
       
   583                     rootPane.setBorder(null);
       
   584                 }
       
   585                 else if ((state & Frame.MAXIMIZED_BOTH) == 0) {
       
   586                     // This is a croak, if state becomes bound, this can
       
   587                     // be nuked.
       
   588                     rootPaneUI.installBorder(rootPane);
       
   589                 }
       
   590                 if (frame.isResizable()) {
       
   591                     if ((state & Frame.MAXIMIZED_BOTH) != 0) {
       
   592                         updateToggleButton(restoreAction, minimizeIcon);
       
   593                         maximizeAction.setEnabled(false);
       
   594                         restoreAction.setEnabled(true);
       
   595                     }
       
   596                     else {
       
   597                         updateToggleButton(maximizeAction, maximizeIcon);
       
   598                         maximizeAction.setEnabled(true);
       
   599                         restoreAction.setEnabled(false);
       
   600                     }
       
   601                     if (toggleButton.getParent() == null ||
       
   602                         iconifyButton.getParent() == null) {
       
   603                         add(toggleButton);
       
   604                         add(iconifyButton);
       
   605                         revalidate();
       
   606                         repaint();
       
   607                     }
       
   608                     toggleButton.setText(null);
       
   609                 }
       
   610                 else {
       
   611                     maximizeAction.setEnabled(false);
       
   612                     restoreAction.setEnabled(false);
       
   613                     if (toggleButton.getParent() != null) {
       
   614                         remove(toggleButton);
       
   615                         revalidate();
       
   616                         repaint();
       
   617                     }
       
   618                 }
       
   619             }
       
   620             else {
       
   621                 // Not contained in a Frame
       
   622                 maximizeAction.setEnabled(false);
       
   623                 restoreAction.setEnabled(false);
       
   624                 iconifyAction.setEnabled(false);
       
   625                 remove(toggleButton);
       
   626                 remove(iconifyButton);
       
   627                 revalidate();
       
   628                 repaint();
       
   629             }
       
   630             closeAction.setEnabled(true);
       
   631             this.state = state;
       
   632         }
       
   633     }
       
   634 
       
   635     /**
       
   636      * Updates the toggle button to contain the Icon <code>icon</code>, and
       
   637      * Action <code>action</code>.
       
   638      */
       
   639     private void updateToggleButton(Action action, Icon icon) {
       
   640         toggleButton.setAction(action);
       
   641         toggleButton.setIcon(icon);
       
   642         toggleButton.setText(null);
       
   643     }
       
   644 
       
   645     /**
       
   646      * Returns the Frame rendering in. This will return null if the
       
   647      * <code>JRootPane</code> is not contained in a <code>Frame</code>.
       
   648      */
       
   649     private Frame getFrame() {
       
   650         Window window = getWindow();
       
   651 
       
   652         if (window instanceof Frame) {
       
   653             return (Frame)window;
       
   654         }
       
   655         return null;
       
   656     }
       
   657 
       
   658     /**
       
   659      * Returns the <code>Window</code> the <code>JRootPane</code> is
       
   660      * contained in. This will return null if there is no parent ancestor
       
   661      * of the <code>JRootPane</code>.
       
   662      */
       
   663     private Window getWindow() {
       
   664         return window;
       
   665     }
       
   666 
       
   667     /**
       
   668      * Returns the String to display as the title.
       
   669      */
       
   670     private String getTitle() {
       
   671         Window w = getWindow();
       
   672 
       
   673         if (w instanceof Frame) {
       
   674             return ((Frame)w).getTitle();
       
   675         }
       
   676         else if (w instanceof Dialog) {
       
   677             return ((Dialog)w).getTitle();
       
   678         }
       
   679         return null;
       
   680     }
       
   681 
       
   682     /**
       
   683      * Renders the TitlePane.
       
   684      */
       
   685     public void paintComponent(Graphics g)  {
       
   686         // As state isn't bound, we need a convenience place to check
       
   687         // if it has changed. Changing the state typically changes the
       
   688         if (getFrame() != null) {
       
   689             setState(getFrame().getExtendedState());
       
   690         }
       
   691         JRootPane rootPane = getRootPane();
       
   692         Window window = getWindow();
       
   693         boolean leftToRight = (window == null) ?
       
   694                                rootPane.getComponentOrientation().isLeftToRight() :
       
   695                                window.getComponentOrientation().isLeftToRight();
       
   696         boolean isSelected = (window == null) ? true : window.isActive();
       
   697         int width = getWidth();
       
   698         int height = getHeight();
       
   699 
       
   700         Color background;
       
   701         Color foreground;
       
   702         Color darkShadow;
       
   703 
       
   704         MetalBumps bumps;
       
   705 
       
   706         if (isSelected) {
       
   707             background = activeBackground;
       
   708             foreground = activeForeground;
       
   709             darkShadow = activeShadow;
       
   710             bumps = activeBumps;
       
   711         } else {
       
   712             background = inactiveBackground;
       
   713             foreground = inactiveForeground;
       
   714             darkShadow = inactiveShadow;
       
   715             bumps = inactiveBumps;
       
   716         }
       
   717 
       
   718         g.setColor(background);
       
   719         g.fillRect(0, 0, width, height);
       
   720 
       
   721         g.setColor( darkShadow );
       
   722         g.drawLine ( 0, height - 1, width, height -1);
       
   723         g.drawLine ( 0, 0, 0 ,0);
       
   724         g.drawLine ( width - 1, 0 , width -1, 0);
       
   725 
       
   726         int xOffset = leftToRight ? 5 : width - 5;
       
   727 
       
   728         if (getWindowDecorationStyle() == JRootPane.FRAME) {
       
   729             xOffset += leftToRight ? IMAGE_WIDTH + 5 : - IMAGE_WIDTH - 5;
       
   730         }
       
   731 
       
   732         String theTitle = getTitle();
       
   733         if (theTitle != null) {
       
   734             FontMetrics fm = SwingUtilities2.getFontMetrics(rootPane, g);
       
   735 
       
   736             g.setColor(foreground);
       
   737 
       
   738             int yOffset = ( (height - fm.getHeight() ) / 2 ) + fm.getAscent();
       
   739 
       
   740             Rectangle rect = new Rectangle(0, 0, 0, 0);
       
   741             if (iconifyButton != null && iconifyButton.getParent() != null) {
       
   742                 rect = iconifyButton.getBounds();
       
   743             }
       
   744             int titleW;
       
   745 
       
   746             if( leftToRight ) {
       
   747                 if (rect.x == 0) {
       
   748                     rect.x = window.getWidth() - window.getInsets().right-2;
       
   749                 }
       
   750                 titleW = rect.x - xOffset - 4;
       
   751                 theTitle = SwingUtilities2.clipStringIfNecessary(
       
   752                                 rootPane, fm, theTitle, titleW);
       
   753             } else {
       
   754                 titleW = xOffset - rect.x - rect.width - 4;
       
   755                 theTitle = SwingUtilities2.clipStringIfNecessary(
       
   756                                 rootPane, fm, theTitle, titleW);
       
   757                 xOffset -= SwingUtilities2.stringWidth(rootPane, fm,
       
   758                                                        theTitle);
       
   759             }
       
   760             int titleLength = SwingUtilities2.stringWidth(rootPane, fm,
       
   761                                                           theTitle);
       
   762             SwingUtilities2.drawString(rootPane, g, theTitle, xOffset,
       
   763                                        yOffset );
       
   764             xOffset += leftToRight ? titleLength + 5  : -5;
       
   765         }
       
   766 
       
   767         int bumpXOffset;
       
   768         int bumpLength;
       
   769         if( leftToRight ) {
       
   770             bumpLength = width - buttonsWidth - xOffset - 5;
       
   771             bumpXOffset = xOffset;
       
   772         } else {
       
   773             bumpLength = xOffset - buttonsWidth - 5;
       
   774             bumpXOffset = buttonsWidth + 5;
       
   775         }
       
   776         int bumpYOffset = 3;
       
   777         int bumpHeight = getHeight() - (2 * bumpYOffset);
       
   778         bumps.setBumpArea( bumpLength, bumpHeight );
       
   779         bumps.paintIcon(this, g, bumpXOffset, bumpYOffset);
       
   780     }
       
   781 
       
   782     /**
       
   783      * Actions used to <code>close</code> the <code>Window</code>.
       
   784      */
       
   785     @SuppressWarnings("serial") // Superclass is not serializable across versions
       
   786     private class CloseAction extends AbstractAction {
       
   787         public CloseAction() {
       
   788             super(UIManager.getString("MetalTitlePane.closeTitle",
       
   789                                       getLocale()));
       
   790         }
       
   791 
       
   792         public void actionPerformed(ActionEvent e) {
       
   793             close();
       
   794         }
       
   795     }
       
   796 
       
   797 
       
   798     /**
       
   799      * Actions used to <code>iconfiy</code> the <code>Frame</code>.
       
   800      */
       
   801     @SuppressWarnings("serial") // Superclass is not serializable across versions
       
   802     private class IconifyAction extends AbstractAction {
       
   803         public IconifyAction() {
       
   804             super(UIManager.getString("MetalTitlePane.iconifyTitle",
       
   805                                       getLocale()));
       
   806         }
       
   807 
       
   808         public void actionPerformed(ActionEvent e) {
       
   809             iconify();
       
   810         }
       
   811     }
       
   812 
       
   813 
       
   814     /**
       
   815      * Actions used to <code>restore</code> the <code>Frame</code>.
       
   816      */
       
   817     @SuppressWarnings("serial") // Superclass is not serializable across versions
       
   818     private class RestoreAction extends AbstractAction {
       
   819         public RestoreAction() {
       
   820             super(UIManager.getString
       
   821                   ("MetalTitlePane.restoreTitle", getLocale()));
       
   822         }
       
   823 
       
   824         public void actionPerformed(ActionEvent e) {
       
   825             restore();
       
   826         }
       
   827     }
       
   828 
       
   829 
       
   830     /**
       
   831      * Actions used to <code>restore</code> the <code>Frame</code>.
       
   832      */
       
   833     @SuppressWarnings("serial") // Superclass is not serializable across versions
       
   834     private class MaximizeAction extends AbstractAction {
       
   835         public MaximizeAction() {
       
   836             super(UIManager.getString("MetalTitlePane.maximizeTitle",
       
   837                                       getLocale()));
       
   838         }
       
   839 
       
   840         public void actionPerformed(ActionEvent e) {
       
   841             maximize();
       
   842         }
       
   843     }
       
   844 
       
   845 
       
   846     /**
       
   847      * Class responsible for drawing the system menu. Looks up the
       
   848      * image to draw from the Frame associated with the
       
   849      * <code>JRootPane</code>.
       
   850      */
       
   851     @SuppressWarnings("serial") // Superclass is not serializable across versions
       
   852     private class SystemMenuBar extends JMenuBar {
       
   853         public void paint(Graphics g) {
       
   854             if (isOpaque()) {
       
   855                 g.setColor(getBackground());
       
   856                 g.fillRect(0, 0, getWidth(), getHeight());
       
   857             }
       
   858 
       
   859             if (systemIcon != null) {
       
   860                 g.drawImage(systemIcon, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, null);
       
   861             } else {
       
   862                 Icon icon = UIManager.getIcon("InternalFrame.icon");
       
   863 
       
   864                 if (icon != null) {
       
   865                     icon.paintIcon(this, g, 0, 0);
       
   866                 }
       
   867             }
       
   868         }
       
   869         public Dimension getMinimumSize() {
       
   870             return getPreferredSize();
       
   871         }
       
   872         public Dimension getPreferredSize() {
       
   873             Dimension size = super.getPreferredSize();
       
   874 
       
   875             return new Dimension(Math.max(IMAGE_WIDTH, size.width),
       
   876                                  Math.max(size.height, IMAGE_HEIGHT));
       
   877         }
       
   878     }
       
   879 
       
   880     private class TitlePaneLayout implements LayoutManager {
       
   881         public void addLayoutComponent(String name, Component c) {}
       
   882         public void removeLayoutComponent(Component c) {}
       
   883         public Dimension preferredLayoutSize(Container c)  {
       
   884             int height = computeHeight();
       
   885             return new Dimension(height, height);
       
   886         }
       
   887 
       
   888         public Dimension minimumLayoutSize(Container c) {
       
   889             return preferredLayoutSize(c);
       
   890         }
       
   891 
       
   892         private int computeHeight() {
       
   893             FontMetrics fm = rootPane.getFontMetrics(getFont());
       
   894             int fontHeight = fm.getHeight();
       
   895             fontHeight += 7;
       
   896             int iconHeight = 0;
       
   897             if (getWindowDecorationStyle() == JRootPane.FRAME) {
       
   898                 iconHeight = IMAGE_HEIGHT;
       
   899             }
       
   900 
       
   901             int finalHeight = Math.max( fontHeight, iconHeight );
       
   902             return finalHeight;
       
   903         }
       
   904 
       
   905         public void layoutContainer(Container c) {
       
   906             boolean leftToRight = (window == null) ?
       
   907                 getRootPane().getComponentOrientation().isLeftToRight() :
       
   908                 window.getComponentOrientation().isLeftToRight();
       
   909 
       
   910             int w = getWidth();
       
   911             int x;
       
   912             int y = 3;
       
   913             int spacing;
       
   914             int buttonHeight;
       
   915             int buttonWidth;
       
   916 
       
   917             if (closeButton != null && closeButton.getIcon() != null) {
       
   918                 buttonHeight = closeButton.getIcon().getIconHeight();
       
   919                 buttonWidth = closeButton.getIcon().getIconWidth();
       
   920             }
       
   921             else {
       
   922                 buttonHeight = IMAGE_HEIGHT;
       
   923                 buttonWidth = IMAGE_WIDTH;
       
   924             }
       
   925 
       
   926             // assumes all buttons have the same dimensions
       
   927             // these dimensions include the borders
       
   928 
       
   929             x = leftToRight ? w : 0;
       
   930 
       
   931             spacing = 5;
       
   932             x = leftToRight ? spacing : w - buttonWidth - spacing;
       
   933             if (menuBar != null) {
       
   934                 menuBar.setBounds(x, y, buttonWidth, buttonHeight);
       
   935             }
       
   936 
       
   937             x = leftToRight ? w : 0;
       
   938             spacing = 4;
       
   939             x += leftToRight ? -spacing -buttonWidth : spacing;
       
   940             if (closeButton != null) {
       
   941                 closeButton.setBounds(x, y, buttonWidth, buttonHeight);
       
   942             }
       
   943 
       
   944             if( !leftToRight ) x += buttonWidth;
       
   945 
       
   946             if (getWindowDecorationStyle() == JRootPane.FRAME) {
       
   947                 if (Toolkit.getDefaultToolkit().isFrameStateSupported(
       
   948                         Frame.MAXIMIZED_BOTH)) {
       
   949                     if (toggleButton.getParent() != null) {
       
   950                         spacing = 10;
       
   951                         x += leftToRight ? -spacing -buttonWidth : spacing;
       
   952                         toggleButton.setBounds(x, y, buttonWidth, buttonHeight);
       
   953                         if (!leftToRight) {
       
   954                             x += buttonWidth;
       
   955                         }
       
   956                     }
       
   957                 }
       
   958 
       
   959                 if (iconifyButton != null && iconifyButton.getParent() != null) {
       
   960                     spacing = 2;
       
   961                     x += leftToRight ? -spacing -buttonWidth : spacing;
       
   962                     iconifyButton.setBounds(x, y, buttonWidth, buttonHeight);
       
   963                     if (!leftToRight) {
       
   964                         x += buttonWidth;
       
   965                     }
       
   966                 }
       
   967             }
       
   968             buttonsWidth = leftToRight ? w - x : x;
       
   969         }
       
   970     }
       
   971 
       
   972 
       
   973 
       
   974     /**
       
   975      * PropertyChangeListener installed on the Window. Updates the necessary
       
   976      * state as the state of the Window changes.
       
   977      */
       
   978     private class PropertyChangeHandler implements PropertyChangeListener {
       
   979         public void propertyChange(PropertyChangeEvent pce) {
       
   980             String name = pce.getPropertyName();
       
   981 
       
   982             // Frame.state isn't currently bound.
       
   983             if ("resizable".equals(name) || "state".equals(name)) {
       
   984                 Frame frame = getFrame();
       
   985 
       
   986                 if (frame != null) {
       
   987                     setState(frame.getExtendedState(), true);
       
   988                 }
       
   989                 if ("resizable".equals(name)) {
       
   990                     getRootPane().repaint();
       
   991                 }
       
   992             }
       
   993             else if ("title".equals(name)) {
       
   994                 repaint();
       
   995             }
       
   996             else if ("componentOrientation" == name) {
       
   997                 revalidate();
       
   998                 repaint();
       
   999             }
       
  1000             else if ("iconImage" == name) {
       
  1001                 updateSystemIcon();
       
  1002                 revalidate();
       
  1003                 repaint();
       
  1004             }
       
  1005         }
       
  1006     }
       
  1007 
       
  1008     /**
       
  1009      * Update the image used for the system icon
       
  1010      */
       
  1011     private void updateSystemIcon() {
       
  1012         Window window = getWindow();
       
  1013         if (window == null) {
       
  1014             systemIcon = null;
       
  1015             return;
       
  1016         }
       
  1017         java.util.List<Image> icons = window.getIconImages();
       
  1018         assert icons != null;
       
  1019 
       
  1020         if (icons.size() == 0) {
       
  1021             systemIcon = null;
       
  1022         }
       
  1023         else if (icons.size() == 1) {
       
  1024             systemIcon = icons.get(0);
       
  1025         }
       
  1026         else {
       
  1027             systemIcon = SunToolkit.getScaledIconImage(icons,
       
  1028                                                        IMAGE_WIDTH,
       
  1029                                                        IMAGE_HEIGHT);
       
  1030         }
       
  1031     }
       
  1032 
       
  1033 
       
  1034     /**
       
  1035      * WindowListener installed on the Window, updates the state as necessary.
       
  1036      */
       
  1037     private class WindowHandler extends WindowAdapter {
       
  1038         public void windowActivated(WindowEvent ev) {
       
  1039             setActive(true);
       
  1040         }
       
  1041 
       
  1042         public void windowDeactivated(WindowEvent ev) {
       
  1043             setActive(false);
       
  1044         }
       
  1045     }
       
  1046 }