Source for javax.swing.plaf.basic.BasicInternalFrameUI

   1: /* BasicInternalFrameUI.java --
   2:    Copyright (C) 2004, 2005, 2006 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.Cursor;
  45: import java.awt.Dimension;
  46: import java.awt.Graphics;
  47: import java.awt.Insets;
  48: import java.awt.LayoutManager;
  49: import java.awt.LayoutManager2;
  50: import java.awt.Point;
  51: import java.awt.Rectangle;
  52: import java.awt.event.ActionEvent;
  53: import java.awt.event.ComponentEvent;
  54: import java.awt.event.ComponentListener;
  55: import java.awt.event.MouseEvent;
  56: import java.beans.PropertyChangeEvent;
  57: import java.beans.PropertyChangeListener;
  58: import java.beans.PropertyVetoException;
  59: 
  60: import javax.swing.AbstractAction;
  61: import javax.swing.ActionMap;
  62: import javax.swing.DefaultDesktopManager;
  63: import javax.swing.DesktopManager;
  64: import javax.swing.JComponent;
  65: import javax.swing.JDesktopPane;
  66: import javax.swing.JInternalFrame;
  67: import javax.swing.KeyStroke;
  68: import javax.swing.LookAndFeel;
  69: import javax.swing.SwingConstants;
  70: import javax.swing.SwingUtilities;
  71: import javax.swing.UIManager;
  72: import javax.swing.border.AbstractBorder;
  73: import javax.swing.event.InternalFrameEvent;
  74: import javax.swing.event.InternalFrameListener;
  75: import javax.swing.event.MouseInputAdapter;
  76: import javax.swing.event.MouseInputListener;
  77: import javax.swing.plaf.ActionMapUIResource;
  78: import javax.swing.plaf.ComponentUI;
  79: import javax.swing.plaf.InternalFrameUI;
  80: import javax.swing.plaf.UIResource;
  81: 
  82: /**
  83:  * This is the UI delegate for the Basic look and feel for JInternalFrames.
  84:  */
  85: public class BasicInternalFrameUI extends InternalFrameUI
  86: {
  87:   /**
  88:    * This is a helper class that listens to the JInternalFrame for
  89:    * InternalFrameEvents.
  90:    */
  91:   protected class BasicInternalFrameListener implements InternalFrameListener
  92:   {
  93:     /**
  94:      * This method is called when the JInternalFrame is activated.
  95:      *
  96:      * @param e The InternalFrameEvent.
  97:      */
  98:     public void internalFrameActivated(InternalFrameEvent e)
  99:     {
 100:       frame.getGlassPane().setVisible(false);
 101:     }
 102: 
 103:     /**
 104:      * This method is called when the JInternalFrame is closed.
 105:      *
 106:      * @param e The InternalFrameEvent.
 107:      */
 108:     public void internalFrameClosed(InternalFrameEvent e)
 109:     {
 110:       // FIXME: Implement.
 111:     }
 112: 
 113:     /**
 114:      * This method is called when the JInternalFrame is closing.
 115:      *
 116:      * @param e The InternalFrameEvent.
 117:      */
 118:     public void internalFrameClosing(InternalFrameEvent e)
 119:     {
 120:       // FIXME: Implement.
 121:     }
 122: 
 123:     /**
 124:      * This method is called when the JInternalFrame is deactivated.
 125:      *
 126:      * @param e The InternalFrameEvent.
 127:      */
 128:     public void internalFrameDeactivated(InternalFrameEvent e)
 129:     {
 130:       frame.getGlassPane().setVisible(true);
 131:     }
 132: 
 133:     /**
 134:      * This method is called when the JInternalFrame is  deiconified.
 135:      *
 136:      * @param e The InternalFrameEvent.
 137:      */
 138:     public void internalFrameDeiconified(InternalFrameEvent e)
 139:     {
 140:       // FIXME: Implement.
 141:     }
 142: 
 143:     /**
 144:      * This method is called when the JInternalFrame is  iconified.
 145:      *
 146:      * @param e The InternalFrameEvent.
 147:      */
 148:     public void internalFrameIconified(InternalFrameEvent e)
 149:     {
 150:       // FIXME: Implement.
 151:     }
 152: 
 153:     /**
 154:      * This method is called when the JInternalFrame is opened.
 155:      *
 156:      * @param e The InternalFrameEvent.
 157:      */
 158:     public void internalFrameOpened(InternalFrameEvent e)
 159:     {
 160:       // FIXME: Implement.
 161:     }
 162:   }
 163: 
 164:   /**
 165:    * This helper class listens to the edges of the JInternalFrame and the
 166:    * TitlePane for mouse events. It is responsible for dragging  and resizing
 167:    * the JInternalFrame in response to the MouseEvents.
 168:    */
 169:   protected class BorderListener extends MouseInputAdapter
 170:     implements SwingConstants
 171:   {
 172:     /**
 173:      * The current shape of the cursor. 
 174:      */
 175:     transient int showingCursor;
 176:     
 177:     /** FIXME: Use for something. */
 178:     protected final int RESIZE_NONE = 0;
 179: 
 180:     /** The x offset from the top left corner of the JInternalFrame. */
 181:     private transient int xOffset;
 182: 
 183:     /** The y offset from the top left corner of the JInternalFrame. */
 184:     private transient int yOffset;
 185: 
 186:     /** The direction that the resize is occuring in. */
 187:     private transient int direction = -1;
 188: 
 189:     /** Cache rectangle that can be reused. */
 190:     private transient Rectangle cacheRect = new Rectangle();
 191:     
 192:     /**
 193:      * This method is called when the mouse is clicked.
 194:      *
 195:      * @param e The MouseEvent.
 196:      */
 197:     public void mouseClicked(MouseEvent e)
 198:     {
 199:       // Do minimization/maximization when double-clicking in the title pane.
 200:       if (e.getSource() == titlePane && e.getClickCount() == 2)
 201:         try
 202:           {
 203:             if (frame.isMaximizable() && ! frame.isMaximum())
 204:               frame.setMaximum(true);
 205:             else if (frame.isMaximum())
 206:               frame.setMaximum(false);
 207:           }
 208:         catch (PropertyVetoException pve)
 209:           {
 210:             // We do nothing if the attempt has been vetoed.
 211:           }
 212:         
 213:       // There is nothing to do when the mouse is clicked
 214:       // on the border.
 215:     }
 216: 
 217:     /**
 218:      * This method is called when the mouse is dragged. This method is
 219:      * responsible for resizing or dragging the JInternalFrame.
 220:      *
 221:      * @param e The MouseEvent.
 222:      */
 223:     public void mouseDragged(MouseEvent e)
 224:     {
 225:       // If the frame is maximized, there is nothing that
 226:       // can be dragged around.
 227:       if (frame.isMaximum())
 228:         return;
 229:       DesktopManager dm = getDesktopManager();
 230:       Rectangle b = frame.getBounds();
 231:       Dimension min = frame.getMinimumSize();
 232:       if (min == null)
 233:         min = new Dimension(0, 0);
 234:       Insets insets = frame.getInsets();
 235:       int x = e.getX();
 236:       int y = e.getY();
 237:       if (e.getSource() == frame && frame.isResizable())
 238:         {
 239:           switch (direction)
 240:             {
 241:             case Cursor.N_RESIZE_CURSOR:
 242:               cacheRect.setBounds(b.x, Math.min(b.y + y, b.y + b.height
 243:                                                          - min.height),
 244:                                   b.width, b.height - y);
 245:               break;
 246:             case Cursor.NE_RESIZE_CURSOR:
 247:               cacheRect.setBounds(b.x, Math.min(b.y + y, b.y + b.height
 248:                                                          - min.height), x + 1,
 249:                                   b.height - y);
 250:               break;
 251:             case Cursor.E_RESIZE_CURSOR:
 252:               cacheRect.setBounds(b.x, b.y, x + 1, b.height);
 253:               break;
 254:             case Cursor.SE_RESIZE_CURSOR:
 255:               cacheRect.setBounds(b.x, b.y, x + 1, y + 1);
 256:               break;
 257:             case Cursor.S_RESIZE_CURSOR:
 258:               cacheRect.setBounds(b.x, b.y, b.width, y + 1);
 259:               break;
 260:             case Cursor.SW_RESIZE_CURSOR:
 261:               cacheRect.setBounds(Math.min(b.x + x, b.x + b.width - min.width),
 262:                                   b.y, b.width - x, y + 1);
 263:               break;
 264:             case Cursor.W_RESIZE_CURSOR:
 265:               cacheRect.setBounds(Math.min(b.x + x, b.x + b.width - min.width),
 266:                                   b.y, b.width - x, b.height);
 267:               break;
 268:             case Cursor.NW_RESIZE_CURSOR:
 269:               cacheRect.setBounds(
 270:                                   Math.min(b.x + x, b.x + b.width - min.width),
 271:                                   Math.min(b.y + y, b.y + b.height - min.height),
 272:                                   b.width - x, b.height - y);
 273:               break;
 274:             }
 275:           dm.resizeFrame(frame, cacheRect.x, cacheRect.y,
 276:                          Math.max(min.width, cacheRect.width),
 277:                          Math.max(min.height, cacheRect.height));
 278:           setCursor(e);
 279:         }
 280:       else if (e.getSource() == titlePane)
 281:         {
 282:           Rectangle fBounds = frame.getBounds();
 283:           frame.putClientProperty("bufferedDragging", Boolean.TRUE);
 284:           dm.dragFrame(frame, e.getX() - xOffset + b.x, e.getY() - yOffset
 285:                                                         + b.y);
 286:         }
 287:     }
 288: 
 289:     /**
 290:      * This method is called when the mouse exits the JInternalFrame.
 291:      * 
 292:      * @param e The MouseEvent.
 293:      */
 294:     public void mouseExited(MouseEvent e)
 295:     {
 296:       if (showingCursor != Cursor.DEFAULT_CURSOR)
 297:         {
 298:           frame.setCursor(Cursor.getDefaultCursor());
 299:           showingCursor = Cursor.DEFAULT_CURSOR;
 300:         }
 301:     }
 302: 
 303:     /**
 304:      * This method is called when the mouse is moved inside the JInternalFrame.
 305:      * 
 306:      * @param e The MouseEvent.
 307:      */
 308:     public void mouseMoved(MouseEvent e)
 309:     {
 310:       // Turn off the resize cursor if we are in the frame header.
 311:       if (showingCursor != Cursor.DEFAULT_CURSOR && e.getSource() != frame)
 312:         {
 313:           frame.setCursor(Cursor.getDefaultCursor());
 314:           showingCursor = Cursor.DEFAULT_CURSOR;
 315:         }
 316:       else if (e.getSource() == frame && frame.isResizable())
 317:         {
 318:           setCursor(e);
 319:         }
 320:     }
 321:     
 322:     /**
 323:      * Set the mouse cursor, how applicable.
 324:      * 
 325:      * @param e the current mouse event.
 326:      */
 327:     void setCursor(MouseEvent e)
 328:     {
 329:       int cursor = sectionOfClick(e.getX(), e.getY());
 330:       if (cursor != showingCursor)
 331:         {
 332:           Cursor resize = Cursor.getPredefinedCursor(cursor);
 333:           frame.setCursor(resize);
 334:           showingCursor = cursor;
 335:         }
 336:     }
 337: 
 338:     /**
 339:      * This method is called when the mouse is pressed.
 340:      * 
 341:      * @param e The MouseEvent.
 342:      */
 343:     public void mousePressed(MouseEvent e)
 344:     {
 345:       activateFrame(frame);
 346:       DesktopManager dm = getDesktopManager();
 347:       int x = e.getX();
 348:       int y = e.getY();
 349:       Insets insets = frame.getInsets();
 350: 
 351:       if (e.getSource() == frame && frame.isResizable())
 352:         {
 353:           direction = sectionOfClick(x, y);
 354:           dm.beginResizingFrame(frame, direction);
 355:         }
 356:       else if (e.getSource() == titlePane)
 357:         {
 358:           Rectangle tBounds = titlePane.getBounds();
 359: 
 360:           xOffset = e.getX() - tBounds.x + insets.left;
 361:           yOffset = e.getY() - tBounds.y + insets.top;
 362: 
 363:           dm.beginDraggingFrame(frame);
 364:         }
 365:     }
 366: 
 367:     /**
 368:      * This method is called when the mouse is released.
 369:      *
 370:      * @param e The MouseEvent.
 371:      */
 372:     public void mouseReleased(MouseEvent e)
 373:     {
 374:       DesktopManager dm = getDesktopManager();
 375:       xOffset = 0;
 376:       yOffset = 0;
 377:       if (e.getSource() == frame && frame.isResizable())
 378:         dm.endResizingFrame(frame);
 379:       else if (e.getSource() == titlePane)
 380:         {
 381:           dm.endDraggingFrame(frame);
 382:           frame.putClientProperty("bufferedDragging", null);
 383:         }
 384:       
 385:       setCursor(e);
 386:     }
 387: 
 388:     /**
 389:      * This method determines the direction of the resize based on the
 390:      * coordinates and the size of the JInternalFrame.
 391:      *
 392:      * @param x The x coordinate of the MouseEvent.
 393:      * @param y The y coordinate of the MouseEvent.
 394:      *
 395:      * @return The cursor constant, determining the resizing direction.
 396:      */
 397:     private int sectionOfClick(int x, int y)
 398:     {
 399:       Rectangle b = frame.getBounds();
 400:       int corner = InternalFrameBorder.cornerSize;
 401:       
 402:       if (x < corner && y < corner)
 403:         return Cursor.NW_RESIZE_CURSOR;
 404:       else if (x > b.width - corner && y < corner)
 405:         return Cursor.NE_RESIZE_CURSOR;
 406:       else if (x > b.width - corner && y > b.height - corner)
 407:         return Cursor.SE_RESIZE_CURSOR;
 408:       else if (x < corner && y > b.height - corner)
 409:         return Cursor.SW_RESIZE_CURSOR;
 410:       else if (y < corner)
 411:         return Cursor.N_RESIZE_CURSOR;
 412:       else if (x < corner)
 413:         return Cursor.W_RESIZE_CURSOR;
 414:       else if (y > b.height - corner)
 415:         return Cursor.S_RESIZE_CURSOR;
 416:       else if (x > b.width - corner)
 417:         return Cursor.E_RESIZE_CURSOR;
 418: 
 419:       return Cursor.DEFAULT_CURSOR;
 420:     }
 421:   }
 422: 
 423:   /**
 424:    * This helper class listens to the JDesktopPane that parents this
 425:    * JInternalFrame and listens for resize events and resizes the
 426:    * JInternalFrame appropriately.
 427:    */
 428:   protected class ComponentHandler implements ComponentListener
 429:   {
 430:     /**
 431:      * This method is called when the JDesktopPane is hidden.
 432:      * 
 433:      * @param e
 434:      *          The ComponentEvent fired.
 435:      */
 436:     public void componentHidden(ComponentEvent e)
 437:     {
 438:       // Do nothing.
 439:     }
 440: 
 441:     /**
 442:      * This method is called when the JDesktopPane is moved.
 443:      * 
 444:      * @param e
 445:      *          The ComponentEvent fired.
 446:      */
 447:     public void componentMoved(ComponentEvent e)
 448:     {
 449:       // Do nothing.
 450:     }
 451: 
 452:     /**
 453:      * This method is called when the JDesktopPane is resized.
 454:      * 
 455:      * @param e
 456:      *          The ComponentEvent fired.
 457:      */
 458:     public void componentResized(ComponentEvent e)
 459:     {
 460:       if (frame.isMaximum())
 461:         {
 462:           Container parent = frame.getParent();
 463:           Insets i = parent.getInsets();
 464:           int width = parent.getWidth() - i.left - i.right;
 465:           int height = parent.getHeight() - i.top - i.bottom;
 466:           frame.setBounds(0, 0, width, height);
 467:         }
 468:     }
 469: 
 470:     /**
 471:      * This method is called when the JDesktopPane is shown.
 472:      * 
 473:      * @param e
 474:      *          The ComponentEvent fired.
 475:      */
 476:     public void componentShown(ComponentEvent e)
 477:     {
 478:       // Do nothing.
 479:     }
 480:   }
 481: 
 482:   /**
 483:    * This helper class acts as the LayoutManager for JInternalFrames.
 484:    */
 485:   public class InternalFrameLayout implements LayoutManager
 486:   {
 487:     /**
 488:      * This method is called when the given Component is added to the
 489:      * JInternalFrame.
 490:      * 
 491:      * @param name
 492:      *          The name of the Component.
 493:      * @param c
 494:      *          The Component added.
 495:      */
 496:     public void addLayoutComponent(String name, Component c)
 497:     {
 498:       // Nothing to do here.
 499:     }
 500: 
 501:     /**
 502:      * This method is used to set the bounds of the children of the
 503:      * JInternalFrame.
 504:      * 
 505:      * @param c
 506:      *          The Container to lay out.
 507:      */
 508:     public void layoutContainer(Container c)
 509:     {
 510:       Dimension dims = frame.getSize();
 511:       Insets insets = frame.getInsets();
 512: 
 513:       dims.width -= insets.left + insets.right;
 514:       dims.height -= insets.top + insets.bottom;
 515: 
 516:       int nh = 0;
 517:       int sh = 0;
 518:       int ew = 0;
 519:       int ww = 0;
 520: 
 521:       if (northPane != null)
 522:         {
 523:           Dimension nDims = northPane.getPreferredSize();
 524:           nh = Math.min(nDims.height, dims.height);
 525: 
 526:           northPane.setBounds(insets.left, insets.top, dims.width, nh);
 527:         }
 528: 
 529:       if (southPane != null)
 530:         {
 531:           Dimension sDims = southPane.getPreferredSize();
 532:           sh = Math.min(sDims.height, dims.height - nh);
 533: 
 534:           southPane.setBounds(insets.left, insets.top + dims.height - sh,
 535:                               dims.width, sh);
 536:         }
 537: 
 538:       int remHeight = dims.height - sh - nh;
 539: 
 540:       if (westPane != null)
 541:         {
 542:           Dimension wDims = westPane.getPreferredSize();
 543:           ww = Math.min(dims.width, wDims.width);
 544: 
 545:           westPane.setBounds(insets.left, insets.top + nh, ww, remHeight);
 546:         }
 547: 
 548:       if (eastPane != null)
 549:         {
 550:           Dimension eDims = eastPane.getPreferredSize();
 551:           ew = Math.min(eDims.width, dims.width - ww);
 552: 
 553:           eastPane.setBounds(insets.left + dims.width - ew, insets.top + nh,
 554:                              ew, remHeight);
 555:         }
 556: 
 557:       int remWidth = dims.width - ww - ew;
 558: 
 559:       frame.getRootPane().setBounds(insets.left + ww, insets.top + nh,
 560:                                     remWidth, remHeight);
 561:     }
 562: 
 563:     /**
 564:      * This method returns the minimum layout size.
 565:      * 
 566:      * @param c
 567:      *          The Container to find a minimum layout size for.
 568:      * @return The minimum dimensions for the JInternalFrame.
 569:      */
 570:     public Dimension minimumLayoutSize(Container c)
 571:     {
 572:       return getSize(c, true);
 573:     }
 574: 
 575:     /**
 576:      * Th8is method returns the preferred layout size.
 577:      * 
 578:      * @param c
 579:      *          The Container to find a preferred layout size for.
 580:      * @return The preferred dimensions for the JInternalFrame.
 581:      */
 582:     public Dimension preferredLayoutSize(Container c)
 583:     {
 584:       return getSize(c, false);
 585:     }
 586: 
 587:     /**
 588:      * DOCUMENT ME!
 589:      * 
 590:      * @param c
 591:      *          DOCUMENT ME!
 592:      * @param min
 593:      *          DOCUMENT ME!
 594:      * @return DOCUMENT ME!
 595:      */
 596:     private Dimension getSize(Container c, boolean min)
 597:     {
 598:       Insets insets = frame.getInsets();
 599: 
 600:       Dimension contentDims = frame.getContentPane().getPreferredSize();
 601:       if (min)
 602:         contentDims.width = contentDims.height = 0;
 603:       int nWidth = 0;
 604:       int nHeight = 0;
 605:       int sWidth = 0;
 606:       int sHeight = 0;
 607:       int eWidth = 0;
 608:       int eHeight = 0;
 609:       int wWidth = 0;
 610:       int wHeight = 0;
 611:       Dimension dims;
 612: 
 613:       if (northPane != null)
 614:         {
 615:           dims = northPane.getPreferredSize();
 616:           if (dims != null)
 617:             {
 618:               nWidth = dims.width;
 619:               nHeight = dims.height;
 620:             }
 621:         }
 622: 
 623:       if (southPane != null)
 624:         {
 625:           dims = southPane.getPreferredSize();
 626:           if (dims != null)
 627:             {
 628:               sWidth = dims.width;
 629:               sHeight = dims.height;
 630:             }
 631:         }
 632: 
 633:       if (eastPane != null)
 634:         {
 635:           dims = eastPane.getPreferredSize();
 636:           if (dims != null)
 637:             {
 638:               sWidth = dims.width;
 639:               sHeight = dims.height;
 640:             }
 641:         }
 642: 
 643:       if (westPane != null)
 644:         {
 645:           dims = westPane.getPreferredSize();
 646:           if (dims != null)
 647:             {
 648:               wWidth = dims.width;
 649:               wHeight = dims.height;
 650:             }
 651:         }
 652: 
 653:       int width = Math.max(sWidth, nWidth);
 654:       width = Math.max(width, contentDims.width + eWidth + wWidth);
 655: 
 656:       int height = Math.max(eHeight, wHeight);
 657:       height = Math.max(height, contentDims.height);
 658:       height += nHeight + sHeight;
 659: 
 660:       width += insets.left + insets.right;
 661:       height += insets.top + insets.bottom;
 662: 
 663:       return new Dimension(width, height);
 664:     }
 665: 
 666:     /**
 667:      * This method is called when a Component is removed from the
 668:      * JInternalFrame.
 669:      *
 670:      * @param c The Component that was removed.
 671:      */
 672:     public void removeLayoutComponent(Component c)
 673:     {
 674:       // Nothing to do here.
 675:     }
 676:   }
 677: 
 678:   /**
 679:    * This helper class is used to listen to the JDesktopPane's glassPane for
 680:    * MouseEvents. The JInternalFrame can then be selected if a click is
 681:    * detected on its children.
 682:    */
 683:   protected class GlassPaneDispatcher implements MouseInputListener
 684:   {
 685:     /** The MouseEvent target. */
 686:     private transient Component mouseEventTarget;
 687: 
 688:     private Component dragTarget;
 689: 
 690:     /**
 691:      * Indicates if we are currently in a dragging operation or not.
 692:      */
 693:     private boolean isDragging;
 694: 
 695:     /**
 696:      * This method is called when the mouse enters the glass pane.
 697:      * 
 698:      * @param e
 699:      *          The MouseEvent.
 700:      */
 701:     public void mouseEntered(MouseEvent e)
 702:     {
 703:       handleEvent(e);
 704:     }
 705: 
 706:     /**
 707:      * This method is called when the mouse is clicked on the glass pane.
 708:      * 
 709:      * @param e
 710:      *          The MouseEvent.
 711:      */
 712:     public void mouseClicked(MouseEvent e)
 713:     {
 714:       handleEvent(e);
 715:     }
 716: 
 717:     /**
 718:      * This method is called when the mouse is dragged in the glass pane.
 719:      * 
 720:      * @param e
 721:      *          The MouseEvent.
 722:      */
 723:     public void mouseDragged(MouseEvent e)
 724:     {
 725:       handleEvent(e);
 726:     }
 727: 
 728:     /**
 729:      * This method is called when the mouse exits the glass pane.
 730:      * 
 731:      * @param e
 732:      *          The MouseEvent.
 733:      */
 734:     public void mouseExited(MouseEvent e)
 735:     {
 736:       handleEvent(e);
 737:     }
 738: 
 739:     /**
 740:      * This method is called when the mouse is moved in the glass pane.
 741:      * 
 742:      * @param e
 743:      *          The MouseEvent.
 744:      */
 745:     public void mouseMoved(MouseEvent e)
 746:     {
 747:       handleEvent(e);
 748:     }
 749: 
 750:     /**
 751:      * This method is called when the mouse is pressed in the glass pane.
 752:      * 
 753:      * @param e
 754:      *          The MouseEvent.
 755:      */
 756:     public void mousePressed(MouseEvent e)
 757:     {
 758:       // Experiments show that this seems to call the
 759:       // borderListener.mousePressed() method to activate the frame.
 760:       if (borderListener != null)
 761:         borderListener.mousePressed(e);
 762:       handleEvent(e);
 763:     }
 764: 
 765:     /**
 766:      * This method is called when the mouse is released in the glass pane.
 767:      * 
 768:      * @param e
 769:      *          The MouseEvent.
 770:      */
 771:     public void mouseReleased(MouseEvent e)
 772:     {
 773:       handleEvent(e);
 774:     }
 775: 
 776:     /**
 777:      * This is a helper method that dispatches the GlassPane MouseEvents to the
 778:      * proper component.
 779:      * 
 780:      * @param e the mouse event to be dispatched
 781:      */
 782:     private void handleEvent(MouseEvent e)
 783:     {
 784:       // Find candidate component inside the JInternalFrame.
 785:       Component target = frame.getLayeredPane().findComponentAt(e.getX(),
 786:                                                                 e.getY());
 787: 
 788:       // Now search upwards to find a component that actually has
 789:       // a MouseListener attached.
 790:       while (target != null
 791:              && target.getMouseListeners().length == 0
 792:              && target.getMouseMotionListeners().length == 0
 793:              && target.getMouseWheelListeners().length == 0)
 794:         {
 795:           target = target.getParent();
 796:         }
 797: 
 798:       if (target != null)
 799:         {
 800:           int id = e.getID();
 801:           switch (id)
 802:           {
 803:             case MouseEvent.MOUSE_ENTERED:
 804:               // Now redispatch the thing.
 805:               if (! isDragging || frame.isSelected())
 806:                 {
 807:                   mouseEventTarget = target;
 808:                   redispatch(id, e, mouseEventTarget);
 809:                 }
 810:               break;
 811:             case MouseEvent.MOUSE_EXITED:
 812:               if (! isDragging || frame.isSelected())
 813:                 {
 814:                   redispatch(id, e, mouseEventTarget);
 815:                 }
 816:               break;
 817:             case MouseEvent.MOUSE_PRESSED:
 818:               mouseEventTarget = target;
 819:               redispatch(id, e, mouseEventTarget);
 820:               // Start dragging.
 821:               dragTarget = target;
 822:               break;
 823:             case MouseEvent.MOUSE_RELEASED:
 824:               if (isDragging)
 825:                 {
 826:                   redispatch(id, e, dragTarget);
 827:                   isDragging = false;
 828:                 }
 829:               else
 830:                 redispatch(id, e, mouseEventTarget);
 831:               break;
 832:             case MouseEvent.MOUSE_CLICKED:
 833:               redispatch(id, e, mouseEventTarget);
 834:               break;
 835:             case MouseEvent.MOUSE_MOVED:
 836:               if (target != mouseEventTarget)
 837:                 {
 838:                   // Create additional MOUSE_EXITED/MOUSE_ENTERED pairs.
 839:                   redispatch(MouseEvent.MOUSE_EXITED, e, mouseEventTarget);
 840:                   mouseEventTarget = target;
 841:                   redispatch(MouseEvent.MOUSE_ENTERED, e, mouseEventTarget);
 842:                 }
 843:               redispatch(id, e, mouseEventTarget);
 844:               break;
 845:             case MouseEvent.MOUSE_DRAGGED:
 846:               if (! isDragging)
 847:                 isDragging = true;
 848:               redispatch(id, e, mouseEventTarget);
 849:               break;
 850:             case MouseEvent.MOUSE_WHEEL:
 851:               redispatch(id, e, mouseEventTarget);
 852:               break;
 853:             default:
 854:               assert false : "Must not reach here";
 855:           }
 856:         }
 857:     }
 858: 
 859:     /**
 860:      * Redispatches the event to the real target with the specified id.
 861:      *
 862:      * @param id the new event ID
 863:      * @param e the original event
 864:      * @param target the real event target
 865:      */
 866:     private void redispatch(int id, MouseEvent e, Component target)
 867:     {
 868:       Point p = SwingUtilities.convertPoint(frame.getLayeredPane(), e.getX(),
 869:                                             e.getY(), target);
 870:       MouseEvent ev = new MouseEvent(target, id, e.getWhen(),
 871:                                      e.getModifiers() | e.getModifiersEx(),
 872:                                      p.x, p.y, e.getClickCount(),
 873:                                      e.isPopupTrigger());
 874:       target.dispatchEvent(ev);
 875:     }
 876:   }
 877: 
 878:   /**
 879:    * This helper class listens for PropertyChangeEvents from the
 880:    * JInternalFrame.
 881:    */
 882:   public class InternalFramePropertyChangeListener
 883:     implements PropertyChangeListener
 884:   {
 885: 
 886:     /**
 887:      * This method is called when one of the JInternalFrame's properties change.
 888:      * 
 889:      * @param evt
 890:      *          The PropertyChangeEvent.
 891:      */
 892:     public void propertyChange(PropertyChangeEvent evt)
 893:     {
 894:       String property = evt.getPropertyName();
 895:       if (property.equals(JInternalFrame.IS_MAXIMUM_PROPERTY))
 896:         {
 897:           if (frame.isMaximum())
 898:             maximizeFrame(frame);
 899:           else
 900:             minimizeFrame(frame);
 901:         }
 902:       else if (property.equals(JInternalFrame.IS_ICON_PROPERTY))
 903:         {
 904:           if (frame.isIcon())
 905:             iconifyFrame(frame);
 906:           else
 907:             deiconifyFrame(frame);
 908:         }
 909:       else if (property.equals(JInternalFrame.IS_SELECTED_PROPERTY))
 910:         {
 911:           Component glassPane = frame.getGlassPane();
 912:           if (frame.isSelected())
 913:             {
 914:               activateFrame(frame);
 915:               glassPane.setVisible(false);
 916:             }
 917:           else
 918:             {
 919:               deactivateFrame(frame);
 920:               glassPane.setVisible(true);
 921:             }
 922:         }
 923:       else if (property.equals(JInternalFrame.ROOT_PANE_PROPERTY)
 924:                || property.equals(JInternalFrame.GLASS_PANE_PROPERTY))
 925:         {
 926:           Component old = (Component) evt.getOldValue();
 927:           if (old != null)
 928:             {
 929:               old.removeMouseListener(glassPaneDispatcher);
 930:               old.removeMouseMotionListener(glassPaneDispatcher);
 931:             }
 932: 
 933:           Component newPane = (Component) evt.getNewValue();
 934:           if (newPane != null)
 935:             {
 936:               newPane.addMouseListener(glassPaneDispatcher);
 937:               newPane.addMouseMotionListener(glassPaneDispatcher);
 938:             }
 939: 
 940:           frame.revalidate();
 941:         }
 942:       else if (property.equals(JInternalFrame.IS_CLOSED_PROPERTY))
 943:         {
 944:           if (evt.getNewValue() == Boolean.TRUE)
 945:             {
 946:               Container parent = frame.getParent();
 947:               if (parent != null)
 948:                 parent.removeComponentListener(componentListener);
 949:               closeFrame(frame);
 950:             }
 951:         }
 952:       else if (property.equals("ancestor"))
 953:         {
 954:           Container newParent = (Container) evt.getNewValue();
 955:           Container oldParent = (Container) evt.getOldValue();
 956:           if (newParent != null)
 957:             {
 958:               newParent.addComponentListener(componentListener);
 959:             }
 960:           else if (oldParent != null)
 961:             {
 962:               oldParent.removeComponentListener(componentListener);
 963:             }
 964:         }
 965:     }
 966:   }
 967: 
 968:   /**
 969:    * This helper class is the border for the JInternalFrame.
 970:    */
 971:   class InternalFrameBorder extends AbstractBorder implements
 972:       UIResource
 973:   {
 974:     /** 
 975:      * The width of the border. 
 976:      */
 977:     static final int bSize = 5;
 978: 
 979:     /**
 980:      * The size of the corners (also used by the mouse listener).
 981:      */
 982:     static final int cornerSize = 10;
 983: 
 984:     /**
 985:      * This method returns whether the border is opaque.
 986:      * 
 987:      * @return Whether the border is opaque.
 988:      */
 989:     public boolean isBorderOpaque()
 990:     {
 991:       return true;
 992:     }
 993: 
 994:     /**
 995:      * This method returns the insets of the border.
 996:      * 
 997:      * @param c
 998:      *          The Component to find border insets for.
 999:      * @return The border insets.
1000:      */
1001:     public Insets getBorderInsets(Component c)
1002:     {
1003:       return new Insets(bSize, bSize, bSize, bSize);
1004:     }
1005: 
1006:     /**
1007:      * This method paints the border.
1008:      * 
1009:      * @param c
1010:      *          The Component that owns the border.
1011:      * @param g
1012:      *          The Graphics object to paint with.
1013:      * @param x
1014:      *          The x coordinate to paint at.
1015:      * @param y
1016:      *          The y coordinate to paint at.
1017:      * @param width
1018:      *          The width of the Component.
1019:      * @param height
1020:      *          The height of the Component.
1021:      */
1022:     public void paintBorder(Component c, Graphics g, int x, int y, int width,
1023:                             int height)
1024:     {
1025:       g.translate(x, y);
1026:       Color saved = g.getColor();
1027:       Rectangle b = frame.getBounds();
1028: 
1029:       Color d = c.getBackground();
1030:       g.setColor(d);
1031:       g.fillRect(0, 0, bSize, b.height);
1032:       g.fillRect(0, 0, b.width, bSize);
1033:       g.fillRect(0, b.height - bSize, b.width, bSize);
1034:       g.fillRect(b.width - bSize, 0, bSize, b.height);
1035: 
1036:       int x1 = 0;
1037:       int x2 = bSize;
1038:       int x3 = b.width - bSize;
1039:       int x4 = b.width;
1040: 
1041:       int y1 = 0;
1042:       int y2 = bSize;
1043:       int y3 = b.height - bSize;
1044:       int y4 = b.height;
1045: 
1046:       g.setColor(Color.GRAY);
1047:       g.fillRect(0, 0, bSize, y4);
1048:       g.fillRect(0, 0, x4, bSize);
1049:       g.fillRect(0, y3, b.width, bSize);
1050:       g.fillRect(x3, 0, bSize, b.height);
1051: 
1052:       g.fill3DRect(0, cornerSize, bSize, b.height - 2 * cornerSize, false);
1053:       g.fill3DRect(cornerSize, 0, b.width - 2 * cornerSize, bSize, false);
1054:       g.fill3DRect(cornerSize, b.height - bSize, b.width - 2 * cornerSize, 
1055:                    bSize, false);
1056:       g.fill3DRect(b.width - bSize, cornerSize, bSize, 
1057:                    b.height - 2 * cornerSize, false);
1058: 
1059:       g.translate(-x, -y);
1060:       g.setColor(saved);
1061:     }
1062:   }
1063: 
1064:   /**
1065:    * This action triggers the system menu.
1066:    *
1067:    * @author Roman Kennke (kennke@aicas.com)
1068:    */
1069:   private class ShowSystemMenuAction
1070:     extends AbstractAction
1071:   {
1072:     public void actionPerformed(ActionEvent e)
1073:     {
1074:       if (titlePane != null)
1075:         {
1076:           titlePane.showSystemMenu();
1077:         }
1078:     }
1079:   }
1080: 
1081:   /**
1082:    * The MouseListener that is responsible for dragging and resizing the
1083:    * JInternalFrame in response to MouseEvents.
1084:    */
1085:   protected MouseInputAdapter borderListener;
1086: 
1087:   /**
1088:    * The ComponentListener that is responsible for resizing the JInternalFrame
1089:    * in response to ComponentEvents from the JDesktopPane.
1090:    */
1091:   protected ComponentListener componentListener;
1092: 
1093:   /**
1094:    * The MouseListener that is responsible for activating the JInternalFrame
1095:    * when the mouse press activates one of its descendents.
1096:    */
1097:   protected MouseInputListener glassPaneDispatcher;
1098: 
1099:   /**
1100:    * The PropertyChangeListener that is responsible for listening to
1101:    * PropertyChangeEvents from the JInternalFrame.
1102:    */
1103:   protected PropertyChangeListener propertyChangeListener;
1104: 
1105:   /** The InternalFrameListener that listens to the JInternalFrame. */
1106:   private transient BasicInternalFrameListener internalFrameListener;
1107: 
1108:   /** The JComponent placed at the east region of the JInternalFrame. */
1109:   protected JComponent eastPane;
1110: 
1111:   /** The JComponent placed at the north region of the JInternalFrame. */
1112:   protected JComponent northPane;
1113: 
1114:   /** The JComponent placed at the south region of the JInternalFrame. */
1115:   protected JComponent southPane;
1116: 
1117:   /** The JComponent placed at the west region of the JInternalFrame. */
1118:   protected JComponent westPane;
1119: 
1120:   /**
1121:    * The Keystroke bound to open the menu.
1122:    * @deprecated
1123:    */
1124:   protected KeyStroke openMenuKey;
1125: 
1126:   /** The TitlePane displayed at the top of the JInternalFrame. */
1127:   protected BasicInternalFrameTitlePane titlePane;
1128: 
1129:   /** The JInternalFrame this UI is responsible for. */
1130:   protected JInternalFrame frame;
1131: 
1132:   /** The LayoutManager used in the JInternalFrame. */
1133:   protected LayoutManager internalFrameLayout;
1134: 
1135:   /** The JDesktopPane that is the parent of the JInternalFrame. */
1136:   private transient JDesktopPane desktopPane;
1137: 
1138:   /**
1139:    * Creates a new BasicInternalFrameUI object.
1140:    *
1141:    * @param b The JInternalFrame this UI will represent.
1142:    */
1143:   public BasicInternalFrameUI(JInternalFrame b)
1144:   {
1145:     // Nothing to do here.
1146:   }
1147: 
1148:   /**
1149:    * This method will create a new BasicInternalFrameUI for the given
1150:    * JComponent.
1151:    *
1152:    * @param b The JComponent to create a BasicInternalFrameUI for.
1153:    *
1154:    * @return A new BasicInternalFrameUI.
1155:    */
1156:   public static ComponentUI createUI(JComponent b)
1157:   {
1158:     return new BasicInternalFrameUI((JInternalFrame) b);
1159:   }
1160: 
1161:   /**
1162:    * This method installs a UI for the JInternalFrame.
1163:    *
1164:    * @param c The JComponent to install this UI on.
1165:    */
1166:   public void installUI(JComponent c)
1167:   {
1168:     if (c instanceof JInternalFrame)
1169:       {
1170:         frame = (JInternalFrame) c;
1171: 
1172:         installDefaults();
1173:         installListeners();
1174:         installComponents();
1175:         installKeyboardActions();
1176: 
1177:         if (! frame.isSelected())
1178:           frame.getGlassPane().setVisible(true);
1179:       }
1180:   }
1181: 
1182:   /**
1183:    * This method reverses the work done by installUI.
1184:    *
1185:    * @param c The JComponent to uninstall this UI for.
1186:    */
1187:   public void uninstallUI(JComponent c)
1188:   {
1189:     uninstallKeyboardActions();
1190:     uninstallComponents();
1191:     uninstallListeners();
1192:     uninstallDefaults();
1193: 
1194:     frame.getRootPane().getGlassPane().setVisible(false);
1195:     frame = null;
1196:   }
1197: 
1198:   /**
1199:    * This method installs the defaults specified by the look and feel.
1200:    */
1201:   protected void installDefaults()
1202:     {
1203:       internalFrameLayout = createLayoutManager();
1204:       frame.setLayout(internalFrameLayout);
1205:       LookAndFeel.installBorder(frame, "InternalFrame.border");
1206:       frame.setFrameIcon(UIManager.getIcon("InternalFrame.icon"));
1207: 
1208:       // Let the content pane inherit the background color from its
1209:       // frame by setting the background to null.
1210:       Component contentPane = frame.getContentPane();
1211:       if (contentPane != null
1212:           && contentPane.getBackground() instanceof UIResource)
1213:         {
1214:           contentPane.setBackground(null);
1215:         }
1216:   }
1217: 
1218:   /**
1219:    * This method installs the keyboard actions for the JInternalFrame.
1220:    */
1221:   protected void installKeyboardActions()
1222:   {
1223:     ActionMapUIResource am = new ActionMapUIResource();
1224:     am.put("showSystemMenu", new ShowSystemMenuAction());
1225: 
1226:     // The RI impl installs the audio actions as parent of the UI action map,
1227:     // so do we.
1228:     BasicLookAndFeel blaf = (BasicLookAndFeel) UIManager.getLookAndFeel();
1229:     ActionMap audioActionMap = blaf.getAudioActionMap();
1230:     am.setParent(audioActionMap);
1231: 
1232:     SwingUtilities.replaceUIActionMap(frame, am);
1233:   }
1234: 
1235:   /**
1236:    * This method installs the Components for the JInternalFrame.
1237:    */
1238:   protected void installComponents()
1239:   {
1240:     setNorthPane(createNorthPane(frame));
1241:     setSouthPane(createSouthPane(frame));
1242:     setEastPane(createEastPane(frame));
1243:     setWestPane(createWestPane(frame));
1244:   }
1245: 
1246:   /**
1247:    * This method installs the listeners for the JInternalFrame.
1248:    */
1249:   protected void installListeners()
1250:   {
1251:     glassPaneDispatcher = createGlassPaneDispatcher();
1252:     createInternalFrameListener();
1253:     borderListener = createBorderListener(frame);
1254:     componentListener = createComponentListener();
1255:     propertyChangeListener = createPropertyChangeListener();
1256: 
1257:     frame.addMouseListener(borderListener);
1258:     frame.addMouseMotionListener(borderListener);
1259:     frame.addInternalFrameListener(internalFrameListener);
1260:     frame.addPropertyChangeListener(propertyChangeListener);
1261:     frame.getRootPane().getGlassPane().addMouseListener(glassPaneDispatcher);
1262:     frame.getRootPane().getGlassPane().addMouseMotionListener(glassPaneDispatcher);
1263: 
1264:     Container parent = frame.getParent();
1265:     if (parent != null)
1266:       {
1267:         parent.addComponentListener(componentListener);
1268:       }
1269:   }
1270: 
1271:   /**
1272:    * This method uninstalls the defaults for the JInternalFrame.
1273:    */
1274:   protected void uninstallDefaults()
1275:   {
1276:     frame.setBorder(null);
1277:     frame.setLayout(null);
1278:     internalFrameLayout = null;
1279:   }
1280: 
1281:   /**
1282:    * This method uninstalls the Components for the JInternalFrame.
1283:    */
1284:   protected void uninstallComponents()
1285:   {
1286:     setNorthPane(null);
1287:     setSouthPane(null);
1288:     setEastPane(null);
1289:     setWestPane(null);
1290:   }
1291: 
1292:   /**
1293:    * This method uninstalls the listeners for the JInternalFrame.
1294:    */
1295:   protected void uninstallListeners()
1296:   {
1297: 
1298:     Container parent = frame.getParent();
1299:     if (parent != null)
1300:       {
1301:         parent.removeComponentListener(componentListener);
1302:       }
1303:     componentListener = null;
1304: 
1305:     frame.getRootPane().getGlassPane().removeMouseMotionListener(glassPaneDispatcher);
1306:     frame.getRootPane().getGlassPane().removeMouseListener(glassPaneDispatcher);
1307: 
1308:     frame.removePropertyChangeListener(propertyChangeListener);
1309:     frame.removeInternalFrameListener(internalFrameListener);
1310:     frame.removeMouseMotionListener(borderListener);
1311:     frame.removeMouseListener(borderListener);
1312: 
1313:     propertyChangeListener = null;
1314: 
1315:     borderListener = null;
1316:     internalFrameListener = null;
1317:     glassPaneDispatcher = null;
1318:   }
1319: 
1320:   /**
1321:    * This method uninstalls the keyboard actions for the JInternalFrame.
1322:    */
1323:   protected void uninstallKeyboardActions()
1324:   {
1325:     SwingUtilities.replaceUIActionMap(frame, null);
1326:     SwingUtilities.replaceUIInputMap(frame, JComponent.WHEN_IN_FOCUSED_WINDOW,
1327:                                      null);
1328:   }
1329: 
1330:   /**
1331:    * This method creates a new LayoutManager for the JInternalFrame.
1332:    *
1333:    * @return A new LayoutManager for the JInternalFrame.
1334:    */
1335:   protected LayoutManager createLayoutManager()
1336:   {
1337:     return new InternalFrameLayout();
1338:   }
1339: 
1340:   /**
1341:    * This method creates a new PropertyChangeListener for the JInternalFrame.
1342:    *
1343:    * @return A new PropertyChangeListener for the JInternalFrame.
1344:    */
1345:   protected PropertyChangeListener createPropertyChangeListener()
1346:   {
1347:     return new InternalFramePropertyChangeListener();
1348:   }
1349: 
1350:   /**
1351:    * This method returns the preferred size of the given JComponent.
1352:    *
1353:    * @param x The JComponent to find a preferred size for.
1354:    *
1355:    * @return The preferred size.
1356:    */
1357:   public Dimension getPreferredSize(JComponent x)
1358:   {
1359:     Dimension pref = null;
1360:     LayoutManager layout = frame.getLayout();
1361:     if (frame == x && layout != null)
1362:       pref = layout.preferredLayoutSize(frame);
1363:     else
1364:       pref = new Dimension(100, 100);
1365:     return pref;
1366:   }
1367: 
1368:   /**
1369:    * This method returns the minimum size of the given JComponent.
1370:    *
1371:    * @param x The JComponent to find a minimum size for.
1372:    *
1373:    * @return The minimum size.
1374:    */
1375:   public Dimension getMinimumSize(JComponent x)
1376:   {
1377:     Dimension min = null;
1378:     LayoutManager layout = frame.getLayout();
1379:     if (frame == x && layout != null)
1380:       min = layout.minimumLayoutSize(frame);
1381:     else
1382:       min = new Dimension(0, 0);
1383:     return min;
1384:   }
1385: 
1386:   /**
1387:    * This method returns the maximum size of the given JComponent.
1388:    *
1389:    * @param x The JComponent to find a maximum size for.
1390:    *
1391:    * @return The maximum size.
1392:    */
1393:   public Dimension getMaximumSize(JComponent x)
1394:   {
1395:     Dimension max = null;
1396:     LayoutManager layout = frame.getLayout();
1397:     if (frame == x && layout != null && layout instanceof LayoutManager2)
1398:       max = ((LayoutManager2) layout).maximumLayoutSize(frame);
1399:     else
1400:       max = new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
1401:     return max;
1402:   }
1403: 
1404:   /**
1405:    * This method replaces the currentPane with the newPane. When replacing it
1406:    * also removes the MouseHandlers for the old pane and installs  them on
1407:    * the new pane.
1408:    *
1409:    * @param currentPane The old pane to remove.
1410:    * @param newPane The new pane to install.
1411:    */
1412:   protected void replacePane(JComponent currentPane, JComponent newPane)
1413:   {
1414:     if (currentPane != null)
1415:       {
1416:         deinstallMouseHandlers(currentPane);
1417:         frame.remove(currentPane);
1418:       }
1419: 
1420:     if (newPane != null)
1421:       {
1422:         installMouseHandlers(newPane);
1423:         frame.add(newPane);
1424:       }
1425:   }
1426: 
1427:   /**
1428:    * This method removes the necessary MouseListeners from the given
1429:    * JComponent.
1430:    *
1431:    * @param c The JComponent to remove MouseListeners from.
1432:    */
1433:   protected void deinstallMouseHandlers(JComponent c)
1434:   {
1435:     c.removeMouseListener(borderListener);
1436:     c.removeMouseMotionListener(borderListener);
1437:   }
1438: 
1439:   /**
1440:    * This method installs the necessary MouseListeners from the given
1441:    * JComponent.
1442:    *
1443:    * @param c The JComponent to install MouseListeners on.
1444:    */
1445:   protected void installMouseHandlers(JComponent c)
1446:   {
1447:     c.addMouseListener(borderListener);
1448:     c.addMouseMotionListener(borderListener);
1449:   }
1450: 
1451:   /**
1452:    * This method creates the north pane used in the JInternalFrame.
1453:    *
1454:    * @param w The JInternalFrame to create a north pane for.
1455:    *
1456:    * @return The north pane.
1457:    */
1458:   protected JComponent createNorthPane(JInternalFrame w)
1459:   {
1460:     titlePane = new BasicInternalFrameTitlePane(w);
1461:     return titlePane;
1462:   }
1463: 
1464:   /**
1465:    * This method creates the west pane used in the JInternalFrame.
1466:    *
1467:    * @param w The JInternalFrame to create a west pane for.
1468:    *
1469:    * @return The west pane.
1470:    */
1471:   protected JComponent createWestPane(JInternalFrame w)
1472:   {
1473:     return null;
1474:   }
1475: 
1476:   /**
1477:    * This method creates the south pane used in the JInternalFrame.
1478:    *
1479:    * @param w The JInternalFrame to create a south pane for.
1480:    *
1481:    * @return The south pane.
1482:    */
1483:   protected JComponent createSouthPane(JInternalFrame w)
1484:   {
1485:     return null;
1486:   }
1487: 
1488:   /**
1489:    * This method creates the east pane used in the JInternalFrame.
1490:    *
1491:    * @param w The JInternalFrame to create an east pane for.
1492:    *
1493:    * @return The east pane.
1494:    */
1495:   protected JComponent createEastPane(JInternalFrame w)
1496:   {
1497:     return null;
1498:   }
1499: 
1500:   /**
1501:    * This method returns a new BorderListener for the given JInternalFrame.
1502:    *
1503:    * @param w The JIntenalFrame to create a BorderListener for.
1504:    *
1505:    * @return A new BorderListener.
1506:    */
1507:   protected MouseInputAdapter createBorderListener(JInternalFrame w)
1508:   {
1509:     return new BorderListener();
1510:   }
1511: 
1512:   /**
1513:    * This method creates a new InternalFrameListener for the JInternalFrame.
1514:    */
1515:   protected void createInternalFrameListener()
1516:   {
1517:     internalFrameListener = new BasicInternalFrameListener();
1518:   }
1519: 
1520:   /**
1521:    * DOCUMENT ME!
1522:    *
1523:    * @return DOCUMENT ME!
1524:    */
1525:   protected final boolean isKeyBindingRegistered()
1526:   {
1527:     // FIXME: Implement.
1528:     return false;
1529:   }
1530: 
1531:   /**
1532:    * DOCUMENT ME!
1533:    *
1534:    * @param b DOCUMENT ME!
1535:    */
1536:   protected final void setKeyBindingRegistered(boolean b)
1537:   {
1538:     // FIXME: Implement.
1539:   }
1540: 
1541:   /**
1542:    * DOCUMENT ME!
1543:    *
1544:    * @return DOCUMENT ME!
1545:    */
1546:   public final boolean isKeyBindingActive()
1547:   {
1548:     // FIXME: Implement.
1549:     return false;
1550:   }
1551: 
1552:   /**
1553:    * DOCUMENT ME!
1554:    *
1555:    * @param b DOCUMENT ME!
1556:    */
1557:   protected final void setKeyBindingActive(boolean b)
1558:   {
1559:     // FIXME: Implement.
1560:   }
1561: 
1562:   /**
1563:    * DOCUMENT ME!
1564:    */
1565:   protected void setupMenuOpenKey()
1566:   {
1567:     // FIXME: Implement.
1568:   }
1569: 
1570:   /**
1571:    * DOCUMENT ME!
1572:    */
1573:   protected void setupMenuCloseKey()
1574:   {
1575:     // FIXME: Implement.
1576:   }
1577: 
1578:   /**
1579:    * This method returns the north pane.
1580:    *
1581:    * @return The north pane.
1582:    */
1583:   public JComponent getNorthPane()
1584:   {
1585:     return northPane;
1586:   }
1587: 
1588:   /**
1589:    * This method sets the north pane to be the given JComponent.
1590:    *
1591:    * @param c The new north pane.
1592:    */
1593:   public void setNorthPane(JComponent c)
1594:   {
1595:     replacePane(northPane, c);
1596:     northPane = c;
1597:     // the following is needed to make internal frames draggable when using
1598:     // the JGoodies PlasticLookAndFeel, because it overrides the 
1599:     // createNorthPane() method and doesn't assign anything to the titlePane
1600:     // field.  It is possible there is another way to make this work, but
1601:     // I didn't find it...
1602:     if (c instanceof BasicInternalFrameTitlePane)
1603:       titlePane = (BasicInternalFrameTitlePane) c;
1604:   }
1605: 
1606:   /**
1607:    * This method returns the south pane.
1608:    *
1609:    * @return The south pane.
1610:    */
1611:   public JComponent getSouthPane()
1612:   {
1613:     return southPane;
1614:   }
1615: 
1616:   /**
1617:    * This method sets the south pane to be the given JComponent.
1618:    *
1619:    * @param c The new south pane.
1620:    */
1621:   public void setSouthPane(JComponent c)
1622:   {
1623:     replacePane(southPane, c);
1624:     southPane = c;
1625:   }
1626: 
1627:   /**
1628:    * This method sets the east pane to be the given JComponent.
1629:    *
1630:    * @param c The new east pane.
1631:    */
1632:   public void setEastPane(JComponent c)
1633:   {
1634:     replacePane(eastPane, c);
1635:     eastPane = c;
1636:   }
1637: 
1638:   /**
1639:    * This method returns the east pane.
1640:    *
1641:    * @return The east pane.
1642:    */
1643:   public JComponent getEastPane()
1644:   {
1645:     return eastPane;
1646:   }
1647: 
1648:   /**
1649:    * This method sets the west pane to be the given JComponent.
1650:    *
1651:    * @param c The new west pane.
1652:    */
1653:   public void setWestPane(JComponent c)
1654:   {
1655:     replacePane(westPane, c);
1656:     westPane = c;
1657:   }
1658: 
1659:   /**
1660:    * This method returns the west pane.
1661:    *
1662:    * @return The west pane.
1663:    */
1664:   public JComponent getWestPane()
1665:   {
1666:     return westPane;
1667:   }
1668: 
1669:   /**
1670:    * This method returns the DesktopManager to use with the JInternalFrame.
1671:    *
1672:    * @return The DesktopManager to use with the JInternalFrame.
1673:    */
1674:   protected DesktopManager getDesktopManager()
1675:   {
1676:     DesktopManager value = null;
1677:     JDesktopPane pane = frame.getDesktopPane();
1678:     if (pane != null)
1679:       value = frame.getDesktopPane().getDesktopManager();
1680:     if (value == null)
1681:       value = createDesktopManager();
1682:     return value;
1683:   }
1684: 
1685:   /**
1686:    * This method returns a default DesktopManager that can be used with this
1687:    * JInternalFrame.
1688:    *
1689:    * @return A default DesktopManager that can be used with this
1690:    *         JInternalFrame.
1691:    */
1692:   protected DesktopManager createDesktopManager()
1693:   {
1694:     return new DefaultDesktopManager();
1695:   }
1696: 
1697:   /**
1698:    * This is a convenience method that closes the JInternalFrame.
1699:    *
1700:    * @param f The JInternalFrame to close.
1701:    */
1702:   protected void closeFrame(JInternalFrame f)
1703:   {
1704:     getDesktopManager().closeFrame(f);
1705:   }
1706: 
1707:   /**
1708:    * This is a convenience method that maximizes the JInternalFrame.
1709:    *
1710:    * @param f The JInternalFrame to maximize.
1711:    */
1712:   protected void maximizeFrame(JInternalFrame f)
1713:   {
1714:     getDesktopManager().maximizeFrame(f);
1715:   }
1716: 
1717:   /**
1718:    * This is a convenience method that minimizes the JInternalFrame.
1719:    *
1720:    * @param f The JInternalFrame to minimize.
1721:    */
1722:   protected void minimizeFrame(JInternalFrame f)
1723:   {
1724:     getDesktopManager().minimizeFrame(f);
1725:   }
1726: 
1727:   /**
1728:    * This is a convenience method that iconifies the JInternalFrame.
1729:    *
1730:    * @param f The JInternalFrame to iconify.
1731:    */
1732:   protected void iconifyFrame(JInternalFrame f)
1733:   {
1734:     getDesktopManager().iconifyFrame(f);
1735:   }
1736: 
1737:   /**
1738:    * This is a convenience method that deiconifies the JInternalFrame.
1739:    *
1740:    * @param f The JInternalFrame to deiconify.
1741:    */
1742:   protected void deiconifyFrame(JInternalFrame f)
1743:   {
1744:     getDesktopManager().deiconifyFrame(f);
1745:   }
1746: 
1747:   /**
1748:    * This is a convenience method that activates the JInternalFrame.
1749:    *
1750:    * @param f The JInternalFrame to activate.
1751:    */
1752:   protected void activateFrame(JInternalFrame f)
1753:   {
1754:     getDesktopManager().activateFrame(f);
1755:   }
1756: 
1757:   /**
1758:    * This is a convenience method that deactivates the JInternalFrame.
1759:    *
1760:    * @param f the JInternalFrame to deactivate
1761:    */
1762:   protected void deactivateFrame(JInternalFrame f)
1763:   {
1764:     getDesktopManager().deactivateFrame(f);
1765:   }
1766: 
1767:   /**
1768:    * This method returns a new ComponentListener for the JDesktopPane.
1769:    *
1770:    * @return A new ComponentListener.
1771:    */
1772:   protected ComponentListener createComponentListener()
1773:   {
1774:     return new ComponentHandler();
1775:   }
1776: 
1777:   /**
1778:    * This method returns a new GlassPaneDispatcher.
1779:    *
1780:    * @return A new GlassPaneDispatcher.
1781:    */
1782:   protected MouseInputListener createGlassPaneDispatcher()
1783:   {
1784:     return new GlassPaneDispatcher();
1785:   }
1786: }