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