Home » openjdk-7 » javax » swing » [javadoc | source]

    1   /*
    2    * Copyright (c) 1997, 2011, 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   
   27   package javax.swing;
   28   
   29   import com.sun.awt.AWTUtilities;
   30   import sun.awt.AWTAccessor;
   31   import sun.awt.SunToolkit;
   32   
   33   import java.awt;
   34   import java.beans.PropertyVetoException;
   35   
   36   /** This is an implementation of the <code>DesktopManager</code>.
   37     * It currently implements the basic behaviors for managing
   38     * <code>JInternalFrame</code>s in an arbitrary parent.
   39     * <code>JInternalFrame</code>s that are not children of a
   40     * <code>JDesktop</code> will use this component
   41     * to handle their desktop-like actions.
   42     * <p>This class provides a policy for the various JInternalFrame methods,
   43     * it is not meant to be called directly rather the various JInternalFrame
   44     * methods will call into the DesktopManager.</p>
   45     * @see JDesktopPane
   46     * @see JInternalFrame
   47     * @author David Kloba
   48     * @author Steve Wilson
   49     */
   50   public class DefaultDesktopManager implements DesktopManager, java.io.Serializable {
   51       final static String HAS_BEEN_ICONIFIED_PROPERTY = "wasIconOnce";
   52   
   53       final static int DEFAULT_DRAG_MODE = 0;
   54       final static int OUTLINE_DRAG_MODE = 1;
   55       final static int FASTER_DRAG_MODE = 2;
   56   
   57       int dragMode = DEFAULT_DRAG_MODE;
   58   
   59       private transient Rectangle currentBounds = null;
   60       private transient Graphics desktopGraphics = null;
   61       private transient Rectangle desktopBounds = null;
   62       private transient Rectangle[] floatingItems = {};
   63   
   64       /**
   65        * Set to true when the user actually drags a frame vs clicks on it
   66        * to start the drag operation.  This is only used when dragging with
   67        * FASTER_DRAG_MODE.
   68        */
   69       private transient boolean didDrag;
   70   
   71       /** Normally this method will not be called. If it is, it
   72         * try to determine the appropriate parent from the desktopIcon of the frame.
   73         * Will remove the desktopIcon from its parent if it successfully adds the frame.
   74         */
   75       public void openFrame(JInternalFrame f) {
   76           if(f.getDesktopIcon().getParent() != null) {
   77               f.getDesktopIcon().getParent().add(f);
   78               removeIconFor(f);
   79           }
   80       }
   81   
   82       /**
   83        * Removes the frame, and, if necessary, the
   84        * <code>desktopIcon</code>, from its parent.
   85        * @param f the <code>JInternalFrame</code> to be removed
   86        */
   87       public void closeFrame(JInternalFrame f) {
   88           JDesktopPane d = f.getDesktopPane();
   89           if (d == null) {
   90               return;
   91           }
   92           boolean findNext = f.isSelected();
   93           Container c = f.getParent();
   94           JInternalFrame nextFrame = null;
   95           if (findNext) {
   96               nextFrame = d.getNextFrame(f);
   97               try { f.setSelected(false); } catch (PropertyVetoException e2) { }
   98           }
   99           if(c != null) {
  100               c.remove(f); // Removes the focus.
  101               c.repaint(f.getX(), f.getY(), f.getWidth(), f.getHeight());
  102           }
  103           removeIconFor(f);
  104           if(f.getNormalBounds() != null)
  105               f.setNormalBounds(null);
  106           if(wasIcon(f))
  107               setWasIcon(f, null);
  108           if (nextFrame != null) {
  109               try { nextFrame.setSelected(true); }
  110               catch (PropertyVetoException e2) { }
  111           } else if (findNext && d.getComponentCount() == 0) {
  112               // It was selected and was the last component on the desktop.
  113               d.requestFocus();
  114           }
  115       }
  116   
  117       /**
  118        * Resizes the frame to fill its parents bounds.
  119        * @param f the frame to be resized
  120        */
  121       public void maximizeFrame(JInternalFrame f) {
  122           if (f.isIcon()) {
  123               try {
  124                   // In turn calls deiconifyFrame in the desktop manager.
  125                   // That method will handle the maximization of the frame.
  126                   f.setIcon(false);
  127               } catch (PropertyVetoException e2) {
  128               }
  129           } else {
  130               f.setNormalBounds(f.getBounds());
  131               Rectangle desktopBounds = f.getParent().getBounds();
  132               setBoundsForFrame(f, 0, 0,
  133                   desktopBounds.width, desktopBounds.height);
  134           }
  135   
  136           // Set the maximized frame as selected.
  137           try {
  138               f.setSelected(true);
  139           } catch (PropertyVetoException e2) {
  140           }
  141       }
  142   
  143       /**
  144        * Restores the frame back to its size and position prior
  145        * to a <code>maximizeFrame</code> call.
  146        * @param f the <code>JInternalFrame</code> to be restored
  147        */
  148       public void minimizeFrame(JInternalFrame f) {
  149           // If the frame was an icon restore it back to an icon.
  150           if (f.isIcon()) {
  151               iconifyFrame(f);
  152               return;
  153           }
  154   
  155           if ((f.getNormalBounds()) != null) {
  156               Rectangle r = f.getNormalBounds();
  157               f.setNormalBounds(null);
  158               try { f.setSelected(true); } catch (PropertyVetoException e2) { }
  159               setBoundsForFrame(f, r.x, r.y, r.width, r.height);
  160           }
  161       }
  162   
  163       /**
  164        * Removes the frame from its parent and adds its
  165        * <code>desktopIcon</code> to the parent.
  166        * @param f the <code>JInternalFrame</code> to be iconified
  167        */
  168       public void iconifyFrame(JInternalFrame f) {
  169           JInternalFrame.JDesktopIcon desktopIcon;
  170           Container c = f.getParent();
  171           JDesktopPane d = f.getDesktopPane();
  172           boolean findNext = f.isSelected();
  173           desktopIcon = f.getDesktopIcon();
  174           if(!wasIcon(f)) {
  175               Rectangle r = getBoundsForIconOf(f);
  176               desktopIcon.setBounds(r.x, r.y, r.width, r.height);
  177               // we must validate the hierarchy to not break the hw/lw mixing
  178               desktopIcon.revalidate();
  179               setWasIcon(f, Boolean.TRUE);
  180           }
  181   
  182           if (c == null || d == null) {
  183               return;
  184           }
  185   
  186           if (c instanceof JLayeredPane) {
  187               JLayeredPane lp = (JLayeredPane)c;
  188               int layer = lp.getLayer(f);
  189               lp.putLayer(desktopIcon, layer);
  190           }
  191   
  192           // If we are maximized we already have the normal bounds recorded
  193           // don't try to re-record them, otherwise we incorrectly set the
  194           // normal bounds to maximized state.
  195           if (!f.isMaximum()) {
  196               f.setNormalBounds(f.getBounds());
  197           }
  198           d.setComponentOrderCheckingEnabled(false);
  199           c.remove(f);
  200           c.add(desktopIcon);
  201           d.setComponentOrderCheckingEnabled(true);
  202           c.repaint(f.getX(), f.getY(), f.getWidth(), f.getHeight());
  203           if (findNext) {
  204               if (d.selectFrame(true) == null) {
  205                   // The icon is the last frame.
  206                   f.restoreSubcomponentFocus();
  207               }
  208           }
  209       }
  210   
  211       /**
  212        * Removes the desktopIcon from its parent and adds its frame
  213        * to the parent.
  214        * @param f the <code>JInternalFrame</code> to be de-iconified
  215        */
  216       public void deiconifyFrame(JInternalFrame f) {
  217           JInternalFrame.JDesktopIcon desktopIcon = f.getDesktopIcon();
  218           Container c = desktopIcon.getParent();
  219           JDesktopPane d = f.getDesktopPane();
  220           if (c != null && d != null) {
  221               c.add(f);
  222               // If the frame is to be restored to a maximized state make
  223               // sure it still fills the whole desktop.
  224               if (f.isMaximum()) {
  225                   Rectangle desktopBounds = c.getBounds();
  226                   if (f.getWidth() != desktopBounds.width ||
  227                           f.getHeight() != desktopBounds.height) {
  228                       setBoundsForFrame(f, 0, 0,
  229                           desktopBounds.width, desktopBounds.height);
  230                   }
  231               }
  232               removeIconFor(f);
  233               if (f.isSelected()) {
  234                   f.moveToFront();
  235                   f.restoreSubcomponentFocus();
  236               }
  237               else {
  238                   try {
  239                       f.setSelected(true);
  240                   } catch (PropertyVetoException e2) {}
  241   
  242               }
  243           }
  244       }
  245   
  246       /** This will activate <b>f</b> moving it to the front. It will
  247         * set the current active frame's (if any)
  248         * <code>IS_SELECTED_PROPERTY</code> to <code>false</code>.
  249         * There can be only one active frame across all Layers.
  250         * @param f the <code>JInternalFrame</code> to be activated
  251         */
  252       public void activateFrame(JInternalFrame f) {
  253           Container p = f.getParent();
  254           Component[] c;
  255           JDesktopPane d = f.getDesktopPane();
  256           JInternalFrame currentlyActiveFrame =
  257             (d == null) ? null : d.getSelectedFrame();
  258           // fix for bug: 4162443
  259           if(p == null) {
  260               // If the frame is not in parent, its icon maybe, check it
  261               p = f.getDesktopIcon().getParent();
  262               if(p == null)
  263                   return;
  264           }
  265           // we only need to keep track of the currentActive InternalFrame, if any
  266           if (currentlyActiveFrame == null){
  267             if (d != null) { d.setSelectedFrame(f);}
  268           } else if (currentlyActiveFrame != f) {
  269             // if not the same frame as the current active
  270             // we deactivate the current
  271             if (currentlyActiveFrame.isSelected()) {
  272               try {
  273                 currentlyActiveFrame.setSelected(false);
  274               }
  275               catch(PropertyVetoException e2) {}
  276             }
  277             if (d != null) { d.setSelectedFrame(f);}
  278           }
  279           f.moveToFront();
  280       }
  281   
  282       // implements javax.swing.DesktopManager
  283       public void deactivateFrame(JInternalFrame f) {
  284         JDesktopPane d = f.getDesktopPane();
  285         JInternalFrame currentlyActiveFrame =
  286             (d == null) ? null : d.getSelectedFrame();
  287         if (currentlyActiveFrame == f)
  288           d.setSelectedFrame(null);
  289       }
  290   
  291       // implements javax.swing.DesktopManager
  292       public void beginDraggingFrame(JComponent f) {
  293           setupDragMode(f);
  294   
  295           if (dragMode == FASTER_DRAG_MODE) {
  296             Component desktop = f.getParent();
  297             floatingItems = findFloatingItems(f);
  298             currentBounds = f.getBounds();
  299             if (desktop instanceof JComponent) {
  300                 desktopBounds = ((JComponent)desktop).getVisibleRect();
  301             }
  302             else {
  303                 desktopBounds = desktop.getBounds();
  304                 desktopBounds.x = desktopBounds.y = 0;
  305             }
  306             desktopGraphics = JComponent.safelyGetGraphics(desktop);
  307             ((JInternalFrame)f).isDragging = true;
  308             didDrag = false;
  309           }
  310   
  311       }
  312   
  313       private void setupDragMode(JComponent f) {
  314           JDesktopPane p = getDesktopPane(f);
  315           Container parent = f.getParent();
  316           dragMode = DEFAULT_DRAG_MODE;
  317           if (p != null) {
  318               String mode = (String)p.getClientProperty("JDesktopPane.dragMode");
  319               Window window = SwingUtilities.getWindowAncestor(f);
  320               if (window != null && !AWTUtilities.isWindowOpaque(window)) {
  321                   dragMode = DEFAULT_DRAG_MODE;
  322               } else if (mode != null && mode.equals("outline")) {
  323                   dragMode = OUTLINE_DRAG_MODE;
  324               } else if (mode != null && mode.equals("faster")
  325                       && f instanceof JInternalFrame
  326                       && ((JInternalFrame)f).isOpaque() &&
  327                          (parent == null || parent.isOpaque())) {
  328                   dragMode = FASTER_DRAG_MODE;
  329               } else {
  330                   if (p.getDragMode() == JDesktopPane.OUTLINE_DRAG_MODE ) {
  331                       dragMode = OUTLINE_DRAG_MODE;
  332                   } else if ( p.getDragMode() == JDesktopPane.LIVE_DRAG_MODE
  333                           && f instanceof JInternalFrame
  334                           && ((JInternalFrame)f).isOpaque()) {
  335                       dragMode = FASTER_DRAG_MODE;
  336                   } else {
  337                       dragMode = DEFAULT_DRAG_MODE;
  338                   }
  339               }
  340           }
  341       }
  342   
  343       private transient Point currentLoc = null;
  344   
  345       /**
  346         * Moves the visible location of the frame being dragged
  347         * to the location specified.  The means by which this occurs can vary depending
  348         * on the dragging algorithm being used.  The actual logical location of the frame
  349         * might not change until <code>endDraggingFrame</code> is called.
  350         */
  351       public void dragFrame(JComponent f, int newX, int newY) {
  352   
  353           if (dragMode == OUTLINE_DRAG_MODE) {
  354               JDesktopPane desktopPane = getDesktopPane(f);
  355               if (desktopPane != null){
  356                 Graphics g = JComponent.safelyGetGraphics(desktopPane);
  357   
  358                 g.setXORMode(Color.white);
  359                 if (currentLoc != null) {
  360                   g.drawRect(currentLoc.x, currentLoc.y,
  361                           f.getWidth()-1, f.getHeight()-1);
  362                 }
  363                 g.drawRect( newX, newY, f.getWidth()-1, f.getHeight()-1);
  364                 /* Work around for 6635462: XOR mode may cause a SurfaceLost on first use.
  365                 * Swing doesn't expect that its XOR drawRect did
  366                 * not complete, so believes that on re-entering at
  367                 * the next update location, that there is an XOR rect
  368                 * to draw out at "currentLoc". But in fact
  369                 * its now got a new clean surface without that rect,
  370                 * so drawing it "out" in fact draws it on, leaving garbage.
  371                 * So only update/set currentLoc if the draw completed.
  372                 */
  373                 sun.java2d.SurfaceData sData =
  374                     ((sun.java2d.SunGraphics2D)g).getSurfaceData();
  375   
  376                 if (!sData.isSurfaceLost()) {
  377                     currentLoc = new Point (newX, newY);
  378                 }
  379   ;
  380                 g.dispose();
  381               }
  382           } else if (dragMode == FASTER_DRAG_MODE) {
  383               dragFrameFaster(f, newX, newY);
  384           } else {
  385               setBoundsForFrame(f, newX, newY, f.getWidth(), f.getHeight());
  386           }
  387       }
  388   
  389       // implements javax.swing.DesktopManager
  390       public void endDraggingFrame(JComponent f) {
  391           if ( dragMode == OUTLINE_DRAG_MODE && currentLoc != null) {
  392               setBoundsForFrame(f, currentLoc.x, currentLoc.y, f.getWidth(), f.getHeight() );
  393               currentLoc = null;
  394           } else if (dragMode == FASTER_DRAG_MODE) {
  395               currentBounds = null;
  396               if (desktopGraphics != null) {
  397                   desktopGraphics.dispose();
  398                   desktopGraphics = null;
  399               }
  400               desktopBounds = null;
  401               ((JInternalFrame)f).isDragging = false;
  402           }
  403       }
  404   
  405       // implements javax.swing.DesktopManager
  406       public void beginResizingFrame(JComponent f, int direction) {
  407           setupDragMode(f);
  408       }
  409   
  410       /**
  411        * Calls <code>setBoundsForFrame</code> with the new values.
  412        * @param f the component to be resized
  413        * @param newX the new x-coordinate
  414        * @param newY the new y-coordinate
  415        * @param newWidth the new width
  416        * @param newHeight the new height
  417        */
  418       public void resizeFrame(JComponent f, int newX, int newY, int newWidth, int newHeight) {
  419   
  420           if ( dragMode == DEFAULT_DRAG_MODE || dragMode == FASTER_DRAG_MODE ) {
  421               setBoundsForFrame(f, newX, newY, newWidth, newHeight);
  422           } else {
  423               JDesktopPane desktopPane = getDesktopPane(f);
  424               if (desktopPane != null){
  425                 Graphics g = JComponent.safelyGetGraphics(desktopPane);
  426   
  427                 g.setXORMode(Color.white);
  428                 if (currentBounds != null) {
  429                   g.drawRect( currentBounds.x, currentBounds.y, currentBounds.width-1, currentBounds.height-1);
  430                 }
  431                 g.drawRect( newX, newY, newWidth-1, newHeight-1);
  432   
  433                 // Work around for 6635462, see comment in dragFrame()
  434                 sun.java2d.SurfaceData sData =
  435                     ((sun.java2d.SunGraphics2D)g).getSurfaceData();
  436                 if (!sData.isSurfaceLost()) {
  437                     currentBounds = new Rectangle (newX, newY, newWidth, newHeight);
  438                 }
  439   
  440                 g.setPaintMode();
  441                 g.dispose();
  442               }
  443           }
  444   
  445       }
  446   
  447       // implements javax.swing.DesktopManager
  448       public void endResizingFrame(JComponent f) {
  449           if ( dragMode == OUTLINE_DRAG_MODE && currentBounds != null) {
  450               setBoundsForFrame(f, currentBounds.x, currentBounds.y, currentBounds.width, currentBounds.height );
  451               currentBounds = null;
  452           }
  453       }
  454   
  455   
  456       /** This moves the <code>JComponent</code> and repaints the damaged areas. */
  457       public void setBoundsForFrame(JComponent f, int newX, int newY, int newWidth, int newHeight) {
  458           f.setBounds(newX, newY, newWidth, newHeight);
  459           // we must validate the hierarchy to not break the hw/lw mixing
  460           f.revalidate();
  461       }
  462   
  463       /** Convenience method to remove the desktopIcon of <b>f</b> is necessary. */
  464       protected void removeIconFor(JInternalFrame f) {
  465           JInternalFrame.JDesktopIcon di = f.getDesktopIcon();
  466           Container c = di.getParent();
  467           if(c != null) {
  468               c.remove(di);
  469               c.repaint(di.getX(), di.getY(), di.getWidth(), di.getHeight());
  470           }
  471       }
  472   
  473       /** The iconifyFrame() code calls this to determine the proper bounds
  474         * for the desktopIcon.
  475         */
  476   
  477       protected Rectangle getBoundsForIconOf(JInternalFrame f) {
  478         //
  479         // Get the icon for this internal frame and its preferred size
  480         //
  481   
  482         JInternalFrame.JDesktopIcon icon = f.getDesktopIcon();
  483         Dimension prefSize = icon.getPreferredSize();
  484         //
  485         // Get the parent bounds and child components.
  486         //
  487   
  488         Container c = f.getParent();
  489         if (c == null) {
  490             c = f.getDesktopIcon().getParent();
  491         }
  492   
  493         if (c == null) {
  494           /* the frame has not yet been added to the parent; how about (0,0) ?*/
  495           return new Rectangle(0, 0, prefSize.width, prefSize.height);
  496         }
  497   
  498         Rectangle parentBounds = c.getBounds();
  499         Component [] components = c.getComponents();
  500   
  501   
  502         //
  503         // Iterate through valid default icon locations and return the
  504         // first one that does not intersect any other icons.
  505         //
  506   
  507         Rectangle availableRectangle = null;
  508         JInternalFrame.JDesktopIcon currentIcon = null;
  509   
  510         int x = 0;
  511         int y = parentBounds.height - prefSize.height;
  512         int w = prefSize.width;
  513         int h = prefSize.height;
  514   
  515         boolean found = false;
  516   
  517         while (!found) {
  518   
  519           availableRectangle = new Rectangle(x,y,w,h);
  520   
  521           found = true;
  522   
  523           for ( int i=0; i<components.length; i++ ) {
  524   
  525             //
  526             // Get the icon for this component
  527             //
  528   
  529             if ( components[i] instanceof JInternalFrame ) {
  530               currentIcon = ((JInternalFrame)components[i]).getDesktopIcon();
  531             }
  532             else if ( components[i] instanceof JInternalFrame.JDesktopIcon ){
  533               currentIcon = (JInternalFrame.JDesktopIcon)components[i];
  534             } else
  535               /* found a child that's neither an internal frame nor
  536                  an icon. I don't believe this should happen, but at
  537                  present it does and causes a null pointer exception.
  538                  Even when that gets fixed, this code protects against
  539                  the npe. hania */
  540               continue;
  541   
  542             //
  543             // If this icon intersects the current location, get next location.
  544             //
  545   
  546             if ( !currentIcon.equals(icon) ) {
  547               if ( availableRectangle.intersects(currentIcon.getBounds()) ) {
  548                 found = false;
  549                 break;
  550               }
  551             }
  552           }
  553   
  554           if (currentIcon == null)
  555             /* didn't find any useful children above. This probably shouldn't
  556              happen, but this check protects against an npe if it ever does
  557              (and it's happening now) */
  558             return availableRectangle;
  559   
  560           x += currentIcon.getBounds().width;
  561   
  562           if ( x + w > parentBounds.width ) {
  563             x = 0;
  564             y -= h;
  565           }
  566         }
  567   
  568         return(availableRectangle);
  569       }
  570   
  571       /**
  572        * Stores the bounds of the component just before a maximize call.
  573        * @param f the component about to be resized
  574        * @param r the normal bounds to be saved away
  575        */
  576       protected void setPreviousBounds(JInternalFrame f, Rectangle r)     {
  577           f.setNormalBounds(r);
  578       }
  579   
  580       /**
  581        * Gets the normal bounds of the component prior to the component
  582        * being maximized.
  583        * @param f the <code>JInternalFrame</code> of interest
  584        * @return the normal bounds of the component
  585        */
  586       protected Rectangle getPreviousBounds(JInternalFrame f)     {
  587           return f.getNormalBounds();
  588       }
  589   
  590       /**
  591        * Sets that the component has been iconized and the bounds of the
  592        * <code>desktopIcon</code> are valid.
  593        */
  594       protected void setWasIcon(JInternalFrame f, Boolean value)  {
  595           if (value != null) {
  596               f.putClientProperty(HAS_BEEN_ICONIFIED_PROPERTY, value);
  597           }
  598       }
  599   
  600       /**
  601        * Returns <code>true</code> if the component has been iconized
  602        * and the bounds of the <code>desktopIcon</code> are valid,
  603        * otherwise returns <code>false</code>.
  604        *
  605        * @param f the <code>JInternalFrame</code> of interest
  606        * @return <code>true</code> if the component has been iconized;
  607        *    otherwise returns <code>false</code>
  608        */
  609       protected boolean wasIcon(JInternalFrame f) {
  610           return (f.getClientProperty(HAS_BEEN_ICONIFIED_PROPERTY) == Boolean.TRUE);
  611       }
  612   
  613   
  614       JDesktopPane getDesktopPane( JComponent frame ) {
  615           JDesktopPane pane = null;
  616           Component c = frame.getParent();
  617   
  618           // Find the JDesktopPane
  619           while ( pane == null ) {
  620               if ( c instanceof JDesktopPane ) {
  621                   pane = (JDesktopPane)c;
  622               }
  623               else if ( c == null ) {
  624                   break;
  625               }
  626               else {
  627                   c = c.getParent();
  628               }
  629           }
  630   
  631           return pane;
  632       }
  633   
  634   
  635     // =========== stuff for faster frame dragging ===================
  636   
  637      private void dragFrameFaster(JComponent f, int newX, int newY) {
  638   
  639         Rectangle previousBounds = new Rectangle(currentBounds.x,
  640                                                  currentBounds.y,
  641                                                  currentBounds.width,
  642                                                  currentBounds.height);
  643   
  644      // move the frame
  645         currentBounds.x = newX;
  646         currentBounds.y = newY;
  647   
  648         if (didDrag) {
  649             // Only initiate cleanup if we have actually done a drag.
  650             emergencyCleanup(f);
  651         }
  652         else {
  653             didDrag = true;
  654             // We reset the danger field as until now we haven't actually
  655             // moved the internal frame so we don't need to initiate repaint.
  656             ((JInternalFrame)f).danger = false;
  657         }
  658   
  659         boolean floaterCollision = isFloaterCollision(previousBounds, currentBounds);
  660   
  661         JComponent parent = (JComponent)f.getParent();
  662         Rectangle visBounds = previousBounds.intersection(desktopBounds);
  663   
  664         RepaintManager currentManager = RepaintManager.currentManager(f);
  665   
  666         currentManager.beginPaint();
  667         try {
  668             if(!floaterCollision) {
  669                 currentManager.copyArea(parent, desktopGraphics, visBounds.x,
  670                                         visBounds.y,
  671                                         visBounds.width,
  672                                         visBounds.height,
  673                                         newX - previousBounds.x,
  674                                         newY - previousBounds.y,
  675                                         true);
  676             }
  677   
  678             f.setBounds(currentBounds);
  679   
  680             if(floaterCollision) {
  681                 // since we couldn't blit we just redraw as fast as possible
  682                 // the isDragging mucking is to avoid activating emergency
  683                 // cleanup
  684                 ((JInternalFrame)f).isDragging = false;
  685                 parent.paintImmediately(currentBounds);
  686                 ((JInternalFrame)f).isDragging = true;
  687             }
  688   
  689             // fake out the repaint manager.  We'll take care of everything
  690   
  691             currentManager.markCompletelyClean(parent);
  692             currentManager.markCompletelyClean(f);
  693   
  694             // compute the minimal newly exposed area
  695             // if the rects intersect then we use computeDifference.  Otherwise
  696             // we'll repaint the entire previous bounds
  697             Rectangle[] dirtyRects = null;
  698             if ( previousBounds.intersects(currentBounds) ) {
  699                 dirtyRects = SwingUtilities.computeDifference(previousBounds,
  700                                                               currentBounds);
  701             } else {
  702                 dirtyRects = new Rectangle[1];
  703                 dirtyRects[0] = previousBounds;
  704             };
  705   
  706             // Fix the damage
  707             for (int i = 0; i < dirtyRects.length; i++) {
  708                 parent.paintImmediately(dirtyRects[i]);
  709             }
  710   
  711             // new areas of blit were exposed
  712             if ( !(visBounds.equals(previousBounds)) ) {
  713                 dirtyRects = SwingUtilities.computeDifference(previousBounds,
  714                                                               desktopBounds);
  715                 for (int i = 0; i < dirtyRects.length; i++) {
  716                     dirtyRects[i].x += newX - previousBounds.x;
  717                     dirtyRects[i].y += newY - previousBounds.y;
  718                     ((JInternalFrame)f).isDragging = false;
  719   
  720                     parent.paintImmediately(dirtyRects[i]);
  721                     ((JInternalFrame)f).isDragging = true;
  722                 }
  723   
  724             }
  725         } finally {
  726             currentManager.endPaint();
  727         }
  728   
  729         // update window if it's non-opaque
  730         Window topLevel = SwingUtilities.getWindowAncestor(f);
  731         Toolkit tk = Toolkit.getDefaultToolkit();
  732         if (!topLevel.isOpaque() &&
  733             (tk instanceof SunToolkit) &&
  734             ((SunToolkit)tk).needUpdateWindow())
  735         {
  736             AWTAccessor.getWindowAccessor().updateWindow(topLevel);
  737         }
  738      }
  739   
  740      private boolean isFloaterCollision(Rectangle moveFrom, Rectangle moveTo) {
  741         if (floatingItems.length == 0) {
  742           // System.out.println("no floaters");
  743            return false;
  744         }
  745   
  746         for (int i = 0; i < floatingItems.length; i++) {
  747            boolean intersectsFrom = moveFrom.intersects(floatingItems[i]);
  748            if (intersectsFrom) {
  749               return true;
  750            }
  751            boolean intersectsTo = moveTo.intersects(floatingItems[i]);
  752            if (intersectsTo) {
  753               return true;
  754            }
  755         }
  756   
  757         return false;
  758      }
  759   
  760      private Rectangle[] findFloatingItems(JComponent f) {
  761         Container desktop = f.getParent();
  762         Component[] children = desktop.getComponents();
  763         int i = 0;
  764         for (i = 0; i < children.length; i++) {
  765            if (children[i] == f) {
  766               break;
  767            }
  768         }
  769         // System.out.println(i);
  770         Rectangle[] floaters = new Rectangle[i];
  771         for (i = 0; i < floaters.length; i++) {
  772            floaters[i] = children[i].getBounds();
  773         }
  774   
  775         return floaters;
  776      }
  777   
  778      /**
  779        * This method is here to clean up problems associated
  780        * with a race condition which can occur when the full contents
  781        * of a copyArea's source argument is not available onscreen.
  782        * This uses brute force to clean up in case of possible damage
  783        */
  784      private void emergencyCleanup(final JComponent f) {
  785   
  786           if ( ((JInternalFrame)f).danger ) {
  787   
  788              SwingUtilities.invokeLater( new Runnable(){
  789                                          public void run(){
  790   
  791                                          ((JInternalFrame)f).isDragging = false;
  792                                          f.paintImmediately(0,0,
  793                                                             f.getWidth(),
  794                                                             f.getHeight());
  795   
  796                                           //finalFrame.repaint();
  797                                           ((JInternalFrame)f).isDragging = true;
  798                                           // System.out.println("repair complete");
  799                                          }});
  800   
  801                ((JInternalFrame)f).danger = false;
  802           }
  803   
  804      }
  805   
  806   
  807   }

Home » openjdk-7 » javax » swing » [javadoc | source]