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