Showing the changes to java/pkg/javax/swing/DefaultDesktopManager.java (1 of 18352 files). Show all
Unified · Split
| @@ -0,0 +1,807 @@ | |||
| 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 | } | ||