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