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 javax.swing.*;
29import javax.swing.plaf.*;
30
31import java.beans.*;
32
33import java.awt.event.*;
34import java.awt.Dimension;
35import java.awt.Insets;
36import java.awt.Graphics;
37import java.awt.KeyboardFocusManager;
38import java.awt.*;
39
40import sun.swing.DefaultLookup;
41import sun.swing.UIAction;
42
43/**
44 * Basic L&F for a desktop.
45 *
46 * @author Steve Wilson
47 */
48public class BasicDesktopPaneUI extends DesktopPaneUI {
49    // Old actions forward to an instance of this.
50    private static final Actions SHARED_ACTION = new Actions();
51    private Handler handler;
52    private PropertyChangeListener pcl;
53
54    /**
55     * The instance of {@code JDesktopPane}.
56     */
57    protected JDesktopPane desktop;
58
59    /**
60     * The instance of {@code DesktopManager}.
61     */
62    protected DesktopManager desktopManager;
63
64    /**
65     * As of Java 2 platform v1.3 this previously undocumented field is no
66     * longer used.
67     * Key bindings are now defined by the LookAndFeel, please refer to
68     * the key bindings specification for further details.
69     *
70     * @deprecated As of 1.3.
71     */
72    @Deprecated
73    protected KeyStroke minimizeKey;
74    /**
75     * As of Java 2 platform v1.3 this previously undocumented field is no
76     * longer used.
77     * Key bindings are now defined by the LookAndFeel, please refer to
78     * the key bindings specification for further details.
79     *
80     * @deprecated As of 1.3.
81     */
82    @Deprecated
83    protected KeyStroke maximizeKey;
84    /**
85     * As of Java 2 platform v1.3 this previously undocumented field is no
86     * longer used.
87     * Key bindings are now defined by the LookAndFeel, please refer to
88     * the key bindings specification for further details.
89     *
90     * @deprecated As of 1.3.
91     */
92    @Deprecated
93    protected KeyStroke closeKey;
94    /**
95     * As of Java 2 platform v1.3 this previously undocumented field is no
96     * longer used.
97     * Key bindings are now defined by the LookAndFeel, please refer to
98     * the key bindings specification for further details.
99     *
100     * @deprecated As of 1.3.
101     */
102    @Deprecated
103    protected KeyStroke navigateKey;
104    /**
105     * As of Java 2 platform v1.3 this previously undocumented field is no
106     * longer used.
107     * Key bindings are now defined by the LookAndFeel, please refer to
108     * the key bindings specification for further details.
109     *
110     * @deprecated As of 1.3.
111     */
112    @Deprecated
113    protected KeyStroke navigateKey2;
114
115    /**
116     * Constructs a new instance of {@code BasicDesktopPaneUI}.
117     *
118     * @param c a component
119     * @return a new instance of {@code BasicDesktopPaneUI}
120     */
121    public static ComponentUI createUI(JComponent c) {
122        return new BasicDesktopPaneUI();
123    }
124
125    /**
126     * Constructs a new instance of {@code BasicDesktopPaneUI}.
127     */
128    public BasicDesktopPaneUI() {
129    }
130
131    public void installUI(JComponent c)   {
132        desktop = (JDesktopPane)c;
133        installDefaults();
134        installDesktopManager();
135        installListeners();
136        installKeyboardActions();
137    }
138
139    public void uninstallUI(JComponent c) {
140        uninstallKeyboardActions();
141        uninstallListeners();
142        uninstallDesktopManager();
143        uninstallDefaults();
144        desktop = null;
145        handler = null;
146    }
147
148    /**
149     * Installs default properties.
150     */
151    protected void installDefaults() {
152        if (desktop.getBackground() == null ||
153            desktop.getBackground() instanceof UIResource) {
154            desktop.setBackground(UIManager.getColor("Desktop.background"));
155        }
156        LookAndFeel.installProperty(desktop, "opaque", Boolean.TRUE);
157    }
158
159    /**
160     * Uninstalls default properties.
161     */
162    protected void uninstallDefaults() { }
163
164    /**
165     * Installs the <code>PropertyChangeListener</code> returned from
166     * <code>createPropertyChangeListener</code> on the
167     * <code>JDesktopPane</code>.
168     *
169     * @since 1.5
170     * @see #createPropertyChangeListener
171     */
172    protected void installListeners() {
173        pcl = createPropertyChangeListener();
174        desktop.addPropertyChangeListener(pcl);
175    }
176
177    /**
178     * Uninstalls the <code>PropertyChangeListener</code> returned from
179     * <code>createPropertyChangeListener</code> from the
180     * <code>JDesktopPane</code>.
181     *
182     * @since 1.5
183     * @see #createPropertyChangeListener
184     */
185    protected void uninstallListeners() {
186        desktop.removePropertyChangeListener(pcl);
187        pcl = null;
188    }
189
190    /**
191     * Installs desktop manager.
192     */
193    protected void installDesktopManager() {
194        desktopManager = desktop.getDesktopManager();
195        if(desktopManager == null) {
196            desktopManager = new BasicDesktopManager();
197            desktop.setDesktopManager(desktopManager);
198        }
199    }
200
201    /**
202     * Uninstalls desktop manager.
203     */
204    protected void uninstallDesktopManager() {
205        if(desktop.getDesktopManager() instanceof UIResource) {
206            desktop.setDesktopManager(null);
207        }
208        desktopManager = null;
209    }
210
211    /**
212     * Installs keyboard actions.
213     */
214    protected void installKeyboardActions(){
215        InputMap inputMap = getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
216        if (inputMap != null) {
217            SwingUtilities.replaceUIInputMap(desktop,
218                        JComponent.WHEN_IN_FOCUSED_WINDOW, inputMap);
219        }
220        inputMap = getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
221        if (inputMap != null) {
222            SwingUtilities.replaceUIInputMap(desktop,
223                        JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
224                        inputMap);
225        }
226
227        LazyActionMap.installLazyActionMap(desktop, BasicDesktopPaneUI.class,
228                "DesktopPane.actionMap");
229        registerKeyboardActions();
230    }
231
232    /**
233     * Registers keyboard actions.
234     */
235    protected void registerKeyboardActions(){
236    }
237
238    /**
239     * Unregisters keyboard actions.
240     */
241    protected void unregisterKeyboardActions(){
242    }
243
244    InputMap getInputMap(int condition) {
245        if (condition == JComponent.WHEN_IN_FOCUSED_WINDOW) {
246            return createInputMap(condition);
247        }
248        else if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) {
249            return (InputMap)DefaultLookup.get(desktop, this,
250                    "Desktop.ancestorInputMap");
251        }
252        return null;
253    }
254
255    InputMap createInputMap(int condition) {
256        if (condition == JComponent.WHEN_IN_FOCUSED_WINDOW) {
257            Object[] bindings = (Object[])DefaultLookup.get(desktop,
258                    this, "Desktop.windowBindings");
259
260            if (bindings != null) {
261                return LookAndFeel.makeComponentInputMap(desktop, bindings);
262            }
263        }
264        return null;
265    }
266
267    static void loadActionMap(LazyActionMap map) {
268        map.put(new Actions(Actions.RESTORE));
269        map.put(new Actions(Actions.CLOSE));
270        map.put(new Actions(Actions.MOVE));
271        map.put(new Actions(Actions.RESIZE));
272        map.put(new Actions(Actions.LEFT));
273        map.put(new Actions(Actions.SHRINK_LEFT));
274        map.put(new Actions(Actions.RIGHT));
275        map.put(new Actions(Actions.SHRINK_RIGHT));
276        map.put(new Actions(Actions.UP));
277        map.put(new Actions(Actions.SHRINK_UP));
278        map.put(new Actions(Actions.DOWN));
279        map.put(new Actions(Actions.SHRINK_DOWN));
280        map.put(new Actions(Actions.ESCAPE));
281        map.put(new Actions(Actions.MINIMIZE));
282        map.put(new Actions(Actions.MAXIMIZE));
283        map.put(new Actions(Actions.NEXT_FRAME));
284        map.put(new Actions(Actions.PREVIOUS_FRAME));
285        map.put(new Actions(Actions.NAVIGATE_NEXT));
286        map.put(new Actions(Actions.NAVIGATE_PREVIOUS));
287    }
288
289    /**
290     * Unregisters keyboard actions.
291     */
292    protected void uninstallKeyboardActions(){
293      unregisterKeyboardActions();
294      SwingUtilities.replaceUIInputMap(desktop, JComponent.
295                                     WHEN_IN_FOCUSED_WINDOW, null);
296      SwingUtilities.replaceUIInputMap(desktop, JComponent.
297                                     WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null);
298      SwingUtilities.replaceUIActionMap(desktop, null);
299    }
300
301    public void paint(Graphics g, JComponent c) {}
302
303    @Override
304    public Dimension getPreferredSize(JComponent c) {
305        return null;
306    }
307
308    @Override
309    public Dimension getMinimumSize(JComponent c) {
310        return new Dimension(0, 0);
311    }
312
313    @Override
314    public Dimension getMaximumSize(JComponent c) {
315        return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
316    }
317
318    /**
319     * Returns the <code>PropertyChangeListener</code> to install on
320     * the <code>JDesktopPane</code>.
321     *
322     * @since 1.5
323     * @return The PropertyChangeListener that will be added to track
324     * changes in the desktop pane.
325     */
326    protected PropertyChangeListener createPropertyChangeListener() {
327        return getHandler();
328    }
329
330    private Handler getHandler() {
331        if (handler == null) {
332            handler = new Handler();
333        }
334        return handler;
335    }
336
337    private class Handler implements PropertyChangeListener {
338        public void propertyChange(PropertyChangeEvent evt) {
339            String propertyName = evt.getPropertyName();
340            if ("desktopManager" == propertyName) {
341                installDesktopManager();
342            }
343        }
344    }
345
346    /**
347     * The default DesktopManager installed by the UI.
348     */
349    @SuppressWarnings("serial") // JDK-implementation class
350    private class BasicDesktopManager extends DefaultDesktopManager
351            implements UIResource {
352    }
353
354    private static class Actions extends UIAction {
355        private static String CLOSE = "close";
356        private static String ESCAPE = "escape";
357        private static String MAXIMIZE = "maximize";
358        private static String MINIMIZE = "minimize";
359        private static String MOVE = "move";
360        private static String RESIZE = "resize";
361        private static String RESTORE = "restore";
362        private static String LEFT = "left";
363        private static String RIGHT = "right";
364        private static String UP = "up";
365        private static String DOWN = "down";
366        private static String SHRINK_LEFT = "shrinkLeft";
367        private static String SHRINK_RIGHT = "shrinkRight";
368        private static String SHRINK_UP = "shrinkUp";
369        private static String SHRINK_DOWN = "shrinkDown";
370        private static String NEXT_FRAME = "selectNextFrame";
371        private static String PREVIOUS_FRAME = "selectPreviousFrame";
372        private static String NAVIGATE_NEXT = "navigateNext";
373        private static String NAVIGATE_PREVIOUS = "navigatePrevious";
374        private final int MOVE_RESIZE_INCREMENT = 10;
375        private static boolean moving = false;
376        private static boolean resizing = false;
377        private static JInternalFrame sourceFrame = null;
378        private static Component focusOwner = null;
379
380        Actions() {
381            super(null);
382        }
383
384        Actions(String name) {
385            super(name);
386        }
387
388        public void actionPerformed(ActionEvent e) {
389            JDesktopPane dp = (JDesktopPane)e.getSource();
390            String key = getName();
391
392            if (CLOSE == key || MAXIMIZE == key || MINIMIZE == key ||
393                    RESTORE == key) {
394                setState(dp, key);
395            }
396            else if (ESCAPE == key) {
397                if (sourceFrame == dp.getSelectedFrame() &&
398                        focusOwner != null) {
399                    focusOwner.requestFocus();
400                }
401                moving = false;
402                resizing = false;
403                sourceFrame = null;
404                focusOwner = null;
405            }
406            else if (MOVE == key || RESIZE == key) {
407                sourceFrame = dp.getSelectedFrame();
408                if (sourceFrame == null) {
409                    return;
410                }
411                moving = (key == MOVE) ? true : false;
412                resizing = (key == RESIZE) ? true : false;
413
414                focusOwner = KeyboardFocusManager.
415                    getCurrentKeyboardFocusManager().getFocusOwner();
416                if (!SwingUtilities.isDescendingFrom(focusOwner, sourceFrame)) {
417                    focusOwner = null;
418                }
419                sourceFrame.requestFocus();
420            }
421            else if (LEFT == key ||
422                     RIGHT == key ||
423                     UP == key ||
424                     DOWN == key ||
425                     SHRINK_RIGHT == key ||
426                     SHRINK_LEFT == key ||
427                     SHRINK_UP == key ||
428                     SHRINK_DOWN == key) {
429                JInternalFrame c = dp.getSelectedFrame();
430                if (sourceFrame == null || c != sourceFrame ||
431                        KeyboardFocusManager.
432                            getCurrentKeyboardFocusManager().getFocusOwner() !=
433                                sourceFrame) {
434                    return;
435                }
436                Insets minOnScreenInsets =
437                    UIManager.getInsets("Desktop.minOnScreenInsets");
438                Dimension size = c.getSize();
439                Dimension minSize = c.getMinimumSize();
440                int dpWidth = dp.getWidth();
441                int dpHeight = dp.getHeight();
442                int delta;
443                Point loc = c.getLocation();
444                if (LEFT == key) {
445                    if (moving) {
446                        c.setLocation(
447                                loc.x + size.width - MOVE_RESIZE_INCREMENT <
448                                    minOnScreenInsets.right ?
449                                        -size.width + minOnScreenInsets.right :
450                                        loc.x - MOVE_RESIZE_INCREMENT,
451                                loc.y);
452                    } else if (resizing) {
453                        c.setLocation(loc.x - MOVE_RESIZE_INCREMENT, loc.y);
454                        c.setSize(size.width + MOVE_RESIZE_INCREMENT,
455                                size.height);
456                    }
457                } else if (RIGHT == key) {
458                    if (moving) {
459                        c.setLocation(
460                                loc.x + MOVE_RESIZE_INCREMENT >
461                                    dpWidth - minOnScreenInsets.left ?
462                                        dpWidth - minOnScreenInsets.left :
463                                        loc.x + MOVE_RESIZE_INCREMENT,
464                                loc.y);
465                    } else if (resizing) {
466                        c.setSize(size.width + MOVE_RESIZE_INCREMENT,
467                                size.height);
468                    }
469                } else if (UP == key) {
470                    if (moving) {
471                        c.setLocation(loc.x,
472                                loc.y + size.height - MOVE_RESIZE_INCREMENT <
473                                    minOnScreenInsets.bottom ?
474                                        -size.height +
475                                            minOnScreenInsets.bottom :
476                                        loc.y - MOVE_RESIZE_INCREMENT);
477                    } else if (resizing) {
478                        c.setLocation(loc.x, loc.y - MOVE_RESIZE_INCREMENT);
479                        c.setSize(size.width,
480                                size.height + MOVE_RESIZE_INCREMENT);
481                    }
482                } else if (DOWN == key) {
483                    if (moving) {
484                        c.setLocation(loc.x,
485                                loc.y + MOVE_RESIZE_INCREMENT >
486                                    dpHeight - minOnScreenInsets.top ?
487                                        dpHeight - minOnScreenInsets.top :
488                                        loc.y + MOVE_RESIZE_INCREMENT);
489                    } else if (resizing) {
490                        c.setSize(size.width,
491                                size.height + MOVE_RESIZE_INCREMENT);
492                    }
493                } else if (SHRINK_LEFT == key && resizing) {
494                    // Make sure we don't resize less than minimum size.
495                    if (minSize.width < (size.width - MOVE_RESIZE_INCREMENT)) {
496                        delta = MOVE_RESIZE_INCREMENT;
497                    } else {
498                        delta = size.width - minSize.width;
499                    }
500
501                    // Ensure that we keep the internal frame on the desktop.
502                    if (loc.x + size.width - delta < minOnScreenInsets.left) {
503                        delta = loc.x + size.width - minOnScreenInsets.left;
504                    }
505                    c.setSize(size.width - delta, size.height);
506                } else if (SHRINK_RIGHT == key && resizing) {
507                    // Make sure we don't resize less than minimum size.
508                    if (minSize.width < (size.width - MOVE_RESIZE_INCREMENT)) {
509                        delta = MOVE_RESIZE_INCREMENT;
510                    } else {
511                        delta = size.width - minSize.width;
512                    }
513
514                    // Ensure that we keep the internal frame on the desktop.
515                    if (loc.x + delta > dpWidth - minOnScreenInsets.right) {
516                        delta = (dpWidth - minOnScreenInsets.right) - loc.x;
517                    }
518
519                    c.setLocation(loc.x + delta, loc.y);
520                    c.setSize(size.width - delta, size.height);
521                } else if (SHRINK_UP == key && resizing) {
522                    // Make sure we don't resize less than minimum size.
523                    if (minSize.height <
524                            (size.height - MOVE_RESIZE_INCREMENT)) {
525                        delta = MOVE_RESIZE_INCREMENT;
526                    } else {
527                        delta = size.height - minSize.height;
528                    }
529
530                    // Ensure that we keep the internal frame on the desktop.
531                    if (loc.y + size.height - delta <
532                            minOnScreenInsets.bottom) {
533                        delta = loc.y + size.height - minOnScreenInsets.bottom;
534                    }
535
536                    c.setSize(size.width, size.height - delta);
537                } else if (SHRINK_DOWN == key  && resizing) {
538                    // Make sure we don't resize less than minimum size.
539                    if (minSize.height <
540                            (size.height - MOVE_RESIZE_INCREMENT)) {
541                        delta = MOVE_RESIZE_INCREMENT;
542                    } else {
543                        delta = size.height - minSize.height;
544                    }
545
546                    // Ensure that we keep the internal frame on the desktop.
547                    if (loc.y + delta > dpHeight - minOnScreenInsets.top) {
548                        delta = (dpHeight - minOnScreenInsets.top) - loc.y;
549                    }
550
551                    c.setLocation(loc.x, loc.y + delta);
552                    c.setSize(size.width, size.height - delta);
553                }
554            }
555            else if (NEXT_FRAME == key || PREVIOUS_FRAME == key) {
556                dp.selectFrame((key == NEXT_FRAME) ? true : false);
557            }
558            else if (NAVIGATE_NEXT == key ||
559                     NAVIGATE_PREVIOUS == key) {
560                boolean moveForward = true;
561                if (NAVIGATE_PREVIOUS == key) {
562                    moveForward = false;
563                }
564                Container cycleRoot = dp.getFocusCycleRootAncestor();
565
566                if (cycleRoot != null) {
567                    FocusTraversalPolicy policy =
568                        cycleRoot.getFocusTraversalPolicy();
569                    if (policy != null && policy instanceof
570                            SortingFocusTraversalPolicy) {
571                        SortingFocusTraversalPolicy sPolicy =
572                            (SortingFocusTraversalPolicy)policy;
573                        boolean idc = sPolicy.getImplicitDownCycleTraversal();
574                        try {
575                            sPolicy.setImplicitDownCycleTraversal(false);
576                            if (moveForward) {
577                                KeyboardFocusManager.
578                                    getCurrentKeyboardFocusManager().
579                                        focusNextComponent(dp);
580                            } else {
581                                KeyboardFocusManager.
582                                    getCurrentKeyboardFocusManager().
583                                    focusPreviousComponent(dp);
584                            }
585                        } finally {
586                            sPolicy.setImplicitDownCycleTraversal(idc);
587                        }
588                    }
589                }
590            }
591        }
592
593        private void setState(JDesktopPane dp, String state) {
594            if (state == CLOSE) {
595                JInternalFrame f = dp.getSelectedFrame();
596                if (f == null) {
597                    return;
598                }
599                f.doDefaultCloseAction();
600            } else if (state == MAXIMIZE) {
601                // maximize the selected frame
602                JInternalFrame f = dp.getSelectedFrame();
603                if (f == null) {
604                    return;
605                }
606                if (!f.isMaximum()) {
607                    if (f.isIcon()) {
608                        try {
609                            f.setIcon(false);
610                            f.setMaximum(true);
611                        } catch (PropertyVetoException pve) {}
612                    } else {
613                        try {
614                            f.setMaximum(true);
615                        } catch (PropertyVetoException pve) {
616                        }
617                    }
618                }
619            } else if (state == MINIMIZE) {
620                // minimize the selected frame
621                JInternalFrame f = dp.getSelectedFrame();
622                if (f == null) {
623                    return;
624                }
625                if (!f.isIcon()) {
626                    try {
627                        f.setIcon(true);
628                    } catch (PropertyVetoException pve) {
629                    }
630                }
631            } else if (state == RESTORE) {
632                // restore the selected minimized or maximized frame
633                JInternalFrame f = dp.getSelectedFrame();
634                if (f == null) {
635                    return;
636                }
637                try {
638                    if (f.isIcon()) {
639                        f.setIcon(false);
640                    } else if (f.isMaximum()) {
641                        f.setMaximum(false);
642                    }
643                    f.setSelected(true);
644                } catch (PropertyVetoException pve) {
645                }
646            }
647        }
648
649        @Override
650        public boolean accept(Object sender) {
651            if (sender instanceof JDesktopPane) {
652                JDesktopPane dp = (JDesktopPane)sender;
653                String action = getName();
654                if (action == Actions.NEXT_FRAME ||
655                    action == Actions.PREVIOUS_FRAME) {
656                    return true;
657                }
658                JInternalFrame iFrame = dp.getSelectedFrame();
659                if (iFrame == null) {
660                    return false;
661                } else if (action == Actions.CLOSE) {
662                    return iFrame.isClosable();
663                } else if (action == Actions.MINIMIZE) {
664                    return iFrame.isIconifiable();
665                } else if (action == Actions.MAXIMIZE) {
666                    return iFrame.isMaximizable();
667                }
668                return true;
669            }
670            return false;
671        }
672    }
673
674
675    /**
676     * Handles restoring a minimized or maximized internal frame.
677     * @since 1.3
678     */
679    @SuppressWarnings("serial") // Superclass is not serializable across versions
680    protected class OpenAction extends AbstractAction {
681        public void actionPerformed(ActionEvent evt) {
682            JDesktopPane dp = (JDesktopPane)evt.getSource();
683            SHARED_ACTION.setState(dp, Actions.RESTORE);
684        }
685
686        public boolean isEnabled() {
687            return true;
688        }
689    }
690
691    /**
692     * Handles closing an internal frame.
693     */
694    @SuppressWarnings("serial") // Superclass is not serializable across versions
695    protected class CloseAction extends AbstractAction {
696        public void actionPerformed(ActionEvent evt) {
697            JDesktopPane dp = (JDesktopPane)evt.getSource();
698            SHARED_ACTION.setState(dp, Actions.CLOSE);
699        }
700
701        public boolean isEnabled() {
702            JInternalFrame iFrame = desktop.getSelectedFrame();
703            if (iFrame != null) {
704                return iFrame.isClosable();
705            }
706            return false;
707        }
708    }
709
710    /**
711     * Handles minimizing an internal frame.
712     */
713    @SuppressWarnings("serial") // Superclass is not serializable across versions
714    protected class MinimizeAction extends AbstractAction {
715        public void actionPerformed(ActionEvent evt) {
716            JDesktopPane dp = (JDesktopPane)evt.getSource();
717            SHARED_ACTION.setState(dp, Actions.MINIMIZE);
718        }
719
720        public boolean isEnabled() {
721            JInternalFrame iFrame = desktop.getSelectedFrame();
722            if (iFrame != null) {
723                return iFrame.isIconifiable();
724            }
725            return false;
726        }
727    }
728
729    /**
730     * Handles maximizing an internal frame.
731     */
732    @SuppressWarnings("serial") // Superclass is not serializable across versions
733    protected class MaximizeAction extends AbstractAction {
734        public void actionPerformed(ActionEvent evt) {
735            JDesktopPane dp = (JDesktopPane)evt.getSource();
736            SHARED_ACTION.setState(dp, Actions.MAXIMIZE);
737        }
738
739        public boolean isEnabled() {
740            JInternalFrame iFrame = desktop.getSelectedFrame();
741            if (iFrame != null) {
742                return iFrame.isMaximizable();
743            }
744            return false;
745        }
746    }
747
748    /**
749     * Handles navigating to the next internal frame.
750     */
751    @SuppressWarnings("serial") // Superclass is not serializable across versions
752    protected class NavigateAction extends AbstractAction {
753        public void actionPerformed(ActionEvent evt) {
754            JDesktopPane dp = (JDesktopPane)evt.getSource();
755            dp.selectFrame(true);
756        }
757
758        public boolean isEnabled() {
759            return true;
760        }
761    }
762}
763