0N/A/*
2362N/A * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage sun.awt.shell;
0N/A
0N/Aimport java.awt.Image;
0N/Aimport java.awt.Toolkit;
0N/Aimport java.awt.image.BufferedImage;
0N/Aimport java.io.File;
0N/Aimport java.io.IOException;
0N/Aimport java.util.*;
1083N/Aimport java.util.concurrent.*;
0N/Aimport javax.swing.SwingConstants;
0N/A
0N/A// NOTE: This class supersedes Win32ShellFolder, which was removed from
0N/A// distribution after version 1.4.2.
0N/A
0N/A/**
0N/A * Win32 Shell Folders
0N/A * <P>
0N/A * <BR>
0N/A * There are two fundamental types of shell folders : file system folders
0N/A * and non-file system folders. File system folders are relatively easy
0N/A * to deal with. Non-file system folders are items such as My Computer,
0N/A * Network Neighborhood, and the desktop. Some of these non-file system
0N/A * folders have special values and properties.
0N/A * <P>
0N/A * <BR>
0N/A * Win32 keeps two basic data structures for shell folders. The first
0N/A * of these is called an ITEMIDLIST. Usually a pointer, called an
0N/A * LPITEMIDLIST, or more frequently just "PIDL". This structure holds
0N/A * a series of identifiers and can be either relative to the desktop
0N/A * (an absolute PIDL), or relative to the shell folder that contains them.
0N/A * Some Win32 functions can take absolute or relative PIDL values, and
0N/A * others can only accept relative values.
0N/A * <BR>
0N/A * The second data structure is an IShellFolder COM interface. Using
0N/A * this interface, one can enumerate the relative PIDLs in a shell
0N/A * folder, get attributes, etc.
0N/A * <BR>
0N/A * All Win32ShellFolder2 objects which are folder types (even non-file
0N/A * system folders) contain an IShellFolder object. Files are named in
0N/A * directories via relative PIDLs.
0N/A *
0N/A * @author Michael Martak
0N/A * @author Leif Samuelsson
0N/A * @author Kenneth Russell
0N/A * @since 1.4 */
0N/A
0N/Afinal class Win32ShellFolder2 extends ShellFolder {
0N/A
0N/A private static native void initIDs();
0N/A
0N/A static {
0N/A initIDs();
0N/A }
0N/A
0N/A // Win32 Shell Folder Constants
0N/A public static final int DESKTOP = 0x0000;
0N/A public static final int INTERNET = 0x0001;
0N/A public static final int PROGRAMS = 0x0002;
0N/A public static final int CONTROLS = 0x0003;
0N/A public static final int PRINTERS = 0x0004;
0N/A public static final int PERSONAL = 0x0005;
0N/A public static final int FAVORITES = 0x0006;
0N/A public static final int STARTUP = 0x0007;
0N/A public static final int RECENT = 0x0008;
0N/A public static final int SENDTO = 0x0009;
0N/A public static final int BITBUCKET = 0x000a;
0N/A public static final int STARTMENU = 0x000b;
0N/A public static final int DESKTOPDIRECTORY = 0x0010;
0N/A public static final int DRIVES = 0x0011;
0N/A public static final int NETWORK = 0x0012;
0N/A public static final int NETHOOD = 0x0013;
0N/A public static final int FONTS = 0x0014;
0N/A public static final int TEMPLATES = 0x0015;
0N/A public static final int COMMON_STARTMENU = 0x0016;
0N/A public static final int COMMON_PROGRAMS = 0X0017;
0N/A public static final int COMMON_STARTUP = 0x0018;
0N/A public static final int COMMON_DESKTOPDIRECTORY = 0x0019;
0N/A public static final int APPDATA = 0x001a;
0N/A public static final int PRINTHOOD = 0x001b;
0N/A public static final int ALTSTARTUP = 0x001d;
0N/A public static final int COMMON_ALTSTARTUP = 0x001e;
0N/A public static final int COMMON_FAVORITES = 0x001f;
0N/A public static final int INTERNET_CACHE = 0x0020;
0N/A public static final int COOKIES = 0x0021;
0N/A public static final int HISTORY = 0x0022;
0N/A
0N/A // Win32 shell folder attributes
0N/A public static final int ATTRIB_CANCOPY = 0x00000001;
0N/A public static final int ATTRIB_CANMOVE = 0x00000002;
0N/A public static final int ATTRIB_CANLINK = 0x00000004;
0N/A public static final int ATTRIB_CANRENAME = 0x00000010;
0N/A public static final int ATTRIB_CANDELETE = 0x00000020;
0N/A public static final int ATTRIB_HASPROPSHEET = 0x00000040;
0N/A public static final int ATTRIB_DROPTARGET = 0x00000100;
0N/A public static final int ATTRIB_LINK = 0x00010000;
0N/A public static final int ATTRIB_SHARE = 0x00020000;
0N/A public static final int ATTRIB_READONLY = 0x00040000;
0N/A public static final int ATTRIB_GHOSTED = 0x00080000;
0N/A public static final int ATTRIB_HIDDEN = 0x00080000;
0N/A public static final int ATTRIB_FILESYSANCESTOR = 0x10000000;
0N/A public static final int ATTRIB_FOLDER = 0x20000000;
0N/A public static final int ATTRIB_FILESYSTEM = 0x40000000;
0N/A public static final int ATTRIB_HASSUBFOLDER = 0x80000000;
0N/A public static final int ATTRIB_VALIDATE = 0x01000000;
0N/A public static final int ATTRIB_REMOVABLE = 0x02000000;
0N/A public static final int ATTRIB_COMPRESSED = 0x04000000;
0N/A public static final int ATTRIB_BROWSABLE = 0x08000000;
0N/A public static final int ATTRIB_NONENUMERATED = 0x00100000;
0N/A public static final int ATTRIB_NEWCONTENT = 0x00200000;
0N/A
0N/A // IShellFolder::GetDisplayNameOf constants
0N/A public static final int SHGDN_NORMAL = 0;
0N/A public static final int SHGDN_INFOLDER = 1;
0N/A public static final int SHGDN_INCLUDE_NONFILESYS= 0x2000;
0N/A public static final int SHGDN_FORADDRESSBAR = 0x4000;
0N/A public static final int SHGDN_FORPARSING = 0x8000;
0N/A
0N/A // Values for system call LoadIcon()
0N/A public enum SystemIcon {
0N/A IDI_APPLICATION(32512),
0N/A IDI_HAND(32513),
0N/A IDI_ERROR(32513),
0N/A IDI_QUESTION(32514),
0N/A IDI_EXCLAMATION(32515),
0N/A IDI_WARNING(32515),
0N/A IDI_ASTERISK(32516),
0N/A IDI_INFORMATION(32516),
0N/A IDI_WINLOGO(32517);
0N/A
0N/A private final int iconID;
0N/A
0N/A SystemIcon(int iconID) {
0N/A this.iconID = iconID;
0N/A }
0N/A
0N/A public int getIconID() {
0N/A return iconID;
0N/A }
0N/A }
0N/A
0N/A static class FolderDisposer implements sun.java2d.DisposerRecord {
0N/A /*
0N/A * This is cached as a concession to getFolderType(), which needs
0N/A * an absolute PIDL.
0N/A */
0N/A long absolutePIDL;
0N/A /*
0N/A * We keep track of shell folders through the IShellFolder
0N/A * interface of their parents plus their relative PIDL.
0N/A */
0N/A long pIShellFolder;
0N/A long relativePIDL;
0N/A
0N/A boolean disposed;
0N/A public void dispose() {
0N/A if (disposed) return;
1453N/A invoke(new Callable<Void>() {
1453N/A public Void call() {
1083N/A if (relativePIDL != 0) {
1083N/A releasePIDL(relativePIDL);
1083N/A }
1083N/A if (absolutePIDL != 0) {
1083N/A releasePIDL(absolutePIDL);
1083N/A }
1083N/A if (pIShellFolder != 0) {
1083N/A releaseIShellFolder(pIShellFolder);
1083N/A }
1083N/A return null;
1083N/A }
1083N/A });
0N/A disposed = true;
0N/A }
0N/A }
0N/A FolderDisposer disposer = new FolderDisposer();
0N/A private void setIShellFolder(long pIShellFolder) {
0N/A disposer.pIShellFolder = pIShellFolder;
0N/A }
0N/A private void setRelativePIDL(long relativePIDL) {
0N/A disposer.relativePIDL = relativePIDL;
0N/A }
0N/A /*
0N/A * The following are for caching various shell folder properties.
0N/A */
0N/A private long pIShellIcon = -1L;
0N/A private String folderType = null;
0N/A private String displayName = null;
0N/A private Image smallIcon = null;
0N/A private Image largeIcon = null;
0N/A private Boolean isDir = null;
0N/A
0N/A /*
0N/A * The following is to identify the My Documents folder as being special
0N/A */
0N/A private boolean isPersonal;
0N/A
1453N/A private static String composePathForCsidl(int csidl) throws IOException, InterruptedException {
1083N/A String path = getFileSystemPath(csidl);
1083N/A return path == null
1083N/A ? ("ShellFolder: 0x" + Integer.toHexString(csidl))
1083N/A : path;
1083N/A }
0N/A
0N/A /**
0N/A * Create a system special shell folder, such as the
0N/A * desktop or Network Neighborhood.
0N/A */
1453N/A Win32ShellFolder2(final int csidl) throws IOException, InterruptedException {
0N/A // Desktop is parent of DRIVES and NETWORK, not necessarily
0N/A // other special shell folders.
1083N/A super(null, composePathForCsidl(csidl));
1453N/A
1453N/A invoke(new Callable<Void>() {
1453N/A public Void call() throws InterruptedException {
1083N/A if (csidl == DESKTOP) {
1083N/A initDesktop();
1083N/A } else {
1083N/A initSpecial(getDesktop().getIShellFolder(), csidl);
1083N/A // At this point, the native method initSpecial() has set our relativePIDL
1083N/A // relative to the Desktop, which may not be our immediate parent. We need
1083N/A // to traverse this ID list and break it into a chain of shell folders from
1083N/A // the top, with each one having an immediate parent and a relativePIDL
1083N/A // relative to that parent.
1083N/A long pIDL = disposer.relativePIDL;
1083N/A parent = getDesktop();
1083N/A while (pIDL != 0) {
1083N/A // Get a child pidl relative to 'parent'
1083N/A long childPIDL = copyFirstPIDLEntry(pIDL);
1083N/A if (childPIDL != 0) {
1083N/A // Get a handle to the the rest of the ID list
1083N/A // i,e, parent's grandchilren and down
1083N/A pIDL = getNextPIDLEntry(pIDL);
1083N/A if (pIDL != 0) {
1083N/A // Now we know that parent isn't immediate to 'this' because it
1083N/A // has a continued ID list. Create a shell folder for this child
1083N/A // pidl and make it the new 'parent'.
1083N/A parent = new Win32ShellFolder2((Win32ShellFolder2) parent, childPIDL);
1083N/A } else {
1083N/A // No grandchildren means we have arrived at the parent of 'this',
1083N/A // and childPIDL is directly relative to parent.
1083N/A disposer.relativePIDL = childPIDL;
1083N/A }
1083N/A } else {
1083N/A break;
1083N/A }
0N/A }
0N/A }
1083N/A return null;
0N/A }
1453N/A }, InterruptedException.class);
0N/A
0N/A sun.java2d.Disposer.addRecord(this, disposer);
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Create a system shell folder
0N/A */
0N/A Win32ShellFolder2(Win32ShellFolder2 parent, long pIShellFolder, long relativePIDL, String path) {
0N/A super(parent, (path != null) ? path : "ShellFolder: ");
0N/A this.disposer.pIShellFolder = pIShellFolder;
0N/A this.disposer.relativePIDL = relativePIDL;
0N/A sun.java2d.Disposer.addRecord(this, disposer);
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Creates a shell folder with a parent and relative PIDL
0N/A */
1453N/A Win32ShellFolder2(final Win32ShellFolder2 parent, final long relativePIDL) throws InterruptedException {
1083N/A super(parent,
1453N/A invoke(new Callable<String>() {
1453N/A public String call() {
1083N/A return getFileSystemPath(parent.getIShellFolder(), relativePIDL);
1083N/A }
1453N/A }, RuntimeException.class)
1083N/A );
0N/A this.disposer.relativePIDL = relativePIDL;
0N/A sun.java2d.Disposer.addRecord(this, disposer);
0N/A }
0N/A
0N/A // Initializes the desktop shell folder
1083N/A // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
0N/A private native void initDesktop();
1083N/A
0N/A // Initializes a special, non-file system shell folder
0N/A // from one of the above constants
1083N/A // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
0N/A private native void initSpecial(long desktopIShellFolder, int csidl);
0N/A
0N/A /** Marks this folder as being the My Documents (Personal) folder */
0N/A public void setIsPersonal() {
0N/A isPersonal = true;
0N/A }
0N/A
0N/A /**
0N/A * This method is implemented to make sure that no instances
0N/A * of <code>ShellFolder</code> are ever serialized. If <code>isFileSystem()</code> returns
0N/A * <code>true</code>, then the object is representable with an instance of
0N/A * <code>java.io.File</code> instead. If not, then the object depends
0N/A * on native PIDL state and should not be serialized.
0N/A *
344N/A * @return a <code>java.io.File</code> replacement object. If the folder
0N/A * is a not a normal directory, then returns the first non-removable
0N/A * drive (normally "C:\").
0N/A */
0N/A protected Object writeReplace() throws java.io.ObjectStreamException {
1453N/A return invoke(new Callable<File>() {
1453N/A public File call() {
1083N/A if (isFileSystem()) {
1083N/A return new File(getPath());
1083N/A } else {
1083N/A Win32ShellFolder2 drives = Win32ShellFolderManager2.getDrives();
1083N/A if (drives != null) {
1083N/A File[] driveRoots = drives.listFiles();
1083N/A if (driveRoots != null) {
1083N/A for (int i = 0; i < driveRoots.length; i++) {
1083N/A if (driveRoots[i] instanceof Win32ShellFolder2) {
1083N/A Win32ShellFolder2 sf = (Win32ShellFolder2) driveRoots[i];
1083N/A if (sf.isFileSystem() && !sf.hasAttribute(ATTRIB_REMOVABLE)) {
1083N/A return new File(sf.getPath());
1083N/A }
1083N/A }
0N/A }
0N/A }
0N/A }
1083N/A // Ouch, we have no hard drives. Return something "valid" anyway.
1083N/A return new File("C:\\");
0N/A }
0N/A }
1083N/A });
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Finalizer to clean up any COM objects or PIDLs used by this object.
0N/A */
0N/A protected void dispose() {
0N/A disposer.dispose();
0N/A }
0N/A
0N/A
0N/A // Given a (possibly multi-level) relative PIDL (with respect to
0N/A // the desktop, at least in all of the usage cases in this code),
0N/A // return a pointer to the next entry. Does not mutate the PIDL in
0N/A // any way. Returns 0 if the null terminator is reached.
0N/A // Needs to be accessible to Win32ShellFolderManager2
0N/A static native long getNextPIDLEntry(long pIDL);
0N/A
0N/A // Given a (possibly multi-level) relative PIDL (with respect to
0N/A // the desktop, at least in all of the usage cases in this code),
0N/A // copy the first entry into a newly-allocated PIDL. Returns 0 if
0N/A // the PIDL is at the end of the list.
0N/A // Needs to be accessible to Win32ShellFolderManager2
0N/A static native long copyFirstPIDLEntry(long pIDL);
0N/A
0N/A // Given a parent's absolute PIDL and our relative PIDL, build an absolute PIDL
0N/A private static native long combinePIDLs(long ppIDL, long pIDL);
0N/A
0N/A // Release a PIDL object
0N/A // Needs to be accessible to Win32ShellFolderManager2
0N/A static native void releasePIDL(long pIDL);
0N/A
0N/A // Release an IShellFolder object
1083N/A // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
0N/A private static native void releaseIShellFolder(long pIShellFolder);
0N/A
0N/A /**
0N/A * Accessor for IShellFolder
0N/A */
1453N/A private long getIShellFolder() {
0N/A if (disposer.pIShellFolder == 0) {
1453N/A try {
1453N/A disposer.pIShellFolder = invoke(new Callable<Long>() {
1453N/A public Long call() {
1083N/A assert(isDirectory());
1083N/A assert(parent != null);
1083N/A long parentIShellFolder = getParentIShellFolder();
1083N/A if (parentIShellFolder == 0) {
1083N/A throw new InternalError("Parent IShellFolder was null for "
1083N/A + getAbsolutePath());
1083N/A }
1083N/A // We are a directory with a parent and a relative PIDL.
1083N/A // We want to bind to the parent so we get an
1083N/A // IShellFolder instance associated with us.
1083N/A long pIShellFolder = bindToObject(parentIShellFolder,
1083N/A disposer.relativePIDL);
1083N/A if (pIShellFolder == 0) {
1083N/A throw new InternalError("Unable to bind "
1083N/A + getAbsolutePath() + " to parent");
1083N/A }
1083N/A return pIShellFolder;
1083N/A }
1453N/A }, RuntimeException.class);
1453N/A } catch (InterruptedException e) {
1453N/A // Ignore error
1453N/A }
0N/A }
0N/A return disposer.pIShellFolder;
0N/A }
0N/A
0N/A /**
0N/A * Get the parent ShellFolder's IShellFolder interface
0N/A */
0N/A public long getParentIShellFolder() {
0N/A Win32ShellFolder2 parent = (Win32ShellFolder2)getParentFile();
0N/A if (parent == null) {
0N/A // Parent should only be null if this is the desktop, whose
0N/A // relativePIDL is relative to its own IShellFolder.
0N/A return getIShellFolder();
0N/A }
0N/A return parent.getIShellFolder();
0N/A }
0N/A
0N/A /**
0N/A * Accessor for relative PIDL
0N/A */
0N/A public long getRelativePIDL() {
0N/A if (disposer.relativePIDL == 0) {
0N/A throw new InternalError("Should always have a relative PIDL");
0N/A }
0N/A return disposer.relativePIDL;
0N/A }
0N/A
0N/A private long getAbsolutePIDL() {
0N/A if (parent == null) {
0N/A // This is the desktop
0N/A return getRelativePIDL();
0N/A } else {
0N/A if (disposer.absolutePIDL == 0) {
0N/A disposer.absolutePIDL = combinePIDLs(((Win32ShellFolder2)parent).getAbsolutePIDL(), getRelativePIDL());
0N/A }
0N/A
0N/A return disposer.absolutePIDL;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Helper function to return the desktop
0N/A */
0N/A public Win32ShellFolder2 getDesktop() {
0N/A return Win32ShellFolderManager2.getDesktop();
0N/A }
0N/A
0N/A /**
0N/A * Helper function to return the desktop IShellFolder interface
0N/A */
0N/A public long getDesktopIShellFolder() {
0N/A return getDesktop().getIShellFolder();
0N/A }
0N/A
0N/A private static boolean pathsEqual(String path1, String path2) {
0N/A // Same effective implementation as Win32FileSystem
0N/A return path1.equalsIgnoreCase(path2);
0N/A }
0N/A
0N/A /**
0N/A * Check to see if two ShellFolder objects are the same
0N/A */
0N/A public boolean equals(Object o) {
0N/A if (o == null || !(o instanceof Win32ShellFolder2)) {
0N/A // Short-circuit circuitous delegation path
0N/A if (!(o instanceof File)) {
0N/A return super.equals(o);
0N/A }
0N/A return pathsEqual(getPath(), ((File) o).getPath());
0N/A }
0N/A Win32ShellFolder2 rhs = (Win32ShellFolder2) o;
0N/A if ((parent == null && rhs.parent != null) ||
0N/A (parent != null && rhs.parent == null)) {
0N/A return false;
0N/A }
0N/A
0N/A if (isFileSystem() && rhs.isFileSystem()) {
0N/A // Only folders with identical parents can be equal
0N/A return (pathsEqual(getPath(), rhs.getPath()) &&
0N/A (parent == rhs.parent || parent.equals(rhs.parent)));
0N/A }
0N/A
0N/A if (parent == rhs.parent || parent.equals(rhs.parent)) {
1453N/A try {
1453N/A return pidlsEqual(getParentIShellFolder(), disposer.relativePIDL, rhs.disposer.relativePIDL);
1453N/A } catch (InterruptedException e) {
1453N/A return false;
1453N/A }
0N/A }
0N/A
0N/A return false;
0N/A }
0N/A
1453N/A private static boolean pidlsEqual(final long pIShellFolder, final long pidl1, final long pidl2)
1453N/A throws InterruptedException {
1453N/A return invoke(new Callable<Boolean>() {
1453N/A public Boolean call() {
1453N/A return compareIDs(pIShellFolder, pidl1, pidl2) == 0;
1083N/A }
1453N/A }, RuntimeException.class);
0N/A }
1083N/A
1083N/A // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
0N/A private static native int compareIDs(long pParentIShellFolder, long pidl1, long pidl2);
0N/A
1903N/A private volatile Boolean cachedIsFileSystem;
1083N/A
0N/A /**
0N/A * @return Whether this is a file system shell folder
0N/A */
1231N/A public boolean isFileSystem() {
1083N/A if (cachedIsFileSystem == null) {
1083N/A cachedIsFileSystem = hasAttribute(ATTRIB_FILESYSTEM);
1083N/A }
1083N/A
1083N/A return cachedIsFileSystem;
0N/A }
0N/A
0N/A /**
0N/A * Return whether the given attribute flag is set for this object
0N/A */
1083N/A public boolean hasAttribute(final int attribute) {
1453N/A Boolean result = invoke(new Callable<Boolean>() {
1453N/A public Boolean call() {
1083N/A // Caching at this point doesn't seem to be cost efficient
1083N/A return (getAttributes0(getParentIShellFolder(),
1231N/A getRelativePIDL(), attribute)
1231N/A & attribute) != 0;
1083N/A }
1083N/A });
1453N/A
1453N/A return result != null && result;
0N/A }
0N/A
0N/A /**
0N/A * Returns the queried attributes specified in attrsMask.
0N/A *
0N/A * Could plausibly be used for attribute caching but have to be
0N/A * very careful not to touch network drives and file system roots
0N/A * with a full attrsMask
1083N/A * NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
0N/A */
1083N/A
0N/A private static native int getAttributes0(long pParentIShellFolder, long pIDL, int attrsMask);
0N/A
0N/A // Return the path to the underlying file system object
1453N/A // Should be called from the COM thread
1083N/A private static String getFileSystemPath(final long parentIShellFolder, final long relativePIDL) {
1453N/A int linkedFolder = ATTRIB_LINK | ATTRIB_FOLDER;
1453N/A if (parentIShellFolder == Win32ShellFolderManager2.getNetwork().getIShellFolder() &&
1453N/A getAttributes0(parentIShellFolder, relativePIDL, linkedFolder) == linkedFolder) {
0N/A
1453N/A String s =
1453N/A getFileSystemPath(Win32ShellFolderManager2.getDesktop().getIShellFolder(),
1453N/A getLinkLocation(parentIShellFolder, relativePIDL, false));
1453N/A if (s != null && s.startsWith("\\\\")) {
1453N/A return s;
0N/A }
1453N/A }
1453N/A return getDisplayNameOf(parentIShellFolder, relativePIDL, SHGDN_FORPARSING);
0N/A }
1083N/A
0N/A // Needs to be accessible to Win32ShellFolderManager2
1453N/A static String getFileSystemPath(final int csidl) throws IOException, InterruptedException {
1453N/A return invoke(new Callable<String>() {
1453N/A public String call() throws IOException {
1083N/A return getFileSystemPath0(csidl);
1083N/A }
1453N/A }, IOException.class);
1083N/A }
1083N/A
1083N/A // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
1083N/A private static native String getFileSystemPath0(int csidl) throws IOException;
0N/A
0N/A // Return whether the path is a network root.
0N/A // Path is assumed to be non-null
0N/A private static boolean isNetworkRoot(String path) {
0N/A return (path.equals("\\\\") || path.equals("\\") || path.equals("//") || path.equals("/"));
0N/A }
0N/A
0N/A /**
0N/A * @return The parent shell folder of this shell folder, null if
0N/A * there is no parent
0N/A */
0N/A public File getParentFile() {
0N/A return parent;
0N/A }
0N/A
0N/A public boolean isDirectory() {
0N/A if (isDir == null) {
0N/A // Folders with SFGAO_BROWSABLE have "shell extension" handlers and are
1560N/A // not traversable in JFileChooser.
1560N/A if (hasAttribute(ATTRIB_FOLDER) && !hasAttribute(ATTRIB_BROWSABLE)) {
0N/A isDir = Boolean.TRUE;
0N/A } else if (isLink()) {
0N/A ShellFolder linkLocation = getLinkLocation(false);
0N/A isDir = Boolean.valueOf(linkLocation != null && linkLocation.isDirectory());
0N/A } else {
0N/A isDir = Boolean.FALSE;
0N/A }
0N/A }
0N/A return isDir.booleanValue();
0N/A }
0N/A
0N/A /*
0N/A * Functions for enumerating an IShellFolder's children
0N/A */
0N/A // Returns an IEnumIDList interface for an IShellFolder. The value
0N/A // returned must be released using releaseEnumObjects().
1453N/A private long getEnumObjects(final boolean includeHiddenFiles) throws InterruptedException {
1453N/A return invoke(new Callable<Long>() {
1453N/A public Long call() {
1453N/A boolean isDesktop = disposer.pIShellFolder == getDesktopIShellFolder();
1453N/A
1083N/A return getEnumObjects(disposer.pIShellFolder, isDesktop, includeHiddenFiles);
1083N/A }
1453N/A }, RuntimeException.class);
0N/A }
1083N/A
0N/A // Returns an IEnumIDList interface for an IShellFolder. The value
0N/A // returned must be released using releaseEnumObjects().
1083N/A // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
0N/A private native long getEnumObjects(long pIShellFolder, boolean isDesktop,
0N/A boolean includeHiddenFiles);
0N/A // Returns the next sequential child as a relative PIDL
0N/A // from an IEnumIDList interface. The value returned must
0N/A // be released using releasePIDL().
1083N/A // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
0N/A private native long getNextChild(long pEnumObjects);
0N/A // Releases the IEnumIDList interface
1083N/A // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
0N/A private native void releaseEnumObjects(long pEnumObjects);
0N/A
0N/A // Returns the IShellFolder of a child from a parent IShellFolder
0N/A // and a relative PIDL. The value returned must be released
0N/A // using releaseIShellFolder().
1083N/A // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
0N/A private static native long bindToObject(long parentIShellFolder, long pIDL);
0N/A
0N/A /**
0N/A * @return An array of shell folders that are children of this shell folder
0N/A * object. The array will be empty if the folder is empty. Returns
0N/A * <code>null</code> if this shellfolder does not denote a directory.
0N/A */
1083N/A public File[] listFiles(final boolean includeHiddenFiles) {
0N/A SecurityManager security = System.getSecurityManager();
0N/A if (security != null) {
0N/A security.checkRead(getPath());
0N/A }
0N/A
1453N/A try {
1453N/A return invoke(new Callable<File[]>() {
1453N/A public File[] call() throws InterruptedException {
1453N/A if (!isDirectory()) {
1453N/A return null;
1453N/A }
1453N/A // Links to directories are not directories and cannot be parents.
1453N/A // This does not apply to folders in My Network Places (NetHood)
1453N/A // because they are both links and real directories!
1453N/A if (isLink() && !hasAttribute(ATTRIB_FOLDER)) {
1453N/A return new File[0];
1453N/A }
1083N/A
1453N/A Win32ShellFolder2 desktop = Win32ShellFolderManager2.getDesktop();
1453N/A Win32ShellFolder2 personal = Win32ShellFolderManager2.getPersonal();
1083N/A
1453N/A // If we are a directory, we have a parent and (at least) a
1453N/A // relative PIDL. We must first ensure we are bound to the
1453N/A // parent so we have an IShellFolder to query.
1453N/A long pIShellFolder = getIShellFolder();
1453N/A // Now we can enumerate the objects in this folder.
1453N/A ArrayList<Win32ShellFolder2> list = new ArrayList<Win32ShellFolder2>();
1453N/A long pEnumObjects = getEnumObjects(includeHiddenFiles);
1453N/A if (pEnumObjects != 0) {
1909N/A try {
1909N/A long childPIDL;
1909N/A int testedAttrs = ATTRIB_FILESYSTEM | ATTRIB_FILESYSANCESTOR;
1909N/A do {
1909N/A childPIDL = getNextChild(pEnumObjects);
1909N/A boolean releasePIDL = true;
1909N/A if (childPIDL != 0 &&
1909N/A (getAttributes0(pIShellFolder, childPIDL, testedAttrs) & testedAttrs) != 0) {
1909N/A Win32ShellFolder2 childFolder;
1909N/A if (Win32ShellFolder2.this.equals(desktop)
1909N/A && personal != null
1909N/A && pidlsEqual(pIShellFolder, childPIDL, personal.disposer.relativePIDL)) {
1909N/A childFolder = personal;
1909N/A } else {
1909N/A childFolder = new Win32ShellFolder2(Win32ShellFolder2.this, childPIDL);
1909N/A releasePIDL = false;
1909N/A }
1909N/A list.add(childFolder);
1453N/A }
1909N/A if (releasePIDL) {
1909N/A releasePIDL(childPIDL);
1909N/A }
1909N/A } while (childPIDL != 0 && !Thread.currentThread().isInterrupted());
1909N/A } finally {
1909N/A releaseEnumObjects(pEnumObjects);
1909N/A }
1453N/A }
1453N/A return Thread.currentThread().isInterrupted()
1453N/A ? new File[0]
1453N/A : list.toArray(new ShellFolder[list.size()]);
0N/A }
1453N/A }, InterruptedException.class);
1453N/A } catch (InterruptedException e) {
1453N/A return new File[0];
1453N/A }
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Look for (possibly special) child folder by it's path
0N/A *
0N/A * @return The child shellfolder, or null if not found.
0N/A */
1453N/A Win32ShellFolder2 getChildByPath(final String filePath) throws InterruptedException {
1453N/A return invoke(new Callable<Win32ShellFolder2>() {
1453N/A public Win32ShellFolder2 call() throws InterruptedException {
1083N/A long pIShellFolder = getIShellFolder();
1453N/A long pEnumObjects = getEnumObjects(true);
1083N/A Win32ShellFolder2 child = null;
1453N/A long childPIDL;
0N/A
1083N/A while ((childPIDL = getNextChild(pEnumObjects)) != 0) {
1083N/A if (getAttributes0(pIShellFolder, childPIDL, ATTRIB_FILESYSTEM) != 0) {
1083N/A String path = getFileSystemPath(pIShellFolder, childPIDL);
1083N/A if (path != null && path.equalsIgnoreCase(filePath)) {
1083N/A long childIShellFolder = bindToObject(pIShellFolder, childPIDL);
1083N/A child = new Win32ShellFolder2(Win32ShellFolder2.this,
1083N/A childIShellFolder, childPIDL, path);
1083N/A break;
1083N/A }
1083N/A }
1083N/A releasePIDL(childPIDL);
0N/A }
1083N/A releaseEnumObjects(pEnumObjects);
1083N/A return child;
0N/A }
1453N/A }, InterruptedException.class);
0N/A }
0N/A
1903N/A private volatile Boolean cachedIsLink;
0N/A
0N/A /**
0N/A * @return Whether this shell folder is a link
0N/A */
1231N/A public boolean isLink() {
1083N/A if (cachedIsLink == null) {
1083N/A cachedIsLink = hasAttribute(ATTRIB_LINK);
1083N/A }
1083N/A
1083N/A return cachedIsLink;
0N/A }
0N/A
0N/A /**
0N/A * @return Whether this shell folder is marked as hidden
0N/A */
0N/A public boolean isHidden() {
0N/A return hasAttribute(ATTRIB_HIDDEN);
0N/A }
0N/A
0N/A
0N/A // Return the link location of a shell folder
1083N/A // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
0N/A private static native long getLinkLocation(long parentIShellFolder,
0N/A long relativePIDL, boolean resolve);
0N/A
0N/A /**
0N/A * @return The shell folder linked to by this shell folder, or null
0N/A * if this shell folder is not a link or is a broken or invalid link
0N/A */
0N/A public ShellFolder getLinkLocation() {
0N/A return getLinkLocation(true);
0N/A }
0N/A
1083N/A private ShellFolder getLinkLocation(final boolean resolve) {
1453N/A return invoke(new Callable<ShellFolder>() {
1453N/A public ShellFolder call() {
1083N/A if (!isLink()) {
1083N/A return null;
1083N/A }
0N/A
1083N/A ShellFolder location = null;
1083N/A long linkLocationPIDL = getLinkLocation(getParentIShellFolder(),
1083N/A getRelativePIDL(), resolve);
1083N/A if (linkLocationPIDL != 0) {
1083N/A try {
1083N/A location =
1083N/A Win32ShellFolderManager2.createShellFolderFromRelativePIDL(getDesktop(),
1083N/A linkLocationPIDL);
1453N/A } catch (InterruptedException e) {
1453N/A // Return null
1083N/A } catch (InternalError e) {
1083N/A // Could be a link to a non-bindable object, such as a network connection
1083N/A // TODO: getIShellFolder() should throw FileNotFoundException instead
1083N/A }
1083N/A }
1083N/A return location;
0N/A }
1083N/A });
0N/A }
0N/A
0N/A // Parse a display name into a PIDL relative to the current IShellFolder.
1453N/A long parseDisplayName(final String name) throws IOException, InterruptedException {
1453N/A return invoke(new Callable<Long>() {
1453N/A public Long call() throws IOException {
1453N/A return parseDisplayName0(getIShellFolder(), name);
1083N/A }
1453N/A }, IOException.class);
0N/A }
1083N/A
1083N/A // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
0N/A private static native long parseDisplayName0(long pIShellFolder, String name) throws IOException;
0N/A
0N/A // Return the display name of a shell folder
1083N/A // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
0N/A private static native String getDisplayNameOf(long parentIShellFolder,
0N/A long relativePIDL,
0N/A int attrs);
0N/A
0N/A /**
0N/A * @return The name used to display this shell folder
0N/A */
0N/A public String getDisplayName() {
0N/A if (displayName == null) {
1083N/A displayName =
1453N/A invoke(new Callable<String>() {
1453N/A public String call() {
1083N/A return getDisplayNameOf(getParentIShellFolder(),
1083N/A getRelativePIDL(), SHGDN_NORMAL);
1083N/A }
1083N/A });
0N/A }
0N/A return displayName;
0N/A }
0N/A
0N/A // Return the folder type of a shell folder
1083N/A // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
0N/A private static native String getFolderType(long pIDL);
0N/A
0N/A /**
0N/A * @return The type of shell folder as a string
0N/A */
0N/A public String getFolderType() {
0N/A if (folderType == null) {
1083N/A final long absolutePIDL = getAbsolutePIDL();
1083N/A folderType =
1453N/A invoke(new Callable<String>() {
1453N/A public String call() {
1083N/A return getFolderType(absolutePIDL);
1083N/A }
1083N/A });
0N/A }
0N/A return folderType;
0N/A }
0N/A
0N/A // Return the executable type of a file system shell folder
0N/A private native String getExecutableType(String path);
0N/A
0N/A /**
0N/A * @return The executable type as a string
0N/A */
0N/A public String getExecutableType() {
0N/A if (!isFileSystem()) {
0N/A return null;
0N/A }
0N/A return getExecutableType(getAbsolutePath());
0N/A }
0N/A
0N/A
0N/A
0N/A // Icons
0N/A
0N/A private static Map smallSystemImages = new HashMap();
0N/A private static Map largeSystemImages = new HashMap();
0N/A private static Map smallLinkedSystemImages = new HashMap();
0N/A private static Map largeLinkedSystemImages = new HashMap();
0N/A
1083N/A // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
0N/A private static native long getIShellIcon(long pIShellFolder);
1083N/A
1083N/A // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
0N/A private static native int getIconIndex(long parentIShellIcon, long relativePIDL);
0N/A
0N/A // Return the icon of a file system shell folder in the form of an HICON
0N/A private static native long getIcon(String absolutePath, boolean getLargeIcon);
1083N/A
1083N/A // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
0N/A private static native long extractIcon(long parentIShellFolder, long relativePIDL,
0N/A boolean getLargeIcon);
0N/A
0N/A // Returns an icon from the Windows system icon list in the form of an HICON
0N/A private static native long getSystemIcon(int iconID);
0N/A private static native long getIconResource(String libName, int iconID,
0N/A int cxDesired, int cyDesired,
0N/A boolean useVGAColors);
0N/A // Note: useVGAColors is ignored on XP and later
0N/A
0N/A // Return the bits from an HICON. This has a side effect of setting
0N/A // the imageHash variable for efficient caching / comparing.
0N/A private static native int[] getIconBits(long hIcon, int iconSize);
0N/A // Dispose the HICON
0N/A private static native void disposeIcon(long hIcon);
0N/A
1736N/A static native int[] getStandardViewButton0(int iconIndex);
0N/A
1453N/A // Should be called from the COM thread
0N/A private long getIShellIcon() {
0N/A if (pIShellIcon == -1L) {
1453N/A pIShellIcon = getIShellIcon(getIShellFolder());
0N/A }
1453N/A
0N/A return pIShellIcon;
0N/A }
0N/A
0N/A private static Image makeIcon(long hIcon, boolean getLargeIcon) {
0N/A if (hIcon != 0L && hIcon != -1L) {
0N/A // Get the bits. This has the side effect of setting the imageHash value for this object.
0N/A int size = getLargeIcon ? 32 : 16;
0N/A int[] iconBits = getIconBits(hIcon, size);
0N/A if (iconBits != null) {
0N/A BufferedImage img = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB);
0N/A img.setRGB(0, 0, size, size, iconBits, 0, size);
0N/A return img;
0N/A }
0N/A }
0N/A return null;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * @return The icon image used to display this shell folder
0N/A */
1083N/A public Image getIcon(final boolean getLargeIcon) {
0N/A Image icon = getLargeIcon ? largeIcon : smallIcon;
0N/A if (icon == null) {
1083N/A icon =
1453N/A invoke(new Callable<Image>() {
1453N/A public Image call() {
1083N/A Image newIcon = null;
1083N/A if (isFileSystem()) {
1083N/A long parentIShellIcon = (parent != null)
1083N/A ? ((Win32ShellFolder2) parent).getIShellIcon()
1083N/A : 0L;
1083N/A long relativePIDL = getRelativePIDL();
0N/A
1083N/A // These are cached per type (using the index in the system image list)
1083N/A int index = getIconIndex(parentIShellIcon, relativePIDL);
1083N/A if (index > 0) {
1083N/A Map imageCache;
1083N/A if (isLink()) {
1083N/A imageCache = getLargeIcon ? largeLinkedSystemImages : smallLinkedSystemImages;
1083N/A } else {
1083N/A imageCache = getLargeIcon ? largeSystemImages : smallSystemImages;
1083N/A }
1083N/A newIcon = (Image) imageCache.get(Integer.valueOf(index));
1083N/A if (newIcon == null) {
1083N/A long hIcon = getIcon(getAbsolutePath(), getLargeIcon);
1083N/A newIcon = makeIcon(hIcon, getLargeIcon);
1083N/A disposeIcon(hIcon);
1083N/A if (newIcon != null) {
1083N/A imageCache.put(Integer.valueOf(index), newIcon);
1083N/A }
1083N/A }
1083N/A }
1083N/A }
1083N/A
1083N/A if (newIcon == null) {
1083N/A // These are only cached per object
1083N/A long hIcon = extractIcon(getParentIShellFolder(),
1083N/A getRelativePIDL(), getLargeIcon);
1083N/A newIcon = makeIcon(hIcon, getLargeIcon);
1083N/A disposeIcon(hIcon);
1083N/A }
1083N/A
1083N/A if (newIcon == null) {
1083N/A newIcon = Win32ShellFolder2.super.getIcon(getLargeIcon);
1083N/A }
1083N/A return newIcon;
0N/A }
1083N/A });
0N/A if (getLargeIcon) {
0N/A largeIcon = icon;
0N/A } else {
0N/A smallIcon = icon;
0N/A }
0N/A }
0N/A return icon;
0N/A }
0N/A
0N/A /**
0N/A * Gets an icon from the Windows system icon list as an <code>Image</code>
0N/A */
0N/A static Image getSystemIcon(SystemIcon iconType) {
0N/A long hIcon = getSystemIcon(iconType.getIconID());
0N/A Image icon = makeIcon(hIcon, true);
0N/A disposeIcon(hIcon);
0N/A return icon;
0N/A }
0N/A
0N/A /**
0N/A * Gets an icon from the Windows system icon list as an <code>Image</code>
0N/A */
231N/A static Image getShell32Icon(int iconID, boolean getLargeIcon) {
0N/A boolean useVGAColors = true; // Will be ignored on XP and later
0N/A
231N/A int size = getLargeIcon ? 32 : 16;
231N/A
0N/A Toolkit toolkit = Toolkit.getDefaultToolkit();
0N/A String shellIconBPP = (String)toolkit.getDesktopProperty("win.icon.shellIconBPP");
0N/A if (shellIconBPP != null) {
0N/A useVGAColors = shellIconBPP.equals("4");
0N/A }
0N/A
231N/A long hIcon = getIconResource("shell32.dll", iconID, size, size, useVGAColors);
0N/A if (hIcon != 0) {
231N/A Image icon = makeIcon(hIcon, getLargeIcon);
0N/A disposeIcon(hIcon);
0N/A return icon;
0N/A }
0N/A return null;
0N/A }
0N/A
0N/A /**
0N/A * Returns the canonical form of this abstract pathname. Equivalent to
0N/A * <code>new&nbsp;Win32ShellFolder2(getParentFile(), this.{@link java.io.File#getCanonicalPath}())</code>.
0N/A *
0N/A * @see java.io.File#getCanonicalFile
0N/A */
0N/A public File getCanonicalFile() throws IOException {
0N/A return this;
0N/A }
0N/A
0N/A /*
0N/A * Indicates whether this is a special folder (includes My Documents)
0N/A */
0N/A public boolean isSpecial() {
0N/A return isPersonal || !isFileSystem() || (this == getDesktop());
0N/A }
0N/A
0N/A /**
0N/A * Compares this object with the specified object for order.
0N/A *
0N/A * @see sun.awt.shell.ShellFolder#compareTo(File)
0N/A */
0N/A public int compareTo(File file2) {
0N/A if (!(file2 instanceof Win32ShellFolder2)) {
0N/A if (isFileSystem() && !isSpecial()) {
0N/A return super.compareTo(file2);
0N/A } else {
0N/A return -1; // Non-file shellfolders sort before files
0N/A }
0N/A }
0N/A return Win32ShellFolderManager2.compareShellFolders(this, (Win32ShellFolder2) file2);
0N/A }
0N/A
0N/A // native constants from commctrl.h
0N/A private static final int LVCFMT_LEFT = 0;
0N/A private static final int LVCFMT_RIGHT = 1;
0N/A private static final int LVCFMT_CENTER = 2;
0N/A
0N/A public ShellFolderColumnInfo[] getFolderColumns() {
1453N/A return invoke(new Callable<ShellFolderColumnInfo[]>() {
1453N/A public ShellFolderColumnInfo[] call() {
1083N/A ShellFolderColumnInfo[] columns = doGetColumnInfo(getIShellFolder());
0N/A
1083N/A if (columns != null) {
1083N/A List<ShellFolderColumnInfo> notNullColumns =
1083N/A new ArrayList<ShellFolderColumnInfo>();
1083N/A for (int i = 0; i < columns.length; i++) {
1083N/A ShellFolderColumnInfo column = columns[i];
1083N/A if (column != null) {
1083N/A column.setAlignment(column.getAlignment() == LVCFMT_RIGHT
1083N/A ? SwingConstants.RIGHT
1083N/A : column.getAlignment() == LVCFMT_CENTER
1083N/A ? SwingConstants.CENTER
1083N/A : SwingConstants.LEADING);
0N/A
5388N/A column.setComparator(new ColumnComparator(Win32ShellFolder2.this, i));
0N/A
1083N/A notNullColumns.add(column);
1083N/A }
1083N/A }
1083N/A columns = new ShellFolderColumnInfo[notNullColumns.size()];
1083N/A notNullColumns.toArray(columns);
0N/A }
1083N/A return columns;
0N/A }
1083N/A });
0N/A }
0N/A
1083N/A public Object getFolderColumnValue(final int column) {
1453N/A return invoke(new Callable<Object>() {
1453N/A public Object call() {
1083N/A return doGetColumnValue(getParentIShellFolder(), getRelativePIDL(), column);
1083N/A }
1083N/A });
0N/A }
0N/A
1083N/A // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
0N/A private native ShellFolderColumnInfo[] doGetColumnInfo(long iShellFolder2);
0N/A
1083N/A // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
0N/A private native Object doGetColumnValue(long parentIShellFolder2, long childPIDL, int columnIdx);
0N/A
1083N/A // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
344N/A private static native int compareIDsByColumn(long pParentIShellFolder, long pidl1, long pidl2, int columnIdx);
0N/A
0N/A
1231N/A public void sortChildren(final List<? extends File> files) {
1231N/A // To avoid loads of synchronizations with Invoker and improve performance we
1231N/A // synchronize the whole code of the sort method once
1453N/A invoke(new Callable<Void>() {
1453N/A public Void call() {
5388N/A Collections.sort(files, new ColumnComparator(Win32ShellFolder2.this, 0));
1231N/A
1231N/A return null;
1231N/A }
1231N/A });
344N/A }
344N/A
344N/A private static class ColumnComparator implements Comparator<File> {
5388N/A private final Win32ShellFolder2 shellFolder;
344N/A
0N/A private final int columnIdx;
0N/A
5388N/A public ColumnComparator(Win32ShellFolder2 shellFolder, int columnIdx) {
5388N/A this.shellFolder = shellFolder;
0N/A this.columnIdx = columnIdx;
0N/A }
0N/A
0N/A // compares 2 objects within this folder by the specified column
1083N/A public int compare(final File o, final File o1) {
1453N/A Integer result = invoke(new Callable<Integer>() {
1453N/A public Integer call() {
1083N/A if (o instanceof Win32ShellFolder2
1453N/A && o1 instanceof Win32ShellFolder2) {
1083N/A // delegates comparison to native method
5388N/A return compareIDsByColumn(shellFolder.getIShellFolder(),
1453N/A ((Win32ShellFolder2) o).getRelativePIDL(),
1453N/A ((Win32ShellFolder2) o1).getRelativePIDL(),
1453N/A columnIdx);
1083N/A }
1083N/A return 0;
1083N/A }
1083N/A });
1453N/A
1453N/A return result == null ? 0 : result;
0N/A }
0N/A }
0N/A}