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
26package javax.swing.plaf.basic;
27
28import java.awt.*;
29import java.awt.event.*;
30import javax.swing.*;
31import javax.swing.plaf.*;
32import javax.swing.event.*;
33import java.beans.*;
34import sun.swing.DefaultLookup;
35import sun.swing.UIAction;
36
37/**
38 * A basic L&F implementation of JInternalFrame.
39 *
40 * @author David Kloba
41 * @author Rich Schiavi
42 */
43public 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        @SuppressWarnings("deprecation")
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}
1738