1 /*
   2  * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javax.swing.plaf.basic;
  27 
  28 import java.awt.*;
  29 import java.awt.event.*;
  30 import javax.swing.*;
  31 import javax.swing.plaf.*;
  32 import javax.swing.event.*;
  33 import java.beans.*;
  34 import sun.swing.DefaultLookup;
  35 import sun.swing.UIAction;
  36 
  37 /**
  38  * A basic L&F implementation of JInternalFrame.
  39  *
  40  * @author David Kloba
  41  * @author Rich Schiavi
  42  */
  43 public class BasicInternalFrameUI extends InternalFrameUI
  44 {
  45     /** frame */
  46     protected JInternalFrame frame;
  47 
  48     private Handler handler;
  49     /** Border listener */
  50     protected MouseInputAdapter          borderListener;
  51     /** Property change listener */
  52     protected PropertyChangeListener     propertyChangeListener;
  53     /** Internal frame layout */
  54     protected LayoutManager              internalFrameLayout;
  55     /** Component listener */
  56     protected ComponentListener          componentListener;
  57     /** Glass pane dispatcher */
  58     protected MouseInputListener         glassPaneDispatcher;
  59     private InternalFrameListener        internalFrameListener;
  60 
  61     /** North pane */
  62     protected JComponent northPane;
  63     /** South pane */
  64     protected JComponent southPane;
  65     /** West pane */
  66     protected JComponent westPane;
  67     /** East pane */
  68     protected JComponent eastPane;
  69     /** Title pane */
  70     protected BasicInternalFrameTitlePane titlePane; // access needs this
  71 
  72     private static DesktopManager sharedDesktopManager;
  73     private boolean componentListenerAdded = false;
  74 
  75     private Rectangle parentBounds;
  76 
  77     private boolean dragging = false;
  78     private boolean resizing = false;
  79 
  80     /**
  81      * As of Java 2 platform v1.3 this previously undocumented field is no
  82      * longer used.
  83      * Key bindings are now defined by the LookAndFeel, please refer to
  84      * the key bindings specification for further details.
  85      *
  86      * @deprecated As of Java 2 platform v1.3.
  87      */
  88     @Deprecated
  89     protected KeyStroke openMenuKey;
  90 
  91     private boolean keyBindingRegistered = false;
  92     private boolean keyBindingActive = false;
  93 
  94 /////////////////////////////////////////////////////////////////////////////
  95 // ComponentUI Interface Implementation methods
  96 /////////////////////////////////////////////////////////////////////////////
  97     /**
  98      * Returns a component UI.
  99      * @param b a component
 100      * @return a component UI
 101      */
 102     public static ComponentUI createUI(JComponent b)    {
 103         return new BasicInternalFrameUI((JInternalFrame)b);
 104     }
 105 
 106     /**
 107      * Constructs a {@code BasicInternalFrameUI}.
 108      * @param b the internal frame
 109      */
 110     public BasicInternalFrameUI(JInternalFrame b)   {
 111         LookAndFeel laf = UIManager.getLookAndFeel();
 112         if (laf instanceof BasicLookAndFeel) {
 113             ((BasicLookAndFeel)laf).installAWTEventListener();
 114         }
 115     }
 116 
 117     /**
 118      * Installs the UI.
 119      * @param c the component
 120      */
 121     public void installUI(JComponent c)   {
 122         super.installUI(c);
 123 
 124         frame = (JInternalFrame)c;
 125 
 126         installDefaults();
 127         installListeners();
 128         installComponents();
 129         installKeyboardActions();
 130 
 131         LookAndFeel.installProperty(frame, "opaque", Boolean.TRUE);
 132     }
 133 
 134     /**
 135      * Uninstalls the UI.
 136      * @param c the component
 137      */
 138     public void uninstallUI(JComponent c) {
 139         if(c != frame)
 140             throw new IllegalComponentStateException(
 141                 this + " was asked to deinstall() "
 142                 + c + " when it only knows about "
 143                 + frame + ".");
 144 
 145         uninstallKeyboardActions();
 146         uninstallComponents();
 147         uninstallListeners();
 148         uninstallDefaults();
 149         updateFrameCursor();
 150         handler = null;
 151         frame = null;
 152     }
 153 
 154     /**
 155      * Installs the defaults.
 156      */
 157     protected void installDefaults(){
 158         Icon frameIcon = frame.getFrameIcon();
 159         if (frameIcon == null || frameIcon instanceof UIResource) {
 160             frame.setFrameIcon(UIManager.getIcon("InternalFrame.icon"));
 161         }
 162 
 163         // Enable the content pane to inherit background color from its
 164         // parent by setting its background color to null.
 165         Container contentPane = frame.getContentPane();
 166         if (contentPane != null) {
 167           Color bg = contentPane.getBackground();
 168           if (bg instanceof UIResource)
 169             contentPane.setBackground(null);
 170         }
 171         frame.setLayout(internalFrameLayout = createLayoutManager());
 172         frame.setBackground(UIManager.getLookAndFeelDefaults().getColor("control"));
 173 
 174         LookAndFeel.installBorder(frame, "InternalFrame.border");
 175 
 176     }
 177     /**
 178      * Installs the keyboard actions.
 179      */
 180     protected void installKeyboardActions(){
 181         createInternalFrameListener();
 182         if (internalFrameListener != null) {
 183             frame.addInternalFrameListener(internalFrameListener);
 184         }
 185 
 186         LazyActionMap.installLazyActionMap(frame, BasicInternalFrameUI.class,
 187             "InternalFrame.actionMap");
 188     }
 189 
 190     static void loadActionMap(LazyActionMap map) {
 191         map.put(new UIAction("showSystemMenu") {
 192             public void actionPerformed(ActionEvent evt) {
 193                 JInternalFrame iFrame = (JInternalFrame)evt.getSource();
 194                 if (iFrame.getUI() instanceof BasicInternalFrameUI) {
 195                     JComponent comp = ((BasicInternalFrameUI)
 196                         iFrame.getUI()).getNorthPane();
 197                     if (comp instanceof BasicInternalFrameTitlePane) {
 198                         ((BasicInternalFrameTitlePane)comp).
 199                             showSystemMenu();
 200                     }
 201                 }
 202             }
 203 
 204             @Override
 205             public boolean accept(Object sender){
 206                 if (sender instanceof JInternalFrame) {
 207                     JInternalFrame iFrame = (JInternalFrame)sender;
 208                     if (iFrame.getUI() instanceof BasicInternalFrameUI) {
 209                         return ((BasicInternalFrameUI)iFrame.getUI()).
 210                             isKeyBindingActive();
 211                     }
 212                 }
 213                 return false;
 214             }
 215         });
 216 
 217         // Set the ActionMap's parent to the Auditory Feedback Action Map
 218         BasicLookAndFeel.installAudioActionMap(map);
 219     }
 220 
 221     /**
 222      * Installs the components.
 223      */
 224     protected void installComponents(){
 225         setNorthPane(createNorthPane(frame));
 226         setSouthPane(createSouthPane(frame));
 227         setEastPane(createEastPane(frame));
 228         setWestPane(createWestPane(frame));
 229     }
 230 
 231     /**
 232      * Installs the listeners.
 233      * @since 1.3
 234      */
 235     protected void installListeners() {
 236         borderListener = createBorderListener(frame);
 237         propertyChangeListener = createPropertyChangeListener();
 238         frame.addPropertyChangeListener(propertyChangeListener);
 239         installMouseHandlers(frame);
 240         glassPaneDispatcher = createGlassPaneDispatcher();
 241         if (glassPaneDispatcher != null) {
 242             frame.getGlassPane().addMouseListener(glassPaneDispatcher);
 243             frame.getGlassPane().addMouseMotionListener(glassPaneDispatcher);
 244         }
 245         componentListener =  createComponentListener();
 246         if (frame.getParent() != null) {
 247           parentBounds = frame.getParent().getBounds();
 248         }
 249         if ((frame.getParent() != null) && !componentListenerAdded) {
 250             frame.getParent().addComponentListener(componentListener);
 251             componentListenerAdded = true;
 252         }
 253     }
 254 
 255     // Provide a FocusListener to listen for a WINDOW_LOST_FOCUS event,
 256     // so that a resize can be cancelled if the focus is lost while resizing
 257     // when an Alt-Tab, modal dialog popup, iconify, dispose, or remove
 258     // of the internal frame occurs.
 259     private WindowFocusListener getWindowFocusListener(){
 260         return getHandler();
 261     }
 262 
 263     // Cancel a resize in progress by calling finishMouseReleased().
 264     private void cancelResize() {
 265         if (resizing) {
 266             if (borderListener instanceof BorderListener) {
 267                 ((BorderListener)borderListener).finishMouseReleased();
 268             }
 269         }
 270     }
 271 
 272     private Handler getHandler() {
 273         if (handler == null) {
 274             handler = new Handler();
 275         }
 276         return handler;
 277     }
 278 
 279     InputMap getInputMap(int condition) {
 280         if (condition == JComponent.WHEN_IN_FOCUSED_WINDOW) {
 281             return createInputMap(condition);
 282         }
 283         return null;
 284     }
 285 
 286     InputMap createInputMap(int condition) {
 287         if (condition == JComponent.WHEN_IN_FOCUSED_WINDOW) {
 288             Object[] bindings = (Object[])DefaultLookup.get(
 289                     frame, this, "InternalFrame.windowBindings");
 290 
 291             if (bindings != null) {
 292                 return LookAndFeel.makeComponentInputMap(frame, bindings);
 293             }
 294         }
 295         return null;
 296     }
 297 
 298     /**
 299      * Uninstalls the defaults.
 300      */
 301     protected void uninstallDefaults() {
 302         Icon frameIcon = frame.getFrameIcon();
 303         if (frameIcon instanceof UIResource) {
 304             frame.setFrameIcon(null);
 305         }
 306         internalFrameLayout = null;
 307         frame.setLayout(null);
 308         LookAndFeel.uninstallBorder(frame);
 309     }
 310 
 311     /**
 312      * Uninstalls the components.
 313      */
 314     protected void uninstallComponents(){
 315         setNorthPane(null);
 316         setSouthPane(null);
 317         setEastPane(null);
 318         setWestPane(null);
 319         if(titlePane != null) {
 320             titlePane.uninstallDefaults();
 321         }
 322         titlePane = null;
 323     }
 324 
 325     /**
 326      * Uninstalls the listeners.
 327      * @since 1.3
 328      */
 329     protected void uninstallListeners() {
 330         if ((frame.getParent() != null) && componentListenerAdded) {
 331             frame.getParent().removeComponentListener(componentListener);
 332             componentListenerAdded = false;
 333         }
 334         componentListener = null;
 335       if (glassPaneDispatcher != null) {
 336           frame.getGlassPane().removeMouseListener(glassPaneDispatcher);
 337           frame.getGlassPane().removeMouseMotionListener(glassPaneDispatcher);
 338           glassPaneDispatcher = null;
 339       }
 340       deinstallMouseHandlers(frame);
 341       frame.removePropertyChangeListener(propertyChangeListener);
 342       propertyChangeListener = null;
 343       borderListener = null;
 344     }
 345 
 346     /**
 347      * Uninstalls the keyboard actions.
 348      */
 349     protected void uninstallKeyboardActions(){
 350         if (internalFrameListener != null) {
 351             frame.removeInternalFrameListener(internalFrameListener);
 352         }
 353         internalFrameListener = null;
 354 
 355         SwingUtilities.replaceUIInputMap(frame, JComponent.
 356                                          WHEN_IN_FOCUSED_WINDOW, null);
 357         SwingUtilities.replaceUIActionMap(frame, null);
 358 
 359     }
 360 
 361     void updateFrameCursor() {
 362         if (resizing) {
 363             return;
 364         }
 365         Cursor s = frame.getLastCursor();
 366         if (s == null) {
 367             s = Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR);
 368         }
 369         frame.setCursor(s);
 370     }
 371 
 372     /**
 373      * Creates the layout manager.
 374      * @return the layout manager
 375      */
 376     protected LayoutManager createLayoutManager(){
 377         return getHandler();
 378     }
 379 
 380     /**
 381      * Creates the property change listener.
 382      * @return the property change listener
 383      */
 384     protected PropertyChangeListener createPropertyChangeListener(){
 385         return getHandler();
 386     }
 387 
 388     /**
 389      * Returns the preferred size.
 390      * @param x the component
 391      * @return the preferred size
 392      */
 393     public Dimension getPreferredSize(JComponent x)    {
 394         if(frame == x)
 395             return frame.getLayout().preferredLayoutSize(x);
 396         return new Dimension(100, 100);
 397     }
 398 
 399     /**
 400      * Returns the minimum size.
 401      * @param x the component
 402      * @return the minimum size
 403      */
 404     public Dimension getMinimumSize(JComponent x)  {
 405         if(frame == x) {
 406             return frame.getLayout().minimumLayoutSize(x);
 407         }
 408         return new Dimension(0, 0);
 409     }
 410 
 411     /**
 412      * Returns the maximum size.
 413      * @param x the component
 414      * @return the maximum size
 415      */
 416     public Dimension getMaximumSize(JComponent x) {
 417         return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
 418     }
 419 
 420 
 421 
 422     /**
 423      * Installs necessary mouse handlers on <code>newPane</code>
 424      * and adds it to the frame.
 425      * Reverse process for the <code>currentPane</code>.
 426      *
 427      * @param currentPane this {@code Jcomponent} is the current pane being
 428      * viewed that has mouse handlers installed
 429      * @param newPane this {@code Jcomponent} is the pane which will be added
 430      * and have mouse handlers installed
 431      */
 432     protected void replacePane(JComponent currentPane, JComponent newPane) {
 433         if(currentPane != null) {
 434             deinstallMouseHandlers(currentPane);
 435             frame.remove(currentPane);
 436         }
 437         if(newPane != null) {
 438            frame.add(newPane);
 439            installMouseHandlers(newPane);
 440         }
 441     }
 442 
 443     /**
 444      * Deinstalls the mouse handlers.
 445      * @param c the component
 446      */
 447     protected void deinstallMouseHandlers(JComponent c) {
 448       c.removeMouseListener(borderListener);
 449       c.removeMouseMotionListener(borderListener);
 450     }
 451 
 452     /**
 453      * Installs the mouse handlers.
 454      * @param c the component
 455      */
 456     protected void installMouseHandlers(JComponent c) {
 457       c.addMouseListener(borderListener);
 458       c.addMouseMotionListener(borderListener);
 459     }
 460 
 461     /**
 462      * Creates the north pane.
 463      * @param w the internal frame
 464      * @return the north pane
 465      */
 466     protected JComponent createNorthPane(JInternalFrame w) {
 467       titlePane = new BasicInternalFrameTitlePane(w);
 468       return titlePane;
 469     }
 470 
 471 
 472     /**
 473      * Creates the north pane.
 474      * @param w the internal frame
 475      * @return the north pane
 476      */
 477     protected JComponent createSouthPane(JInternalFrame w) {
 478         return null;
 479     }
 480 
 481     /**
 482      * Creates the west pane.
 483      * @param w the internal frame
 484      * @return the west pane
 485      */
 486     protected JComponent createWestPane(JInternalFrame w) {
 487         return null;
 488     }
 489 
 490     /**
 491      * Creates the east pane.
 492      * @param w the internal frame
 493      * @return the east pane
 494      */
 495     protected JComponent createEastPane(JInternalFrame w) {
 496         return null;
 497     }
 498 
 499     /**
 500      * Creates the border listener.
 501      * @param w the internal frame
 502      * @return the border listener
 503      */
 504     protected MouseInputAdapter createBorderListener(JInternalFrame w) {
 505         return new BorderListener();
 506     }
 507 
 508     /**
 509      * Creates the internal frame listener.
 510      */
 511     protected void createInternalFrameListener(){
 512         internalFrameListener = getHandler();
 513     }
 514 
 515     /**
 516      * Returns whether or no the key binding is registered.
 517      * @return whether or no the key binding is registered
 518      */
 519     protected final boolean isKeyBindingRegistered(){
 520       return keyBindingRegistered;
 521     }
 522 
 523     /**
 524      * Sets the key binding registration.
 525      * @param b new value for key binding registration
 526      */
 527     protected final void setKeyBindingRegistered(boolean b){
 528       keyBindingRegistered = b;
 529     }
 530 
 531     /**
 532      * Returns whether or no the key binding is active.
 533      * @return whether or no the key binding is active
 534      */
 535     public final boolean isKeyBindingActive(){
 536       return keyBindingActive;
 537     }
 538 
 539     /**
 540      * Sets the key binding activity.
 541      * @param b new value for key binding activity
 542      */
 543     protected final void setKeyBindingActive(boolean b){
 544       keyBindingActive = b;
 545     }
 546 
 547 
 548     /**
 549      * Setup the menu open key.
 550      */
 551     protected void setupMenuOpenKey(){
 552         // PENDING(hania): Why are these WHEN_IN_FOCUSED_WINDOWs? Shouldn't
 553         // they be WHEN_ANCESTOR_OF_FOCUSED_COMPONENT?
 554         // Also, no longer registering on the desktopicon, the previous
 555         // action did nothing.
 556         InputMap map = getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
 557         SwingUtilities.replaceUIInputMap(frame,
 558                                       JComponent.WHEN_IN_FOCUSED_WINDOW, map);
 559         //ActionMap actionMap = getActionMap();
 560         //SwingUtilities.replaceUIActionMap(frame, actionMap);
 561     }
 562 
 563     /**
 564      * Setup the menu close key.
 565      */
 566     protected void setupMenuCloseKey(){
 567     }
 568 
 569     /**
 570      * Returns the north pane.
 571      * @return the north pane
 572      */
 573     public JComponent getNorthPane() {
 574         return northPane;
 575     }
 576 
 577     /**
 578      * Sets the north pane.
 579      * @param c the new north pane
 580      */
 581     public void setNorthPane(JComponent c) {
 582         if (northPane != null &&
 583                 northPane instanceof BasicInternalFrameTitlePane) {
 584             ((BasicInternalFrameTitlePane)northPane).uninstallListeners();
 585         }
 586         replacePane(northPane, c);
 587         northPane = c;
 588         if (c instanceof BasicInternalFrameTitlePane) {
 589           titlePane = (BasicInternalFrameTitlePane)c;
 590         }
 591     }
 592 
 593     /**
 594      * Returns the south pane.
 595      * @return the south pane
 596      */
 597     public JComponent getSouthPane() {
 598         return southPane;
 599     }
 600 
 601     /**
 602      * Sets the south pane.
 603      * @param c the new south pane
 604      */
 605     public void setSouthPane(JComponent c) {
 606         southPane = c;
 607     }
 608 
 609     /**
 610      * Returns the west pane.
 611      * @return the west pane
 612      */
 613     public JComponent getWestPane() {
 614         return westPane;
 615     }
 616 
 617     /**
 618      * Sets the west pane.
 619      * @param c the new west pane
 620      */
 621     public void setWestPane(JComponent c) {
 622         westPane = c;
 623     }
 624 
 625     /**
 626      * Returns the east pane.
 627      * @return the east pane
 628      */
 629     public JComponent getEastPane() {
 630         return eastPane;
 631     }
 632 
 633     /**
 634      * Sets the east pane.
 635      * @param c the new east pane
 636      */
 637     public void setEastPane(JComponent c) {
 638         eastPane = c;
 639     }
 640 
 641     /**
 642      * Internal frame property change listener.
 643      */
 644     public class InternalFramePropertyChangeListener implements
 645         PropertyChangeListener {
 646         // NOTE: This class exists only for backward compatibility. All
 647         // its functionality has been moved into Handler. If you need to add
 648         // new functionality add it to the Handler, but make sure this
 649         // class calls into the Handler.
 650         /**
 651          * Detects changes in state from the JInternalFrame and handles
 652          * actions.
 653          */
 654         public void propertyChange(PropertyChangeEvent evt) {
 655             getHandler().propertyChange(evt);
 656         }
 657     }
 658 
 659     /**
 660      * Internal frame layout.
 661      */
 662   public class InternalFrameLayout implements LayoutManager {
 663     // NOTE: This class exists only for backward compatibility. All
 664     // its functionality has been moved into Handler. If you need to add
 665     // new functionality add it to the Handler, but make sure this
 666     // class calls into the Handler.
 667       /**
 668        * {@inheritDoc}
 669        */
 670     public void addLayoutComponent(String name, Component c) {
 671         getHandler().addLayoutComponent(name, c);
 672     }
 673 
 674       /**
 675        * {@inheritDoc}
 676        */
 677     public void removeLayoutComponent(Component c) {
 678         getHandler().removeLayoutComponent(c);
 679     }
 680 
 681       /**
 682        * {@inheritDoc}
 683        */
 684     public Dimension preferredLayoutSize(Container c)  {
 685         return getHandler().preferredLayoutSize(c);
 686     }
 687 
 688       /**
 689        * {@inheritDoc}
 690        */
 691     public Dimension minimumLayoutSize(Container c) {
 692         return getHandler().minimumLayoutSize(c);
 693     }
 694 
 695       /**
 696        * {@inheritDoc}
 697        */
 698     public void layoutContainer(Container c) {
 699         getHandler().layoutContainer(c);
 700     }
 701   }
 702 
 703 /// DesktopManager methods
 704     /**
 705      * Returns the proper DesktopManager. Calls getDesktopPane() to
 706      * find the JDesktop component and returns the desktopManager from
 707      * it. If this fails, it will return a default DesktopManager that
 708      * should work in arbitrary parents.
 709      * @return the proper DesktopManager
 710      */
 711     protected DesktopManager getDesktopManager() {
 712         if(frame.getDesktopPane() != null
 713            && frame.getDesktopPane().getDesktopManager() != null)
 714             return frame.getDesktopPane().getDesktopManager();
 715         if(sharedDesktopManager == null)
 716           sharedDesktopManager = createDesktopManager();
 717         return sharedDesktopManager;
 718     }
 719 
 720     /**
 721      * Creates the desktop manager.
 722      * @return the desktop manager
 723      */
 724     protected DesktopManager createDesktopManager(){
 725       return new DefaultDesktopManager();
 726     }
 727 
 728     /**
 729      * This method is called when the user wants to close the frame.
 730      * The <code>playCloseSound</code> Action is fired.
 731      * This action is delegated to the desktopManager.
 732      *
 733      * @param f the {@code JInternalFrame} being viewed
 734      */
 735     protected void closeFrame(JInternalFrame f) {
 736         // Internal Frame Auditory Cue Activation
 737         BasicLookAndFeel.playSound(frame,"InternalFrame.closeSound");
 738         // delegate to desktop manager
 739         getDesktopManager().closeFrame(f);
 740     }
 741 
 742     /**
 743      * This method is called when the user wants to maximize the frame.
 744      * The <code>playMaximizeSound</code> Action is fired.
 745      * This action is delegated to the desktopManager.
 746      *
 747      * @param f the {@code JInternalFrame} being viewed
 748      */
 749     protected void maximizeFrame(JInternalFrame f) {
 750         // Internal Frame Auditory Cue Activation
 751         BasicLookAndFeel.playSound(frame,"InternalFrame.maximizeSound");
 752         // delegate to desktop manager
 753         getDesktopManager().maximizeFrame(f);
 754     }
 755 
 756     /**
 757      * This method is called when the user wants to minimize the frame.
 758      * The <code>playRestoreDownSound</code> Action is fired.
 759      * This action is delegated to the desktopManager.
 760      *
 761      * @param f the {@code JInternalFrame} being viewed
 762      */
 763     protected void minimizeFrame(JInternalFrame f) {
 764         // Internal Frame Auditory Cue Activation
 765         if ( ! f.isIcon() ) {
 766             // This method seems to regularly get called after an
 767             // internal frame is iconified. Don't play this sound then.
 768             BasicLookAndFeel.playSound(frame,"InternalFrame.restoreDownSound");
 769         }
 770         // delegate to desktop manager
 771         getDesktopManager().minimizeFrame(f);
 772     }
 773 
 774     /**
 775      * This method is called when the user wants to iconify the frame.
 776      * The <code>playMinimizeSound</code> Action is fired.
 777      * This action is delegated to the desktopManager.
 778      *
 779      * @param f the {@code JInternalFrame} being viewed
 780      */
 781     protected void iconifyFrame(JInternalFrame f) {
 782         // Internal Frame Auditory Cue Activation
 783         BasicLookAndFeel.playSound(frame, "InternalFrame.minimizeSound");
 784         // delegate to desktop manager
 785         getDesktopManager().iconifyFrame(f);
 786     }
 787 
 788     /**
 789      * This method is called when the user wants to deiconify the frame.
 790      * The <code>playRestoreUpSound</code> Action is fired.
 791      * This action is delegated to the desktopManager.
 792      *
 793      * @param f the {@code JInternalFrame} being viewed
 794      */
 795     protected void deiconifyFrame(JInternalFrame f) {
 796         // Internal Frame Auditory Cue Activation
 797         if ( ! f.isMaximum() ) {
 798             // This method seems to regularly get called after an
 799             // internal frame is maximized. Don't play this sound then.
 800             BasicLookAndFeel.playSound(frame, "InternalFrame.restoreUpSound");
 801         }
 802         // delegate to desktop manager
 803         getDesktopManager().deiconifyFrame(f);
 804     }
 805 
 806     /**
 807       * This method is called when the frame becomes selected.
 808       * This action is delegated to the desktopManager.
 809       *
 810       * @param f the {@code JInternalFrame} being viewed
 811       */
 812     protected void activateFrame(JInternalFrame f) {
 813         getDesktopManager().activateFrame(f);
 814     }
 815     /**
 816      * This method is called when the frame is no longer selected.
 817      * This action is delegated to the desktopManager.
 818      *
 819      * @param f the {@code JInternalFrame} being viewed
 820      */
 821     protected void deactivateFrame(JInternalFrame f) {
 822         getDesktopManager().deactivateFrame(f);
 823     }
 824 
 825     /////////////////////////////////////////////////////////////////////////
 826     /// Border Listener Class
 827     /////////////////////////////////////////////////////////////////////////
 828     /**
 829      * Listens for border adjustments.
 830      */
 831     protected class BorderListener extends MouseInputAdapter implements SwingConstants
 832     {
 833         // _x & _y are the mousePressed location in absolute coordinate system
 834         int _x, _y;
 835         // __x & __y are the mousePressed location in source view's coordinate system
 836         int __x, __y;
 837         Rectangle startingBounds;
 838         int resizeDir;
 839 
 840         /** resize none */
 841         protected final int RESIZE_NONE  = 0;
 842         private boolean discardRelease = false;
 843 
 844         int resizeCornerSize = 16;
 845 
 846         public void mouseClicked(MouseEvent e) {
 847             if(e.getClickCount() > 1 && e.getSource() == getNorthPane()) {
 848                 if(frame.isIconifiable() && frame.isIcon()) {
 849                     try { frame.setIcon(false); } catch (PropertyVetoException e2) { }
 850                 } else if(frame.isMaximizable()) {
 851                     if(!frame.isMaximum())
 852                         try { frame.setMaximum(true); } catch (PropertyVetoException e2) { }
 853                     else
 854                         try { frame.setMaximum(false); } catch (PropertyVetoException e3) { }
 855                 }
 856             }
 857         }
 858 
 859         // Factor out finishMouseReleased() from mouseReleased(), so that
 860         // it can be called by cancelResize() without passing it a null
 861         // MouseEvent.
 862         void finishMouseReleased() {
 863            if (discardRelease) {
 864              discardRelease = false;
 865              return;
 866           }
 867             if (resizeDir == RESIZE_NONE) {
 868                 getDesktopManager().endDraggingFrame(frame);
 869                 dragging = false;
 870             } else {
 871                 // Remove the WindowFocusListener for handling a
 872                 // WINDOW_LOST_FOCUS event with a cancelResize().
 873                 Window windowAncestor =
 874                     SwingUtilities.getWindowAncestor(frame);
 875                 if (windowAncestor != null) {
 876                     windowAncestor.removeWindowFocusListener(
 877                         getWindowFocusListener());
 878                 }
 879                 Container c = frame.getTopLevelAncestor();
 880                 if (c instanceof RootPaneContainer) {
 881                     Component glassPane = ((RootPaneContainer)c).getGlassPane();
 882                     glassPane.setCursor(Cursor.getPredefinedCursor(
 883                         Cursor.DEFAULT_CURSOR));
 884                     glassPane.setVisible(false);
 885                 }
 886                 getDesktopManager().endResizingFrame(frame);
 887                 resizing = false;
 888                 updateFrameCursor();
 889             }
 890             _x = 0;
 891             _y = 0;
 892             __x = 0;
 893             __y = 0;
 894             startingBounds = null;
 895             resizeDir = RESIZE_NONE;
 896             // Set discardRelease to true, so that only a mousePressed()
 897             // which sets it to false, will allow entry to the above code
 898             // for finishing a resize.
 899             discardRelease = true;
 900         }
 901 
 902         public void mouseReleased(MouseEvent e) {
 903             finishMouseReleased();
 904         }
 905 
 906         public void mousePressed(MouseEvent e) {
 907             Point p = SwingUtilities.convertPoint((Component)e.getSource(),
 908                         e.getX(), e.getY(), null);
 909             __x = e.getX();
 910             __y = e.getY();
 911             _x = p.x;
 912             _y = p.y;
 913             startingBounds = frame.getBounds();
 914             resizeDir = RESIZE_NONE;
 915             discardRelease = false;
 916 
 917             try { frame.setSelected(true); }
 918             catch (PropertyVetoException e1) { }
 919 
 920             Insets i = frame.getInsets();
 921 
 922             Point ep = new Point(__x, __y);
 923             if (e.getSource() == getNorthPane()) {
 924                 Point np = getNorthPane().getLocation();
 925                 ep.x += np.x;
 926                 ep.y += np.y;
 927             }
 928 
 929             if (e.getSource() == getNorthPane()) {
 930                 if (ep.x > i.left && ep.y > i.top && ep.x < frame.getWidth() - i.right) {
 931                     getDesktopManager().beginDraggingFrame(frame);
 932                     dragging = true;
 933                     return;
 934                 }
 935             }
 936             if (!frame.isResizable()) {
 937               return;
 938             }
 939 
 940             if (e.getSource() == frame || e.getSource() == getNorthPane()) {
 941                 if (ep.x <= i.left) {
 942                     if (ep.y < resizeCornerSize + i.top) {
 943                         resizeDir = NORTH_WEST;
 944                     } else if (ep.y > frame.getHeight()
 945                               - resizeCornerSize - i.bottom) {
 946                         resizeDir = SOUTH_WEST;
 947                     } else {
 948                         resizeDir = WEST;
 949 }
 950                 } else if (ep.x >= frame.getWidth() - i.right) {
 951                     if (ep.y < resizeCornerSize + i.top) {
 952                         resizeDir = NORTH_EAST;
 953                     } else if (ep.y > frame.getHeight()
 954                               - resizeCornerSize - i.bottom) {
 955                         resizeDir = SOUTH_EAST;
 956                     } else {
 957                         resizeDir = EAST;
 958                     }
 959                 } else if (ep.y <= i.top) {
 960                     if (ep.x < resizeCornerSize + i.left) {
 961                         resizeDir = NORTH_WEST;
 962                     } else if (ep.x > frame.getWidth()
 963                               - resizeCornerSize - i.right) {
 964                         resizeDir = NORTH_EAST;
 965                     } else {
 966                         resizeDir = NORTH;
 967                     }
 968                 } else if (ep.y >= frame.getHeight() - i.bottom) {
 969                     if (ep.x < resizeCornerSize + i.left) {
 970                         resizeDir = SOUTH_WEST;
 971                     } else if (ep.x > frame.getWidth()
 972                               - resizeCornerSize - i.right) {
 973                         resizeDir = SOUTH_EAST;
 974                     } else {
 975                       resizeDir = SOUTH;
 976                     }
 977                 } else {
 978                     /* the mouse press happened inside the frame, not in the
 979                      border */
 980                   discardRelease = true;
 981                   return;
 982                 }
 983                 Cursor s = Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR);
 984                 switch (resizeDir) {
 985                 case SOUTH:
 986                   s = Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR);
 987                   break;
 988                 case NORTH:
 989                   s = Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR);
 990                   break;
 991                 case WEST:
 992                   s = Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR);
 993                   break;
 994                 case EAST:
 995                   s = Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR);
 996                   break;
 997                 case SOUTH_EAST:
 998                   s = Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR);
 999                   break;
1000                 case SOUTH_WEST:
1001                   s = Cursor.getPredefinedCursor(Cursor.SW_RESIZE_CURSOR);
1002                   break;
1003                 case NORTH_WEST:
1004                   s = Cursor.getPredefinedCursor(Cursor.NW_RESIZE_CURSOR);
1005                   break;
1006                 case NORTH_EAST:
1007                   s = Cursor.getPredefinedCursor(Cursor.NE_RESIZE_CURSOR);
1008                   break;
1009                 }
1010                 Container c = frame.getTopLevelAncestor();
1011                 if (c instanceof RootPaneContainer) {
1012                     Component glassPane = ((RootPaneContainer)c).getGlassPane();
1013                     glassPane.setVisible(true);
1014                     glassPane.setCursor(s);
1015                 }
1016                 getDesktopManager().beginResizingFrame(frame, resizeDir);
1017                 resizing = true;
1018                 // Add the WindowFocusListener for handling a
1019                 // WINDOW_LOST_FOCUS event with a cancelResize().
1020                 Window windowAncestor = SwingUtilities.getWindowAncestor(frame);
1021                 if (windowAncestor != null) {
1022                     windowAncestor.addWindowFocusListener(
1023                         getWindowFocusListener());
1024                 }
1025                 return;
1026             }
1027         }
1028 
1029         public void mouseDragged(MouseEvent e) {
1030 
1031             if ( startingBounds == null ) {
1032               // (STEVE) Yucky work around for bug ID 4106552
1033                  return;
1034             }
1035 
1036             Point p = SwingUtilities.convertPoint((Component)e.getSource(),
1037                     e.getX(), e.getY(), null);
1038             int deltaX = _x - p.x;
1039             int deltaY = _y - p.y;
1040             Dimension min = frame.getMinimumSize();
1041             Dimension max = frame.getMaximumSize();
1042             int newX, newY, newW, newH;
1043             Insets i = frame.getInsets();
1044 
1045             // Handle a MOVE
1046             if (dragging) {
1047                 if (frame.isMaximum() || ((e.getModifiers() &
1048                         InputEvent.BUTTON1_MASK) !=
1049                         InputEvent.BUTTON1_MASK)) {
1050                     // don't allow moving of frames if maximixed or left mouse
1051                     // button was not used.
1052                     return;
1053                 }
1054                 int pWidth, pHeight;
1055                 Dimension s = frame.getParent().getSize();
1056                 pWidth = s.width;
1057                 pHeight = s.height;
1058 
1059 
1060                 newX = startingBounds.x - deltaX;
1061                 newY = startingBounds.y - deltaY;
1062 
1063                 // Make sure we stay in-bounds
1064                 if(newX + i.left <= -__x)
1065                     newX = -__x - i.left + 1;
1066                 if(newY + i.top <= -__y)
1067                     newY = -__y - i.top + 1;
1068                 if(newX + __x + i.right >= pWidth)
1069                     newX = pWidth - __x - i.right - 1;
1070                 if(newY + __y + i.bottom >= pHeight)
1071                     newY =  pHeight - __y - i.bottom - 1;
1072 
1073                 getDesktopManager().dragFrame(frame, newX, newY);
1074                 return;
1075             }
1076 
1077             if(!frame.isResizable()) {
1078                 return;
1079             }
1080 
1081             newX = frame.getX();
1082             newY = frame.getY();
1083             newW = frame.getWidth();
1084             newH = frame.getHeight();
1085 
1086             parentBounds = frame.getParent().getBounds();
1087 
1088             switch(resizeDir) {
1089             case RESIZE_NONE:
1090                 return;
1091             case NORTH:
1092                 if(startingBounds.height + deltaY < min.height)
1093                     deltaY = -(startingBounds.height - min.height);
1094                 else if(startingBounds.height + deltaY > max.height)
1095                     deltaY = max.height - startingBounds.height;
1096                 if (startingBounds.y - deltaY < 0) {deltaY = startingBounds.y;}
1097 
1098                 newX = startingBounds.x;
1099                 newY = startingBounds.y - deltaY;
1100                 newW = startingBounds.width;
1101                 newH = startingBounds.height + deltaY;
1102                 break;
1103             case NORTH_EAST:
1104                 if(startingBounds.height + deltaY < min.height)
1105                     deltaY = -(startingBounds.height - min.height);
1106                 else if(startingBounds.height + deltaY > max.height)
1107                     deltaY = max.height - startingBounds.height;
1108                 if (startingBounds.y - deltaY < 0) {deltaY = startingBounds.y;}
1109 
1110                 if(startingBounds.width - deltaX < min.width)
1111                     deltaX = startingBounds.width - min.width;
1112                 else if(startingBounds.width - deltaX > max.width)
1113                     deltaX = -(max.width - startingBounds.width);
1114                 if (startingBounds.x + startingBounds.width - deltaX >
1115                     parentBounds.width) {
1116                   deltaX = startingBounds.x + startingBounds.width -
1117                     parentBounds.width;
1118                 }
1119 
1120                 newX = startingBounds.x;
1121                 newY = startingBounds.y - deltaY;
1122                 newW = startingBounds.width - deltaX;
1123                 newH = startingBounds.height + deltaY;
1124                 break;
1125             case EAST:
1126                 if(startingBounds.width - deltaX < min.width)
1127                     deltaX = startingBounds.width - min.width;
1128                 else if(startingBounds.width - deltaX > max.width)
1129                     deltaX = -(max.width - startingBounds.width);
1130                 if (startingBounds.x + startingBounds.width - deltaX >
1131                     parentBounds.width) {
1132                   deltaX = startingBounds.x + startingBounds.width -
1133                     parentBounds.width;
1134                 }
1135 
1136                 newW = startingBounds.width - deltaX;
1137                 newH = startingBounds.height;
1138                 break;
1139             case SOUTH_EAST:
1140                 if(startingBounds.width - deltaX < min.width)
1141                     deltaX = startingBounds.width - min.width;
1142                 else if(startingBounds.width - deltaX > max.width)
1143                     deltaX = -(max.width - startingBounds.width);
1144                 if (startingBounds.x + startingBounds.width - deltaX >
1145                     parentBounds.width) {
1146                   deltaX = startingBounds.x + startingBounds.width -
1147                     parentBounds.width;
1148                 }
1149 
1150                 if(startingBounds.height - deltaY < min.height)
1151                     deltaY = startingBounds.height - min.height;
1152                 else if(startingBounds.height - deltaY > max.height)
1153                     deltaY = -(max.height - startingBounds.height);
1154                 if (startingBounds.y + startingBounds.height - deltaY >
1155                      parentBounds.height) {
1156                   deltaY = startingBounds.y + startingBounds.height -
1157                     parentBounds.height ;
1158                 }
1159 
1160                 newW = startingBounds.width - deltaX;
1161                 newH = startingBounds.height - deltaY;
1162                 break;
1163             case SOUTH:
1164                 if(startingBounds.height - deltaY < min.height)
1165                     deltaY = startingBounds.height - min.height;
1166                 else if(startingBounds.height - deltaY > max.height)
1167                     deltaY = -(max.height - startingBounds.height);
1168                 if (startingBounds.y + startingBounds.height - deltaY >
1169                      parentBounds.height) {
1170                   deltaY = startingBounds.y + startingBounds.height -
1171                     parentBounds.height ;
1172                 }
1173 
1174                 newW = startingBounds.width;
1175                 newH = startingBounds.height - deltaY;
1176                 break;
1177             case SOUTH_WEST:
1178                 if(startingBounds.height - deltaY < min.height)
1179                     deltaY = startingBounds.height - min.height;
1180                 else if(startingBounds.height - deltaY > max.height)
1181                     deltaY = -(max.height - startingBounds.height);
1182                 if (startingBounds.y + startingBounds.height - deltaY >
1183                      parentBounds.height) {
1184                   deltaY = startingBounds.y + startingBounds.height -
1185                     parentBounds.height ;
1186                 }
1187 
1188                 if(startingBounds.width + deltaX < min.width)
1189                     deltaX = -(startingBounds.width - min.width);
1190                 else if(startingBounds.width + deltaX > max.width)
1191                     deltaX = max.width - startingBounds.width;
1192                 if (startingBounds.x - deltaX < 0) {
1193                   deltaX = startingBounds.x;
1194                 }
1195 
1196                 newX = startingBounds.x - deltaX;
1197                 newY = startingBounds.y;
1198                 newW = startingBounds.width + deltaX;
1199                 newH = startingBounds.height - deltaY;
1200                 break;
1201             case WEST:
1202                 if(startingBounds.width + deltaX < min.width)
1203                     deltaX = -(startingBounds.width - min.width);
1204                 else if(startingBounds.width + deltaX > max.width)
1205                     deltaX = max.width - startingBounds.width;
1206                 if (startingBounds.x - deltaX < 0) {
1207                   deltaX = startingBounds.x;
1208                 }
1209 
1210                 newX = startingBounds.x - deltaX;
1211                 newY = startingBounds.y;
1212                 newW = startingBounds.width + deltaX;
1213                 newH = startingBounds.height;
1214                 break;
1215             case NORTH_WEST:
1216                 if(startingBounds.width + deltaX < min.width)
1217                     deltaX = -(startingBounds.width - min.width);
1218                 else if(startingBounds.width + deltaX > max.width)
1219                     deltaX = max.width - startingBounds.width;
1220                 if (startingBounds.x - deltaX < 0) {
1221                   deltaX = startingBounds.x;
1222                 }
1223 
1224                 if(startingBounds.height + deltaY < min.height)
1225                     deltaY = -(startingBounds.height - min.height);
1226                 else if(startingBounds.height + deltaY > max.height)
1227                     deltaY = max.height - startingBounds.height;
1228                 if (startingBounds.y - deltaY < 0) {deltaY = startingBounds.y;}
1229 
1230                 newX = startingBounds.x - deltaX;
1231                 newY = startingBounds.y - deltaY;
1232                 newW = startingBounds.width + deltaX;
1233                 newH = startingBounds.height + deltaY;
1234                 break;
1235             default:
1236                 return;
1237             }
1238             getDesktopManager().resizeFrame(frame, newX, newY, newW, newH);
1239         }
1240 
1241         public void mouseMoved(MouseEvent e)    {
1242 
1243             if(!frame.isResizable())
1244                 return;
1245 
1246             if (e.getSource() == frame || e.getSource() == getNorthPane()) {
1247                 Insets i = frame.getInsets();
1248                 Point ep = new Point(e.getX(), e.getY());
1249                 if (e.getSource() == getNorthPane()) {
1250                     Point np = getNorthPane().getLocation();
1251                     ep.x += np.x;
1252                     ep.y += np.y;
1253                 }
1254                 if(ep.x <= i.left) {
1255                     if(ep.y < resizeCornerSize + i.top)
1256                         frame.setCursor(Cursor.getPredefinedCursor(Cursor.NW_RESIZE_CURSOR));
1257                     else if(ep.y > frame.getHeight() - resizeCornerSize - i.bottom)
1258                         frame.setCursor(Cursor.getPredefinedCursor(Cursor.SW_RESIZE_CURSOR));
1259                     else
1260                         frame.setCursor(Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR));
1261                 } else if(ep.x >= frame.getWidth() - i.right) {
1262                     if(e.getY() < resizeCornerSize + i.top)
1263                         frame.setCursor(Cursor.getPredefinedCursor(Cursor.NE_RESIZE_CURSOR));
1264                     else if(ep.y > frame.getHeight() - resizeCornerSize - i.bottom)
1265                         frame.setCursor(Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR));
1266                     else
1267                         frame.setCursor(Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR));
1268                 } else if(ep.y <= i.top) {
1269                     if(ep.x < resizeCornerSize + i.left)
1270                         frame.setCursor(Cursor.getPredefinedCursor(Cursor.NW_RESIZE_CURSOR));
1271                     else if(ep.x > frame.getWidth() - resizeCornerSize - i.right)
1272                         frame.setCursor(Cursor.getPredefinedCursor(Cursor.NE_RESIZE_CURSOR));
1273                     else
1274                         frame.setCursor(Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR));
1275                 } else if(ep.y >= frame.getHeight() - i.bottom) {
1276                     if(ep.x < resizeCornerSize + i.left)
1277                         frame.setCursor(Cursor.getPredefinedCursor(Cursor.SW_RESIZE_CURSOR));
1278                     else if(ep.x > frame.getWidth() - resizeCornerSize - i.right)
1279                         frame.setCursor(Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR));
1280                     else
1281                         frame.setCursor(Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR));
1282                 }
1283                 else
1284                     updateFrameCursor();
1285                 return;
1286             }
1287 
1288             updateFrameCursor();
1289         }
1290 
1291         public void mouseEntered(MouseEvent e)    {
1292             updateFrameCursor();
1293         }
1294 
1295         public void mouseExited(MouseEvent e)    {
1296             updateFrameCursor();
1297         }
1298 
1299     }    /// End BorderListener Class
1300 
1301     /**
1302      * Component handler.
1303      */
1304     protected class ComponentHandler implements ComponentListener {
1305       // NOTE: This class exists only for backward compatibility. All
1306       // its functionality has been moved into Handler. If you need to add
1307       // new functionality add it to the Handler, but make sure this
1308       // class calls into the Handler.
1309       /** Invoked when a JInternalFrame's parent's size changes. */
1310       public void componentResized(ComponentEvent e) {
1311           getHandler().componentResized(e);
1312       }
1313 
1314         /**
1315          * {@inheritDoc}
1316          */
1317       public void componentMoved(ComponentEvent e) {
1318           getHandler().componentMoved(e);
1319       }
1320         /**
1321          * {@inheritDoc}
1322          */
1323       public void componentShown(ComponentEvent e) {
1324           getHandler().componentShown(e);
1325       }
1326         /**
1327          * {@inheritDoc}
1328          */
1329       public void componentHidden(ComponentEvent e) {
1330           getHandler().componentHidden(e);
1331       }
1332     }
1333 
1334     /**
1335      * Creates a component listener.
1336      * @return a component listener
1337      */
1338     protected ComponentListener createComponentListener() {
1339       return getHandler();
1340     }
1341 
1342 
1343     /**
1344      * Glass pane dispatcher.
1345      */
1346     protected class GlassPaneDispatcher implements MouseInputListener {
1347         // NOTE: This class exists only for backward compatibility. All
1348         // its functionality has been moved into Handler. If you need to add
1349         // new functionality add it to the Handler, but make sure this
1350         // class calls into the Handler.
1351         /**
1352          * {@inheritDoc}
1353          */
1354         public void mousePressed(MouseEvent e) {
1355             getHandler().mousePressed(e);
1356         }
1357 
1358         /**
1359          * {@inheritDoc}
1360          */
1361         public void mouseEntered(MouseEvent e) {
1362             getHandler().mouseEntered(e);
1363         }
1364 
1365         /**
1366          * {@inheritDoc}
1367          */
1368         public void mouseMoved(MouseEvent e) {
1369             getHandler().mouseMoved(e);
1370         }
1371 
1372         /**
1373          * {@inheritDoc}
1374          */
1375         public void mouseExited(MouseEvent e) {
1376             getHandler().mouseExited(e);
1377         }
1378 
1379         /**
1380          * {@inheritDoc}
1381          */
1382         public void mouseClicked(MouseEvent e) {
1383             getHandler().mouseClicked(e);
1384         }
1385 
1386         /**
1387          * {@inheritDoc}
1388          */
1389         public void mouseReleased(MouseEvent e) {
1390             getHandler().mouseReleased(e);
1391         }
1392 
1393         /**
1394          * {@inheritDoc}
1395          */
1396         public void mouseDragged(MouseEvent e) {
1397             getHandler().mouseDragged(e);
1398         }
1399     }
1400 
1401     /**
1402      * Creates a {@code GlassPaneDispatcher}.
1403      * @return a {@code GlassPaneDispatcher}
1404      */
1405     protected MouseInputListener createGlassPaneDispatcher() {
1406         return null;
1407     }
1408 
1409     /**
1410      * Basic internal frame listener.
1411      */
1412     protected class BasicInternalFrameListener implements InternalFrameListener
1413     {
1414       // NOTE: This class exists only for backward compatibility. All
1415       // its functionality has been moved into Handler. If you need to add
1416       // new functionality add it to the Handler, but make sure this
1417       // class calls into the Handler.
1418         /**
1419          * {@inheritDoc}
1420          */
1421       public void internalFrameClosing(InternalFrameEvent e) {
1422           getHandler().internalFrameClosing(e);
1423       }
1424 
1425         /**
1426          * {@inheritDoc}
1427          */
1428       public void internalFrameClosed(InternalFrameEvent e) {
1429           getHandler().internalFrameClosed(e);
1430       }
1431 
1432         /**
1433          * {@inheritDoc}
1434          */
1435       public void internalFrameOpened(InternalFrameEvent e) {
1436           getHandler().internalFrameOpened(e);
1437       }
1438 
1439         /**
1440          * {@inheritDoc}
1441          */
1442       public void internalFrameIconified(InternalFrameEvent e) {
1443           getHandler().internalFrameIconified(e);
1444       }
1445 
1446         /**
1447          * {@inheritDoc}
1448          */
1449       public void internalFrameDeiconified(InternalFrameEvent e) {
1450           getHandler().internalFrameDeiconified(e);
1451       }
1452 
1453         /**
1454          * {@inheritDoc}
1455          */
1456       public void internalFrameActivated(InternalFrameEvent e) {
1457           getHandler().internalFrameActivated(e);
1458       }
1459 
1460         /**
1461          * {@inheritDoc}
1462          */
1463       public void internalFrameDeactivated(InternalFrameEvent e) {
1464           getHandler().internalFrameDeactivated(e);
1465       }
1466     }
1467 
1468     private class Handler implements ComponentListener, InternalFrameListener,
1469             LayoutManager, MouseInputListener, PropertyChangeListener,
1470             WindowFocusListener, SwingConstants {
1471 
1472         public void windowGainedFocus(WindowEvent e) {
1473         }
1474 
1475         public void windowLostFocus(WindowEvent e) {
1476             // Cancel a resize which may be in progress, when a
1477             // WINDOW_LOST_FOCUS event occurs, which may be
1478             // caused by an Alt-Tab or a modal dialog popup.
1479             cancelResize();
1480         }
1481 
1482         // ComponentHandler methods
1483         /** Invoked when a JInternalFrame's parent's size changes. */
1484         public void componentResized(ComponentEvent e) {
1485             // Get the JInternalFrame's parent container size
1486             Rectangle parentNewBounds = ((Component) e.getSource()).getBounds();
1487             JInternalFrame.JDesktopIcon icon = null;
1488 
1489             if (frame != null) {
1490                 icon = frame.getDesktopIcon();
1491                 // Resize the internal frame if it is maximized and relocate
1492                 // the associated icon as well.
1493                 if (frame.isMaximum()) {
1494                     frame.setBounds(0, 0, parentNewBounds.width,
1495                         parentNewBounds.height);
1496                 }
1497             }
1498 
1499             // Relocate the icon base on the new parent bounds.
1500             if (icon != null) {
1501                 Rectangle iconBounds = icon.getBounds();
1502                 int y = iconBounds.y +
1503                         (parentNewBounds.height - parentBounds.height);
1504                 icon.setBounds(iconBounds.x, y,
1505                         iconBounds.width, iconBounds.height);
1506             }
1507 
1508             // Update the new parent bounds for next resize.
1509             if (!parentBounds.equals(parentNewBounds)) {
1510                 parentBounds = parentNewBounds;
1511             }
1512 
1513             // Validate the component tree for this container.
1514             if (frame != null) frame.validate();
1515         }
1516 
1517         public void componentMoved(ComponentEvent e) {}
1518         public void componentShown(ComponentEvent e) {}
1519         public void componentHidden(ComponentEvent e) {}
1520 
1521 
1522         // InternalFrameListener
1523         public void internalFrameClosed(InternalFrameEvent e) {
1524             frame.removeInternalFrameListener(getHandler());
1525         }
1526 
1527         public void internalFrameActivated(InternalFrameEvent e) {
1528             if (!isKeyBindingRegistered()){
1529                 setKeyBindingRegistered(true);
1530                 setupMenuOpenKey();
1531                 setupMenuCloseKey();
1532             }
1533             if (isKeyBindingRegistered())
1534                 setKeyBindingActive(true);
1535         }
1536 
1537         public void internalFrameDeactivated(InternalFrameEvent e) {
1538             setKeyBindingActive(false);
1539         }
1540 
1541         public void internalFrameClosing(InternalFrameEvent e) { }
1542         public void internalFrameOpened(InternalFrameEvent e) { }
1543         public void internalFrameIconified(InternalFrameEvent e) { }
1544         public void internalFrameDeiconified(InternalFrameEvent e) { }
1545 
1546 
1547         // LayoutManager
1548         public void addLayoutComponent(String name, Component c) {}
1549         public void removeLayoutComponent(Component c) {}
1550         public Dimension preferredLayoutSize(Container c)  {
1551             Dimension result;
1552             Insets i = frame.getInsets();
1553 
1554             result = new Dimension(frame.getRootPane().getPreferredSize());
1555             result.width += i.left + i.right;
1556             result.height += i.top + i.bottom;
1557 
1558             if(getNorthPane() != null) {
1559                 Dimension d = getNorthPane().getPreferredSize();
1560                 result.width = Math.max(d.width, result.width);
1561                 result.height += d.height;
1562             }
1563 
1564             if(getSouthPane() != null) {
1565                 Dimension d = getSouthPane().getPreferredSize();
1566                 result.width = Math.max(d.width, result.width);
1567                 result.height += d.height;
1568             }
1569 
1570             if(getEastPane() != null) {
1571                 Dimension d = getEastPane().getPreferredSize();
1572                 result.width += d.width;
1573                 result.height = Math.max(d.height, result.height);
1574             }
1575 
1576             if(getWestPane() != null) {
1577                 Dimension d = getWestPane().getPreferredSize();
1578                 result.width += d.width;
1579                 result.height = Math.max(d.height, result.height);
1580             }
1581             return result;
1582         }
1583 
1584         public Dimension minimumLayoutSize(Container c) {
1585             // The minimum size of the internal frame only takes into
1586             // account the title pane since you are allowed to resize
1587             // the frames to the point where just the title pane is visible.
1588             Dimension result = new Dimension();
1589             if (getNorthPane() != null &&
1590                 getNorthPane() instanceof BasicInternalFrameTitlePane) {
1591                   result = new Dimension(getNorthPane().getMinimumSize());
1592             }
1593             Insets i = frame.getInsets();
1594             result.width += i.left + i.right;
1595             result.height += i.top + i.bottom;
1596 
1597             return result;
1598         }
1599 
1600         public void layoutContainer(Container c) {
1601             Insets i = frame.getInsets();
1602             int cx, cy, cw, ch;
1603 
1604             cx = i.left;
1605             cy = i.top;
1606             cw = frame.getWidth() - i.left - i.right;
1607             ch = frame.getHeight() - i.top - i.bottom;
1608 
1609             if(getNorthPane() != null) {
1610                 Dimension size = getNorthPane().getPreferredSize();
1611                 if (DefaultLookup.getBoolean(frame, BasicInternalFrameUI.this,
1612                           "InternalFrame.layoutTitlePaneAtOrigin", false)) {
1613                     cy = 0;
1614                     ch += i.top;
1615                     getNorthPane().setBounds(0, 0, frame.getWidth(),
1616                                              size.height);
1617                 }
1618                 else {
1619                     getNorthPane().setBounds(cx, cy, cw, size.height);
1620                 }
1621                 cy += size.height;
1622                 ch -= size.height;
1623             }
1624 
1625             if(getSouthPane() != null) {
1626                 Dimension size = getSouthPane().getPreferredSize();
1627                 getSouthPane().setBounds(cx, frame.getHeight()
1628                                                     - i.bottom - size.height,
1629                                                     cw, size.height);
1630                 ch -= size.height;
1631             }
1632 
1633             if(getWestPane() != null) {
1634                 Dimension size = getWestPane().getPreferredSize();
1635                 getWestPane().setBounds(cx, cy, size.width, ch);
1636                 cw -= size.width;
1637                 cx += size.width;
1638             }
1639 
1640             if(getEastPane() != null) {
1641                 Dimension size = getEastPane().getPreferredSize();
1642                 getEastPane().setBounds(cw - size.width, cy, size.width, ch);
1643                 cw -= size.width;
1644             }
1645 
1646             if(frame.getRootPane() != null) {
1647                 frame.getRootPane().setBounds(cx, cy, cw, ch);
1648             }
1649         }
1650 
1651 
1652         // MouseInputListener
1653         public void mousePressed(MouseEvent e) { }
1654 
1655         public void mouseEntered(MouseEvent e) { }
1656 
1657         public void mouseMoved(MouseEvent e) { }
1658 
1659         public void mouseExited(MouseEvent e) { }
1660 
1661         public void mouseClicked(MouseEvent e) { }
1662 
1663         public void mouseReleased(MouseEvent e) { }
1664 
1665         public void mouseDragged(MouseEvent e) { }
1666 
1667         // PropertyChangeListener
1668         public void propertyChange(PropertyChangeEvent evt) {
1669             String prop = evt.getPropertyName();
1670             JInternalFrame f = (JInternalFrame)evt.getSource();
1671             Object newValue = evt.getNewValue();
1672             Object oldValue = evt.getOldValue();
1673 
1674             if (JInternalFrame.IS_CLOSED_PROPERTY == prop) {
1675                 if (newValue == Boolean.TRUE) {
1676                     // Cancel a resize in progress if the internal frame
1677                     // gets a setClosed(true) or dispose().
1678                     cancelResize();
1679                     if ((frame.getParent() != null) && componentListenerAdded) {
1680                         frame.getParent().removeComponentListener(componentListener);
1681                     }
1682                     closeFrame(f);
1683                 }
1684             } else if (JInternalFrame.IS_MAXIMUM_PROPERTY == prop) {
1685                 if(newValue == Boolean.TRUE) {
1686                     maximizeFrame(f);
1687                 } else {
1688                     minimizeFrame(f);
1689                 }
1690             } else if(JInternalFrame.IS_ICON_PROPERTY == prop) {
1691                 if (newValue == Boolean.TRUE) {
1692                     iconifyFrame(f);
1693                 } else {
1694                     deiconifyFrame(f);
1695                 }
1696             } else if (JInternalFrame.IS_SELECTED_PROPERTY == prop) {
1697                 if (newValue == Boolean.TRUE && oldValue == Boolean.FALSE) {
1698                     activateFrame(f);
1699                 } else if (newValue == Boolean.FALSE &&
1700                            oldValue == Boolean.TRUE) {
1701                     deactivateFrame(f);
1702                 }
1703             } else if (prop == "ancestor") {
1704                 if (newValue == null) {
1705                     // Cancel a resize in progress, if the internal frame
1706                     // gets a remove(), removeNotify() or setIcon(true).
1707                     cancelResize();
1708                 }
1709                 if (frame.getParent() != null) {
1710                     parentBounds = f.getParent().getBounds();
1711                 } else {
1712                     parentBounds = null;
1713                 }
1714                 if ((frame.getParent() != null) && frame.isIcon()) {
1715                     Boolean value = (Boolean) frame.getClientProperty("wasIconOnce");
1716                     if (Boolean.FALSE.equals(value)) {
1717                         iconifyFrame(frame);
1718                     }
1719                 }
1720                 if ((frame.getParent() != null) && !componentListenerAdded) {
1721                     f.getParent().addComponentListener(componentListener);
1722                     componentListenerAdded = true;
1723                 }
1724             } else if (JInternalFrame.TITLE_PROPERTY == prop ||
1725                     prop == "closable" || prop == "iconable" ||
1726                     prop == "maximizable") {
1727                 Dimension dim = frame.getMinimumSize();
1728                 Dimension frame_dim = frame.getSize();
1729                 if (dim.width > frame_dim.width) {
1730                     frame.setSize(dim.width, frame_dim.height);
1731                 }
1732             }
1733         }
1734     }
1735 }