Package sun.awt.shell

Source Code of sun.awt.shell.Win32ShellFolder2$ColumnComparator

/*
* Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
* Copyright (C) 2009 Volker Berlin (i-net software)
* Copyright (C) 2010 Karsten Heinrich (i-net software)
* 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.  Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

package sun.awt.shell;

import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.swing.SwingConstants;

import cli.System.IntPtr;
import cli.System.Drawing.Bitmap;

// NOTE: This class basically a conversion of the OpenJDK Wen32ShellFolder2, but uses
// .NET pointers and objects instead of representing pointers as long

/**
* Win32 Shell Folders
* <P>
* <BR>
* There are two fundamental types of shell folders : file system folders
* and non-file system folders.  File system folders are relatively easy
* to deal with.  Non-file system folders are items such as My Computer,
* Network Neighborhood, and the desktop.  Some of these non-file system
* folders have special values and properties.
* <P>
* <BR>
* Win32 keeps two basic data structures for shell folders.  The first
* of these is called an ITEMIDLIST.  Usually a pointer, called an
* LPITEMIDLIST, or more frequently just "PIDL".  This structure holds
* a series of identifiers and can be either relative to the desktop
* (an absolute PIDL), or relative to the shell folder that contains them.
* Some Win32 functions can take absolute or relative PIDL values, and
* others can only accept relative values.
* <BR>
* The second data structure is an IShellFolder COM interface.  Using
* this interface, one can enumerate the relative PIDLs in a shell
* folder, get attributes, etc.
* <BR>
* All Win32ShellFolder2Orig objects which are folder types (even non-file
* system folders) contain an IShellFolder object. Files are named in
* directories via relative PIDLs.
*
* @author Michael Martak
* @author Leif Samuelsson
* @author Kenneth Russell
* @author Volker Berlin
* @author Karsten Heinrich
* */

final class Win32ShellFolder2 extends ShellFolder {

    // Win32 Shell Folder Constants
    public static final int DESKTOP = 0x0000;
    public static final int INTERNET = 0x0001;
    public static final int PROGRAMS = 0x0002;
    public static final int CONTROLS = 0x0003;
    public static final int PRINTERS = 0x0004;
    public static final int PERSONAL = 0x0005;
    public static final int FAVORITES = 0x0006;
    public static final int STARTUP = 0x0007;
    public static final int RECENT = 0x0008;
    public static final int SENDTO = 0x0009;
    public static final int BITBUCKET = 0x000a;
    public static final int STARTMENU = 0x000b;
    public static final int DESKTOPDIRECTORY = 0x0010;
    public static final int DRIVES = 0x0011;
    public static final int NETWORK = 0x0012;
    public static final int NETHOOD = 0x0013;
    public static final int FONTS = 0x0014;
    public static final int TEMPLATES = 0x0015;
    public static final int COMMON_STARTMENU = 0x0016;
    public static final int COMMON_PROGRAMS = 0X0017;
    public static final int COMMON_STARTUP = 0x0018;
    public static final int COMMON_DESKTOPDIRECTORY = 0x0019;
    public static final int APPDATA = 0x001a;
    public static final int PRINTHOOD = 0x001b;
    public static final int ALTSTARTUP = 0x001d;
    public static final int COMMON_ALTSTARTUP = 0x001e;
    public static final int COMMON_FAVORITES = 0x001f;
    public static final int INTERNET_CACHE = 0x0020;
    public static final int COOKIES = 0x0021;
    public static final int HISTORY = 0x0022;

    // Win32 shell folder attributes
    public static final int ATTRIB_CANCOPY = 0x00000001;
    public static final int ATTRIB_CANMOVE = 0x00000002;
    public static final int ATTRIB_CANLINK = 0x00000004;
    public static final int ATTRIB_CANRENAME = 0x00000010;
    public static final int ATTRIB_CANDELETE = 0x00000020;
    public static final int ATTRIB_HASPROPSHEET = 0x00000040;
    public static final int ATTRIB_DROPTARGET = 0x00000100;
    public static final int ATTRIB_LINK = 0x00010000;
    public static final int ATTRIB_SHARE = 0x00020000;
    public static final int ATTRIB_READONLY = 0x00040000;
    public static final int ATTRIB_GHOSTED = 0x00080000;
    public static final int ATTRIB_HIDDEN = 0x00080000;
    public static final int ATTRIB_FILESYSANCESTOR = 0x10000000;
    public static final int ATTRIB_FOLDER = 0x20000000;
    public static final int ATTRIB_FILESYSTEM = 0x40000000;
    public static final int ATTRIB_HASSUBFOLDER = 0x80000000;
    public static final int ATTRIB_VALIDATE = 0x01000000;
    public static final int ATTRIB_REMOVABLE = 0x02000000;
    public static final int ATTRIB_COMPRESSED = 0x04000000;
    public static final int ATTRIB_BROWSABLE = 0x08000000;
    public static final int ATTRIB_NONENUMERATED = 0x00100000;
    public static final int ATTRIB_NEWCONTENT = 0x00200000;

    // IShellFolder::GetDisplayNameOf constants
    public static final int SHGDN_NORMAL = 0; // is used alone, returns the name of the item itself without extension
    public static final int SHGDN_INFOLDER = 1; // name relative to the parent folder, use this flag in combinations with SHGDN_FORPARSING and SHGDN_FOREDITING.
    public static final int SHGDN_INCLUDE_NONFILESYS = 0x2000; // The name is used for in-place editing when the user renames the item.
    public static final int SHGDN_FORADDRESSBAR = 0x4000; // The name is displayed in an address bar combo box.
    public static final int SHGDN_FORPARSING = 0x8000; // return a parsable display name relative to desktop

    static class FolderDisposer implements  sun.java2d.DisposerRecord {
        /*
         * This is cached as a concession to getFolderType(), which needs
         * an absolute PIDL.
         */
        cli.System.IntPtr absolutePIDL;
        /*
         * We keep track of shell folders through the IShellFolder
         * interface of their parents plus their relative PIDL.
         */
        cli.System.Object pIShellFolder;
        cli.System.IntPtr relativePIDL;

        boolean disposed;
        @cli.System.Security.SecuritySafeCriticalAttribute.Annotation
        public void dispose() {
            if (disposed)
                return;
            if ( relativePIDL != null && !cli.System.IntPtr.Zero.Equals( relativePIDL ) ) {
                releasePIDL(relativePIDL);
            }
            if ( absolutePIDL != null && !cli.System.IntPtr.Zero.Equals( absolutePIDL ) ) {
                releasePIDL(absolutePIDL);
            }
            if ( pIShellFolder != null ) {
                releaseIShellFolder(pIShellFolder);
            }
            disposed = true;
        }
    }

    FolderDisposer disposer = new FolderDisposer();

    private void setIShellFolder( cli.System.Object iShellFolder ) {
        disposer.pIShellFolder = iShellFolder;
    }

    private void setRelativePIDL(cli.System.IntPtr relativePIDL) {
        disposer.relativePIDL = relativePIDL;
    }

    /*
     * The following are for caching various shell folder properties.
     */
    private cli.System.Object pIShellIcon = null;
    private String folderType = null;
    private String displayName = null;
    private Image smallIcon = null;
    private Image largeIcon = null;
    private Boolean isDir = null;

    /*
     * The following is to identify the My Documents folder as being special
     */
    private boolean isPersonal;

    /**
     * Create a system special shell folder, such as the
     * desktop or Network Neighborhood.
     */
    @cli.System.Security.SecuritySafeCriticalAttribute.Annotation
    Win32ShellFolder2(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) {
          // compared to the Java implementation we require two steps here since
          // we don't have a callback from the native methods in to this instance
            setIShellFolder( initDesktopFolder() );
            setRelativePIDL( initDesktopPIDL() );
        } else {
          cli.System.Object desktopFolder = getDesktop().getIShellFolder();
          cli.System.IntPtr pidl = initSpecialPIDL( desktopFolder, csidl );
            setRelativePIDL( pidl );
            setIShellFolder( initSpecialFolder(desktopFolder, pidl) );
            // 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.
            bindToDesktop();
        }

        sun.java2d.Disposer.addRecord(this , disposer);
    }

        @cli.System.Security.SecuritySafeCriticalAttribute.Annotation
  protected void bindToDesktop() {
    cli.System.IntPtr pIDL = disposer.relativePIDL;
    parent = getDesktop();
    while ( pIDL != null && !cli.System.IntPtr.Zero.Equals( pIDL ) ) {
        // Get a child pidl relative to 'parent'
      cli.System.IntPtr childPIDL = copyFirstPIDLEntry(pIDL);
        if (childPIDL != null && !cli.System.IntPtr.Zero.Equals( childPIDL ) ) {
            // Get a handle to the the rest of the ID list
            // i,e, parent's grandchilren and down
            pIDL = getNextPIDLEntry(pIDL);
            if ( pIDL != null && !cli.System.IntPtr.Zero.Equals( pIDL ) ) {
                // 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;
        }
    }
  }

    /**
     * Create a system shell folder
     */
    @cli.System.Security.SecurityCriticalAttribute.Annotation
    Win32ShellFolder2(Win32ShellFolder2 parent, cli.System.Object pIShellFolder, cli.System.IntPtr relativePIDL, String path) {
        super (parent, (path != null) ? path : "ShellFolder: ");
        this .disposer.pIShellFolder = pIShellFolder;
        this .disposer.relativePIDL = relativePIDL;
        sun.java2d.Disposer.addRecord(this , disposer);
    }

    /**
     * Creates a shell folder with a parent and relative PIDL
     */
    @cli.System.Security.SecurityCriticalAttribute.Annotation
    Win32ShellFolder2(Win32ShellFolder2 parent, cli.System.IntPtr relativePIDL) {
        super (parent, getFileSystemPath(parent.getIShellFolder(), relativePIDL));
        this .disposer.relativePIDL = relativePIDL;
        getAbsolutePath();
        sun.java2d.Disposer.addRecord(this , disposer);
    }

    // Initializes the desktop shell folder
    /**
     * Returns the pIDL of the Desktop folder (pIDL root)
     * @return the pIDL of the Desktop folder (pIDL root)
     */
    private static native cli.System.IntPtr initDesktopPIDL();
    /**
     * Returns the IShellFolder pointer of the Desktop folder (pIDL root)
     * @return the IShellFolder pointer of the Desktop folder (pIDL root)
     */
    private static native cli.System.Object initDesktopFolder();

    // Initializes a special, non-file system shell folder
    // from one of the above constants
    /**
     * initializes a special folder
     * @param desktopIShellFolder the IShellFolder reference of the desktop folder
     * @param csidl the CSIDL of the requested special folder
     * @return the pIDL of the special folder relative to the desktop root
     */
    private static native cli.System.IntPtr initSpecialPIDL(cli.System.Object desktopIShellFolder, int csidl);
    /**
     * initializes a special folder
     * @param desktopIShellFolder the IShellFolder reference of the desktop folder
     * @param pidl the pIDL of the requested folder relative to the desktopIShellFolder
     * @return the IShellFolder reference for the requested folder
     */
    @cli.System.Security.SecurityCriticalAttribute.Annotation
    private static native cli.System.Object initSpecialFolder(cli.System.Object desktopIShellFolder, cli.System.IntPtr pidl);

    /** Marks this folder as being the My Documents (Personal) folder */
    public void setIsPersonal() {
        isPersonal = true;
    }

    /**
     * This method is implemented to make sure that no instances
     * of <code>ShellFolder</code> are ever serialized. If <code>isFileSystem()</code> returns
     * <code>true</code>, then the object is representable with an instance of
     * <code>java.io.File</code> instead. If not, then the object depends
     * on native PIDL state and should not be serialized.
     *
     * @returns a <code>java.io.File</code> replacement object. If the folder
     * is a not a normal directory, then returns the first non-removable
     * 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());
                            }
                        }
                    }
                }
            }
            // Ouch, we have no hard drives. Return something "valid" anyway.
            return new File("C:\\");
        }
    }

    /**
     * Finalizer to clean up any COM objects or PIDLs used by this object.
     */
    protected void dispose() {
        disposer.dispose();
    }

    // Given a (possibly multi-level) relative PIDL (with respect to
    // the desktop, at least in all of the usage cases in this code),
    // return a pointer to the next entry. Does not mutate the PIDL in
    // any way. Returns 0 if the null terminator is reached.
    // Needs to be accessible to Win32ShellFolderManager2
    @cli.System.Security.SecurityCriticalAttribute.Annotation
    static native cli.System.IntPtr getNextPIDLEntry(cli.System.IntPtr pIDL);

    // Given a (possibly multi-level) relative PIDL (with respect to
    // the desktop, at least in all of the usage cases in this code),
    // copy the first entry into a newly-allocated PIDL. Returns 0 if
    // the PIDL is at the end of the list.
    // Needs to be accessible to Win32ShellFolderManager2
    @cli.System.Security.SecurityCriticalAttribute.Annotation
    static native cli.System.IntPtr copyFirstPIDLEntry(cli.System.IntPtr pIDL);

    // Given a parent's absolute PIDL and our relative PIDL, build an absolute PIDL
    /**
     * Combines a parent pIDL with a descendant pIDL. It doesn't matter whether the parent pIDL
     * is relative or absolute since this is only a concatenation of the IDLs
     * @param ppIDL the parent pIDL
     * @param pIDL the pIDL relative to the ppIDL
     * @return a pIDL for the item referenced by the original pIDL but relative to the parent of ppIDL
     */
    @cli.System.Security.SecurityCriticalAttribute.Annotation
    private static native cli.System.IntPtr combinePIDLs(cli.System.IntPtr ppIDL, cli.System.IntPtr pIDL);

    // Release a PIDL object
    // Needs to be accessible to Win32ShellFolderManager2
    @cli.System.Security.SecurityCriticalAttribute.Annotation
    static native void releasePIDL(cli.System.IntPtr pIDL);

    // Release an IShellFolder object
    @cli.System.Security.SecurityCriticalAttribute.Annotation
    static native void releaseIShellFolder( cli.System.Object iShellFolder );

    /**
     * Accessor for IShellFolder
     */
    @cli.System.Security.SecuritySafeCriticalAttribute.Annotation
    public cli.System.Object getIShellFolder() {
        if (disposer.pIShellFolder == null ) {
            assert (isDirectory());
            assert (parent != null);
            cli.System.Object parentIShellFolder = getParentIShellFolder();
            if (parentIShellFolder == null) {
                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 == null ) {
                throw new InternalError("Unable to bind " + getAbsolutePath() + " to parent");
            }
        }
        return disposer.pIShellFolder;
    }

    /**
     * Get the parent ShellFolder's IShellFolder interface
     */
    public cli.System.Object getParentIShellFolder() {
        Win32ShellFolder2 parent = (Win32ShellFolder2) getParentFile();
        cli.System.Object parentFolder;
        if (parent == null) {
            // Parent should only be null if this is the desktop, whose
            // relativePIDL is relative to its own IShellFolder.
          parentFolder = getIShellFolder();
        } else {
          parentFolder = parent.getIShellFolder();
        }
        return parentFolder;
    }

    /**
     * Accessor for relative PIDL
     */
    public cli.System.IntPtr getRelativePIDL() {
        if (disposer.relativePIDL == null) {
            throw new InternalError( "Should always have a relative PIDL" );
        }
        return disposer.relativePIDL;
    }

    @cli.System.Security.SecuritySafeCriticalAttribute.Annotation
    private cli.System.IntPtr getAbsolutePIDL() {
        if (parent == null) {
            // This is the desktop
            return getRelativePIDL();
        } else {
            if (disposer.absolutePIDL == null || disposer.absolutePIDL.Equals( IntPtr.Zero )) {
                disposer.absolutePIDL = combinePIDLs( ((Win32ShellFolder2) parent).getAbsolutePIDL(), getRelativePIDL());
            }

            return disposer.absolutePIDL;
        }
    }

    /**
     * Helper function to return the desktop
     */
    public Win32ShellFolder2 getDesktop() {
        return Win32ShellFolderManager2.getDesktop();
    }

    /**
     * Helper function to return the desktop IShellFolder interface
     */
    public cli.System.Object getDesktopIShellFolder() {
        return getDesktop().getIShellFolder();
    }

    private static boolean pathsEqual(String path1, String path2) {
        // Same effective implementation as Win32FileSystem
        return path1.equalsIgnoreCase(path2);
    }

    /**
     * Check to see if two ShellFolder objects are the same
     */
    @cli.System.Security.SecuritySafeCriticalAttribute.Annotation
    public boolean equals(Object o) {
        if (o == null || !(o instanceof  Win32ShellFolder2)) {
            // Short-circuit circuitous delegation path
            if (!(o instanceof  File)) {
                return super .equals(o);
            }
            return pathsEqual(getPath(), ((File) o).getPath());
        }
        Win32ShellFolder2 rhs = (Win32ShellFolder2) o;
        if ((parent == null && rhs.parent != null) || (parent != null && rhs.parent == null)) {
            return false;
        }

        if (isFileSystem() && rhs.isFileSystem()) {
            // Only folders with identical parents can be equal
            return (pathsEqual(getPath(), rhs.getPath()) && (parent == rhs.parent || parent.equals(rhs.parent)));
        }

        if (parent == rhs.parent || parent.equals(rhs.parent)) {
            return pidlsEqual(getParentIShellFolder(), disposer.relativePIDL, rhs.disposer.relativePIDL);
        }

        return false;
    }

    @cli.System.Security.SecurityCriticalAttribute.Annotation
    private static boolean pidlsEqual(cli.System.Object pIShellFolder, cli.System.IntPtr pidl1, cli.System.IntPtr pidl2) {
        return (compareIDs(pIShellFolder, pidl1, pidl2) == 0);
    }

    @cli.System.Security.SecurityCriticalAttribute.Annotation
    private static native int compareIDs(cli.System.Object pParentIShellFolder, cli.System.IntPtr pidl1, cli.System.IntPtr pidl2);

    /**
     * @return Whether this is a file system shell folder
     */
    public boolean isFileSystem() {
        return hasAttribute(ATTRIB_FILESYSTEM);
    }

    /**
     * Return whether the given attribute flag is set for this object
     */
    @cli.System.Security.SecuritySafeCriticalAttribute.Annotation
    public boolean hasAttribute(int attribute) {
        // Caching at this point doesn't seem to be cost efficient
        return (getAttributes0(getParentIShellFolder(), getRelativePIDL(), attribute) & attribute) != 0;
    }

    /**
     * Returns the queried attributes specified in attrsMask.
     *
     * 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
     */
    @cli.System.Security.SecurityCriticalAttribute.Annotation
    private static native int getAttributes0(cli.System.Object pParentIShellFolder, cli.System.IntPtr pIDL, int attrsMask);

    // Return the path to the underlying file system object
    @cli.System.Security.SecurityCriticalAttribute.Annotation
    private static String getFileSystemPath(cli.System.Object parentIShellFolder, cli.System.IntPtr relativePIDL) {
        int linkedFolder = ATTRIB_LINK | ATTRIB_FOLDER;
        if (parentIShellFolder == Win32ShellFolderManager2.getNetwork().getIShellFolder()
                && getAttributes0(parentIShellFolder, relativePIDL, linkedFolder) == linkedFolder) {

          cli.System.Object desktopIShellFolder = Win32ShellFolderManager2.getDesktop().getIShellFolder();
            String path = getDisplayNameOf(parentIShellFolder, relativePIDL, SHGDN_FORPARSING );
      String s = getFileSystemPath(desktopIShellFolder, getLinkLocation( path, false));
            if (s != null && s.startsWith("\\\\")) {
                return s;
            }
        }
        return getDisplayNameOf(parentIShellFolder, relativePIDL, SHGDN_NORMAL | SHGDN_FORPARSING);
    }

    // Needs to be accessible to Win32ShellFolderManager2
    static native String getFileSystemPath(int csidl)
            throws IOException;

    // Return whether the path is a network root.
    // Path is assumed to be non-null
    private static boolean isNetworkRoot(String path) {
        return (path.equals("\\\\") || path.equals("\\") || path.equals("//") || path.equals("/"));
    }

    /**
     * @return The parent shell folder of this shell folder, null if
     * there is no parent
     */
    public File getParentFile() {
        return parent;
    }

    public boolean isDirectory() {
        if (isDir == null) {
            // Folders with SFGAO_BROWSABLE have "shell extension" handlers and are
            // not traversable in JFileChooser.
            if ((hasAttribute(ATTRIB_HASSUBFOLDER) || hasAttribute(ATTRIB_FOLDER)) && (!hasAttribute(ATTRIB_BROWSABLE) )) {
                isDir = Boolean.TRUE;
            } else if (isLink()) {
                ShellFolder linkLocation = getLinkLocation(false);
                isDir = Boolean.valueOf(linkLocation != null && linkLocation.isDirectory());
            } else {
                isDir = Boolean.FALSE;
            }
        }
        return isDir.booleanValue();
    }

    /*
     * Functions for enumerating an IShellFolder's children
     */
    // Returns an IEnumIDList interface for an IShellFolder.  The value
    // returned must be released using releaseEnumObjects().
    /**
     * Returns an IEnumIDList interface for an IShellFolder.  The value
     * returned must be released using releaseEnumObjects().
     * @param pIShellFolder the IShellFolder instance of the parent shell folder
     * @param includeHiddenFiles if true, hidden files will be included in the enumeration
     * @return an instance of IEnumIDList
     */
    private cli.System.Object getEnumObjects(cli.System.Object pIShellFolder, boolean includeHiddenFiles) {
        boolean isDesktop = (disposer.pIShellFolder == getDesktopIShellFolder());
        return getEnumObjects(disposer.pIShellFolder, isDesktop, includeHiddenFiles);
    }

    /**
     * Returns an IEnumIDList interface for an IShellFolder.  The value
     * returned must be released using releaseEnumObjects().
     * @param pIShellFolder the IShellFolder instance of the parent shell folder
     * @param isDesktop must be set to true, if the pIShellFolder is the desktop shell folder
     * @param includeHiddenFiles if true, hidden files will be included in the enumeration
     * @return an instance of IEnumIDList
     */
    private static native cli.System.Object getEnumObjects(cli.System.Object 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().
     * @param pEnumObjects the IEnumIDList instance to get the next child from
     * @return the next child or {@link IntPtr#Zero} if the end of the enumeration is reached
     */
    private static native cli.System.IntPtr getNextChild(cli.System.Object pEnumObjects);

    /**
     * Releases the IEnumIDList interface
     * @param pEnumObjects an IEnumIDList instance
     */
    @cli.System.Security.SecurityCriticalAttribute.Annotation
    private static native void releaseEnumObjects(cli.System.Object pEnumObjects);

    /**
     * Returns the IShellFolder of a child from a parent IShellFolder and a relative pIDL. The pIDL
     * may as well be any other  descendant of the shell folder - at least this is, what the windows API
     * documentation says. 
     * The value returned must be released using releaseIShellFolder().
     * @param parentIShellFolder an IShellFolder instance as root for the pIDL
     * @param pIDL a pIDL relative to the parent shell folder
     * @return a NEW instance of an IShellFolder for the path given by the pIDL, may be null if the path is invalid
     */
    @cli.System.Security.SecurityCriticalAttribute.Annotation
    private static native cli.System.Object bindToObject(cli.System.Object parentIShellFolder, cli.System.IntPtr pIDL);

    /**
     * @return An array of shell folders that are children of this shell folder
     *         object. The array will be empty if the folder is empty.  Returns
     *         <code>null</code> if this shellfolder does not denote a directory.
     */
    @cli.System.Security.SecuritySafeCriticalAttribute.Annotation
    public File[] listFiles(boolean includeHiddenFiles) {
        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.
        cli.System.Object pIShellFolder = getIShellFolder();
        // Now we can enumerate the objects in this folder.
        ArrayList list = new ArrayList();
        cli.System.Object pEnumObjects = getEnumObjects(pIShellFolder, includeHiddenFiles);
        if (pEnumObjects != null) {
          cli.System.IntPtr childPIDL = null;
            int testedAttrs = ATTRIB_FILESYSTEM | ATTRIB_FILESYSANCESTOR;
            do {
                if (Thread.currentThread().isInterrupted()) {
                    return new File[0];
                }
                childPIDL = getNextChild(pEnumObjects);
                boolean releasePIDL = true;
                if ( childPIDL != null && !cli.System.IntPtr.Zero.Equals( childPIDL ) && (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);
                }
                if (releasePIDL) {
                    releasePIDL(childPIDL);
                }
            } while (childPIDL != null && !childPIDL.Equals( cli.System.IntPtr.Zero ));
            releaseEnumObjects(pEnumObjects);
        }
        return (ShellFolder[]) list.toArray(new ShellFolder[list.size()]);
    }

    /**
     * Look for (possibly special) child folder by it's path. Note: this will not work an an ancestor(not child)
     * of the current folder.
     * @return The child shell folder, or null if not found.
     */
    @cli.System.Security.SecuritySafeCriticalAttribute.Annotation
    Win32ShellFolder2 getChildByPath(String filePath) {
      cli.System.Object pIShellFolder = getIShellFolder();
      cli.System.Object pEnumObjects = getEnumObjects(pIShellFolder, true);
        Win32ShellFolder2 child = null;
        cli.System.IntPtr childPIDL = null;
       
        childPIDL = getNextChild(pEnumObjects);
        while ( childPIDL != null && !cli.System.IntPtr.Zero.Equals( childPIDL ) ) {
            if (getAttributes0(pIShellFolder, childPIDL, ATTRIB_FILESYSTEM) != 0) {
                String path = getFileSystemPath(pIShellFolder, childPIDL);
                if (path != null && path.equalsIgnoreCase(filePath)) {
                  cli.System.Object childIShellFolder = bindToObject( pIShellFolder, childPIDL);
                    child = new Win32ShellFolder2(this, childIShellFolder, childPIDL, path);
                    break;
                }
            }
            releasePIDL(childPIDL);
            childPIDL = getNextChild(pEnumObjects);
        }
        releaseEnumObjects(pEnumObjects);
        return child;
    }

    /**
     * @return Whether this shell folder is a link
     */
    public boolean isLink() {
        return hasAttribute(ATTRIB_LINK);
    }

    /**
     * @return Whether this shell folder is marked as hidden
     */
    public boolean isHidden() {
        return hasAttribute(ATTRIB_HIDDEN);
    }

    // Return the link location of a shell folder
    /**
     * Resolves the link location of an item to an ABSOLUTE pIDL
     * @param parentIShellFolder the pointer to the parent IShellFolder of the item
     * @param relativePIDL a single-level pIDL to the item
     * @param resolve
     */
    private static native cli.System.IntPtr getLinkLocation( String path, boolean resolve);

    /**
     * @return The shell folder linked to by this shell folder, or null
     * if this shell folder is not a link or is a broken or invalid link
     */
    public ShellFolder getLinkLocation() {
        return getLinkLocation(true);
    }

    @cli.System.Security.SecuritySafeCriticalAttribute.Annotation
    private ShellFolder getLinkLocation(boolean resolve) {
        if (!isLink()) {
            return null;
        }

        ShellFolder location = null;
        cli.System.IntPtr linkLocationPIDL = getLinkLocation( getAbsolutePath(), resolve);
        if (linkLocationPIDL != null && !cli.System.IntPtr.Zero.Equals( linkLocationPIDL ) ) {
            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;
    }

    /**
     * Parse a display name into a PIDL relative to the current IShellFolder.
     * @param name the name or relative path
     * @return a pIDL for the path, may be {@link IntPtr#Zero} if not found
     * @throws FileNotFoundException
     */
    cli.System.IntPtr parseDisplayName(String name) throws FileNotFoundException {
        try {
            return parseDisplayName0(getIShellFolder(), name);
        } catch (IOException e) {
            throw new FileNotFoundException("Could not find file " + name);
        }
    }

    private static native cli.System.IntPtr parseDisplayName0(cli.System.Object pIShellFolder, String name) throws IOException;

    /**
     * Returns the display name of an item in a folder
     * @param parentIShellFolder the pointer to the IShellFolder interface of the parent folder
     * @param relativePIDL single-level pIDL to the requested item within the parent folder
     * @param attrs formatting attributes for the display name, refer to SHGDN in MSDN
     * @return
     */
    @cli.System.Security.SecurityCriticalAttribute.Annotation
    private static native String getDisplayNameOf( cli.System.Object parentIShellFolder, cli.System.IntPtr relativePIDL, int attrs);

    /**
     * @return The name used to display this shell folder
     */
    @cli.System.Security.SecuritySafeCriticalAttribute.Annotation
    public String getDisplayName() {
        if (displayName == null) {
            displayName = getDisplayNameOf(getParentIShellFolder(), getRelativePIDL(), SHGDN_NORMAL);
        }
        return displayName;
    }

    // Return the folder type of a shell folder
    @cli.System.Security.SecurityCriticalAttribute.Annotation
    private static native String getFolderType(cli.System.IntPtr pIDL);

    /**
     * @return The type of shell folder as a string
     */
    @cli.System.Security.SecuritySafeCriticalAttribute.Annotation
    public String getFolderType() {
        if (folderType == null) {
            folderType = getFolderType(getAbsolutePIDL());
        }
        return folderType;
    }

    // Return the executable type of a file system shell folder
    private static native String getExecutableType(String path);

    /**
     * @return The executable type as a string
     */
    public String getExecutableType() {
        if (!isFileSystem()) {
            return null;
        }
        return getExecutableType(getAbsolutePath());
    }

    // Icons

    private static Map smallSystemImages = new HashMap();
    private static Map largeSystemImages = new HashMap();
    private static Map smallLinkedSystemImages = new HashMap();
    private static Map largeLinkedSystemImages = new HashMap();

    /**
     * Returns the icon index in the system image list 
     * @param parentIShellIcon the the pointer to the IShellIcon instance of the parent folder
     * @param relativePIDL the relative pIDL to the requested item
     * @return the system image list index for the icon of the item or zero, if there is no entry
     */
    @cli.System.Security.SecurityCriticalAttribute.Annotation
    private static native int getIconIndex(cli.System.Object parentIShellFolder, cli.System.IntPtr relativePIDL);

    // Return the icon of a file system shell folder in the form of an HICON
    private static native cli.System.IntPtr getIcon(String absolutePath, boolean getLargeIcon);

    @cli.System.Security.SecurityCriticalAttribute.Annotation
    private static native cli.System.IntPtr extractIcon(cli.System.Object parentIShellFolder, cli.System.IntPtr relativePIDL, boolean getLargeIcon);

    /**
     * Returns the {@link Bitmap} for a HICON.
     */
    @cli.System.Security.SecurityCriticalAttribute.Annotation
    private static native Bitmap getIconBits(cli.System.IntPtr hIcon, int size);

    /**
     * Disposes a icon handle
     * @param hIcon the handle to be disposed
     */
    @cli.System.Security.SecurityCriticalAttribute.Annotation
    private static native void disposeIcon(cli.System.IntPtr hIcon);

    static int[] fileChooserBitmapBits = null;
    static Image[] fileChooserIcons = null;

    static Image getFileChooserIcon(int idx){
        if(fileChooserIcons == null){
            fileChooserIcons = new Image[47];

            try{
                Bitmap bitmap = getFileChooserBitmap();
                if (bitmap == null) {
                    return null;
                }
               
                for(int i = 0; i < fileChooserIcons.length; i++){
                    cli.System.Drawing.Rectangle rect = new cli.System.Drawing.Rectangle(16 * i, 0, 16, 16);
                    Bitmap icon = bitmap.Clone(rect, bitmap.get_PixelFormat());
                    fileChooserIcons[i] = new BufferedImage(icon);
                }
            }catch(Throwable ex){
                ex.printStackTrace();
            }
        }
        return fileChooserIcons[idx];
    }
   
    private static native Bitmap getFileChooserBitmap();

    /**
     * Creates a Java icon for a HICON pointer
     * @param hIcon the handle for the icon
     * @param getLargeIcon true for a large icon, false for a small icon
     * @return the created image or null, if the handle is invalid
     */
    @cli.System.Security.SecurityCriticalAttribute.Annotation
    private static Image makeIcon(cli.System.IntPtr hIcon, boolean getLargeIcon) {
        if (hIcon != null ) {
            // Get the bits.  This has the side effect of setting the imageHash value for this object.
            Bitmap bitmap = getIconBits(hIcon, getLargeIcon ? 32 : 16 );
            if (bitmap == null) {
                return null;
            }           
            return new BufferedImage(bitmap);
        }
        return null;
    }

    /**
     * @return The icon image used to display this shell folder
     */
    @cli.System.Security.SecuritySafeCriticalAttribute.Annotation
    public Image getIcon(boolean getLargeIcon) {
        Image icon = getLargeIcon ? largeIcon : smallIcon;
        if (icon == null) {
            cli.System.IntPtr relativePIDL = getRelativePIDL();

            if (isFileSystem() && parent != null) {
                // These are cached per type (using the index in the system image list)
                int index = getIconIndex( ((Win32ShellFolder2)parent).getIShellFolder(), 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) {
                      cli.System.IntPtr hIcon = getIcon(getAbsolutePath(), getLargeIcon);
                        icon = makeIcon(hIcon, getLargeIcon);
                        disposeIcon(hIcon);
                        if (icon != null) {
                            imageCache.put(Integer.valueOf(index), icon);
                        }
                    }
                }
            }

            if (icon == null) {
                // These are only cached per object
              cli.System.IntPtr 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;
    }

    /**
     * Gets an icon from the Windows system icon list as an <code>Image</code>
     */
    static Image getShell32Icon(int iconID) {
        Bitmap bitmap = getShell32IconResourceAsBitmap(iconID);
        if (bitmap == null) {
            return null;
        }
        return new BufferedImage(bitmap);
    }
   
    private static native Bitmap getShell32IconResourceAsBitmap(int iconID);

    /**
     * Returns the canonical form of this abstract pathname.  Equivalent to
     * <code>new&nbsp;Win32ShellFolder2Orig(getParentFile(), this.{@link java.io.File#getCanonicalPath}())</code>.
     *
     * @see java.io.File#getCanonicalFile
     */
    public File getCanonicalFile() throws IOException {
        return this ;
    }

    /*
     * Indicates whether this is a special folder (includes My Documents)
     */
    public boolean isSpecial() {
        return isPersonal || !isFileSystem() || (this  == getDesktop());
    }

    /**
     * Compares this object with the specified object for order.
     *
     * @see sun.awt.shell.ShellFolder#compareTo(File)
     */
    public int compareTo(File file2) {
        if (!(file2 instanceof  Win32ShellFolder2)) {
            if (isFileSystem() && !isSpecial()) {
                return super .compareTo(file2);
            } else {
                return -1; // Non-file shellfolders sort before files
            }
        }
        return Win32ShellFolderManager2.compareShellFolders(this ,
                (Win32ShellFolder2) file2);
    }

    // native constants from commctrl.h
    private static final int LVCFMT_LEFT = 0;
    private static final int LVCFMT_RIGHT = 1;
    private static final int LVCFMT_CENTER = 2;

    public ShellFolderColumnInfo[] getFolderColumns() {
      Object o = doGetColumnInfo(getIShellFolder());
        ShellFolderColumnInfo[] columns = (ShellFolderColumnInfo[]) o;

        if (columns != null) {
            List<ShellFolderColumnInfo> notNullColumns = new ArrayList<ShellFolderColumnInfo>();
            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(i));

                    notNullColumns.add(column);
                }
            }
            columns = new ShellFolderColumnInfo[notNullColumns.size()];
            notNullColumns.toArray(columns);
        }
        return columns;
    }

    public Object getFolderColumnValue(int column) {
        return doGetColumnValue(getParentIShellFolder(), getRelativePIDL(), column);
    }

    private static native cli.System.Object /*ShellFolderColumnInfo[]*/ doGetColumnInfo( cli.System.Object iShellFolder2 );

    private static native Object doGetColumnValue(cli.System.Object parentIShellFolder2, cli.System.IntPtr childPIDL, int columnIdx);

    private static native int compareIDsByColumn(cli.System.Object pParentIShellFolder, cli.System.IntPtr pidl1, cli.System.IntPtr pidl2, int columnIdx);

    private class ColumnComparator implements  Comparator {
        private final int columnIdx;

        public ColumnComparator(int columnIdx) {
            this .columnIdx = columnIdx;
        }

        // compares 2 objects within this folder by the specified column
        public int compare(Object o, Object o1) {
            if (o instanceof  Win32ShellFolder2 && o1 instanceof  Win32ShellFolder2) {
                // delegates comparison to native method
                return compareIDsByColumn(getIShellFolder(),
                        ((Win32ShellFolder2) o).getRelativePIDL(),
                        ((Win32ShellFolder2) o1).getRelativePIDL(),
                        columnIdx);
            }
            return 0;
        }
    }
}
TOP

Related Classes of sun.awt.shell.Win32ShellFolder2$ColumnComparator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.