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