From 06d5f1e07f8ba64f7fb29daf7b717e533c93dce1 Mon Sep 17 00:00:00 2001
From: Peter Zhelezniakov
Date: Wed, 4 Feb 2009 18:48:24 +0300
Subject: [PATCH 01/16] 6588003: LayoutQueue shares mutable implementation
across AppContexts
DefaultQueue property is made per-AppContext
Reviewed-by: alexp
---
.../classes/javax/swing/text/LayoutQueue.java | 31 +++++++---
.../swing/text/LayoutQueue/Test6588003.java | 59 +++++++++++++++++++
2 files changed, 81 insertions(+), 9 deletions(-)
create mode 100644 jdk/test/javax/swing/text/LayoutQueue/Test6588003.java
diff --git a/jdk/src/share/classes/javax/swing/text/LayoutQueue.java b/jdk/src/share/classes/javax/swing/text/LayoutQueue.java
index e02f9b0f9b6..dbb5d00ccce 100644
--- a/jdk/src/share/classes/javax/swing/text/LayoutQueue.java
+++ b/jdk/src/share/classes/javax/swing/text/LayoutQueue.java
@@ -25,6 +25,7 @@
package javax.swing.text;
import java.util.Vector;
+import sun.awt.AppContext;
/**
* A queue of text layout tasks.
@@ -35,10 +36,10 @@ import java.util.Vector;
*/
public class LayoutQueue {
- Vector tasks;
- Thread worker;
+ private static final Object DEFAULT_QUEUE = new Object();
- static LayoutQueue defaultQueue;
+ private Vector tasks;
+ private Thread worker;
/**
* Construct a layout queue.
@@ -51,19 +52,31 @@ public class LayoutQueue {
* Fetch the default layout queue.
*/
public static LayoutQueue getDefaultQueue() {
- if (defaultQueue == null) {
- defaultQueue = new LayoutQueue();
+ AppContext ac = AppContext.getAppContext();
+ synchronized (DEFAULT_QUEUE) {
+ LayoutQueue defaultQueue = (LayoutQueue) ac.get(DEFAULT_QUEUE);
+ if (defaultQueue == null) {
+ defaultQueue = new LayoutQueue();
+ ac.put(DEFAULT_QUEUE, defaultQueue);
+ }
+ return defaultQueue;
}
- return defaultQueue;
}
/**
* Set the default layout queue.
*
- * @param q the new queue.
+ * @param defaultQueue the new queue.
*/
- public static void setDefaultQueue(LayoutQueue q) {
- defaultQueue = q;
+ public static void setDefaultQueue(LayoutQueue defaultQueue) {
+ synchronized (DEFAULT_QUEUE) {
+ AppContext ac = AppContext.getAppContext();
+ if (defaultQueue == null) {
+ ac.remove(DEFAULT_QUEUE);
+ } else {
+ ac.put(DEFAULT_QUEUE, defaultQueue);
+ }
+ }
}
/**
diff --git a/jdk/test/javax/swing/text/LayoutQueue/Test6588003.java b/jdk/test/javax/swing/text/LayoutQueue/Test6588003.java
new file mode 100644
index 00000000000..d14d6a56a95
--- /dev/null
+++ b/jdk/test/javax/swing/text/LayoutQueue/Test6588003.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ @bug 6588003
+ @summary LayoutQueue should not share its DefaultQueue across AppContexts
+ @author Peter Zhelezniakov
+ @run main Test6588003
+*/
+
+import javax.swing.text.LayoutQueue;
+import sun.awt.SunToolkit;
+
+public class Test6588003 implements Runnable {
+ private static final LayoutQueue DEFAULT = new LayoutQueue();
+
+ public static void main(String[] args) throws InterruptedException {
+ LayoutQueue.setDefaultQueue(DEFAULT);
+
+ ThreadGroup group = new ThreadGroup("Test6588003");
+ Thread thread = new Thread(group, new Test6588003());
+ thread.start();
+ thread.join();
+
+ if (LayoutQueue.getDefaultQueue() != DEFAULT) {
+ throw new RuntimeException("Sharing detected");
+ }
+ }
+
+ public void run() {
+ SunToolkit.createNewAppContext();
+
+ if (LayoutQueue.getDefaultQueue() == DEFAULT) {
+ throw new RuntimeException("Sharing detected");
+ }
+
+ LayoutQueue.setDefaultQueue(new LayoutQueue());
+ }
+}
From 837ece487dd4c28c9d20b914695e5eae5277bb24 Mon Sep 17 00:00:00 2001
From: Sergey Malenkov
Date: Thu, 5 Feb 2009 14:48:10 +0300
Subject: [PATCH 02/16] 4769844: classes in java.beans that are serializable
but don't define serialVersionUID
Reviewed-by: peterz, rupashka
---
.../share/classes/java/beans/IndexedPropertyChangeEvent.java | 3 ++-
jdk/src/share/classes/java/beans/IntrospectionException.java | 3 ++-
jdk/src/share/classes/java/beans/PropertyChangeEvent.java | 3 ++-
jdk/src/share/classes/java/beans/PropertyVetoException.java | 4 ++--
.../classes/java/beans/beancontext/BeanContextEvent.java | 3 ++-
.../java/beans/beancontext/BeanContextMembershipEvent.java | 3 ++-
.../beans/beancontext/BeanContextServiceAvailableEvent.java | 3 ++-
.../beans/beancontext/BeanContextServiceRevokedEvent.java | 3 ++-
.../java/beans/beancontext/BeanContextServicesSupport.java | 4 +++-
jdk/src/share/classes/sun/beans/editors/ColorEditor.java | 4 +++-
jdk/src/share/classes/sun/beans/editors/FontEditor.java | 3 ++-
11 files changed, 24 insertions(+), 12 deletions(-)
diff --git a/jdk/src/share/classes/java/beans/IndexedPropertyChangeEvent.java b/jdk/src/share/classes/java/beans/IndexedPropertyChangeEvent.java
index ea78643e435..951cd871fe5 100644
--- a/jdk/src/share/classes/java/beans/IndexedPropertyChangeEvent.java
+++ b/jdk/src/share/classes/java/beans/IndexedPropertyChangeEvent.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2003 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -41,6 +41,7 @@ package java.beans;
* @author Mark Davidson
*/
public class IndexedPropertyChangeEvent extends PropertyChangeEvent {
+ private static final long serialVersionUID = -320227448495806870L;
private int index;
diff --git a/jdk/src/share/classes/java/beans/IntrospectionException.java b/jdk/src/share/classes/java/beans/IntrospectionException.java
index cac0b20fc01..2f5a65eda73 100644
--- a/jdk/src/share/classes/java/beans/IntrospectionException.java
+++ b/jdk/src/share/classes/java/beans/IntrospectionException.java
@@ -1,5 +1,5 @@
/*
- * Copyright 1996-1998 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1996-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -36,6 +36,7 @@ package java.beans;
public
class IntrospectionException extends Exception {
+ private static final long serialVersionUID = -3728150539969542619L;
/**
* Constructs an IntrospectionException with a
diff --git a/jdk/src/share/classes/java/beans/PropertyChangeEvent.java b/jdk/src/share/classes/java/beans/PropertyChangeEvent.java
index 69f523d92e3..3e0c9cef6f9 100644
--- a/jdk/src/share/classes/java/beans/PropertyChangeEvent.java
+++ b/jdk/src/share/classes/java/beans/PropertyChangeEvent.java
@@ -1,5 +1,5 @@
/*
- * Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1996-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -44,6 +44,7 @@ package java.beans;
*/
public class PropertyChangeEvent extends java.util.EventObject {
+ private static final long serialVersionUID = 7042693688939648123L;
/**
* Constructs a new PropertyChangeEvent.
diff --git a/jdk/src/share/classes/java/beans/PropertyVetoException.java b/jdk/src/share/classes/java/beans/PropertyVetoException.java
index f736b3bade5..73376496b53 100644
--- a/jdk/src/share/classes/java/beans/PropertyVetoException.java
+++ b/jdk/src/share/classes/java/beans/PropertyVetoException.java
@@ -1,5 +1,5 @@
/*
- * Copyright 1996-1998 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1996-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -33,7 +33,7 @@ package java.beans;
public
class PropertyVetoException extends Exception {
-
+ private static final long serialVersionUID = 129596057694162164L;
/**
* Constructs a PropertyVetoException with a
diff --git a/jdk/src/share/classes/java/beans/beancontext/BeanContextEvent.java b/jdk/src/share/classes/java/beans/beancontext/BeanContextEvent.java
index 4574605a154..2530869534b 100644
--- a/jdk/src/share/classes/java/beans/beancontext/BeanContextEvent.java
+++ b/jdk/src/share/classes/java/beans/beancontext/BeanContextEvent.java
@@ -1,5 +1,5 @@
/*
- * Copyright 1997-2003 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -48,6 +48,7 @@ import java.beans.beancontext.BeanContext;
*/
public abstract class BeanContextEvent extends EventObject {
+ private static final long serialVersionUID = 7267998073569045052L;
/**
* Contruct a BeanContextEvent
diff --git a/jdk/src/share/classes/java/beans/beancontext/BeanContextMembershipEvent.java b/jdk/src/share/classes/java/beans/beancontext/BeanContextMembershipEvent.java
index 7e6c1ae0a69..3752e390341 100644
--- a/jdk/src/share/classes/java/beans/beancontext/BeanContextMembershipEvent.java
+++ b/jdk/src/share/classes/java/beans/beancontext/BeanContextMembershipEvent.java
@@ -1,5 +1,5 @@
/*
- * Copyright 1997-2004 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -55,6 +55,7 @@ import java.util.Iterator;
* @see java.beans.beancontext.BeanContextMembershipListener
*/
public class BeanContextMembershipEvent extends BeanContextEvent {
+ private static final long serialVersionUID = 3499346510334590959L;
/**
* Contruct a BeanContextMembershipEvent
diff --git a/jdk/src/share/classes/java/beans/beancontext/BeanContextServiceAvailableEvent.java b/jdk/src/share/classes/java/beans/beancontext/BeanContextServiceAvailableEvent.java
index 558c7f9f363..7bb47a66033 100644
--- a/jdk/src/share/classes/java/beans/beancontext/BeanContextServiceAvailableEvent.java
+++ b/jdk/src/share/classes/java/beans/beancontext/BeanContextServiceAvailableEvent.java
@@ -1,5 +1,5 @@
/*
- * Copyright 1998-2004 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -40,6 +40,7 @@ import java.util.Iterator;
*/
public class BeanContextServiceAvailableEvent extends BeanContextEvent {
+ private static final long serialVersionUID = -5333985775656400778L;
/**
* Construct a BeanContextAvailableServiceEvent.
diff --git a/jdk/src/share/classes/java/beans/beancontext/BeanContextServiceRevokedEvent.java b/jdk/src/share/classes/java/beans/beancontext/BeanContextServiceRevokedEvent.java
index a508f4ca157..50d888cdf7e 100644
--- a/jdk/src/share/classes/java/beans/beancontext/BeanContextServiceRevokedEvent.java
+++ b/jdk/src/share/classes/java/beans/beancontext/BeanContextServiceRevokedEvent.java
@@ -1,5 +1,5 @@
/*
- * Copyright 1998-2004 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -37,6 +37,7 @@ import java.beans.beancontext.BeanContextServices;
*
*/
public class BeanContextServiceRevokedEvent extends BeanContextEvent {
+ private static final long serialVersionUID = -1295543154724961754L;
/**
* Construct a BeanContextServiceEvent.
diff --git a/jdk/src/share/classes/java/beans/beancontext/BeanContextServicesSupport.java b/jdk/src/share/classes/java/beans/beancontext/BeanContextServicesSupport.java
index d9552c8a34e..54dfdd7d227 100644
--- a/jdk/src/share/classes/java/beans/beancontext/BeanContextServicesSupport.java
+++ b/jdk/src/share/classes/java/beans/beancontext/BeanContextServicesSupport.java
@@ -1,5 +1,5 @@
/*
- * Copyright 1998-2006 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -60,6 +60,7 @@ import java.util.Locale;
public class BeanContextServicesSupport extends BeanContextSupport
implements BeanContextServices {
+ private static final long serialVersionUID = -8494482757288719206L;
/**
*
@@ -594,6 +595,7 @@ public class BeanContextServicesSupport extends BeanContextSupport
*/
protected static class BCSSServiceProvider implements Serializable {
+ private static final long serialVersionUID = 861278251667444782L;
BCSSServiceProvider(Class sc, BeanContextServiceProvider bcsp) {
super();
diff --git a/jdk/src/share/classes/sun/beans/editors/ColorEditor.java b/jdk/src/share/classes/sun/beans/editors/ColorEditor.java
index a3610e0ee2e..55dd9137be1 100644
--- a/jdk/src/share/classes/sun/beans/editors/ColorEditor.java
+++ b/jdk/src/share/classes/sun/beans/editors/ColorEditor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 1996-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1996-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -29,6 +29,8 @@ import java.awt.*;
import java.beans.*;
public class ColorEditor extends Panel implements PropertyEditor {
+ private static final long serialVersionUID = 1781257185164716054L;
+
public ColorEditor() {
setLayout(null);
diff --git a/jdk/src/share/classes/sun/beans/editors/FontEditor.java b/jdk/src/share/classes/sun/beans/editors/FontEditor.java
index 88de9aea48f..04d4c187e22 100644
--- a/jdk/src/share/classes/sun/beans/editors/FontEditor.java
+++ b/jdk/src/share/classes/sun/beans/editors/FontEditor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 1996-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1996-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -29,6 +29,7 @@ import java.awt.*;
import java.beans.*;
public class FontEditor extends Panel implements java.beans.PropertyEditor {
+ private static final long serialVersionUID = 6732704486002715933L;
public FontEditor() {
setLayout(null);
From 8f96eb9cea9b9b3886bb21a76da4aa9bcc5dc0a6 Mon Sep 17 00:00:00 2001
From: Sergey Malenkov
Date: Thu, 5 Feb 2009 17:00:57 +0300
Subject: [PATCH 03/16] 6669869: Beans.isDesignTime() and other queries should
be per-AppContext
Reviewed-by: peterz, rupashka
---
jdk/src/share/classes/java/beans/Beans.java | 96 ++++++++++---------
.../beans/Beans/6669869/TestDesignTime.java | 52 ++++++++++
.../beans/Beans/6669869/TestGuiAvailable.java | 53 ++++++++++
3 files changed, 158 insertions(+), 43 deletions(-)
create mode 100644 jdk/test/java/beans/Beans/6669869/TestDesignTime.java
create mode 100644 jdk/test/java/beans/Beans/6669869/TestGuiAvailable.java
diff --git a/jdk/src/share/classes/java/beans/Beans.java b/jdk/src/share/classes/java/beans/Beans.java
index f19b21aead2..8a750a8b15c 100644
--- a/jdk/src/share/classes/java/beans/Beans.java
+++ b/jdk/src/share/classes/java/beans/Beans.java
@@ -1,5 +1,5 @@
/*
- * Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1996-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,26 +27,41 @@ package java.beans;
import com.sun.beans.finder.ClassFinder;
-import java.applet.*;
+import java.applet.Applet;
+import java.applet.AppletContext;
+import java.applet.AppletStub;
+import java.applet.AudioClip;
-import java.awt.*;
-
-import java.beans.AppletInitializer;
+import java.awt.GraphicsEnvironment;
+import java.awt.Image;
import java.beans.beancontext.BeanContext;
-import java.io.*;
-
-import java.lang.reflect.Constructor;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectStreamClass;
+import java.io.StreamCorruptedException;
import java.net.URL;
-import java.lang.reflect.Array;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Vector;
+
+import sun.awt.AppContext;
/**
* This class provides some general purpose beans control methods.
*/
public class Beans {
+ private static final Object DESIGN_TIME = new Object();
+ private static final Object GUI_AVAILABLE = new Object();
/**
*
@@ -59,12 +74,12 @@ public class Beans {
* @param beanName the name of the bean within the class-loader.
* For example "sun.beanbox.foobah"
*
- * @exception java.lang.ClassNotFoundException if the class of a serialized
+ * @exception ClassNotFoundException if the class of a serialized
* object could not be found.
- * @exception java.io.IOException if an I/O error occurs.
+ * @exception IOException if an I/O error occurs.
*/
- public static Object instantiate(ClassLoader cls, String beanName) throws java.io.IOException, ClassNotFoundException {
+ public static Object instantiate(ClassLoader cls, String beanName) throws IOException, ClassNotFoundException {
return Beans.instantiate(cls, beanName, null, null);
}
@@ -80,12 +95,12 @@ public class Beans {
* For example "sun.beanbox.foobah"
* @param beanContext The BeanContext in which to nest the new bean
*
- * @exception java.lang.ClassNotFoundException if the class of a serialized
+ * @exception ClassNotFoundException if the class of a serialized
* object could not be found.
- * @exception java.io.IOException if an I/O error occurs.
+ * @exception IOException if an I/O error occurs.
*/
- public static Object instantiate(ClassLoader cls, String beanName, BeanContext beanContext) throws java.io.IOException, ClassNotFoundException {
+ public static Object instantiate(ClassLoader cls, String beanName, BeanContext beanContext) throws IOException, ClassNotFoundException {
return Beans.instantiate(cls, beanName, beanContext, null);
}
@@ -135,19 +150,19 @@ public class Beans {
* @param beanContext The BeanContext in which to nest the new bean
* @param initializer The AppletInitializer for the new bean
*
- * @exception java.lang.ClassNotFoundException if the class of a serialized
+ * @exception ClassNotFoundException if the class of a serialized
* object could not be found.
- * @exception java.io.IOException if an I/O error occurs.
+ * @exception IOException if an I/O error occurs.
*/
public static Object instantiate(ClassLoader cls, String beanName, BeanContext beanContext, AppletInitializer initializer)
- throws java.io.IOException, ClassNotFoundException {
+ throws IOException, ClassNotFoundException {
- java.io.InputStream ins;
- java.io.ObjectInputStream oins = null;
+ InputStream ins;
+ ObjectInputStream oins = null;
Object result = null;
boolean serialized = false;
- java.io.IOException serex = null;
+ IOException serex = null;
// If the given classloader is null, we check if an
// system classloader is available and (if so)
@@ -166,8 +181,8 @@ public class Beans {
// Try to find a serialized object with this name
final String serName = beanName.replace('.','/').concat(".ser");
final ClassLoader loader = cls;
- ins = (InputStream)java.security.AccessController.doPrivileged
- (new java.security.PrivilegedAction() {
+ ins = (InputStream)AccessController.doPrivileged
+ (new PrivilegedAction() {
public Object run() {
if (loader == null)
return ClassLoader.getSystemResourceAsStream(serName);
@@ -185,7 +200,7 @@ public class Beans {
result = oins.readObject();
serialized = true;
oins.close();
- } catch (java.io.IOException ex) {
+ } catch (IOException ex) {
ins.close();
// Drop through and try opening the class. But remember
// the exception in case we can't find the class either.
@@ -264,8 +279,8 @@ public class Beans {
final ClassLoader cloader = cls;
objectUrl = (URL)
- java.security.AccessController.doPrivileged
- (new java.security.PrivilegedAction() {
+ AccessController.doPrivileged
+ (new PrivilegedAction() {
public Object run() {
if (cloader == null)
return ClassLoader.getSystemResource
@@ -377,10 +392,11 @@ public class Beans {
* @return True if we are running in an application construction
* environment.
*
- * @see java.beans.DesignMode
+ * @see DesignMode
*/
public static boolean isDesignTime() {
- return designTime;
+ Object value = AppContext.getAppContext().get(DESIGN_TIME);
+ return (value instanceof Boolean) && (Boolean) value;
}
/**
@@ -393,11 +409,12 @@ public class Beans {
* false in a server environment or if an application is
* running as part of a batch job.
*
- * @see java.beans.Visibility
+ * @see Visibility
*
*/
public static boolean isGuiAvailable() {
- return guiAvailable;
+ Object value = AppContext.getAppContext().get(GUI_AVAILABLE);
+ return (value instanceof Boolean) ? (Boolean) value : !GraphicsEnvironment.isHeadless();
}
/**
@@ -423,7 +440,7 @@ public class Beans {
if (sm != null) {
sm.checkPropertiesAccess();
}
- designTime = isDesignTime;
+ AppContext.getAppContext().put(DESIGN_TIME, Boolean.valueOf(isDesignTime));
}
/**
@@ -449,14 +466,7 @@ public class Beans {
if (sm != null) {
sm.checkPropertiesAccess();
}
- guiAvailable = isGuiAvailable;
- }
-
-
- private static boolean designTime;
- private static boolean guiAvailable;
- static {
- guiAvailable = !GraphicsEnvironment.isHeadless();
+ AppContext.getAppContext().put(GUI_AVAILABLE, Boolean.valueOf(isGuiAvailable));
}
}
@@ -501,7 +511,7 @@ class ObjectInputStreamWithLoader extends ObjectInputStream
class BeansAppletContext implements AppletContext {
Applet target;
- java.util.Hashtable imageCache = new java.util.Hashtable();
+ Hashtable imageCache = new Hashtable();
BeansAppletContext(Applet target) {
this.target = target;
@@ -546,8 +556,8 @@ class BeansAppletContext implements AppletContext {
return null;
}
- public java.util.Enumeration getApplets() {
- java.util.Vector applets = new java.util.Vector();
+ public Enumeration getApplets() {
+ Vector applets = new Vector();
applets.addElement(target);
return applets.elements();
}
@@ -573,7 +583,7 @@ class BeansAppletContext implements AppletContext {
return null;
}
- public java.util.Iterator getStreamKeys(){
+ public Iterator getStreamKeys(){
// We do nothing.
return null;
}
diff --git a/jdk/test/java/beans/Beans/6669869/TestDesignTime.java b/jdk/test/java/beans/Beans/6669869/TestDesignTime.java
new file mode 100644
index 00000000000..e78142a2b90
--- /dev/null
+++ b/jdk/test/java/beans/Beans/6669869/TestDesignTime.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6669869
+ * @summary Tests DesignTime property in different application contexts
+ * @author Sergey Malenkov
+ */
+
+import java.beans.Beans;
+import sun.awt.SunToolkit;
+
+public class TestDesignTime implements Runnable {
+ public static void main(String[] args) throws InterruptedException {
+ if (Beans.isDesignTime()) {
+ throw new Error("unexpected DesignTime property");
+ }
+ Beans.setDesignTime(!Beans.isDesignTime());
+ ThreadGroup group = new ThreadGroup("$$$");
+ Thread thread = new Thread(group, new TestDesignTime());
+ thread.start();
+ thread.join();
+ }
+
+ public void run() {
+ SunToolkit.createNewAppContext();
+ if (Beans.isDesignTime()) {
+ throw new Error("shared DesignTime property");
+ }
+ }
+}
diff --git a/jdk/test/java/beans/Beans/6669869/TestGuiAvailable.java b/jdk/test/java/beans/Beans/6669869/TestGuiAvailable.java
new file mode 100644
index 00000000000..7144b6fad3b
--- /dev/null
+++ b/jdk/test/java/beans/Beans/6669869/TestGuiAvailable.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6669869
+ * @summary Tests GuiAvailable property in different application contexts
+ * @author Sergey Malenkov
+ */
+
+import java.awt.GraphicsEnvironment;
+import java.beans.Beans;
+import sun.awt.SunToolkit;
+
+public class TestGuiAvailable implements Runnable {
+ public static void main(String[] args) throws InterruptedException {
+ if (Beans.isGuiAvailable() == GraphicsEnvironment.isHeadless()) {
+ throw new Error("unexpected GuiAvailable property");
+ }
+ Beans.setGuiAvailable(!Beans.isGuiAvailable());
+ ThreadGroup group = new ThreadGroup("$$$");
+ Thread thread = new Thread(group, new TestGuiAvailable());
+ thread.start();
+ thread.join();
+ }
+
+ public void run() {
+ SunToolkit.createNewAppContext();
+ if (Beans.isGuiAvailable() == GraphicsEnvironment.isHeadless()) {
+ throw new Error("shared GuiAvailable property");
+ }
+ }
+}
From a21476939e4a000ab5ee85f0939c99b4afb80312 Mon Sep 17 00:00:00 2001
From: Peter Zhelezniakov
Date: Thu, 5 Feb 2009 19:16:13 +0300
Subject: [PATCH 04/16] 6801769: 6588003 should be backed out from jdk7
Reviewed-by: alexp
---
.../classes/javax/swing/text/LayoutQueue.java | 31 ++++++-------------
1 file changed, 9 insertions(+), 22 deletions(-)
diff --git a/jdk/src/share/classes/javax/swing/text/LayoutQueue.java b/jdk/src/share/classes/javax/swing/text/LayoutQueue.java
index dbb5d00ccce..e02f9b0f9b6 100644
--- a/jdk/src/share/classes/javax/swing/text/LayoutQueue.java
+++ b/jdk/src/share/classes/javax/swing/text/LayoutQueue.java
@@ -25,7 +25,6 @@
package javax.swing.text;
import java.util.Vector;
-import sun.awt.AppContext;
/**
* A queue of text layout tasks.
@@ -36,10 +35,10 @@ import sun.awt.AppContext;
*/
public class LayoutQueue {
- private static final Object DEFAULT_QUEUE = new Object();
+ Vector tasks;
+ Thread worker;
- private Vector tasks;
- private Thread worker;
+ static LayoutQueue defaultQueue;
/**
* Construct a layout queue.
@@ -52,31 +51,19 @@ public class LayoutQueue {
* Fetch the default layout queue.
*/
public static LayoutQueue getDefaultQueue() {
- AppContext ac = AppContext.getAppContext();
- synchronized (DEFAULT_QUEUE) {
- LayoutQueue defaultQueue = (LayoutQueue) ac.get(DEFAULT_QUEUE);
- if (defaultQueue == null) {
- defaultQueue = new LayoutQueue();
- ac.put(DEFAULT_QUEUE, defaultQueue);
- }
- return defaultQueue;
+ if (defaultQueue == null) {
+ defaultQueue = new LayoutQueue();
}
+ return defaultQueue;
}
/**
* Set the default layout queue.
*
- * @param defaultQueue the new queue.
+ * @param q the new queue.
*/
- public static void setDefaultQueue(LayoutQueue defaultQueue) {
- synchronized (DEFAULT_QUEUE) {
- AppContext ac = AppContext.getAppContext();
- if (defaultQueue == null) {
- ac.remove(DEFAULT_QUEUE);
- } else {
- ac.put(DEFAULT_QUEUE, defaultQueue);
- }
- }
+ public static void setDefaultQueue(LayoutQueue q) {
+ defaultQueue = q;
}
/**
From b8af3d50192f8bc98d83f8102f0fd1989f302e32 Mon Sep 17 00:00:00 2001
From: Artem Ananiev
Date: Thu, 12 Feb 2009 14:19:06 +0300
Subject: [PATCH 05/16] 6799345: JFC demos threw exception in the Java Console
when applets are closed
Reviewed-by: alexp, peterz
---
.../classes/javax/swing/SwingWorker.java | 50 +++--
.../share/classes/javax/swing/TimerQueue.java | 9 +-
.../swing/system/6799345/TestShutdown.java | 203 ++++++++++++++++++
3 files changed, 234 insertions(+), 28 deletions(-)
create mode 100644 jdk/test/javax/swing/system/6799345/TestShutdown.java
diff --git a/jdk/src/share/classes/javax/swing/SwingWorker.java b/jdk/src/share/classes/javax/swing/SwingWorker.java
index 9eca7d535f6..263284acc4e 100644
--- a/jdk/src/share/classes/javax/swing/SwingWorker.java
+++ b/jdk/src/share/classes/javax/swing/SwingWorker.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -778,35 +778,33 @@ public abstract class SwingWorker implements RunnableFuture {
threadFactory);
appContext.put(SwingWorker.class, executorService);
- //register shutdown hook for this executor service
+ // Don't use ShutdownHook here as it's not enough. We should track
+ // AppContext disposal instead of JVM shutdown, see 6799345 for details
final ExecutorService es = executorService;
- final Runnable shutdownHook =
- new Runnable() {
- final WeakReference executorServiceRef =
- new WeakReference(es);
- public void run() {
- final ExecutorService executorService =
- executorServiceRef.get();
- if (executorService != null) {
- AccessController.doPrivileged(
- new PrivilegedAction() {
- public Void run() {
- executorService.shutdown();
- return null;
+ appContext.addPropertyChangeListener(AppContext.DISPOSED_PROPERTY_NAME,
+ new PropertyChangeListener() {
+ @Override
+ public void propertyChange(PropertyChangeEvent pce) {
+ boolean disposed = (Boolean)pce.getNewValue();
+ if (disposed) {
+ final WeakReference executorServiceRef =
+ new WeakReference(es);
+ final ExecutorService executorService =
+ executorServiceRef.get();
+ if (executorService != null) {
+ AccessController.doPrivileged(
+ new PrivilegedAction() {
+ public Void run() {
+ executorService.shutdown();
+ return null;
+ }
}
- });
+ );
+ }
}
}
- };
-
- AccessController.doPrivileged(
- new PrivilegedAction() {
- public Void run() {
- Runtime.getRuntime().addShutdownHook(
- new Thread(shutdownHook));
- return null;
- }
- });
+ }
+ );
}
return executorService;
}
diff --git a/jdk/src/share/classes/javax/swing/TimerQueue.java b/jdk/src/share/classes/javax/swing/TimerQueue.java
index f68f4e99688..642bc56bac7 100644
--- a/jdk/src/share/classes/javax/swing/TimerQueue.java
+++ b/jdk/src/share/classes/javax/swing/TimerQueue.java
@@ -1,5 +1,5 @@
/*
- * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -191,7 +191,12 @@ class TimerQueue implements Runnable
} finally {
timer.getLock().unlock();
}
- } catch (InterruptedException ignore) {
+ } catch (InterruptedException ie) {
+ // Shouldn't ignore InterruptedExceptions here, so AppContext
+ // is disposed gracefully, see 6799345 for details
+ if (AppContext.getAppContext().isDisposed()) {
+ break;
+ }
}
}
}
diff --git a/jdk/test/javax/swing/system/6799345/TestShutdown.java b/jdk/test/javax/swing/system/6799345/TestShutdown.java
new file mode 100644
index 00000000000..694df3eac01
--- /dev/null
+++ b/jdk/test/javax/swing/system/6799345/TestShutdown.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ @bug 6799345
+ @summary Tests that no exceptions are thrown from TimerQueue and
+SwingWorker on AppContext shutdown
+ @author art
+ @run main TestShutdown
+*/
+
+import java.awt.*;
+import java.awt.event.*;
+
+import java.util.*;
+
+import javax.swing.*;
+
+import sun.awt.*;
+
+public class TestShutdown
+{
+ private static AppContext targetAppContext;
+
+ private static JFrame f;
+ private static JTextField tf;
+
+ private static volatile boolean exceptionsOccurred = false;
+ private static volatile boolean appcontextInitDone = false;
+
+ private static int timerValue = 0;
+
+ public static void main(String[] args)
+ throws Exception
+ {
+ ThreadGroup tg = new TestThreadGroup("TTG");
+ Thread t = new Thread(tg, new TestRunnable(), "InitThread");
+ t.start();
+
+ while (!appcontextInitDone)
+ {
+ Thread.sleep(500);
+ }
+
+ targetAppContext.dispose();
+
+ if (exceptionsOccurred)
+ {
+ throw new RuntimeException("Test FAILED: some exceptions occurred");
+ }
+ }
+
+ static void initGUI()
+ {
+ f = new JFrame("F");
+ f.setBounds(100, 100, 200, 100);
+ tf = new JTextField("Test");
+ f.add(tf);
+ f.setVisible(true);
+ }
+
+ static void startGUI()
+ {
+ // caret blink Timer
+ tf.requestFocusInWindow();
+
+ // misc Timer
+ ActionListener al = new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent ae)
+ {
+ System.out.println("Timer tick: " + timerValue++);
+ }
+ };
+ new javax.swing.Timer(30, al).start();
+ }
+
+ static class TestThreadGroup extends ThreadGroup
+ {
+ public TestThreadGroup(String name)
+ {
+ super(name);
+ }
+
+ @Override
+ public synchronized void uncaughtException(Thread thread, Throwable t)
+ {
+ if (t instanceof ThreadDeath)
+ {
+ // this one is expected, rethrow
+ throw (ThreadDeath)t;
+ }
+ System.err.println("Test FAILED: an exception is caught in the " +
+ "target thread group on thread " + thread.getName());
+ t.printStackTrace(System.err);
+ exceptionsOccurred = true;
+ }
+ }
+
+ static class TestRunnable implements Runnable
+ {
+ @Override
+ public void run()
+ {
+ SunToolkit stk = (SunToolkit)Toolkit.getDefaultToolkit();
+ targetAppContext = stk.createNewAppContext();
+
+ // create and show frame and text field
+ SwingUtilities.invokeLater(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ initGUI();
+ }
+ });
+ stk.realSync();
+
+ // start some Timers
+ SwingUtilities.invokeLater(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ startGUI();
+ }
+ });
+ stk.realSync();
+
+ // start multiple SwingWorkers
+ while (!Thread.interrupted())
+ {
+ try
+ {
+ new TestSwingWorker().execute();
+ Thread.sleep(40);
+ }
+ catch (Exception e)
+ {
+ // exception here is expected, skip
+ break;
+ }
+ }
+ }
+ }
+
+ static class TestSwingWorker extends SwingWorker
+ {
+ @Override
+ public String doInBackground()
+ {
+ Random r = new Random();
+ for (int i = 0; i < 10; i++)
+ {
+ try
+ {
+ int delay = r.nextInt() % 50;
+ Thread.sleep(delay);
+ publish(delay);
+ }
+ catch (Exception z)
+ {
+ break;
+ }
+ }
+ if (!appcontextInitDone)
+ {
+ appcontextInitDone = true;
+ }
+ return "Done";
+ }
+
+ @Override
+ public void process(java.util.List chunks)
+ {
+ for (Integer i : chunks)
+ {
+ System.err.println("Processed: " + i);
+ }
+ }
+ }
+}
From 07338e17b5b23fc0d5df60d6ef839a5facd1fae3 Mon Sep 17 00:00:00 2001
From: Peter Zhelezniakov
Date: Tue, 24 Feb 2009 19:17:51 +0300
Subject: [PATCH 06/16] 6804221: Three tests for JTabbedPane produce VM crash
on rhel3
Reviewed-by: stayer, campbell
---
jdk/src/solaris/native/sun/awt/gtk2_interface.c | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/jdk/src/solaris/native/sun/awt/gtk2_interface.c b/jdk/src/solaris/native/sun/awt/gtk2_interface.c
index cfbc5ef6f6e..1afeeef173b 100644
--- a/jdk/src/solaris/native/sun/awt/gtk2_interface.c
+++ b/jdk/src/solaris/native/sun/awt/gtk2_interface.c
@@ -93,6 +93,7 @@ static int gtk2_pixbuf_height = 0;
/* Static buffer for conversion from java.lang.String to UTF-8 */
static char convertionBuffer[CONV_BUFFER_SIZE];
+static gboolean new_combo = TRUE;
const char ENV_PREFIX[] = "GTK_MODULES=";
/*******************/
@@ -608,6 +609,7 @@ gboolean gtk2_load()
dlsym(gtk2_libhandle, "gtk_combo_box_entry_new");
if (fp_gtk_combo_box_entry_new == NULL) {
fp_gtk_combo_box_entry_new = dl_symbol("gtk_combo_new");
+ new_combo = FALSE;
}
fp_gtk_separator_tool_item_new =
@@ -1423,17 +1425,13 @@ static GtkWidget *gtk2_get_widget(WidgetType widget_type)
*/
GtkWidget *combo = (*fp_gtk_combo_box_entry_new)();
- if (widget_type == COMBO_BOX_TEXT_FIELD)
- (*fp_gtk_container_add)((GtkContainer *)combo, result);
- else
- {
+ if (new_combo && widget_type == COMBO_BOX_ARROW_BUTTON) {
(*fp_gtk_widget_set_parent)(result, combo);
((GtkBin*)combo)->child = result;
+ } else {
+ (*fp_gtk_container_add)((GtkContainer *)combo, result);
}
-
(*fp_gtk_container_add)((GtkContainer *)gtk2_fixed, combo);
- (*fp_gtk_widget_realize)(result);
- return result;
}
else if (widget_type != TOOL_TIP &&
widget_type != INTERNAL_FRAME &&
From 95a3c4a81f7e58041681cfc6da30f9a016bf6b92 Mon Sep 17 00:00:00 2001
From: Pavel Porvatov
Date: Thu, 26 Feb 2009 11:44:43 +0300
Subject: [PATCH 07/16] 6794831: Infinite loop while painting ticks on Slider
with maximum=MAX_INT
Reviewed-by: malenkov
---
.../javax/swing/plaf/basic/BasicSliderUI.java | 66 +++++++----
.../swing/JSlider/6794831/bug6794831.java | 105 ++++++++++++++++++
2 files changed, 148 insertions(+), 23 deletions(-)
create mode 100644 jdk/test/javax/swing/JSlider/6794831/bug6794831.java
diff --git a/jdk/src/share/classes/javax/swing/plaf/basic/BasicSliderUI.java b/jdk/src/share/classes/javax/swing/plaf/basic/BasicSliderUI.java
index 864ad13264a..0a858d41c18 100644
--- a/jdk/src/share/classes/javax/swing/plaf/basic/BasicSliderUI.java
+++ b/jdk/src/share/classes/javax/swing/plaf/basic/BasicSliderUI.java
@@ -1004,47 +1004,62 @@ public class BasicSliderUI extends SliderUI{
g.setColor(DefaultLookup.getColor(slider, this, "Slider.tickColor", Color.black));
if ( slider.getOrientation() == JSlider.HORIZONTAL ) {
- g.translate( 0, tickBounds.y);
+ g.translate(0, tickBounds.y);
- int value = slider.getMinimum();
- int xPos;
+ if (slider.getMinorTickSpacing() > 0) {
+ int value = slider.getMinimum();
- if ( slider.getMinorTickSpacing() > 0 ) {
while ( value <= slider.getMaximum() ) {
- xPos = xPositionForValue( value );
+ int xPos = xPositionForValue(value);
paintMinorTickForHorizSlider( g, tickBounds, xPos );
+
+ // Overflow checking
+ if (Integer.MAX_VALUE - slider.getMinorTickSpacing() < value) {
+ break;
+ }
+
value += slider.getMinorTickSpacing();
}
}
- if ( slider.getMajorTickSpacing() > 0 ) {
- value = slider.getMinimum();
+ if (slider.getMajorTickSpacing() > 0) {
+ int value = slider.getMinimum();
while ( value <= slider.getMaximum() ) {
- xPos = xPositionForValue( value );
+ int xPos = xPositionForValue(value);
paintMajorTickForHorizSlider( g, tickBounds, xPos );
+
+ // Overflow checking
+ if (Integer.MAX_VALUE - slider.getMajorTickSpacing() < value) {
+ break;
+ }
+
value += slider.getMajorTickSpacing();
}
}
g.translate( 0, -tickBounds.y);
- }
- else {
- g.translate(tickBounds.x, 0);
+ } else {
+ g.translate(tickBounds.x, 0);
- int value = slider.getMinimum();
- int yPos;
-
- if ( slider.getMinorTickSpacing() > 0 ) {
+ if (slider.getMinorTickSpacing() > 0) {
int offset = 0;
if(!BasicGraphicsUtils.isLeftToRight(slider)) {
offset = tickBounds.width - tickBounds.width / 2;
g.translate(offset, 0);
}
- while ( value <= slider.getMaximum() ) {
- yPos = yPositionForValue( value );
+ int value = slider.getMinimum();
+
+ while (value <= slider.getMaximum()) {
+ int yPos = yPositionForValue(value);
paintMinorTickForVertSlider( g, tickBounds, yPos );
+
+ // Overflow checking
+ if (Integer.MAX_VALUE - slider.getMinorTickSpacing() < value) {
+ break;
+ }
+
value += slider.getMinorTickSpacing();
}
@@ -1053,15 +1068,22 @@ public class BasicSliderUI extends SliderUI{
}
}
- if ( slider.getMajorTickSpacing() > 0 ) {
- value = slider.getMinimum();
+ if (slider.getMajorTickSpacing() > 0) {
if(!BasicGraphicsUtils.isLeftToRight(slider)) {
g.translate(2, 0);
}
- while ( value <= slider.getMaximum() ) {
- yPos = yPositionForValue( value );
+ int value = slider.getMinimum();
+
+ while (value <= slider.getMaximum()) {
+ int yPos = yPositionForValue(value);
paintMajorTickForVertSlider( g, tickBounds, yPos );
+
+ // Overflow checking
+ if (Integer.MAX_VALUE - slider.getMajorTickSpacing() < value) {
+ break;
+ }
+
value += slider.getMajorTickSpacing();
}
@@ -1775,8 +1797,6 @@ public class BasicSliderUI extends SliderUI{
thumbMiddle = thumbLeft + halfThumbWidth;
slider.setValue(valueForXPosition(thumbMiddle));
break;
- default:
- return;
}
}
diff --git a/jdk/test/javax/swing/JSlider/6794831/bug6794831.java b/jdk/test/javax/swing/JSlider/6794831/bug6794831.java
new file mode 100644
index 00000000000..a147987d417
--- /dev/null
+++ b/jdk/test/javax/swing/JSlider/6794831/bug6794831.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 6794831
+ * @summary Infinite loop while painting ticks on Slider with maximum=MAX_INT
+ * @author Pavel Porvatov
+ @run main bug6794831
+ */
+
+import javax.swing.*;
+import javax.swing.plaf.basic.BasicSliderUI;
+import java.awt.image.BufferedImage;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class bug6794831 {
+ private final CountDownLatch countDownLatch = new CountDownLatch(1);
+
+ public static void main(String args[]) throws InterruptedException {
+ new bug6794831().run();
+ }
+
+ private void run() throws InterruptedException {
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ for (UIManager.LookAndFeelInfo lookAndFeelInfo : UIManager.getInstalledLookAndFeels()) {
+ try {
+ UIManager.setLookAndFeel(lookAndFeelInfo.getClassName());
+ } catch (Exception e) {
+ fail(e.getMessage());
+ }
+
+ BufferedImage image = new BufferedImage(300, 200, BufferedImage.TYPE_INT_ARGB);
+
+ // Test 1
+ JSlider slider = new JSlider(0, Integer.MAX_VALUE - 1, 0);
+
+ slider.setMajorTickSpacing((Integer.MAX_VALUE - 1) / 4);
+ slider.setPaintTicks(true);
+
+ ((BasicSliderUI) slider.getUI()).paintTicks(image.getGraphics());
+
+ // Test 2
+ slider = new JSlider(0, Integer.MAX_VALUE - 1, 0);
+
+ slider.setMinorTickSpacing((Integer.MAX_VALUE - 1) / 4);
+ slider.setPaintTicks(true);
+
+ ((BasicSliderUI) slider.getUI()).paintTicks(image.getGraphics());
+
+ // Test 3
+ slider = new JSlider(0, Integer.MAX_VALUE - 1, 0);
+
+ slider.setOrientation(JSlider.VERTICAL);
+ slider.setMajorTickSpacing((Integer.MAX_VALUE - 1) / 4);
+ slider.setPaintTicks(true);
+
+ ((BasicSliderUI) slider.getUI()).paintTicks(image.getGraphics());
+
+ // Test 4
+ slider = new JSlider(0, Integer.MAX_VALUE - 1, 0);
+
+ slider.setOrientation(JSlider.VERTICAL);
+ slider.setMinorTickSpacing((Integer.MAX_VALUE - 1) / 4);
+ slider.setPaintTicks(true);
+
+ ((BasicSliderUI) slider.getUI()).paintTicks(image.getGraphics());
+
+ countDownLatch.countDown();
+ }
+ }
+ });
+
+ if (countDownLatch.await(3000, TimeUnit.MILLISECONDS)) {
+ System.out.println("bug6794831 passed");
+ } else {
+ fail("bug6794831 failed");
+ }
+ }
+
+ private static void fail(String msg) {
+ throw new RuntimeException(msg);
+ }
+}
From 93c4a7033c7ad17a7a3d225f465fcd2c50dc5782 Mon Sep 17 00:00:00 2001
From: Pavel Porvatov
Date: Thu, 12 Mar 2009 14:00:26 +0300
Subject: [PATCH 08/16] 6491795: COM should be initialized for Shell API calls
in ShellFolder2.cpp
Reviewed-by: peterz, loneid
---
.../swing/plaf/basic/BasicDirectoryModel.java | 173 ++---
.../classes/sun/awt/shell/ShellFolder.java | 30 +
.../sun/awt/shell/ShellFolderManager.java | 17 +-
jdk/src/share/classes/sun/swing/FilePane.java | 11 +
.../sun/awt/shell/Win32ShellFolder2.java | 650 +++++++++++-------
.../awt/shell/Win32ShellFolderManager2.java | 101 +++
.../native/sun/windows/ShellFolder2.cpp | 153 ++---
.../JFileChooser/6570445/bug6570445.java | 20 +
8 files changed, 712 insertions(+), 443 deletions(-)
create mode 100644 jdk/test/javax/swing/JFileChooser/6570445/bug6570445.java
diff --git a/jdk/src/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java b/jdk/src/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java
index 8cff0a3e7cb..b823553b627 100644
--- a/jdk/src/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java
+++ b/jdk/src/share/classes/javax/swing/plaf/basic/BasicDirectoryModel.java
@@ -27,6 +27,7 @@ package javax.swing.plaf.basic;
import java.io.File;
import java.util.*;
+import java.util.concurrent.Callable;
import javax.swing.*;
import javax.swing.filechooser.*;
import javax.swing.event.*;
@@ -223,113 +224,115 @@ public class BasicDirectoryModel extends AbstractListModel implements PropertyCh
this.fid = fid;
}
- private void invokeLater(DoChangeContents runnable) {
- runnables.addElement(runnable);
- SwingUtilities.invokeLater(runnable);
- }
-
public void run() {
run0();
setBusy(false, fid);
}
public void run0() {
- FileSystemView fileSystem = filechooser.getFileSystemView();
+ DoChangeContents doChangeContents = ShellFolder.getInvoker().invoke(new Callable() {
+ public DoChangeContents call() throws Exception {
+ FileSystemView fileSystem = filechooser.getFileSystemView();
- File[] list = fileSystem.getFiles(currentDirectory, filechooser.isFileHidingEnabled());
+ File[] list = fileSystem.getFiles(currentDirectory, filechooser.isFileHidingEnabled());
- Vector acceptsList = new Vector();
+ Vector acceptsList = new Vector();
- if (isInterrupted()) {
- return;
- }
+ if (isInterrupted()) {
+ return null;
+ }
- // run through the file list, add directories and selectable files to fileCache
- for (File file : list) {
- if (filechooser.accept(file)) {
- acceptsList.addElement(file);
- }
- }
+ // run through the file list, add directories and selectable files to fileCache
+ for (File file : list) {
+ if (filechooser.accept(file)) {
+ acceptsList.addElement(file);
+ }
+ }
- if (isInterrupted()) {
- return;
- }
+ if (isInterrupted()) {
+ return null;
+ }
- // First sort alphabetically by filename
- sort(acceptsList);
+ // First sort alphabetically by filename
+ sort(acceptsList);
- Vector newDirectories = new Vector(50);
- Vector newFiles = new Vector();
- // run through list grabbing directories in chunks of ten
- for(int i = 0; i < acceptsList.size(); i++) {
- File f = acceptsList.elementAt(i);
- boolean isTraversable = filechooser.isTraversable(f);
- if (isTraversable) {
- newDirectories.addElement(f);
- } else if (!isTraversable && filechooser.isFileSelectionEnabled()) {
- newFiles.addElement(f);
- }
- if(isInterrupted()) {
- return;
- }
- }
+ Vector newDirectories = new Vector(50);
+ Vector newFiles = new Vector();
+ // run through list grabbing directories in chunks of ten
+ for (int i = 0; i < acceptsList.size(); i++) {
+ File f = acceptsList.elementAt(i);
+ boolean isTraversable = filechooser.isTraversable(f);
+ if (isTraversable) {
+ newDirectories.addElement(f);
+ } else if (!isTraversable && filechooser.isFileSelectionEnabled()) {
+ newFiles.addElement(f);
+ }
+ if (isInterrupted()) {
+ return null;
+ }
+ }
- Vector newFileCache = new Vector(newDirectories);
- newFileCache.addAll(newFiles);
+ Vector newFileCache = new Vector(newDirectories);
+ newFileCache.addAll(newFiles);
- int newSize = newFileCache.size();
- int oldSize = fileCache.size();
+ int newSize = newFileCache.size();
+ int oldSize = fileCache.size();
- if (newSize > oldSize) {
- //see if interval is added
- int start = oldSize;
- int end = newSize;
- for (int i = 0; i < oldSize; i++) {
- if (!newFileCache.get(i).equals(fileCache.get(i))) {
- start = i;
- for (int j = i; j < newSize; j++) {
- if (newFileCache.get(j).equals(fileCache.get(i))) {
- end = j;
+ if (newSize > oldSize) {
+ //see if interval is added
+ int start = oldSize;
+ int end = newSize;
+ for (int i = 0; i < oldSize; i++) {
+ if (!newFileCache.get(i).equals(fileCache.get(i))) {
+ start = i;
+ for (int j = i; j < newSize; j++) {
+ if (newFileCache.get(j).equals(fileCache.get(i))) {
+ end = j;
+ break;
+ }
+ }
break;
}
}
- break;
+ if (start >= 0 && end > start
+ && newFileCache.subList(end, newSize).equals(fileCache.subList(start, oldSize))) {
+ if (isInterrupted()) {
+ return null;
+ }
+ return new DoChangeContents(newFileCache.subList(start, end), start, null, 0, fid);
+ }
+ } else if (newSize < oldSize) {
+ //see if interval is removed
+ int start = -1;
+ int end = -1;
+ for (int i = 0; i < newSize; i++) {
+ if (!newFileCache.get(i).equals(fileCache.get(i))) {
+ start = i;
+ end = i + oldSize - newSize;
+ break;
+ }
+ }
+ if (start >= 0 && end > start
+ && fileCache.subList(end, oldSize).equals(newFileCache.subList(start, newSize))) {
+ if (isInterrupted()) {
+ return null;
+ }
+ return new DoChangeContents(null, 0, new Vector(fileCache.subList(start, end)), start, fid);
+ }
}
- }
- if (start >= 0 && end > start
- && newFileCache.subList(end, newSize).equals(fileCache.subList(start, oldSize))) {
- if(isInterrupted()) {
- return;
+ if (!fileCache.equals(newFileCache)) {
+ if (isInterrupted()) {
+ cancelRunnables(runnables);
+ }
+ return new DoChangeContents(newFileCache, 0, fileCache, 0, fid);
}
- invokeLater(new DoChangeContents(newFileCache.subList(start, end), start, null, 0, fid));
- newFileCache = null;
+ return null;
}
- } else if (newSize < oldSize) {
- //see if interval is removed
- int start = -1;
- int end = -1;
- for (int i = 0; i < newSize; i++) {
- if (!newFileCache.get(i).equals(fileCache.get(i))) {
- start = i;
- end = i + oldSize - newSize;
- break;
- }
- }
- if (start >= 0 && end > start
- && fileCache.subList(end, oldSize).equals(newFileCache.subList(start, newSize))) {
- if(isInterrupted()) {
- return;
- }
- invokeLater(new DoChangeContents(null, 0, new Vector(fileCache.subList(start, end)),
- start, fid));
- newFileCache = null;
- }
- }
- if (newFileCache != null && !fileCache.equals(newFileCache)) {
- if (isInterrupted()) {
- cancelRunnables(runnables);
- }
- invokeLater(new DoChangeContents(newFileCache, 0, fileCache, 0, fid));
+ });
+
+ if (doChangeContents != null) {
+ runnables.addElement(doChangeContents);
+ SwingUtilities.invokeLater(doChangeContents);
}
}
diff --git a/jdk/src/share/classes/sun/awt/shell/ShellFolder.java b/jdk/src/share/classes/sun/awt/shell/ShellFolder.java
index 16c1b12cb80..0e75ac183dc 100644
--- a/jdk/src/share/classes/sun/awt/shell/ShellFolder.java
+++ b/jdk/src/share/classes/sun/awt/shell/ShellFolder.java
@@ -31,6 +31,7 @@ import java.awt.Toolkit;
import java.io.*;
import java.io.FileNotFoundException;
import java.util.*;
+import java.util.concurrent.Callable;
/**
* @author Michael Martak
@@ -461,6 +462,35 @@ public abstract class ShellFolder extends File {
return null;
}
+ private static Invoker invoker;
+
+ /**
+ * Provides the single access point to the {@link Invoker}. It is guaranteed that the value
+ * returned by this method will be always the same.
+ *
+ * @return the singleton instance of {@link Invoker}
+ */
+ public static Invoker getInvoker() {
+ if (invoker == null) {
+ invoker = shellFolderManager.createInvoker();
+ }
+ return invoker;
+ }
+
+ /**
+ * Interface allowing to invoke tasks in different environments on different platforms.
+ */
+ public static interface Invoker {
+ /**
+ * Invokes a callable task. If the {@code task} throws a checked exception,
+ * it will be wrapped into a {@link RuntimeException}
+ *
+ * @param task a task to invoke
+ * @return the result of {@code task}'s invokation
+ */
+ T invoke(Callable task);
+ }
+
/**
* Provides a default comparator for the default column set
*/
diff --git a/jdk/src/share/classes/sun/awt/shell/ShellFolderManager.java b/jdk/src/share/classes/sun/awt/shell/ShellFolderManager.java
index 8fb15bf0cf8..dc8901f7bc5 100644
--- a/jdk/src/share/classes/sun/awt/shell/ShellFolderManager.java
+++ b/jdk/src/share/classes/sun/awt/shell/ShellFolderManager.java
@@ -27,6 +27,7 @@ package sun.awt.shell;
import java.io.File;
import java.io.FileNotFoundException;
+import java.util.concurrent.Callable;
/**
* @author Michael Martak
@@ -96,9 +97,23 @@ class ShellFolderManager {
}
public boolean isFileSystemRoot(File dir) {
- if (dir instanceof ShellFolder && !((ShellFolder)dir).isFileSystem()) {
+ if (dir instanceof ShellFolder && !((ShellFolder) dir).isFileSystem()) {
return false;
}
return (dir.getParentFile() == null);
}
+
+ protected ShellFolder.Invoker createInvoker() {
+ return new DirectInvoker();
+ }
+
+ private static class DirectInvoker implements ShellFolder.Invoker {
+ public T invoke(Callable task) {
+ try {
+ return task.call();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
}
diff --git a/jdk/src/share/classes/sun/swing/FilePane.java b/jdk/src/share/classes/sun/swing/FilePane.java
index de5ad7c4831..71112b319d8 100644
--- a/jdk/src/share/classes/sun/swing/FilePane.java
+++ b/jdk/src/share/classes/sun/swing/FilePane.java
@@ -34,6 +34,7 @@ import java.text.DateFormat;
import java.text.MessageFormat;
import java.util.*;
import java.util.List;
+import java.util.concurrent.Callable;
import javax.swing.*;
import javax.swing.border.*;
@@ -900,6 +901,16 @@ public class FilePane extends JPanel implements PropertyChangeListener {
}
}
+ @Override
+ public void sort() {
+ ShellFolder.getInvoker().invoke(new Callable() {
+ public Void call() throws Exception {
+ DetailsTableRowSorter.super.sort();
+ return null;
+ }
+ });
+ }
+
public void modelStructureChanged() {
super.modelStructureChanged();
updateComparators(detailsTableModel.getColumns());
diff --git a/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolder2.java b/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolder2.java
index 418dc8f59db..bc81b80e793 100644
--- a/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolder2.java
+++ b/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolder2.java
@@ -32,6 +32,7 @@ import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.*;
+import java.util.concurrent.*;
import javax.swing.SwingConstants;
// NOTE: This class supersedes Win32ShellFolder, which was removed from
@@ -184,15 +185,20 @@ final class Win32ShellFolder2 extends ShellFolder {
boolean disposed;
public void dispose() {
if (disposed) return;
- if (relativePIDL != 0) {
- releasePIDL(relativePIDL);
- }
- if (absolutePIDL != 0) {
- releasePIDL(absolutePIDL);
- }
- if (pIShellFolder != 0) {
- releaseIShellFolder(pIShellFolder);
- }
+ ShellFolder.getInvoker().invoke(new Callable() {
+ public Void call() throws Exception {
+ if (relativePIDL != 0) {
+ releasePIDL(relativePIDL);
+ }
+ if (absolutePIDL != 0) {
+ releasePIDL(absolutePIDL);
+ }
+ if (pIShellFolder != 0) {
+ releaseIShellFolder(pIShellFolder);
+ }
+ return null;
+ }
+ });
disposed = true;
}
}
@@ -218,50 +224,59 @@ final class Win32ShellFolder2 extends ShellFolder {
*/
private boolean isPersonal;
+ private static String composePathForCsidl(int csidl) throws IOException {
+ String path = getFileSystemPath(csidl);
+ return path == null
+ ? ("ShellFolder: 0x" + Integer.toHexString(csidl))
+ : path;
+ }
/**
* Create a system special shell folder, such as the
* desktop or Network Neighborhood.
*/
- Win32ShellFolder2(int csidl) throws IOException {
+ Win32ShellFolder2(final int csidl) throws IOException {
// Desktop is parent of DRIVES and NETWORK, not necessarily
// other special shell folders.
- super(null,
- (getFileSystemPath(csidl) == null)
- ? ("ShellFolder: 0x"+Integer.toHexString(csidl)) : getFileSystemPath(csidl));
- if (csidl == DESKTOP) {
- initDesktop();
- } else {
- initSpecial(getDesktop().getIShellFolder(), csidl);
- // At this point, the native method initSpecial() has set our relativePIDL
- // relative to the Desktop, which may not be our immediate parent. We need
- // to traverse this ID list and break it into a chain of shell folders from
- // the top, with each one having an immediate parent and a relativePIDL
- // relative to that parent.
- long pIDL = disposer.relativePIDL;
- parent = getDesktop();
- while (pIDL != 0) {
- // Get a child pidl relative to 'parent'
- long childPIDL = copyFirstPIDLEntry(pIDL);
- if (childPIDL != 0) {
- // Get a handle to the the rest of the ID list
- // i,e, parent's grandchilren and down
- pIDL = getNextPIDLEntry(pIDL);
- if (pIDL != 0) {
- // Now we know that parent isn't immediate to 'this' because it
- // has a continued ID list. Create a shell folder for this child
- // pidl and make it the new 'parent'.
- parent = new Win32ShellFolder2((Win32ShellFolder2)parent, childPIDL);
- } else {
- // No grandchildren means we have arrived at the parent of 'this',
- // and childPIDL is directly relative to parent.
- disposer.relativePIDL = childPIDL;
- }
+ super(null, composePathForCsidl(csidl));
+ ShellFolder.getInvoker().invoke(new Callable() {
+ public Void call() throws Exception {
+ if (csidl == DESKTOP) {
+ initDesktop();
} else {
- break;
+ initSpecial(getDesktop().getIShellFolder(), csidl);
+ // At this point, the native method initSpecial() has set our relativePIDL
+ // relative to the Desktop, which may not be our immediate parent. We need
+ // to traverse this ID list and break it into a chain of shell folders from
+ // the top, with each one having an immediate parent and a relativePIDL
+ // relative to that parent.
+ long pIDL = disposer.relativePIDL;
+ parent = getDesktop();
+ while (pIDL != 0) {
+ // Get a child pidl relative to 'parent'
+ long childPIDL = copyFirstPIDLEntry(pIDL);
+ if (childPIDL != 0) {
+ // Get a handle to the the rest of the ID list
+ // i,e, parent's grandchilren and down
+ pIDL = getNextPIDLEntry(pIDL);
+ if (pIDL != 0) {
+ // Now we know that parent isn't immediate to 'this' because it
+ // has a continued ID list. Create a shell folder for this child
+ // pidl and make it the new 'parent'.
+ parent = new Win32ShellFolder2((Win32ShellFolder2) parent, childPIDL);
+ } else {
+ // No grandchildren means we have arrived at the parent of 'this',
+ // and childPIDL is directly relative to parent.
+ disposer.relativePIDL = childPIDL;
+ }
+ } else {
+ break;
+ }
+ }
}
+ return null;
}
- }
+ });
sun.java2d.Disposer.addRecord(this, disposer);
}
@@ -281,17 +296,26 @@ final class Win32ShellFolder2 extends ShellFolder {
/**
* Creates a shell folder with a parent and relative PIDL
*/
- Win32ShellFolder2(Win32ShellFolder2 parent, long relativePIDL) {
- super(parent, getFileSystemPath(parent.getIShellFolder(), relativePIDL));
+ Win32ShellFolder2(final Win32ShellFolder2 parent, final long relativePIDL) {
+ super(parent,
+ ShellFolder.getInvoker().invoke(new Callable() {
+ public String call() throws Exception {
+ return getFileSystemPath(parent.getIShellFolder(), relativePIDL);
+ }
+ })
+ );
this.disposer.relativePIDL = relativePIDL;
getAbsolutePath();
sun.java2d.Disposer.addRecord(this, disposer);
}
// Initializes the desktop shell folder
+ // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
private native void initDesktop();
+
// Initializes a special, non-file system shell folder
// from one of the above constants
+ // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
private native void initSpecial(long desktopIShellFolder, int csidl);
/** Marks this folder as being the My Documents (Personal) folder */
@@ -311,26 +335,30 @@ final class Win32ShellFolder2 extends ShellFolder {
* drive (normally "C:\").
*/
protected Object writeReplace() throws java.io.ObjectStreamException {
- if (isFileSystem()) {
- return new File(getPath());
- } else {
- Win32ShellFolder2 drives = Win32ShellFolderManager2.getDrives();
- if (drives != null) {
- File[] driveRoots = drives.listFiles();
- if (driveRoots != null) {
- for (int i = 0; i < driveRoots.length; i++) {
- if (driveRoots[i] instanceof Win32ShellFolder2) {
- Win32ShellFolder2 sf = (Win32ShellFolder2)driveRoots[i];
- if (sf.isFileSystem() && !sf.hasAttribute(ATTRIB_REMOVABLE)) {
- return new File(sf.getPath());
+ return ShellFolder.getInvoker().invoke(new Callable() {
+ public File call() throws Exception {
+ if (isFileSystem()) {
+ return new File(getPath());
+ } else {
+ Win32ShellFolder2 drives = Win32ShellFolderManager2.getDrives();
+ if (drives != null) {
+ File[] driveRoots = drives.listFiles();
+ if (driveRoots != null) {
+ for (int i = 0; i < driveRoots.length; i++) {
+ if (driveRoots[i] instanceof Win32ShellFolder2) {
+ Win32ShellFolder2 sf = (Win32ShellFolder2) driveRoots[i];
+ if (sf.isFileSystem() && !sf.hasAttribute(ATTRIB_REMOVABLE)) {
+ return new File(sf.getPath());
+ }
+ }
}
}
}
+ // Ouch, we have no hard drives. Return something "valid" anyway.
+ return new File("C:\\");
}
}
- // Ouch, we have no hard drives. Return something "valid" anyway.
- return new File("C:\\");
- }
+ });
}
@@ -364,6 +392,7 @@ final class Win32ShellFolder2 extends ShellFolder {
static native void releasePIDL(long pIDL);
// Release an IShellFolder object
+ // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
private static native void releaseIShellFolder(long pIShellFolder);
/**
@@ -371,18 +400,28 @@ final class Win32ShellFolder2 extends ShellFolder {
*/
public long getIShellFolder() {
if (disposer.pIShellFolder == 0) {
- assert(isDirectory());
- assert(parent != null);
- long parentIShellFolder = getParentIShellFolder();
- if (parentIShellFolder == 0) {
- throw new InternalError("Parent IShellFolder was null for " + getAbsolutePath());
- }
- // We are a directory with a parent and a relative PIDL.
- // We want to bind to the parent so we get an IShellFolder instance associated with us.
- disposer.pIShellFolder = bindToObject(parentIShellFolder, disposer.relativePIDL);
- if (disposer.pIShellFolder == 0) {
- throw new InternalError("Unable to bind " + getAbsolutePath() + " to parent");
- }
+ disposer.pIShellFolder =
+ ShellFolder.getInvoker().invoke(new Callable() {
+ public Long call() throws Exception {
+ assert(isDirectory());
+ assert(parent != null);
+ long parentIShellFolder = getParentIShellFolder();
+ if (parentIShellFolder == 0) {
+ throw new InternalError("Parent IShellFolder was null for "
+ + getAbsolutePath());
+ }
+ // We are a directory with a parent and a relative PIDL.
+ // We want to bind to the parent so we get an
+ // IShellFolder instance associated with us.
+ long pIShellFolder = bindToObject(parentIShellFolder,
+ disposer.relativePIDL);
+ if (pIShellFolder == 0) {
+ throw new InternalError("Unable to bind "
+ + getAbsolutePath() + " to parent");
+ }
+ return pIShellFolder;
+ }
+ });
}
return disposer.pIShellFolder;
}
@@ -472,24 +511,42 @@ final class Win32ShellFolder2 extends ShellFolder {
return false;
}
- private static boolean pidlsEqual(long pIShellFolder, long pidl1, long pidl2) {
- return (compareIDs(pIShellFolder, pidl1, pidl2) == 0);
+ private static boolean pidlsEqual(final long pIShellFolder, final long pidl1, final long pidl2) {
+ return ShellFolder.getInvoker().invoke(new Callable() {
+ public Boolean call() throws Exception {
+ return (compareIDs(pIShellFolder, pidl1, pidl2) == 0);
+ }
+ });
}
+
+ // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
private static native int compareIDs(long pParentIShellFolder, long pidl1, long pidl2);
+ private Boolean cachedIsFileSystem;
+
/**
* @return Whether this is a file system shell folder
*/
- public boolean isFileSystem() {
- return hasAttribute(ATTRIB_FILESYSTEM);
+ public synchronized boolean isFileSystem() {
+ if (cachedIsFileSystem == null) {
+ cachedIsFileSystem = hasAttribute(ATTRIB_FILESYSTEM);
+ }
+
+ return cachedIsFileSystem;
}
/**
* Return whether the given attribute flag is set for this object
*/
- public boolean hasAttribute(int attribute) {
- // Caching at this point doesn't seem to be cost efficient
- return (getAttributes0(getParentIShellFolder(), getRelativePIDL(), attribute) & attribute) != 0;
+ public boolean hasAttribute(final int attribute) {
+ return ShellFolder.getInvoker().invoke(new Callable() {
+ public Boolean call() throws Exception {
+ // Caching at this point doesn't seem to be cost efficient
+ return (getAttributes0(getParentIShellFolder(),
+ getRelativePIDL(), attribute)
+ & attribute) != 0;
+ }
+ });
}
/**
@@ -498,26 +555,42 @@ final class Win32ShellFolder2 extends ShellFolder {
* Could plausibly be used for attribute caching but have to be
* very careful not to touch network drives and file system roots
* with a full attrsMask
+ * NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
*/
+
private static native int getAttributes0(long pParentIShellFolder, long pIDL, int attrsMask);
// Return the path to the underlying file system object
- private static String getFileSystemPath(long parentIShellFolder, long relativePIDL) {
- int linkedFolder = ATTRIB_LINK | ATTRIB_FOLDER;
- if (parentIShellFolder == Win32ShellFolderManager2.getNetwork().getIShellFolder() &&
- getAttributes0(parentIShellFolder, relativePIDL, linkedFolder) == linkedFolder) {
+ private static String getFileSystemPath(final long parentIShellFolder, final long relativePIDL) {
+ return ShellFolder.getInvoker().invoke(new Callable() {
+ public String call() throws Exception {
+ int linkedFolder = ATTRIB_LINK | ATTRIB_FOLDER;
+ if (parentIShellFolder == Win32ShellFolderManager2.getNetwork().getIShellFolder() &&
+ getAttributes0(parentIShellFolder, relativePIDL, linkedFolder) == linkedFolder) {
- String s =
- getFileSystemPath(Win32ShellFolderManager2.getDesktop().getIShellFolder(),
- getLinkLocation(parentIShellFolder, relativePIDL, false));
- if (s != null && s.startsWith("\\\\")) {
- return s;
+ String s =
+ getFileSystemPath(Win32ShellFolderManager2.getDesktop().getIShellFolder(),
+ getLinkLocation(parentIShellFolder, relativePIDL, false));
+ if (s != null && s.startsWith("\\\\")) {
+ return s;
+ }
+ }
+ return getDisplayNameOf(parentIShellFolder, relativePIDL, SHGDN_FORPARSING);
}
- }
- return getDisplayNameOf(parentIShellFolder, relativePIDL, SHGDN_NORMAL | SHGDN_FORPARSING);
+ });
}
+
// Needs to be accessible to Win32ShellFolderManager2
- static native String getFileSystemPath(int csidl) throws IOException;
+ static String getFileSystemPath(final int csidl) throws IOException {
+ return ShellFolder.getInvoker().invoke(new Callable() {
+ public String call() throws Exception {
+ return getFileSystemPath0(csidl);
+ }
+ });
+ }
+
+ // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
+ private static native String getFileSystemPath0(int csidl) throws IOException;
// Return whether the path is a network root.
// Path is assumed to be non-null
@@ -557,24 +630,33 @@ final class Win32ShellFolder2 extends ShellFolder {
*/
// Returns an IEnumIDList interface for an IShellFolder. The value
// returned must be released using releaseEnumObjects().
- private long getEnumObjects(long pIShellFolder, boolean includeHiddenFiles) {
- boolean isDesktop = (disposer.pIShellFolder == getDesktopIShellFolder());
- return getEnumObjects(disposer.pIShellFolder, isDesktop, includeHiddenFiles);
+ private long getEnumObjects(long pIShellFolder, final boolean includeHiddenFiles) {
+ final boolean isDesktop = (disposer.pIShellFolder == getDesktopIShellFolder());
+ return ShellFolder.getInvoker().invoke(new Callable() {
+ public Long call() throws Exception {
+ return getEnumObjects(disposer.pIShellFolder, isDesktop, includeHiddenFiles);
+ }
+ });
}
+
// Returns an IEnumIDList interface for an IShellFolder. The value
// returned must be released using releaseEnumObjects().
+ // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
private native long getEnumObjects(long pIShellFolder, boolean isDesktop,
boolean includeHiddenFiles);
// Returns the next sequential child as a relative PIDL
// from an IEnumIDList interface. The value returned must
// be released using releasePIDL().
+ // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
private native long getNextChild(long pEnumObjects);
// Releases the IEnumIDList interface
+ // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
private native void releaseEnumObjects(long pEnumObjects);
// Returns the IShellFolder of a child from a parent IShellFolder
// and a relative PIDL. The value returned must be released
// using releaseIShellFolder().
+ // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
private static native long bindToObject(long parentIShellFolder, long pIDL);
/**
@@ -582,60 +664,64 @@ final class Win32ShellFolder2 extends ShellFolder {
* object. The array will be empty if the folder is empty. Returns
* null if this shellfolder does not denote a directory.
*/
- public File[] listFiles(boolean includeHiddenFiles) {
+ public File[] listFiles(final boolean includeHiddenFiles) {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkRead(getPath());
}
- if (!isDirectory()) {
- return null;
- }
- // Links to directories are not directories and cannot be parents.
- // This does not apply to folders in My Network Places (NetHood)
- // because they are both links and real directories!
- if (isLink() && !hasAttribute(ATTRIB_FOLDER)) {
- return new File[0];
- }
- Win32ShellFolder2 desktop = Win32ShellFolderManager2.getDesktop();
- Win32ShellFolder2 personal = Win32ShellFolderManager2.getPersonal();
-
- // If we are a directory, we have a parent and (at least) a
- // relative PIDL. We must first ensure we are bound to the
- // parent so we have an IShellFolder to query.
- long pIShellFolder = getIShellFolder();
- // Now we can enumerate the objects in this folder.
- ArrayList list = new ArrayList();
- long pEnumObjects = getEnumObjects(pIShellFolder, includeHiddenFiles);
- if (pEnumObjects != 0) {
- long childPIDL;
- int testedAttrs = ATTRIB_FILESYSTEM | ATTRIB_FILESYSANCESTOR;
- do {
- if (Thread.currentThread().isInterrupted()) {
+ return ShellFolder.getInvoker().invoke(new Callable() {
+ public File[] call() throws Exception {
+ if (!isDirectory()) {
+ return null;
+ }
+ // Links to directories are not directories and cannot be parents.
+ // This does not apply to folders in My Network Places (NetHood)
+ // because they are both links and real directories!
+ if (isLink() && !hasAttribute(ATTRIB_FOLDER)) {
return new File[0];
}
- childPIDL = getNextChild(pEnumObjects);
- boolean releasePIDL = true;
- if (childPIDL != 0 &&
- (getAttributes0(pIShellFolder, childPIDL, testedAttrs) & testedAttrs) != 0) {
- Win32ShellFolder2 childFolder = null;
- if (this.equals(desktop)
- && personal != null
- && pidlsEqual(pIShellFolder, childPIDL, personal.disposer.relativePIDL)) {
- childFolder = personal;
- } else {
- childFolder = new Win32ShellFolder2(this, childPIDL);
- releasePIDL = false;
- }
- list.add(childFolder);
+
+ Win32ShellFolder2 desktop = Win32ShellFolderManager2.getDesktop();
+ Win32ShellFolder2 personal = Win32ShellFolderManager2.getPersonal();
+
+ // If we are a directory, we have a parent and (at least) a
+ // relative PIDL. We must first ensure we are bound to the
+ // parent so we have an IShellFolder to query.
+ long pIShellFolder = getIShellFolder();
+ // Now we can enumerate the objects in this folder.
+ ArrayList list = new ArrayList();
+ long pEnumObjects = getEnumObjects(pIShellFolder, includeHiddenFiles);
+ if (pEnumObjects != 0) {
+ long childPIDL;
+ int testedAttrs = ATTRIB_FILESYSTEM | ATTRIB_FILESYSANCESTOR;
+ do {
+ childPIDL = getNextChild(pEnumObjects);
+ boolean releasePIDL = true;
+ if (childPIDL != 0 &&
+ (getAttributes0(pIShellFolder, childPIDL, testedAttrs) & testedAttrs) != 0) {
+ Win32ShellFolder2 childFolder;
+ if (Win32ShellFolder2.this.equals(desktop)
+ && personal != null
+ && pidlsEqual(pIShellFolder, childPIDL, personal.disposer.relativePIDL)) {
+ childFolder = personal;
+ } else {
+ childFolder = new Win32ShellFolder2(Win32ShellFolder2.this, childPIDL);
+ releasePIDL = false;
+ }
+ list.add(childFolder);
+ }
+ if (releasePIDL) {
+ releasePIDL(childPIDL);
+ }
+ } while (childPIDL != 0 && !Thread.currentThread().isInterrupted());
+ releaseEnumObjects(pEnumObjects);
}
- if (releasePIDL) {
- releasePIDL(childPIDL);
- }
- } while (childPIDL != 0);
- releaseEnumObjects(pEnumObjects);
- }
- return list.toArray(new ShellFolder[list.size()]);
+ return Thread.currentThread().isInterrupted()
+ ? new File[0]
+ : list.toArray(new ShellFolder[list.size()]);
+ }
+ });
}
@@ -644,33 +730,43 @@ final class Win32ShellFolder2 extends ShellFolder {
*
* @return The child shellfolder, or null if not found.
*/
- Win32ShellFolder2 getChildByPath(String filePath) {
- long pIShellFolder = getIShellFolder();
- long pEnumObjects = getEnumObjects(pIShellFolder, true);
- Win32ShellFolder2 child = null;
- long childPIDL;
+ Win32ShellFolder2 getChildByPath(final String filePath) {
+ return ShellFolder.getInvoker().invoke(new Callable() {
+ public Win32ShellFolder2 call() throws Exception {
+ long pIShellFolder = getIShellFolder();
+ long pEnumObjects = getEnumObjects(pIShellFolder, true);
+ Win32ShellFolder2 child = null;
+ long childPIDL = 0;
- while ((childPIDL = getNextChild(pEnumObjects)) != 0) {
- if (getAttributes0(pIShellFolder, childPIDL, ATTRIB_FILESYSTEM) != 0) {
- String path = getFileSystemPath(pIShellFolder, childPIDL);
- if (path != null && path.equalsIgnoreCase(filePath)) {
- long childIShellFolder = bindToObject(pIShellFolder, childPIDL);
- child = new Win32ShellFolder2(this, childIShellFolder, childPIDL, path);
- break;
+ while ((childPIDL = getNextChild(pEnumObjects)) != 0) {
+ if (getAttributes0(pIShellFolder, childPIDL, ATTRIB_FILESYSTEM) != 0) {
+ String path = getFileSystemPath(pIShellFolder, childPIDL);
+ if (path != null && path.equalsIgnoreCase(filePath)) {
+ long childIShellFolder = bindToObject(pIShellFolder, childPIDL);
+ child = new Win32ShellFolder2(Win32ShellFolder2.this,
+ childIShellFolder, childPIDL, path);
+ break;
+ }
+ }
+ releasePIDL(childPIDL);
}
+ releaseEnumObjects(pEnumObjects);
+ return child;
}
- releasePIDL(childPIDL);
- }
- releaseEnumObjects(pEnumObjects);
- return child;
+ });
}
+ private Boolean cachedIsLink;
/**
* @return Whether this shell folder is a link
*/
- public boolean isLink() {
- return hasAttribute(ATTRIB_LINK);
+ public synchronized boolean isLink() {
+ if (cachedIsLink == null) {
+ cachedIsLink = hasAttribute(ATTRIB_LINK);
+ }
+
+ return cachedIsLink;
}
/**
@@ -682,6 +778,7 @@ final class Win32ShellFolder2 extends ShellFolder {
// Return the link location of a shell folder
+ // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
private static native long getLinkLocation(long parentIShellFolder,
long relativePIDL, boolean resolve);
@@ -693,38 +790,52 @@ final class Win32ShellFolder2 extends ShellFolder {
return getLinkLocation(true);
}
- private ShellFolder getLinkLocation(boolean resolve) {
- if (!isLink()) {
- return null;
- }
+ private ShellFolder getLinkLocation(final boolean resolve) {
+ return ShellFolder.getInvoker().invoke(new Callable() {
+ public ShellFolder call() throws Exception {
+ if (!isLink()) {
+ return null;
+ }
- ShellFolder location = null;
- long linkLocationPIDL = getLinkLocation(getParentIShellFolder(),
- getRelativePIDL(), resolve);
- if (linkLocationPIDL != 0) {
- try {
- location =
- Win32ShellFolderManager2.createShellFolderFromRelativePIDL(getDesktop(),
- linkLocationPIDL);
- } catch (InternalError e) {
- // Could be a link to a non-bindable object, such as a network connection
- // TODO: getIShellFolder() should throw FileNotFoundException instead
+ ShellFolder location = null;
+ long linkLocationPIDL = getLinkLocation(getParentIShellFolder(),
+ getRelativePIDL(), resolve);
+ if (linkLocationPIDL != 0) {
+ try {
+ location =
+ Win32ShellFolderManager2.createShellFolderFromRelativePIDL(getDesktop(),
+ linkLocationPIDL);
+ } catch (InternalError e) {
+ // Could be a link to a non-bindable object, such as a network connection
+ // TODO: getIShellFolder() should throw FileNotFoundException instead
+ }
+ }
+ return location;
}
- }
- return location;
+ });
}
// Parse a display name into a PIDL relative to the current IShellFolder.
- long parseDisplayName(String name) throws FileNotFoundException {
+ long parseDisplayName(final String name) throws FileNotFoundException {
try {
- return parseDisplayName0(getIShellFolder(), name);
- } catch (IOException e) {
- throw new FileNotFoundException("Could not find file " + name);
+ return ShellFolder.getInvoker().invoke(new Callable() {
+ public Long call() throws Exception {
+ return parseDisplayName0(getIShellFolder(), name);
+ }
+ });
+ } catch (RuntimeException e) {
+ if (e.getCause() instanceof IOException) {
+ throw new FileNotFoundException("Could not find file " + name);
+ }
+ throw e;
}
}
+
+ // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
private static native long parseDisplayName0(long pIShellFolder, String name) throws IOException;
// Return the display name of a shell folder
+ // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
private static native String getDisplayNameOf(long parentIShellFolder,
long relativePIDL,
int attrs);
@@ -734,12 +845,19 @@ final class Win32ShellFolder2 extends ShellFolder {
*/
public String getDisplayName() {
if (displayName == null) {
- displayName = getDisplayNameOf(getParentIShellFolder(), getRelativePIDL(), SHGDN_NORMAL);
+ displayName =
+ ShellFolder.getInvoker().invoke(new Callable() {
+ public String call() throws Exception {
+ return getDisplayNameOf(getParentIShellFolder(),
+ getRelativePIDL(), SHGDN_NORMAL);
+ }
+ });
}
return displayName;
}
// Return the folder type of a shell folder
+ // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
private static native String getFolderType(long pIDL);
/**
@@ -747,7 +865,13 @@ final class Win32ShellFolder2 extends ShellFolder {
*/
public String getFolderType() {
if (folderType == null) {
- folderType = getFolderType(getAbsolutePIDL());
+ final long absolutePIDL = getAbsolutePIDL();
+ folderType =
+ ShellFolder.getInvoker().invoke(new Callable() {
+ public String call() throws Exception {
+ return getFolderType(absolutePIDL);
+ }
+ });
}
return folderType;
}
@@ -774,11 +898,16 @@ final class Win32ShellFolder2 extends ShellFolder {
private static Map smallLinkedSystemImages = new HashMap();
private static Map largeLinkedSystemImages = new HashMap();
+ // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
private static native long getIShellIcon(long pIShellFolder);
+
+ // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
private static native int getIconIndex(long parentIShellIcon, long relativePIDL);
// Return the icon of a file system shell folder in the form of an HICON
private static native long getIcon(String absolutePath, boolean getLargeIcon);
+
+ // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
private static native long extractIcon(long parentIShellFolder, long relativePIDL,
boolean getLargeIcon);
@@ -799,7 +928,12 @@ final class Win32ShellFolder2 extends ShellFolder {
private long getIShellIcon() {
if (pIShellIcon == -1L) {
- pIShellIcon = getIShellIcon(getIShellFolder());
+ pIShellIcon =
+ ShellFolder.getInvoker().invoke(new Callable() {
+ public Long call() throws Exception {
+ return getIShellIcon(getIShellFolder());
+ }
+ });
}
return pIShellIcon;
}
@@ -850,50 +984,60 @@ final class Win32ShellFolder2 extends ShellFolder {
/**
* @return The icon image used to display this shell folder
*/
- public Image getIcon(boolean getLargeIcon) {
+ public Image getIcon(final boolean getLargeIcon) {
Image icon = getLargeIcon ? largeIcon : smallIcon;
if (icon == null) {
- long parentIShellIcon = (parent != null) ? ((Win32ShellFolder2)parent).getIShellIcon() : 0L;
- long relativePIDL = getRelativePIDL();
+ icon =
+ ShellFolder.getInvoker().invoke(new Callable() {
+ public Image call() throws Exception {
+ Image newIcon = null;
+ if (isFileSystem()) {
+ long parentIShellIcon = (parent != null)
+ ? ((Win32ShellFolder2) parent).getIShellIcon()
+ : 0L;
+ long relativePIDL = getRelativePIDL();
- if (isFileSystem()) {
- // These are cached per type (using the index in the system image list)
- int index = getIconIndex(parentIShellIcon, relativePIDL);
- if (index > 0) {
- Map imageCache;
- if (isLink()) {
- imageCache = getLargeIcon ? largeLinkedSystemImages : smallLinkedSystemImages;
- } else {
- imageCache = getLargeIcon ? largeSystemImages : smallSystemImages;
- }
- icon = (Image)imageCache.get(Integer.valueOf(index));
- if (icon == null) {
- long hIcon = getIcon(getAbsolutePath(), getLargeIcon);
- icon = makeIcon(hIcon, getLargeIcon);
- disposeIcon(hIcon);
- if (icon != null) {
- imageCache.put(Integer.valueOf(index), icon);
+ // These are cached per type (using the index in the system image list)
+ int index = getIconIndex(parentIShellIcon, relativePIDL);
+ if (index > 0) {
+ Map imageCache;
+ if (isLink()) {
+ imageCache = getLargeIcon ? largeLinkedSystemImages : smallLinkedSystemImages;
+ } else {
+ imageCache = getLargeIcon ? largeSystemImages : smallSystemImages;
+ }
+ newIcon = (Image) imageCache.get(Integer.valueOf(index));
+ if (newIcon == null) {
+ long hIcon = getIcon(getAbsolutePath(), getLargeIcon);
+ newIcon = makeIcon(hIcon, getLargeIcon);
+ disposeIcon(hIcon);
+ if (newIcon != null) {
+ imageCache.put(Integer.valueOf(index), newIcon);
+ }
+ }
+ }
}
+
+ if (newIcon == null) {
+ // These are only cached per object
+ long hIcon = extractIcon(getParentIShellFolder(),
+ getRelativePIDL(), getLargeIcon);
+ newIcon = makeIcon(hIcon, getLargeIcon);
+ disposeIcon(hIcon);
+ }
+
+ if (newIcon == null) {
+ newIcon = Win32ShellFolder2.super.getIcon(getLargeIcon);
+ }
+ return newIcon;
}
- }
- }
-
- if (icon == null) {
- // These are only cached per object
- long hIcon = extractIcon(getParentIShellFolder(), getRelativePIDL(), getLargeIcon);
- icon = makeIcon(hIcon, getLargeIcon);
- disposeIcon(hIcon);
- }
-
+ });
if (getLargeIcon) {
largeIcon = icon;
} else {
smallIcon = icon;
}
}
- if (icon == null) {
- icon = super.getIcon(getLargeIcon);
- }
return icon;
}
@@ -969,39 +1113,50 @@ final class Win32ShellFolder2 extends ShellFolder {
private static final int LVCFMT_CENTER = 2;
public ShellFolderColumnInfo[] getFolderColumns() {
- ShellFolderColumnInfo[] columns = doGetColumnInfo(getIShellFolder());
+ return ShellFolder.getInvoker().invoke(new Callable() {
+ public ShellFolderColumnInfo[] call() throws Exception {
+ ShellFolderColumnInfo[] columns = doGetColumnInfo(getIShellFolder());
- if (columns != null) {
- List notNullColumns =
- new ArrayList();
- for (int i = 0; i < columns.length; i++) {
- ShellFolderColumnInfo column = columns[i];
- if (column != null) {
- column.setAlignment(column.getAlignment() == LVCFMT_RIGHT
- ? SwingConstants.RIGHT
- : column.getAlignment() == LVCFMT_CENTER
- ? SwingConstants.CENTER
- : SwingConstants.LEADING);
+ if (columns != null) {
+ List notNullColumns =
+ new ArrayList();
+ for (int i = 0; i < columns.length; i++) {
+ ShellFolderColumnInfo column = columns[i];
+ if (column != null) {
+ column.setAlignment(column.getAlignment() == LVCFMT_RIGHT
+ ? SwingConstants.RIGHT
+ : column.getAlignment() == LVCFMT_CENTER
+ ? SwingConstants.CENTER
+ : SwingConstants.LEADING);
- column.setComparator(new ColumnComparator(getIShellFolder(), i));
+ column.setComparator(new ColumnComparator(getIShellFolder(), i));
- notNullColumns.add(column);
+ notNullColumns.add(column);
+ }
+ }
+ columns = new ShellFolderColumnInfo[notNullColumns.size()];
+ notNullColumns.toArray(columns);
}
+ return columns;
}
- columns = new ShellFolderColumnInfo[notNullColumns.size()];
- notNullColumns.toArray(columns);
- }
- return columns;
+ });
}
- public Object getFolderColumnValue(int column) {
- return doGetColumnValue(getParentIShellFolder(), getRelativePIDL(), column);
+ public Object getFolderColumnValue(final int column) {
+ return ShellFolder.getInvoker().invoke(new Callable