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