History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/javax/swing/DefaultDesktopManager.java (1 of 18352 files). Show all

Unified · Split

java/pkg/javax/swing/DefaultDesktopManager.java+807−0
@@ -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+}