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