Source for javax.swing.plaf.basic.BasicInternalFrameTitlePane

   1: /* BasicInternalFrameTitlePane.java --
   2:    Copyright (C) 2004, 2005 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package javax.swing.plaf.basic;
  40: 
  41: import java.awt.Color;
  42: import java.awt.Component;
  43: import java.awt.Container;
  44: import java.awt.Dimension;
  45: import java.awt.Font;
  46: import java.awt.FontMetrics;
  47: import java.awt.Graphics;
  48: import java.awt.Insets;
  49: import java.awt.LayoutManager;
  50: import java.awt.Rectangle;
  51: import java.awt.event.ActionEvent;
  52: import java.awt.event.KeyEvent;
  53: import java.beans.PropertyChangeEvent;
  54: import java.beans.PropertyChangeListener;
  55: import java.beans.PropertyVetoException;
  56: 
  57: import javax.swing.AbstractAction;
  58: import javax.swing.Action;
  59: import javax.swing.Icon;
  60: import javax.swing.JButton;
  61: import javax.swing.JComponent;
  62: import javax.swing.JInternalFrame;
  63: import javax.swing.JLabel;
  64: import javax.swing.JMenu;
  65: import javax.swing.JMenuBar;
  66: import javax.swing.JMenuItem;
  67: import javax.swing.SwingConstants;
  68: import javax.swing.SwingUtilities;
  69: import javax.swing.UIManager;
  70: 
  71: /**
  72:  * This class acts as a titlebar for JInternalFrames.
  73:  */
  74: public class BasicInternalFrameTitlePane extends JComponent
  75: {
  76:   /**
  77:    * The Action responsible for closing the JInternalFrame.
  78:    *
  79:    * @specnote Apparently this class was intended to be protected,
  80:    *           but was made public by a compiler bug and is now
  81:    *           public for compatibility.
  82:    */
  83:   public class CloseAction extends AbstractAction
  84:   {
  85:     /**
  86:      * Creates a new action.
  87:      */
  88:     public CloseAction()
  89:     {
  90:       super("Close");
  91:     }
  92:     
  93:     /**
  94:      * This method is called when something closes the JInternalFrame.
  95:      *
  96:      * @param e The ActionEvent.
  97:      */
  98:     public void actionPerformed(ActionEvent e)
  99:     {
 100:       if (frame.isClosable())
 101:         {
 102:           try
 103:             {
 104:               frame.setClosed(true);
 105:             }
 106:           catch (PropertyVetoException pve)
 107:             {
 108:               // We do nothing if the attempt has been vetoed.
 109:             }
 110:         }
 111:     }
 112:   }
 113: 
 114:   /**
 115:    * This Action is responsible for iconifying the JInternalFrame.
 116:    *
 117:    * @specnote Apparently this class was intended to be protected,
 118:    *           but was made public by a compiler bug and is now
 119:    *           public for compatibility.
 120:    */
 121:   public class IconifyAction extends AbstractAction
 122:   {
 123:     /**
 124:      * Creates a new action.
 125:      */
 126:     public IconifyAction()
 127:     {
 128:       super("Minimize");
 129:     }
 130: 
 131:     /**
 132:      * This method is called when the user wants to iconify the
 133:      * JInternalFrame.
 134:      *
 135:      * @param e The ActionEvent.
 136:      */
 137:     public void actionPerformed(ActionEvent e)
 138:     {
 139:       if (frame.isIconifiable() && ! frame.isIcon())
 140:         {
 141:           try
 142:             {
 143:               frame.setIcon(true);
 144:             }
 145:           catch (PropertyVetoException pve)
 146:             {
 147:               // We do nothing if the attempt has been vetoed.
 148:             }
 149:         }
 150:     }
 151:   }
 152: 
 153:   /**
 154:    * This Action is responsible for maximizing the JInternalFrame.
 155:    *
 156:    * @specnote Apparently this class was intended to be protected,
 157:    *           but was made public by a compiler bug and is now
 158:    *           public for compatibility.
 159:    */
 160:   public class MaximizeAction extends AbstractAction
 161:   {
 162:     /**
 163:      * Creates a new action.
 164:      */
 165:     public MaximizeAction()
 166:     {
 167:       super("Maximize");
 168:     }
 169:     /**
 170:      * This method is called when the user wants to maximize the
 171:      * JInternalFrame.
 172:      *
 173:      * @param e The ActionEvent.
 174:      */
 175:     public void actionPerformed(ActionEvent e)
 176:     {
 177:       try
 178:         {
 179:           if (frame.isMaximizable() && ! frame.isMaximum())
 180:             {
 181:               frame.setMaximum(true);
 182:               maxButton.setIcon(minIcon);
 183:             }
 184:           else if (frame.isMaximum())
 185:             {
 186:               frame.setMaximum(false);
 187:               maxButton.setIcon(maxIcon);
 188:             }
 189:         }
 190:       catch (PropertyVetoException pve)
 191:         {
 192:           // We do nothing if the attempt has been vetoed.
 193:         }
 194:     }
 195:   }
 196: 
 197:   /**
 198:    * This Action is responsible for dragging the JInternalFrame.
 199:    *
 200:    * @specnote Apparently this class was intended to be protected,
 201:    *           but was made public by a compiler bug and is now
 202:    *           public for compatibility.
 203:    */
 204:   public class MoveAction extends AbstractAction
 205:   {
 206:     /**
 207:      * Creates a new action.
 208:      */
 209:     public MoveAction()
 210:     {
 211:       super("Move");
 212:     }
 213:     /**
 214:      * This method is called when the user wants to drag the JInternalFrame.
 215:      *
 216:      * @param e The ActionEvent.
 217:      */
 218:     public void actionPerformed(ActionEvent e)
 219:     {
 220:       // FIXME: Implement keyboard driven? move actions.
 221:     }
 222:   }
 223: 
 224:   /**
 225:    * This Action is responsible for restoring the JInternalFrame. Restoring
 226:    * the JInternalFrame is the same as setting the maximum property to false.
 227:    *
 228:    * @specnote Apparently this class was intended to be protected,
 229:    *           but was made public by a compiler bug and is now
 230:    *           public for compatibility.
 231:    */
 232:   public class RestoreAction extends AbstractAction
 233:   {
 234:     /**
 235:      * Creates a new action.
 236:      */
 237:     public RestoreAction()
 238:     {
 239:       super("Restore");
 240:     }
 241:     /**
 242:      * This method is called when the user wants to restore the
 243:      * JInternalFrame.
 244:      *
 245:      * @param e The ActionEvent.
 246:      */
 247:     public void actionPerformed(ActionEvent e)
 248:     {
 249:       if (frame.isMaximum())
 250:         {
 251:           try
 252:             {
 253:               frame.setMaximum(false);
 254:             }
 255:           catch (PropertyVetoException pve)
 256:             {
 257:               // We do nothing if the attempt has been vetoed.
 258:             }
 259:         }
 260:     }
 261:   }
 262: 
 263:   /**
 264:    * This action is responsible for sizing the JInternalFrame.
 265:    *
 266:    * @specnote Apparently this class was intended to be protected,
 267:    *           but was made public by a compiler bug and is now
 268:    *           public for compatibility.
 269:    */
 270:   public class SizeAction extends AbstractAction
 271:   {
 272:     /**
 273:      * Creates a new action.
 274:      */
 275:     public SizeAction()
 276:     {
 277:       super("Size");
 278:     }
 279:     /**
 280:      * This method is called when the user wants to resize the JInternalFrame.
 281:      *
 282:      * @param e The ActionEvent.
 283:      */
 284:     public void actionPerformed(ActionEvent e)
 285:     {
 286:       // FIXME: Not sure how size actions should be handled.
 287:     }
 288:   }
 289: 
 290:   /**
 291:    * This class is responsible for handling property change events from the
 292:    * JInternalFrame and adjusting the Title Pane as necessary.
 293:    *
 294:    * @specnote Apparently this class was intended to be protected,
 295:    *           but was made public by a compiler bug and is now
 296:    *           public for compatibility.
 297:    */
 298:   public class PropertyChangeHandler implements PropertyChangeListener
 299:   {
 300:     /**
 301:      * This method is called when a PropertyChangeEvent is received by the
 302:      * Title Pane.
 303:      *
 304:      * @param evt The PropertyChangeEvent.
 305:      */
 306:     public void propertyChange(PropertyChangeEvent evt)
 307:     {
 308:       String propName = evt.getPropertyName();
 309:       if (propName.equals("closable"))
 310:         {
 311:           if (evt.getNewValue().equals(Boolean.TRUE))
 312:             closeButton.setVisible(true);
 313:           else
 314:             closeButton.setVisible(false);
 315:         }
 316:       else if (propName.equals("iconable"))
 317:         {
 318:           if (evt.getNewValue().equals(Boolean.TRUE))
 319:             iconButton.setVisible(true);
 320:           else
 321:             iconButton.setVisible(false);
 322:         }
 323:       else if (propName.equals("maximizable"))
 324:         {
 325:           if (evt.getNewValue().equals(Boolean.TRUE))
 326:             maxButton.setVisible(true);
 327:           else
 328:             maxButton.setVisible(false);
 329:         }
 330:       enableActions();
 331:     }
 332:   }
 333: 
 334:   /**
 335:    * This class acts as the MenuBar for the TitlePane. Clicking on the Frame
 336:    * Icon in the top left corner will activate it.
 337:    *
 338:    * @specnote Apparently this class was intended to be protected,
 339:    *           but was made public by a compiler bug and is now
 340:    *           public for compatibility.
 341:    */
 342:   public class SystemMenuBar extends JMenuBar
 343:   {
 344:     /**
 345:      * This method returns true if it can receive focus.
 346:      *
 347:      * @return True if this Component can receive focus.
 348:      */
 349:     public boolean isFocusTraversable()
 350:     {
 351:       return true;
 352:     }
 353: 
 354:     /**
 355:      * This method returns true if this Component is expected to paint all of
 356:      * itself.
 357:      *
 358:      * @return True if this Component is expect to paint all of itself.
 359:      */
 360:     public boolean isOpaque()
 361:     {
 362:       return true;
 363:     }
 364: 
 365:     /**
 366:      * This method paints this Component.
 367:      *
 368:      * @param g The Graphics object to paint with.
 369:      */
 370:     public void paint(Graphics g)
 371:     {
 372:       Icon frameIcon = frame.getFrameIcon();
 373:       if (frameIcon == null)
 374:     frameIcon = BasicDesktopIconUI.defaultIcon;
 375:       frameIcon.paintIcon(this, g, 0, 0);
 376:     }
 377: 
 378:     /**
 379:      * This method requests that focus be given to this Component.
 380:      */
 381:     public void requestFocus()
 382:     {
 383:       super.requestFocus();
 384:     }
 385:   }
 386: 
 387:   /**
 388:    * This class acts as the Layout Manager for the TitlePane.
 389:    *
 390:    * @specnote Apparently this class was intended to be protected,
 391:    *           but was made public by a compiler bug and is now
 392:    *           public for compatibility.
 393:    */
 394:   public class TitlePaneLayout implements LayoutManager
 395:   {
 396:     /**
 397:      * Creates a new <code>TitlePaneLayout</code> object.
 398:      */
 399:     public TitlePaneLayout()
 400:     {
 401:       // Do nothing.
 402:     }
 403: 
 404:     /**
 405:      * This method is called when adding a Component to the Container.
 406:      *
 407:      * @param name The name to reference the added Component by.
 408:      * @param c The Component to add.
 409:      */
 410:     public void addLayoutComponent(String name, Component c)
 411:     {
 412:       // Do nothing.
 413:     }
 414: 
 415:     /**
 416:      * This method is called to lay out the children of the Title Pane.
 417:      *
 418:      * @param c The Container to lay out.
 419:      */
 420:     public void layoutContainer(Container c)
 421:     {
 422:       Dimension size = c.getSize();
 423:       Insets insets = c.getInsets();
 424:       int width = size.width - insets.left - insets.right;
 425:       int height = size.height - insets.top - insets.bottom;
 426: 
 427:       // MenuBar is always present and located at the top left corner.
 428:       Dimension menupref = menuBar.getPreferredSize();
 429:       menuBar.setBounds(insets.left, insets.top, menupref.width, height);
 430: 
 431:       int loc = width + insets.left - 1;
 432:       int top = insets.top + 1;
 433:       int buttonHeight = height - 4;
 434:       if (closeButton.isVisible())
 435:         {
 436:           int buttonWidth = closeIcon.getIconWidth();
 437:           loc -= buttonWidth + 2;
 438:           closeButton.setBounds(loc, top, buttonWidth, buttonHeight);
 439:         }
 440: 
 441:       if (maxButton.isVisible())
 442:         {
 443:           int buttonWidth = maxIcon.getIconWidth();
 444:           loc -= buttonWidth + 2;
 445:           maxButton.setBounds(loc, top, buttonWidth, buttonHeight);
 446:         }
 447: 
 448:       if (iconButton.isVisible())
 449:         {
 450:           int buttonWidth = iconIcon.getIconWidth();
 451:           loc -= buttonWidth + 2;
 452:           iconButton.setBounds(loc, top, buttonWidth, buttonHeight);
 453:         }
 454: 
 455:       if (title != null)
 456:     title.setBounds(insets.left + menupref.width, insets.top,
 457:                     loc - menupref.width - insets.left, height);
 458:     }
 459: 
 460:     /**
 461:      * This method returns the minimum size of the given Container given the
 462:      * children that it has.
 463:      *
 464:      * @param c The Container to get a minimum size for.
 465:      *
 466:      * @return The minimum size of the Container.
 467:      */
 468:     public Dimension minimumLayoutSize(Container c)
 469:     {
 470:       return preferredLayoutSize(c);
 471:     }
 472: 
 473:     /**
 474:      * This method returns the preferred size of the given Container taking
 475:      * into account the children that it has.
 476:      *
 477:      * @param c The Container to lay out.
 478:      *
 479:      * @return The preferred size of the Container.
 480:      */
 481:     public Dimension preferredLayoutSize(Container c)
 482:     {
 483:       return new Dimension(22, 18);
 484:     }
 485: 
 486:     /**
 487:      * This method is called when removing a Component from the Container.
 488:      *
 489:      * @param c The Component to remove.
 490:      */
 491:     public void removeLayoutComponent(Component c)
 492:     {
 493:       // Nothing to do here.
 494:     }
 495:   }
 496: 
 497:   /**
 498:    * This helper class is used to create the minimize, maximize and close
 499:    * buttons in the top right corner of the Title Pane. These buttons are
 500:    * special since they cannot be given focus and have no border.
 501:    */
 502:   private class PaneButton extends JButton
 503:   {
 504:     /**
 505:      * Creates a new PaneButton object with the given Action.
 506:      *
 507:      * @param a The Action that the button uses.
 508:      */
 509:     public PaneButton(Action a)
 510:     {
 511:       super(a);
 512:       setMargin(new Insets(0, 0, 0, 0));
 513:     }
 514: 
 515:     /**
 516:      * This method returns true if the Component can be focused.
 517:      *
 518:      * @return false.
 519:      */
 520:     public boolean isFocusable()
 521:     {
 522:       // These buttons cannot be given focus.
 523:       return false;
 524:     }
 525: 
 526:   }
 527: 
 528:   /** The action command for the Close action. */
 529:   protected static final String CLOSE_CMD;
 530: 
 531:   /** The action command for the Minimize action. */
 532:   protected static final String ICONIFY_CMD;
 533: 
 534:   /** The action command for the Maximize action. */
 535:   protected static final String MAXIMIZE_CMD;
 536: 
 537:   /** The action command for the Move action. */
 538:   protected static final String MOVE_CMD;
 539: 
 540:   /** The action command for the Restore action. */
 541:   protected static final String RESTORE_CMD;
 542: 
 543:   /** The action command for the Size action. */
 544:   protected static final String SIZE_CMD;
 545: 
 546:   /** The action associated with closing the JInternalFrame. */
 547:   protected Action closeAction;
 548: 
 549:   /** The action associated with iconifying the JInternalFrame. */
 550:   protected Action iconifyAction;
 551: 
 552:   /** The action associated with maximizing the JInternalFrame. */
 553:   protected Action maximizeAction;
 554: 
 555:   /** The action associated with moving the JInternalFrame. */
 556:   protected Action moveAction;
 557: 
 558:   /** The action associated with restoring the JInternalFrame. */
 559:   protected Action restoreAction;
 560: 
 561:   /** The action associated with resizing the JInternalFrame. */
 562:   protected Action sizeAction;
 563: 
 564:   /** The button that closes the JInternalFrame. */
 565:   protected JButton closeButton;
 566: 
 567:   /** The button that iconifies the JInternalFrame. */
 568:   protected JButton iconButton;
 569: 
 570:   /** The button that maximizes the JInternalFrame. */
 571:   protected JButton maxButton;
 572: 
 573:   /** The icon displayed in the restore button. */
 574:   protected Icon minIcon = BasicIconFactory.createEmptyFrameIcon();
 575: 
 576:   /** The icon displayed in the maximize button. */
 577:   protected Icon maxIcon = BasicIconFactory.createEmptyFrameIcon();
 578: 
 579:   /** The icon displayed in the iconify button. */
 580:   protected Icon iconIcon = BasicIconFactory.createEmptyFrameIcon();
 581: 
 582:   /** The icon displayed in the close button. */
 583:   protected Icon closeIcon;
 584:   
 585:   /** The JInternalFrame that this TitlePane is used in. */
 586:   protected JInternalFrame frame;
 587: 
 588:   /** The JMenuBar that is located at the top left of the Title Pane. */
 589:   protected JMenuBar menuBar;
 590: 
 591:   /** The JMenu inside the menuBar. */
 592:   protected JMenu windowMenu;
 593: 
 594:   /**
 595:    * The text color of the TitlePane when the JInternalFrame is not selected.
 596:    */
 597:   protected Color notSelectedTextColor;
 598: 
 599:   /**
 600:    * The background color of the TitlePane when the JInternalFrame is not
 601:    * selected.
 602:    */
 603:   protected Color notSelectedTitleColor;
 604: 
 605:   /** The text color of the titlePane when the JInternalFrame is selected. */
 606:   protected Color selectedTextColor;
 607: 
 608:   /**
 609:    * The background color of the TitlePane when the JInternalFrame is
 610:    * selected.
 611:    */
 612:   protected Color selectedTitleColor;
 613: 
 614:   /** The Property Change listener that listens to the JInternalFrame. */
 615:   protected PropertyChangeListener propertyChangeListener;
 616: 
 617:   /**
 618:    * The label used to display the title. This label is not added to the
 619:    * TitlePane.
 620:    * This is package-private to avoid an accessor method.
 621:    */
 622:   transient JLabel title;
 623:   
 624:   static
 625:     {
 626:       // not constants in JDK
 627:       CLOSE_CMD = "Close";
 628:       ICONIFY_CMD = "Minimize";
 629:       MAXIMIZE_CMD = "Maximize";
 630:       MOVE_CMD = "Move";
 631:       RESTORE_CMD = "Restore";
 632:       SIZE_CMD = "Size";
 633:     }
 634: 
 635:   /**
 636:    * Creates a new BasicInternalFrameTitlePane object that is used in the
 637:    * given JInternalFrame.
 638:    *
 639:    * @param f The JInternalFrame this BasicInternalFrameTitlePane will be used
 640:    *        in.
 641:    */
 642:   public BasicInternalFrameTitlePane(JInternalFrame f)
 643:   {
 644:     frame = f;
 645:     setLayout(createLayout());
 646:     title = new JLabel();
 647:     title.setHorizontalAlignment(SwingConstants.LEFT);
 648:     title.setHorizontalTextPosition(SwingConstants.LEFT);
 649:     title.setOpaque(false);
 650:     setOpaque(true);
 651: 
 652:     setBackground(Color.LIGHT_GRAY);
 653:     setOpaque(true);
 654: 
 655:     installTitlePane();
 656:   }
 657: 
 658:   /**
 659:    * This method installs the TitlePane onto the JInternalFrameTitlePane. It
 660:    * also creates any children components that need to be created and adds
 661:    * listeners to the appropriate components.
 662:    */
 663:   protected void installTitlePane()
 664:   {
 665:     installDefaults();
 666:     installListeners();
 667:     createActions();
 668: 
 669:     assembleSystemMenu();
 670: 
 671:     createButtons();
 672:     setButtonIcons();
 673:     addSubComponents();
 674:     enableActions();
 675:   }
 676: 
 677:   /**
 678:    * This method adds the sub components to the TitlePane.
 679:    */
 680:   protected void addSubComponents()
 681:   {
 682:     add(menuBar);
 683: 
 684:     add(closeButton);
 685:     add(iconButton);
 686:     add(maxButton);
 687:   }
 688: 
 689:   /**
 690:    * This method creates the actions that are used to manipulate the
 691:    * JInternalFrame.
 692:    */
 693:   protected void createActions()
 694:   {
 695:     closeAction = new CloseAction();
 696:     closeAction.putValue(AbstractAction.ACTION_COMMAND_KEY, CLOSE_CMD);
 697: 
 698:     iconifyAction = new IconifyAction();
 699:     iconifyAction.putValue(AbstractAction.ACTION_COMMAND_KEY, ICONIFY_CMD);
 700: 
 701:     maximizeAction = new MaximizeAction();
 702:     maximizeAction.putValue(AbstractAction.ACTION_COMMAND_KEY, MAXIMIZE_CMD);
 703: 
 704:     sizeAction = new SizeAction();
 705:     sizeAction.putValue(AbstractAction.ACTION_COMMAND_KEY, SIZE_CMD);
 706: 
 707:     restoreAction = new RestoreAction();
 708:     restoreAction.putValue(AbstractAction.ACTION_COMMAND_KEY, RESTORE_CMD);
 709: 
 710:     moveAction = new MoveAction();
 711:     moveAction.putValue(AbstractAction.ACTION_COMMAND_KEY, MOVE_CMD);
 712:   }
 713: 
 714:   /**
 715:    * This method is used to install the listeners.
 716:    */
 717:   protected void installListeners()
 718:   {
 719:     propertyChangeListener = createPropertyChangeListener();
 720:     frame.addPropertyChangeListener(propertyChangeListener);
 721:   }
 722: 
 723:   /**
 724:    * This method is used to uninstall the listeners.
 725:    */
 726:   protected void uninstallListeners()
 727:   {
 728:     frame.removePropertyChangeListener(propertyChangeListener);
 729:     propertyChangeListener = null;
 730:   }
 731: 
 732:   /**
 733:    * This method installs the defaults determined by the look and feel.
 734:    */
 735:   protected void installDefaults()
 736:   {
 737:     title.setFont(UIManager.getFont("InternalFrame.titleFont"));
 738:     selectedTextColor = UIManager.getColor("InternalFrame.activeTitleForeground");
 739:     selectedTitleColor = UIManager.getColor("InternalFrame.activeTitleBackground");
 740:     notSelectedTextColor = UIManager.getColor("InternalFrame.inactiveTitleForeground");
 741:     notSelectedTitleColor = UIManager.getColor("InternalFrame.inactiveTitleBackground");
 742:   
 743:     closeIcon = UIManager.getIcon("InternalFrame.closeIcon");
 744:     iconIcon = UIManager.getIcon("InternalFrame.iconifyIcon");
 745:     maxIcon = UIManager.getIcon("InternalFrame.maximizeIcon");
 746:   }
 747: 
 748:   /**
 749:    * This method uninstalls the defaults.
 750:    */
 751:   protected void uninstallDefaults()
 752:   {
 753:     setFont(null);
 754:     selectedTextColor = null;
 755:     selectedTitleColor = null;
 756:     notSelectedTextColor = null;
 757:     notSelectedTitleColor = null;
 758:     
 759:     closeIcon = null;
 760:     iconIcon = null;
 761:     maxIcon = null;
 762:   }
 763: 
 764:   /**
 765:    * This method creates the buttons used in the TitlePane.
 766:    */
 767:   protected void createButtons()
 768:   {
 769:     closeButton = new PaneButton(closeAction);
 770:     closeButton.setText(null);
 771:     if (!frame.isClosable())
 772:       closeButton.setVisible(false);
 773:     iconButton = new PaneButton(iconifyAction);
 774:     iconButton.setText(null);
 775:     if (!frame.isIconifiable())
 776:       iconButton.setVisible(false);
 777:     maxButton = new PaneButton(maximizeAction);
 778:     maxButton.setText(null);
 779:     if (!frame.isMaximizable())
 780:       maxButton.setVisible(false);
 781:   }
 782: 
 783:   /**
 784:    * Set icons for the minimize-, maximize- and close-buttons.
 785:    */
 786:   protected void setButtonIcons()
 787:   {
 788:     if (closeIcon != null && closeButton != null)
 789:       closeButton.setIcon(closeIcon);
 790:     if (iconIcon != null && iconButton != null)
 791:       iconButton.setIcon(iconIcon);
 792:     if (maxIcon != null && maxButton != null)
 793:       maxButton.setIcon(maxIcon);
 794:   }
 795: 
 796:   /**
 797:    * This method creates the MenuBar used in the TitlePane.
 798:    */
 799:   protected void assembleSystemMenu()
 800:   {
 801:     menuBar = createSystemMenuBar();
 802:     windowMenu = createSystemMenu();
 803: 
 804:     menuBar.add(windowMenu);
 805: 
 806:     addSystemMenuItems(windowMenu);
 807:     enableActions();
 808:   }
 809: 
 810:   /**
 811:    * This method adds the MenuItems to the given JMenu.
 812:    *
 813:    * @param systemMenu The JMenu to add MenuItems to.
 814:    */
 815:   protected void addSystemMenuItems(JMenu systemMenu)
 816:   {
 817:     JMenuItem tmp;
 818: 
 819:     tmp = new JMenuItem(RESTORE_CMD);
 820:     tmp.addActionListener(restoreAction);
 821:     tmp.setMnemonic(KeyEvent.VK_R);
 822:     systemMenu.add(tmp);
 823: 
 824:     tmp = new JMenuItem(MOVE_CMD);
 825:     tmp.addActionListener(moveAction);
 826:     tmp.setMnemonic(KeyEvent.VK_M);
 827:     systemMenu.add(tmp);
 828: 
 829:     tmp = new JMenuItem(SIZE_CMD);
 830:     tmp.addActionListener(sizeAction);
 831:     tmp.setMnemonic(KeyEvent.VK_S);
 832:     systemMenu.add(tmp);
 833: 
 834:     tmp = new JMenuItem(ICONIFY_CMD);
 835:     tmp.addActionListener(iconifyAction);
 836:     tmp.setMnemonic(KeyEvent.VK_N);
 837:     systemMenu.add(tmp);
 838: 
 839:     tmp = new JMenuItem(MAXIMIZE_CMD);
 840:     tmp.addActionListener(maximizeAction);
 841:     tmp.setMnemonic(KeyEvent.VK_X);
 842:     systemMenu.add(tmp);
 843: 
 844:     systemMenu.addSeparator();
 845: 
 846:     tmp = new JMenuItem(CLOSE_CMD);
 847:     tmp.addActionListener(closeAction);
 848:     tmp.setMnemonic(KeyEvent.VK_C);
 849:     systemMenu.add(tmp);
 850:   }
 851: 
 852:   /**
 853:    * This method creates a new JMenubar.
 854:    *
 855:    * @return A new JMenuBar.
 856:    */
 857:   protected JMenuBar createSystemMenuBar()
 858:   {
 859:     if (menuBar == null)
 860:       menuBar = new SystemMenuBar();
 861:     menuBar.removeAll();
 862:     return menuBar;
 863:   }
 864: 
 865:   /**
 866:    * This method creates a new JMenu.
 867:    *
 868:    * @return A new JMenu.
 869:    */
 870:   protected JMenu createSystemMenu()
 871:   {
 872:     if (windowMenu == null)
 873:       windowMenu = new JMenu();
 874:     windowMenu.removeAll();
 875:     return windowMenu;
 876:   }
 877: 
 878:   /**
 879:    * This method programmatically shows the JMenu.
 880:    */
 881:   protected void showSystemMenu()
 882:   {
 883:     // FIXME: Untested as KeyEvents are not hooked up.
 884:     menuBar.getMenu(1).getPopupMenu().show();
 885:   }
 886: 
 887:   /**
 888:    * This method paints the TitlePane.
 889:    *
 890:    * @param g The Graphics object to paint with.
 891:    */
 892:   public void paintComponent(Graphics g)
 893:   {
 894:     paintTitleBackground(g);
 895:     if (frame.getTitle() != null && title != null)
 896:       {
 897:     Color saved = g.getColor();
 898:         Font f = title.getFont();
 899:         g.setFont(f);
 900:         FontMetrics fm = g.getFontMetrics(f);
 901:     if (frame.isSelected())
 902:       g.setColor(selectedTextColor);
 903:     else
 904:       g.setColor(notSelectedTextColor);
 905:     title.setText(getTitle(frame.getTitle(), fm, title.getBounds().width));
 906:     SwingUtilities.paintComponent(g, title, null, title.getBounds());
 907:     g.setColor(saved);
 908:       }
 909:   }
 910: 
 911:   /**
 912:    * This method paints the TitlePane's background.
 913:    *
 914:    * @param g The Graphics object to paint with.
 915:    */
 916:   protected void paintTitleBackground(Graphics g)
 917:   {
 918:     if (!isOpaque())
 919:       return;
 920: 
 921:     Color saved = g.getColor();
 922:     Dimension dims = getSize();
 923: 
 924:     Color bg = getBackground();
 925:     if (frame.isSelected())
 926:       bg = selectedTitleColor;
 927:     else
 928:       bg = notSelectedTitleColor;
 929:     g.setColor(bg);
 930:     g.fillRect(0, 0, dims.width, dims.height);
 931:     g.setColor(saved);
 932:   }
 933: 
 934:   /**
 935:    * This method returns the title string based on the available width and the
 936:    * font metrics.
 937:    *
 938:    * @param text The desired title.
 939:    * @param fm The FontMetrics of the font used.
 940:    * @param availableWidth The available width.
 941:    *
 942:    * @return The allowable string.
 943:    */
 944:   protected String getTitle(String text, FontMetrics fm, int availableWidth)
 945:   {
 946:     Rectangle vr = new Rectangle(0, 0, availableWidth, fm.getHeight());
 947:     Rectangle ir = new Rectangle();
 948:     Rectangle tr = new Rectangle();
 949:     String value = SwingUtilities.layoutCompoundLabel(this, fm, text, null,
 950:                                                       SwingConstants.CENTER,
 951:                                                       SwingConstants.LEFT,
 952:                                                       SwingConstants.CENTER,
 953:                                                       SwingConstants.LEFT, vr,
 954:                                                       ir, tr, 0);
 955:     return value;
 956:   }
 957: 
 958:   /**
 959:    * This method fires something similar to a WINDOW_CLOSING event.
 960:    *
 961:    * @param frame The JInternalFrame that is being closed.
 962:    */
 963:   protected void postClosingEvent(JInternalFrame frame)
 964:   {
 965:     // FIXME: Implement postClosingEvent when I figure out what
 966:     // it's supposed to do.
 967:     // It says that this fires an WINDOW_CLOSING like event. 
 968:     // So the closest thing is some kind of InternalFrameEvent.
 969:     // But none is fired.
 970:     // Can't see it called or anything.
 971:   }
 972: 
 973:   /**
 974:    * This method enables the actions for the TitlePane given the frame's
 975:    * properties.
 976:    */
 977:   protected void enableActions()
 978:   {
 979:     closeAction.setEnabled(frame.isClosable());
 980: 
 981:     iconifyAction.setEnabled(frame.isIconifiable());
 982:     // The maximize action is responsible for restoring it
 983:     // as well, if clicked from the button
 984:     maximizeAction.setEnabled(frame.isMaximizable());
 985: 
 986:     // The restoring action is only active when selected
 987:     // from the menu.
 988:     restoreAction.setEnabled(frame.isMaximum());
 989: 
 990:     sizeAction.setEnabled(frame.isResizable());
 991: 
 992:     // FIXME: Tie MoveAction enabled status to a variable.
 993:     moveAction.setEnabled(false);
 994:   }
 995: 
 996:   /**
 997:    * This method creates a new PropertyChangeListener.
 998:    *
 999:    * @return A new PropertyChangeListener.
1000:    */
1001:   protected PropertyChangeListener createPropertyChangeListener()
1002:   {
1003:     return new PropertyChangeHandler();
1004:   }
1005: 
1006:   /**
1007:    * This method creates a new LayoutManager for the TitlePane.
1008:    *
1009:    * @return A new LayoutManager.
1010:    */
1011:   protected LayoutManager createLayout()
1012:   {
1013:     return new TitlePaneLayout();
1014:   }
1015: }