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