~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to external/ikvm/openjdk/sun/awt/shell/Win32ShellFolder2.java

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved.
 
3
 * Copyright (C) 2009 Volker Berlin (i-net software)
 
4
 * Copyright (C) 2010 Karsten Heinrich (i-net software)
 
5
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 
6
 *
 
7
 * This code is free software; you can redistribute it and/or modify it
 
8
 * under the terms of the GNU General Public License version 2 only, as
 
9
 * published by the Free Software Foundation.  Oracle designates this
 
10
 * particular file as subject to the "Classpath" exception as provided
 
11
 * by Oracle in the LICENSE file that accompanied this code.
 
12
 *
 
13
 * This code is distributed in the hope that it will be useful, but WITHOUT
 
14
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
15
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 
16
 * version 2 for more details (a copy is included in the LICENSE file that
 
17
 * accompanied this code).
 
18
 *
 
19
 * You should have received a copy of the GNU General Public License version
 
20
 * 2 along with this work; if not, write to the Free Software Foundation,
 
21
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 
22
 *
 
23
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 
24
 * or visit www.oracle.com if you need additional information or have any
 
25
 * questions.
 
26
 */
 
27
 
 
28
package sun.awt.shell;
 
29
 
 
30
import java.awt.Image;
 
31
import java.awt.image.BufferedImage;
 
32
import java.io.File;
 
33
import java.io.FileNotFoundException;
 
34
import java.io.IOException;
 
35
import java.util.*;
 
36
import java.util.concurrent.*;
 
37
import javax.swing.SwingConstants;
 
38
 
 
39
import cli.System.IntPtr;
 
40
import cli.System.Drawing.Bitmap;
 
41
 
 
42
// NOTE: This class basically a conversion of the OpenJDK Wen32ShellFolder2, but uses
 
43
// .NET pointers and objects instead of representing pointers as long
 
44
 
 
45
/**
 
46
 * Win32 Shell Folders
 
47
 * <P>
 
48
 * <BR>
 
49
 * There are two fundamental types of shell folders : file system folders
 
50
 * and non-file system folders.  File system folders are relatively easy
 
51
 * to deal with.  Non-file system folders are items such as My Computer,
 
52
 * Network Neighborhood, and the desktop.  Some of these non-file system
 
53
 * folders have special values and properties.
 
54
 * <P>
 
55
 * <BR>
 
56
 * Win32 keeps two basic data structures for shell folders.  The first
 
57
 * of these is called an ITEMIDLIST.  Usually a pointer, called an
 
58
 * LPITEMIDLIST, or more frequently just "PIDL".  This structure holds
 
59
 * a series of identifiers and can be either relative to the desktop
 
60
 * (an absolute PIDL), or relative to the shell folder that contains them.
 
61
 * Some Win32 functions can take absolute or relative PIDL values, and
 
62
 * others can only accept relative values.
 
63
 * <BR>
 
64
 * The second data structure is an IShellFolder COM interface.  Using
 
65
 * this interface, one can enumerate the relative PIDLs in a shell
 
66
 * folder, get attributes, etc.
 
67
 * <BR>
 
68
 * All Win32ShellFolder2 objects which are folder types (even non-file
 
69
 * system folders) contain an IShellFolder object. Files are named in
 
70
 * directories via relative PIDLs.
 
71
 *
 
72
 * @author Michael Martak
 
73
 * @author Leif Samuelsson
 
74
 * @author Kenneth Russell
 
75
 * @author Volker Berlin
 
76
 * @author Karsten Heinrich
 
77
 * @since 1.4 */
 
78
 
 
79
final class Win32ShellFolder2 extends ShellFolder {
 
80
 
 
81
    // Win32 Shell Folder Constants
 
82
    public static final int DESKTOP = 0x0000;
 
83
    public static final int INTERNET = 0x0001;
 
84
    public static final int PROGRAMS = 0x0002;
 
85
    public static final int CONTROLS = 0x0003;
 
86
    public static final int PRINTERS = 0x0004;
 
87
    public static final int PERSONAL = 0x0005;
 
88
    public static final int FAVORITES = 0x0006;
 
89
    public static final int STARTUP = 0x0007;
 
90
    public static final int RECENT = 0x0008;
 
91
    public static final int SENDTO = 0x0009;
 
92
    public static final int BITBUCKET = 0x000a;
 
93
    public static final int STARTMENU = 0x000b;
 
94
    public static final int DESKTOPDIRECTORY = 0x0010;
 
95
    public static final int DRIVES = 0x0011;
 
96
    public static final int NETWORK = 0x0012;
 
97
    public static final int NETHOOD = 0x0013;
 
98
    public static final int FONTS = 0x0014;
 
99
    public static final int TEMPLATES = 0x0015;
 
100
    public static final int COMMON_STARTMENU = 0x0016;
 
101
    public static final int COMMON_PROGRAMS = 0X0017;
 
102
    public static final int COMMON_STARTUP = 0x0018;
 
103
    public static final int COMMON_DESKTOPDIRECTORY = 0x0019;
 
104
    public static final int APPDATA = 0x001a;
 
105
    public static final int PRINTHOOD = 0x001b;
 
106
    public static final int ALTSTARTUP = 0x001d;
 
107
    public static final int COMMON_ALTSTARTUP = 0x001e;
 
108
    public static final int COMMON_FAVORITES = 0x001f;
 
109
    public static final int INTERNET_CACHE = 0x0020;
 
110
    public static final int COOKIES = 0x0021;
 
111
    public static final int HISTORY = 0x0022;
 
112
 
 
113
    // Win32 shell folder attributes
 
114
    public static final int ATTRIB_CANCOPY          = 0x00000001;
 
115
    public static final int ATTRIB_CANMOVE          = 0x00000002;
 
116
    public static final int ATTRIB_CANLINK          = 0x00000004;
 
117
    public static final int ATTRIB_CANRENAME        = 0x00000010;
 
118
    public static final int ATTRIB_CANDELETE        = 0x00000020;
 
119
    public static final int ATTRIB_HASPROPSHEET     = 0x00000040;
 
120
    public static final int ATTRIB_DROPTARGET       = 0x00000100;
 
121
    public static final int ATTRIB_LINK             = 0x00010000;
 
122
    public static final int ATTRIB_SHARE            = 0x00020000;
 
123
    public static final int ATTRIB_READONLY         = 0x00040000;
 
124
    public static final int ATTRIB_GHOSTED          = 0x00080000;
 
125
    public static final int ATTRIB_HIDDEN           = 0x00080000;
 
126
    public static final int ATTRIB_FILESYSANCESTOR  = 0x10000000;
 
127
    public static final int ATTRIB_FOLDER           = 0x20000000;
 
128
    public static final int ATTRIB_FILESYSTEM       = 0x40000000;
 
129
    public static final int ATTRIB_HASSUBFOLDER     = 0x80000000;
 
130
    public static final int ATTRIB_VALIDATE         = 0x01000000;
 
131
    public static final int ATTRIB_REMOVABLE        = 0x02000000;
 
132
    public static final int ATTRIB_COMPRESSED       = 0x04000000;
 
133
    public static final int ATTRIB_BROWSABLE        = 0x08000000;
 
134
    public static final int ATTRIB_NONENUMERATED    = 0x00100000;
 
135
    public static final int ATTRIB_NEWCONTENT       = 0x00200000;
 
136
 
 
137
    // IShellFolder::GetDisplayNameOf constants
 
138
    public static final int SHGDN_NORMAL            = 0;
 
139
    public static final int SHGDN_INFOLDER          = 1;
 
140
    public static final int SHGDN_INCLUDE_NONFILESYS= 0x2000;
 
141
    public static final int SHGDN_FORADDRESSBAR     = 0x4000;
 
142
    public static final int SHGDN_FORPARSING        = 0x8000;
 
143
 
 
144
    // Values for system call LoadIcon()
 
145
    public enum SystemIcon {
 
146
        IDI_APPLICATION(32512),
 
147
        IDI_HAND(32513),
 
148
        IDI_ERROR(32513),
 
149
        IDI_QUESTION(32514),
 
150
        IDI_EXCLAMATION(32515),
 
151
        IDI_WARNING(32515),
 
152
        IDI_ASTERISK(32516),
 
153
        IDI_INFORMATION(32516),
 
154
        IDI_WINLOGO(32517);
 
155
 
 
156
        private final int iconID;
 
157
 
 
158
        SystemIcon(int iconID) {
 
159
            this.iconID = iconID;
 
160
        }
 
161
 
 
162
        public int getIconID() {
 
163
            return iconID;
 
164
        }
 
165
    }
 
166
 
 
167
    static class FolderDisposer implements sun.java2d.DisposerRecord {
 
168
        /*
 
169
         * This is cached as a concession to getFolderType(), which needs
 
170
         * an absolute PIDL.
 
171
         */
 
172
        cli.System.IntPtr absolutePIDL;
 
173
        /*
 
174
         * We keep track of shell folders through the IShellFolder
 
175
         * interface of their parents plus their relative PIDL.
 
176
         */
 
177
        cli.System.Object pIShellFolder;
 
178
        cli.System.IntPtr relativePIDL;
 
179
 
 
180
        boolean disposed;
 
181
 
 
182
        @cli.System.Security.SecuritySafeCriticalAttribute.Annotation
 
183
        public void dispose() {
 
184
            if (disposed)
 
185
                return;
 
186
            if ( relativePIDL != null && !cli.System.IntPtr.Zero.Equals( relativePIDL ) ) {
 
187
                releasePIDL(relativePIDL);
 
188
            }
 
189
            if ( absolutePIDL != null && !cli.System.IntPtr.Zero.Equals( absolutePIDL ) ) {
 
190
                releasePIDL(absolutePIDL);
 
191
            }
 
192
            if ( pIShellFolder != null ) {
 
193
                releaseIShellFolder(pIShellFolder);
 
194
            }
 
195
            disposed = true;
 
196
        }
 
197
    }
 
198
 
 
199
    FolderDisposer disposer = new FolderDisposer();
 
200
 
 
201
    private void setIShellFolder( cli.System.Object iShellFolder ) {
 
202
        disposer.pIShellFolder = iShellFolder;
 
203
    }
 
204
 
 
205
    private void setRelativePIDL(cli.System.IntPtr relativePIDL) {
 
206
        disposer.relativePIDL = relativePIDL;
 
207
    }
 
208
 
 
209
    /*
 
210
     * The following are for caching various shell folder properties.
 
211
     */
 
212
    private cli.System.Object pIShellIcon = null;
 
213
    private String folderType = null;
 
214
    private String displayName = null;
 
215
    private Image smallIcon = null;
 
216
    private Image largeIcon = null;
 
217
    private Boolean isDir = null;
 
218
 
 
219
    /*
 
220
     * The following is to identify the My Documents folder as being special
 
221
     */
 
222
    private boolean isPersonal;
 
223
 
 
224
    /**
 
225
     * Create a system special shell folder, such as the
 
226
     * desktop or Network Neighborhood.
 
227
     */
 
228
    @cli.System.Security.SecuritySafeCriticalAttribute.Annotation
 
229
    Win32ShellFolder2(final int csidl) throws IOException, InterruptedException {
 
230
        // Desktop is parent of DRIVES and NETWORK, not necessarily
 
231
        // other special shell folders.
 
232
        super ( null, (getFileSystemPath(csidl) == null) ? ("ShellFolder: 0x" + Integer.toHexString(csidl)) : getFileSystemPath(csidl));
 
233
        if (csidl == DESKTOP) {
 
234
                // compared to the Java implementation we require two steps here since
 
235
                // we don't have a callback from the native methods in to this instance
 
236
            setIShellFolder( initDesktopFolder() );
 
237
            setRelativePIDL( initDesktopPIDL() );
 
238
        } else {
 
239
                cli.System.Object desktopFolder = getDesktop().getIShellFolder();
 
240
                cli.System.IntPtr pidl = initSpecialPIDL( desktopFolder, csidl );
 
241
            setRelativePIDL( pidl );
 
242
            setIShellFolder( initSpecialFolder(desktopFolder, pidl) );
 
243
            // At this point, the native method initSpecial() has set our relativePIDL
 
244
            // relative to the Desktop, which may not be our immediate parent. We need
 
245
            // to traverse this ID list and break it into a chain of shell folders from
 
246
            // the top, with each one having an immediate parent and a relativePIDL
 
247
            // relative to that parent.
 
248
            bindToDesktop();
 
249
        }
 
250
 
 
251
        sun.java2d.Disposer.addRecord(this , disposer);
 
252
    }
 
253
 
 
254
        @cli.System.Security.SecuritySafeCriticalAttribute.Annotation
 
255
        protected void bindToDesktop() {
 
256
                cli.System.IntPtr pIDL = disposer.relativePIDL;
 
257
                parent = getDesktop();
 
258
                while ( pIDL != null && !cli.System.IntPtr.Zero.Equals( pIDL ) ) {
 
259
                    // Get a child pidl relative to 'parent'
 
260
                        cli.System.IntPtr childPIDL = copyFirstPIDLEntry(pIDL);
 
261
                    if (childPIDL != null && !cli.System.IntPtr.Zero.Equals( childPIDL ) ) {
 
262
                        // Get a handle to the the rest of the ID list
 
263
                        // i,e, parent's grandchilren and down
 
264
                        pIDL = getNextPIDLEntry(pIDL);
 
265
                        if ( pIDL != null && !cli.System.IntPtr.Zero.Equals( pIDL ) ) {
 
266
                            // Now we know that parent isn't immediate to 'this' because it
 
267
                            // has a continued ID list. Create a shell folder for this child
 
268
                            // pidl and make it the new 'parent'.
 
269
                            parent = new Win32ShellFolder2( (Win32ShellFolder2) parent, childPIDL );
 
270
                        } else {
 
271
                            // No grandchildren means we have arrived at the parent of 'this',
 
272
                            // and childPIDL is directly relative to parent.
 
273
                            disposer.relativePIDL = childPIDL;
 
274
                        }
 
275
                    } else {
 
276
                        break;
 
277
                    }
 
278
                }
 
279
        }
 
280
 
 
281
    /**
 
282
     * Create a system shell folder
 
283
     */
 
284
    @cli.System.Security.SecurityCriticalAttribute.Annotation
 
285
    Win32ShellFolder2(Win32ShellFolder2 parent, cli.System.Object pIShellFolder, cli.System.IntPtr relativePIDL, String path) {
 
286
        super(parent, (path != null) ? path : "ShellFolder: ");
 
287
        this.disposer.pIShellFolder = pIShellFolder;
 
288
        this.disposer.relativePIDL = relativePIDL;
 
289
        sun.java2d.Disposer.addRecord(this, disposer);
 
290
    }
 
291
 
 
292
    /**
 
293
     * Creates a shell folder with a parent and relative PIDL
 
294
     */
 
295
    @cli.System.Security.SecurityCriticalAttribute.Annotation
 
296
    Win32ShellFolder2(Win32ShellFolder2 parent, cli.System.IntPtr relativePIDL) {
 
297
        super (parent, getFileSystemPath(parent.getIShellFolder(), relativePIDL));
 
298
        this .disposer.relativePIDL = relativePIDL;
 
299
        getAbsolutePath();
 
300
        sun.java2d.Disposer.addRecord(this , disposer);
 
301
    }
 
302
 
 
303
    // Initializes the desktop shell folder
 
304
    /**
 
305
     * Returns the pIDL of the Desktop folder (pIDL root)
 
306
     * @return the pIDL of the Desktop folder (pIDL root)
 
307
     */
 
308
    @cli.System.Security.SecurityCriticalAttribute.Annotation
 
309
    private static native cli.System.IntPtr initDesktopPIDL();
 
310
    /**
 
311
     * Returns the IShellFolder pointer of the Desktop folder (pIDL root)
 
312
     * @return the IShellFolder pointer of the Desktop folder (pIDL root)
 
313
     */
 
314
    @cli.System.Security.SecurityCriticalAttribute.Annotation
 
315
    private static native cli.System.Object initDesktopFolder();
 
316
 
 
317
    // Initializes a special, non-file system shell folder
 
318
    // from one of the above constants
 
319
    /**
 
320
     * initializes a special folder
 
321
     * @param desktopIShellFolder the IShellFolder reference of the desktop folder
 
322
     * @param csidl the CSIDL of the requested special folder
 
323
     * @return the pIDL of the special folder relative to the desktop root
 
324
     */
 
325
    @cli.System.Security.SecurityCriticalAttribute.Annotation
 
326
    private static native cli.System.IntPtr initSpecialPIDL(cli.System.Object desktopIShellFolder, int csidl);
 
327
    /**
 
328
     * initializes a special folder
 
329
     * @param desktopIShellFolder the IShellFolder reference of the desktop folder
 
330
     * @param pidl the pIDL of the requested folder relative to the desktopIShellFolder
 
331
     * @return the IShellFolder reference for the requested folder
 
332
     */
 
333
    @cli.System.Security.SecurityCriticalAttribute.Annotation
 
334
    private static native cli.System.Object initSpecialFolder(cli.System.Object desktopIShellFolder, cli.System.IntPtr pidl);
 
335
 
 
336
    /** Marks this folder as being the My Documents (Personal) folder */
 
337
    public void setIsPersonal() {
 
338
        isPersonal = true;
 
339
    }
 
340
 
 
341
    /**
 
342
     * This method is implemented to make sure that no instances
 
343
     * of <code>ShellFolder</code> are ever serialized. If <code>isFileSystem()</code> returns
 
344
     * <code>true</code>, then the object is representable with an instance of
 
345
     * <code>java.io.File</code> instead. If not, then the object depends
 
346
     * on native PIDL state and should not be serialized.
 
347
     *
 
348
     * @returns a <code>java.io.File</code> replacement object. If the folder
 
349
     * is a not a normal directory, then returns the first non-removable
 
350
     * drive (normally "C:\").
 
351
     */
 
352
    protected Object writeReplace()
 
353
            throws java.io.ObjectStreamException {
 
354
        if (isFileSystem()) {
 
355
            return new File(getPath());
 
356
        } else {
 
357
            Win32ShellFolder2 drives = Win32ShellFolderManager2.getDrives();
 
358
            if (drives != null) {
 
359
                File[] driveRoots = drives.listFiles();
 
360
                if (driveRoots != null) {
 
361
                    for (int i = 0; i < driveRoots.length; i++) {
 
362
                        if (driveRoots[i] instanceof  Win32ShellFolder2) {
 
363
                            Win32ShellFolder2 sf = (Win32ShellFolder2) driveRoots[i];
 
364
                            if (sf.isFileSystem() && !sf.hasAttribute(ATTRIB_REMOVABLE)) {
 
365
                                return new File(sf.getPath());
 
366
                            }
 
367
                        }
 
368
                    }
 
369
                }
 
370
            }
 
371
            // Ouch, we have no hard drives. Return something "valid" anyway.
 
372
            return new File("C:\\");
 
373
        }
 
374
    }
 
375
 
 
376
    /**
 
377
     * Finalizer to clean up any COM objects or PIDLs used by this object.
 
378
     */
 
379
    protected void dispose() {
 
380
        disposer.dispose();
 
381
    }
 
382
 
 
383
    // Given a (possibly multi-level) relative PIDL (with respect to
 
384
    // the desktop, at least in all of the usage cases in this code),
 
385
    // return a pointer to the next entry. Does not mutate the PIDL in
 
386
    // any way. Returns 0 if the null terminator is reached.
 
387
    // Needs to be accessible to Win32ShellFolderManager2
 
388
    @cli.System.Security.SecurityCriticalAttribute.Annotation
 
389
    static native cli.System.IntPtr getNextPIDLEntry(cli.System.IntPtr pIDL);
 
390
 
 
391
    // Given a (possibly multi-level) relative PIDL (with respect to
 
392
    // the desktop, at least in all of the usage cases in this code),
 
393
    // copy the first entry into a newly-allocated PIDL. Returns 0 if
 
394
    // the PIDL is at the end of the list.
 
395
    // Needs to be accessible to Win32ShellFolderManager2
 
396
    @cli.System.Security.SecurityCriticalAttribute.Annotation
 
397
    static native cli.System.IntPtr copyFirstPIDLEntry(cli.System.IntPtr pIDL);
 
398
 
 
399
    // Given a parent's absolute PIDL and our relative PIDL, build an absolute PIDL
 
400
    /**
 
401
     * Combines a parent pIDL with a descendant pIDL. It doesn't matter whether the parent pIDL
 
402
     * is relative or absolute since this is only a concatenation of the IDLs
 
403
     * @param ppIDL the parent pIDL
 
404
     * @param pIDL the pIDL relative to the ppIDL
 
405
     * @return a pIDL for the item referenced by the original pIDL but relative to the parent of ppIDL 
 
406
     */
 
407
    @cli.System.Security.SecurityCriticalAttribute.Annotation
 
408
    private static native cli.System.IntPtr combinePIDLs(cli.System.IntPtr ppIDL, cli.System.IntPtr pIDL);
 
409
 
 
410
    // Release a PIDL object
 
411
    // Needs to be accessible to Win32ShellFolderManager2
 
412
    @cli.System.Security.SecurityCriticalAttribute.Annotation
 
413
    static native void releasePIDL(cli.System.IntPtr pIDL);
 
414
 
 
415
    // Release an IShellFolder object
 
416
    @cli.System.Security.SecurityCriticalAttribute.Annotation
 
417
    static native void releaseIShellFolder( cli.System.Object iShellFolder );
 
418
 
 
419
    /**
 
420
     * Accessor for IShellFolder
 
421
     */
 
422
    @cli.System.Security.SecuritySafeCriticalAttribute.Annotation
 
423
    public cli.System.Object getIShellFolder() {
 
424
        if (disposer.pIShellFolder == null ) {
 
425
            assert (isDirectory());
 
426
            assert (parent != null);
 
427
            cli.System.Object parentIShellFolder = getParentIShellFolder();
 
428
            if (parentIShellFolder == null) {
 
429
                throw new InternalError( "Parent IShellFolder was null for " + getAbsolutePath() );
 
430
            }
 
431
            // We are a directory with a parent and a relative PIDL.
 
432
            // We want to bind to the parent so we get an IShellFolder instance associated with us.
 
433
            disposer.pIShellFolder = bindToObject(parentIShellFolder, disposer.relativePIDL);
 
434
            if (disposer.pIShellFolder == null ) {
 
435
                throw new InternalError("Unable to bind " + getAbsolutePath() + " to parent");
 
436
            }
 
437
        }
 
438
        return disposer.pIShellFolder;
 
439
    }
 
440
 
 
441
    /**
 
442
     * Get the parent ShellFolder's IShellFolder interface
 
443
     */
 
444
    public cli.System.Object getParentIShellFolder() {
 
445
        Win32ShellFolder2 parent = (Win32ShellFolder2) getParentFile();
 
446
        cli.System.Object parentFolder;
 
447
        if (parent == null) {
 
448
            // Parent should only be null if this is the desktop, whose
 
449
            // relativePIDL is relative to its own IShellFolder.
 
450
                parentFolder = getIShellFolder();
 
451
        } else {
 
452
                parentFolder = parent.getIShellFolder();
 
453
        }
 
454
        return parentFolder;
 
455
    }
 
456
 
 
457
    /**
 
458
     * Accessor for relative PIDL
 
459
     */
 
460
    public cli.System.IntPtr getRelativePIDL() {
 
461
        if (disposer.relativePIDL == null) {
 
462
            throw new InternalError( "Should always have a relative PIDL" );
 
463
        }
 
464
        return disposer.relativePIDL;
 
465
    }
 
466
 
 
467
    @cli.System.Security.SecuritySafeCriticalAttribute.Annotation
 
468
    private cli.System.IntPtr getAbsolutePIDL() {
 
469
        if (parent == null) {
 
470
            // This is the desktop
 
471
            return getRelativePIDL();
 
472
        } else {
 
473
            if (disposer.absolutePIDL == null || disposer.absolutePIDL.Equals( IntPtr.Zero )) {
 
474
                disposer.absolutePIDL = combinePIDLs( ((Win32ShellFolder2) parent).getAbsolutePIDL(), getRelativePIDL());
 
475
            }
 
476
 
 
477
            return disposer.absolutePIDL;
 
478
        }
 
479
    }
 
480
 
 
481
    /**
 
482
     * Helper function to return the desktop
 
483
     */
 
484
    public Win32ShellFolder2 getDesktop() {
 
485
        return Win32ShellFolderManager2.getDesktop();
 
486
    }
 
487
 
 
488
    /**
 
489
     * Helper function to return the desktop IShellFolder interface
 
490
     */
 
491
    public cli.System.Object getDesktopIShellFolder() {
 
492
        return getDesktop().getIShellFolder();
 
493
    }
 
494
 
 
495
    private static boolean pathsEqual(String path1, String path2) {
 
496
        // Same effective implementation as Win32FileSystem
 
497
        return path1.equalsIgnoreCase(path2);
 
498
    }
 
499
 
 
500
    /**
 
501
     * Check to see if two ShellFolder objects are the same
 
502
     */
 
503
    @cli.System.Security.SecuritySafeCriticalAttribute.Annotation
 
504
    public boolean equals(Object o) {
 
505
        if (o == null || !(o instanceof Win32ShellFolder2)) {
 
506
            // Short-circuit circuitous delegation path
 
507
            if (!(o instanceof File)) {
 
508
                return super.equals(o);
 
509
            }
 
510
            return pathsEqual(getPath(), ((File) o).getPath());
 
511
        }
 
512
        Win32ShellFolder2 rhs = (Win32ShellFolder2) o;
 
513
        if ((parent == null && rhs.parent != null) ||
 
514
            (parent != null && rhs.parent == null)) {
 
515
            return false;
 
516
        }
 
517
 
 
518
        if (isFileSystem() && rhs.isFileSystem()) {
 
519
            // Only folders with identical parents can be equal
 
520
            return (pathsEqual(getPath(), rhs.getPath()) &&
 
521
                    (parent == rhs.parent || parent.equals(rhs.parent)));
 
522
        }
 
523
 
 
524
        if (parent == rhs.parent || parent.equals(rhs.parent)) {
 
525
            try {
 
526
                return pidlsEqual(getParentIShellFolder(), disposer.relativePIDL, rhs.disposer.relativePIDL);
 
527
            } catch (InterruptedException e) {
 
528
                return false;
 
529
            }
 
530
        }
 
531
 
 
532
        return false;
 
533
    }
 
534
 
 
535
    @cli.System.Security.SecurityCriticalAttribute.Annotation
 
536
    static boolean pidlsEqual(final cli.System.Object pIShellFolder, final cli.System.IntPtr pidl1, final cli.System.IntPtr pidl2)
 
537
            throws InterruptedException {
 
538
        return invoke(new Callable<Boolean>() {
 
539
            @cli.System.Security.SecuritySafeCriticalAttribute.Annotation
 
540
            public Boolean call() {
 
541
                return compareIDs(pIShellFolder, pidl1, pidl2) == 0;
 
542
            }
 
543
        }, RuntimeException.class);
 
544
    }
 
545
 
 
546
    @cli.System.Security.SecurityCriticalAttribute.Annotation
 
547
    static native int compareIDs(cli.System.Object pParentIShellFolder, cli.System.IntPtr pidl1, cli.System.IntPtr pidl2);
 
548
 
 
549
    private volatile Boolean cachedIsFileSystem;
 
550
 
 
551
    /**
 
552
     * @return Whether this is a file system shell folder
 
553
     */
 
554
    public boolean isFileSystem() {
 
555
        if (cachedIsFileSystem == null) {
 
556
            cachedIsFileSystem = hasAttribute(ATTRIB_FILESYSTEM);
 
557
        }
 
558
 
 
559
        return cachedIsFileSystem;
 
560
    }
 
561
 
 
562
    /**
 
563
     * Return whether the given attribute flag is set for this object
 
564
     */
 
565
    @cli.System.Security.SecuritySafeCriticalAttribute.Annotation
 
566
    public boolean hasAttribute(int attribute) {
 
567
        // Caching at this point doesn't seem to be cost efficient
 
568
        return (getAttributes0(getParentIShellFolder(), getRelativePIDL(), attribute) & attribute) != 0;
 
569
    }
 
570
 
 
571
    /**
 
572
     * Returns the queried attributes specified in attrsMask.
 
573
     *
 
574
     * Could plausibly be used for attribute caching but have to be
 
575
     * very careful not to touch network drives and file system roots
 
576
     * with a full attrsMask
 
577
     */
 
578
    @cli.System.Security.SecurityCriticalAttribute.Annotation
 
579
    static native int getAttributes0(cli.System.Object pParentIShellFolder, cli.System.IntPtr pIDL, int attrsMask);
 
580
 
 
581
    // Return the path to the underlying file system object
 
582
    @cli.System.Security.SecurityCriticalAttribute.Annotation
 
583
    private static String getFileSystemPath(cli.System.Object parentIShellFolder, cli.System.IntPtr relativePIDL) {
 
584
        int linkedFolder = ATTRIB_LINK | ATTRIB_FOLDER;
 
585
        if (parentIShellFolder == Win32ShellFolderManager2.getNetwork().getIShellFolder() &&
 
586
                getAttributes0(parentIShellFolder, relativePIDL, linkedFolder) == linkedFolder) {
 
587
 
 
588
                cli.System.Object desktopIShellFolder = Win32ShellFolderManager2.getDesktop().getIShellFolder();
 
589
            String path = getDisplayNameOf(parentIShellFolder, relativePIDL, SHGDN_FORPARSING );
 
590
                        String s = getFileSystemPath(desktopIShellFolder, getLinkLocation( path, false));
 
591
            if (s != null && s.startsWith("\\\\")) {
 
592
                return s;
 
593
            }
 
594
        }
 
595
        return getDisplayNameOf(parentIShellFolder, relativePIDL, SHGDN_NORMAL | SHGDN_FORPARSING);
 
596
    }
 
597
 
 
598
    // Needs to be accessible to Win32ShellFolderManager2
 
599
    @cli.System.Security.SecurityCriticalAttribute.Annotation
 
600
    static native String getFileSystemPath(int csidl) throws IOException, InterruptedException;
 
601
 
 
602
    // Return whether the path is a network root.
 
603
    // Path is assumed to be non-null
 
604
    private static boolean isNetworkRoot(String path) {
 
605
        return (path.equals("\\\\") || path.equals("\\") || path.equals("//") || path.equals("/"));
 
606
    }
 
607
 
 
608
    /**
 
609
     * @return The parent shell folder of this shell folder, null if
 
610
     * there is no parent
 
611
     */
 
612
    public File getParentFile() {
 
613
        return parent;
 
614
    }
 
615
 
 
616
    public boolean isDirectory() {
 
617
        if (isDir == null) {
 
618
            // Folders with SFGAO_BROWSABLE have "shell extension" handlers and are
 
619
            // not traversable in JFileChooser.
 
620
            if (hasAttribute(ATTRIB_FOLDER) && !hasAttribute(ATTRIB_BROWSABLE)) {
 
621
                isDir = Boolean.TRUE;
 
622
            } else if (isLink()) {
 
623
                ShellFolder linkLocation = getLinkLocation(false);
 
624
                isDir = Boolean.valueOf(linkLocation != null && linkLocation.isDirectory());
 
625
            } else {
 
626
                isDir = Boolean.FALSE;
 
627
            }
 
628
        }
 
629
        return isDir.booleanValue();
 
630
    }
 
631
 
 
632
    /*
 
633
     * Functions for enumerating an IShellFolder's children
 
634
     */
 
635
    // Returns an IEnumIDList interface for an IShellFolder.  The value
 
636
    // returned must be released using releaseEnumObjects().
 
637
    /**
 
638
     * Returns an IEnumIDList interface for an IShellFolder.  The value 
 
639
     * returned must be released using releaseEnumObjects().
 
640
     * @param pIShellFolder the IShellFolder instance of the parent shell folder
 
641
     * @param includeHiddenFiles if true, hidden files will be included in the enumeration
 
642
     * @return an instance of IEnumIDList 
 
643
     */
 
644
    @cli.System.Security.SecurityCriticalAttribute.Annotation
 
645
    cli.System.Object getEnumObjects(cli.System.Object pIShellFolder, boolean includeHiddenFiles) {
 
646
        boolean isDesktop = (disposer.pIShellFolder == getDesktopIShellFolder());
 
647
        return getEnumObjects(disposer.pIShellFolder, isDesktop, includeHiddenFiles);
 
648
    }
 
649
 
 
650
    /**
 
651
     * Returns an IEnumIDList interface for an IShellFolder.  The value 
 
652
     * returned must be released using releaseEnumObjects().
 
653
     * @param pIShellFolder the IShellFolder instance of the parent shell folder
 
654
     * @param isDesktop must be set to true, if the pIShellFolder is the desktop shell folder
 
655
     * @param includeHiddenFiles if true, hidden files will be included in the enumeration
 
656
     * @return an instance of IEnumIDList 
 
657
     */
 
658
    @cli.System.Security.SecurityCriticalAttribute.Annotation
 
659
    private static native cli.System.Object getEnumObjects(cli.System.Object pIShellFolder, boolean isDesktop, boolean includeHiddenFiles);
 
660
 
 
661
    /**
 
662
     * Returns the next sequential child as a relative PIDL
 
663
     * from an IEnumIDList interface.  The value returned must
 
664
     * be released using releasePIDL().
 
665
     * @param pEnumObjects the IEnumIDList instance to get the next child from
 
666
     * @return the next child or {@link IntPtr#Zero} if the end of the enumeration is reached 
 
667
     */
 
668
    @cli.System.Security.SecurityCriticalAttribute.Annotation
 
669
    static native cli.System.IntPtr getNextChild(cli.System.Object pEnumObjects);
 
670
 
 
671
    /**
 
672
     * Releases the IEnumIDList interface
 
673
     * @param pEnumObjects an IEnumIDList instance 
 
674
     */
 
675
    @cli.System.Security.SecurityCriticalAttribute.Annotation
 
676
    static native void releaseEnumObjects(cli.System.Object pEnumObjects);
 
677
 
 
678
    /**
 
679
     * Returns the IShellFolder of a child from a parent IShellFolder and a relative pIDL. The pIDL
 
680
     * may as well be any other  descendant of the shell folder - at least this is, what the windows API 
 
681
     * documentation says.  
 
682
     * The value returned must be released using releaseIShellFolder().
 
683
     * @param parentIShellFolder an IShellFolder instance as root for the pIDL 
 
684
     * @param pIDL a pIDL relative to the parent shell folder
 
685
     * @return a NEW instance of an IShellFolder for the path given by the pIDL, may be null if the path is invalid
 
686
     */
 
687
    @cli.System.Security.SecurityCriticalAttribute.Annotation
 
688
    private static native cli.System.Object bindToObject(cli.System.Object parentIShellFolder, cli.System.IntPtr pIDL);
 
689
 
 
690
    /**
 
691
     * @return An array of shell folders that are children of this shell folder
 
692
     *         object. The array will be empty if the folder is empty.  Returns
 
693
     *         <code>null</code> if this shellfolder does not denote a directory.
 
694
     */
 
695
    @cli.System.Security.SecuritySafeCriticalAttribute.Annotation
 
696
    public File[] listFiles(final boolean includeHiddenFiles) {
 
697
        SecurityManager security = System.getSecurityManager();
 
698
        if (security != null) {
 
699
            security.checkRead(getPath());
 
700
        }
 
701
 
 
702
        try {
 
703
            return invoke(new Callable<File[]>() {
 
704
                @cli.System.Security.SecuritySafeCriticalAttribute.Annotation
 
705
                public File[] call() throws InterruptedException {
 
706
                    if (!isDirectory()) {
 
707
                        return null;
 
708
                    }
 
709
                    // Links to directories are not directories and cannot be parents.
 
710
                    // This does not apply to folders in My Network Places (NetHood)
 
711
                    // because they are both links and real directories!
 
712
                    if (isLink() && !hasAttribute(ATTRIB_FOLDER)) {
 
713
                        return new File[0];
 
714
                    }
 
715
 
 
716
                    Win32ShellFolder2 desktop = Win32ShellFolderManager2.getDesktop();
 
717
                    Win32ShellFolder2 personal = Win32ShellFolderManager2.getPersonal();
 
718
 
 
719
                    // If we are a directory, we have a parent and (at least) a
 
720
                    // relative PIDL. We must first ensure we are bound to the
 
721
                    // parent so we have an IShellFolder to query.
 
722
                    cli.System.Object pIShellFolder = getIShellFolder();
 
723
                    // Now we can enumerate the objects in this folder.
 
724
                    ArrayList<Win32ShellFolder2> list = new ArrayList<Win32ShellFolder2>();
 
725
                    cli.System.Object pEnumObjects = getEnumObjects(pIShellFolder, includeHiddenFiles);
 
726
                    if (pEnumObjects != null) {
 
727
                        cli.System.IntPtr childPIDL = null;
 
728
                        int testedAttrs = ATTRIB_FILESYSTEM | ATTRIB_FILESYSANCESTOR;
 
729
                        do {
 
730
                            if (Thread.currentThread().isInterrupted()) {
 
731
                                return new File[0];
 
732
                            }
 
733
                            childPIDL = getNextChild(pEnumObjects);
 
734
                            boolean releasePIDL = true;
 
735
                            if ( childPIDL != null && !cli.System.IntPtr.Zero.Equals( childPIDL ) && (getAttributes0(pIShellFolder, childPIDL, testedAttrs) & testedAttrs) != 0) {
 
736
                                Win32ShellFolder2 childFolder = null;
 
737
                                if (this .equals(desktop) && personal != null
 
738
                                        && pidlsEqual(pIShellFolder, childPIDL, personal.disposer.relativePIDL) ) {
 
739
                                    childFolder = personal;
 
740
                                } else {
 
741
                                    childFolder = new Win32ShellFolder2(Win32ShellFolder2.this , childPIDL);
 
742
                                    releasePIDL = false;
 
743
                                }
 
744
                                list.add(childFolder);
 
745
                            }
 
746
                            if (releasePIDL) {
 
747
                                releasePIDL(childPIDL);
 
748
                            }
 
749
                        } while (childPIDL != null && !childPIDL.Equals( cli.System.IntPtr.Zero ));
 
750
                        releaseEnumObjects(pEnumObjects);
 
751
                    }
 
752
                    return Thread.currentThread().isInterrupted()
 
753
                        ? new File[0]
 
754
                        : list.toArray(new ShellFolder[list.size()]);
 
755
                }
 
756
            }, InterruptedException.class);
 
757
        } catch (InterruptedException e) {
 
758
            return new File[0];
 
759
        }
 
760
    }
 
761
 
 
762
 
 
763
    /**
 
764
     * Look for (possibly special) child folder by it's path. Note: this will not work an an ancestor(not child)
 
765
     * of the current folder. 
 
766
     * @return The child shell folder, or null if not found.
 
767
     */
 
768
    @cli.System.Security.SecuritySafeCriticalAttribute.Annotation
 
769
    Win32ShellFolder2 getChildByPath(String filePath) {
 
770
        cli.System.Object pIShellFolder = getIShellFolder();
 
771
        cli.System.Object pEnumObjects = getEnumObjects(pIShellFolder, true);
 
772
        Win32ShellFolder2 child = null;
 
773
        cli.System.IntPtr childPIDL = null;
 
774
        
 
775
        childPIDL = getNextChild(pEnumObjects);
 
776
        while ( childPIDL != null && !cli.System.IntPtr.Zero.Equals( childPIDL ) ) {
 
777
            if (getAttributes0(pIShellFolder, childPIDL, ATTRIB_FILESYSTEM) != 0) {
 
778
                String path = getFileSystemPath(pIShellFolder, childPIDL);
 
779
                if (path != null && path.equalsIgnoreCase(filePath)) {
 
780
                        cli.System.Object childIShellFolder = bindToObject( pIShellFolder, childPIDL);
 
781
                    child = new Win32ShellFolder2(this, childIShellFolder, childPIDL, path);
 
782
                    break;
 
783
                }
 
784
            }
 
785
            releasePIDL(childPIDL);
 
786
            childPIDL = getNextChild(pEnumObjects);
 
787
        }
 
788
        releaseEnumObjects(pEnumObjects);
 
789
        return child;
 
790
    }
 
791
 
 
792
    private volatile Boolean cachedIsLink;
 
793
 
 
794
    /**
 
795
     * @return Whether this shell folder is a link
 
796
     */
 
797
    public boolean isLink() {
 
798
        if (cachedIsLink == null) {
 
799
            cachedIsLink = hasAttribute(ATTRIB_LINK);
 
800
        }
 
801
 
 
802
        return cachedIsLink;
 
803
    }
 
804
 
 
805
    /**
 
806
     * @return Whether this shell folder is marked as hidden
 
807
     */
 
808
    public boolean isHidden() {
 
809
        return hasAttribute(ATTRIB_HIDDEN);
 
810
    }
 
811
 
 
812
    // Return the link location of a shell folder
 
813
    /**
 
814
     * Resolves the link location of an item to an ABSOLUTE pIDL
 
815
     * @param parentIShellFolder the pointer to the parent IShellFolder of the item
 
816
     * @param relativePIDL a single-level pIDL to the item
 
817
     * @param resolve 
 
818
     */
 
819
    @cli.System.Security.SecurityCriticalAttribute.Annotation
 
820
    static native cli.System.IntPtr getLinkLocation( String path, boolean resolve);
 
821
 
 
822
    /**
 
823
     * @return The shell folder linked to by this shell folder, or null
 
824
     * if this shell folder is not a link or is a broken or invalid link
 
825
     */
 
826
    public ShellFolder getLinkLocation()  {
 
827
        return getLinkLocation(true);
 
828
    }
 
829
 
 
830
    @cli.System.Security.SecuritySafeCriticalAttribute.Annotation
 
831
    private ShellFolder getLinkLocation(final boolean resolve) {
 
832
        return invoke(new Callable<ShellFolder>() {
 
833
            @cli.System.Security.SecuritySafeCriticalAttribute.Annotation
 
834
            public ShellFolder call() {
 
835
                if (!isLink()) {
 
836
                    return null;
 
837
                }
 
838
 
 
839
                ShellFolder location = null;
 
840
                cli.System.IntPtr linkLocationPIDL = getLinkLocation( getAbsolutePath(), resolve);
 
841
                if (linkLocationPIDL != null && !cli.System.IntPtr.Zero.Equals( linkLocationPIDL ) ) {
 
842
                    try {
 
843
                        location =
 
844
                                Win32ShellFolderManager2.createShellFolderFromRelativePIDL(getDesktop(),
 
845
                                        linkLocationPIDL);
 
846
                    } catch (InterruptedException e) {
 
847
                        // Return null
 
848
                    } catch (InternalError e) {
 
849
                        // Could be a link to a non-bindable object, such as a network connection
 
850
                        // TODO: getIShellFolder() should throw FileNotFoundException instead
 
851
                    }
 
852
                }
 
853
                return location;
 
854
            }
 
855
        });
 
856
    }
 
857
 
 
858
    /**
 
859
     * Parse a display name into a PIDL relative to the current IShellFolder.
 
860
     * @param name the name or relative path
 
861
     * @return a pIDL for the path, may be {@link IntPtr#Zero} if not found
 
862
     * @throws FileNotFoundException
 
863
     */
 
864
    @cli.System.Security.SecurityCriticalAttribute.Annotation
 
865
    cli.System.IntPtr parseDisplayName(String name) throws FileNotFoundException {
 
866
        try {
 
867
            return parseDisplayName0(getIShellFolder(), name);
 
868
        } catch (IOException e) {
 
869
            throw new FileNotFoundException("Could not find file " + name);
 
870
        }
 
871
    }
 
872
 
 
873
    @cli.System.Security.SecurityCriticalAttribute.Annotation
 
874
    private static native cli.System.IntPtr parseDisplayName0(cli.System.Object pIShellFolder, String name) throws IOException;
 
875
 
 
876
    /**
 
877
     * Returns the display name of an item in a folder
 
878
     * @param parentIShellFolder the pointer to the IShellFolder interface of the parent folder
 
879
     * @param relativePIDL single-level pIDL to the requested item within the parent folder
 
880
     * @param attrs formatting attributes for the display name, refer to SHGDN in MSDN
 
881
     * @return
 
882
     */
 
883
    @cli.System.Security.SecurityCriticalAttribute.Annotation
 
884
    private static native String getDisplayNameOf( cli.System.Object parentIShellFolder, cli.System.IntPtr relativePIDL, int attrs);
 
885
 
 
886
    /**
 
887
     * @return The name used to display this shell folder
 
888
     */
 
889
    @cli.System.Security.SecuritySafeCriticalAttribute.Annotation
 
890
    public String getDisplayName() {
 
891
        if (displayName == null) {
 
892
            displayName = getDisplayNameOf(getParentIShellFolder(), getRelativePIDL(), SHGDN_NORMAL);
 
893
        }
 
894
        return displayName;
 
895
    }
 
896
 
 
897
    // Return the folder type of a shell folder
 
898
    @cli.System.Security.SecurityCriticalAttribute.Annotation
 
899
    private static native String getFolderType(cli.System.IntPtr pIDL);
 
900
 
 
901
    /**
 
902
     * @return The type of shell folder as a string
 
903
     */
 
904
    @cli.System.Security.SecuritySafeCriticalAttribute.Annotation
 
905
    public String getFolderType() {
 
906
        if (folderType == null) {
 
907
            folderType = getFolderType(getAbsolutePIDL());
 
908
        }
 
909
        return folderType;
 
910
    }
 
911
 
 
912
    // Return the executable type of a file system shell folder
 
913
    private static native String getExecutableType(String path);
 
914
 
 
915
    /**
 
916
     * @return The executable type as a string
 
917
     */
 
918
    public String getExecutableType() {
 
919
        if (!isFileSystem()) {
 
920
            return null;
 
921
        }
 
922
        return getExecutableType(getAbsolutePath());
 
923
    }
 
924
 
 
925
    // Icons
 
926
 
 
927
    private static Map smallSystemImages = new HashMap();
 
928
    private static Map largeSystemImages = new HashMap();
 
929
    private static Map smallLinkedSystemImages = new HashMap();
 
930
    private static Map largeLinkedSystemImages = new HashMap();
 
931
 
 
932
    /**
 
933
     * Returns the icon index in the system image list  
 
934
     * @param parentIShellIcon the the pointer to the IShellIcon instance of the parent folder 
 
935
     * @param relativePIDL the relative pIDL to the requested item
 
936
     * @return the system image list index for the icon of the item or zero, if there is no entry
 
937
     */
 
938
    @cli.System.Security.SecurityCriticalAttribute.Annotation
 
939
    private static native int getIconIndex(cli.System.Object parentIShellFolder, cli.System.IntPtr relativePIDL);
 
940
 
 
941
    // Return the icon of a file system shell folder in the form of an HICON
 
942
    @cli.System.Security.SecurityCriticalAttribute.Annotation
 
943
    private static native cli.System.IntPtr getIcon(String absolutePath, boolean getLargeIcon);
 
944
 
 
945
    @cli.System.Security.SecurityCriticalAttribute.Annotation
 
946
    private static native cli.System.IntPtr extractIcon(cli.System.Object parentIShellFolder, cli.System.IntPtr relativePIDL,
 
947
                                           boolean getLargeIcon);
 
948
 
 
949
    /**
 
950
     * Returns the {@link Bitmap} for a HICON.
 
951
     */
 
952
    @cli.System.Security.SecurityCriticalAttribute.Annotation
 
953
    private static native Bitmap getIconBits(cli.System.IntPtr hIcon, int size);
 
954
 
 
955
    /**
 
956
     * Disposes a icon handle
 
957
     * @param hIcon the handle to be disposed
 
958
     */
 
959
    @cli.System.Security.SecurityCriticalAttribute.Annotation
 
960
    private static native void disposeIcon(cli.System.IntPtr hIcon);
 
961
 
 
962
    @cli.System.Security.SecurityCriticalAttribute.Annotation
 
963
    static native Bitmap getStandardViewButton0(int iconIndex);
 
964
 
 
965
    /**
 
966
     * Creates a Java icon for a HICON pointer
 
967
     * @param hIcon the handle for the icon
 
968
     * @param getLargeIcon true for a large icon, false for a small icon
 
969
     * @return the created image or null, if the handle is invalid
 
970
     */
 
971
    @cli.System.Security.SecurityCriticalAttribute.Annotation
 
972
    private static Image makeIcon(cli.System.IntPtr hIcon, boolean getLargeIcon) {
 
973
        if (hIcon != null ) {
 
974
            // Get the bits.  This has the side effect of setting the imageHash value for this object.
 
975
            Bitmap bitmap = getIconBits(hIcon, getLargeIcon ? 32 : 16 );
 
976
            if (bitmap == null) {
 
977
                return null;
 
978
            }            
 
979
            return new BufferedImage(bitmap);
 
980
        }
 
981
        return null;
 
982
    }
 
983
 
 
984
 
 
985
    /**
 
986
     * @return The icon image used to display this shell folder
 
987
     */
 
988
    @cli.System.Security.SecuritySafeCriticalAttribute.Annotation
 
989
    public Image getIcon(boolean getLargeIcon) {
 
990
        Image icon = getLargeIcon ? largeIcon : smallIcon;
 
991
        if (icon == null) {
 
992
            cli.System.IntPtr relativePIDL = getRelativePIDL();
 
993
 
 
994
            if (isFileSystem() && parent != null) {
 
995
                // These are cached per type (using the index in the system image list)
 
996
                int index = getIconIndex( ((Win32ShellFolder2)parent).getIShellFolder(), relativePIDL);
 
997
                if (index > 0) {
 
998
                    Map imageCache;
 
999
                    if (isLink()) {
 
1000
                        imageCache = getLargeIcon ? largeLinkedSystemImages : smallLinkedSystemImages;
 
1001
                    } else {
 
1002
                        imageCache = getLargeIcon ? largeSystemImages : smallSystemImages;
 
1003
                    }
 
1004
                    icon = (Image) imageCache.get(Integer.valueOf(index));
 
1005
                    if (icon == null) {
 
1006
                        cli.System.IntPtr hIcon = getIcon(getAbsolutePath(), getLargeIcon);
 
1007
                        icon = makeIcon(hIcon, getLargeIcon);
 
1008
                        disposeIcon(hIcon);
 
1009
                        if (icon != null) {
 
1010
                            imageCache.put(Integer.valueOf(index), icon);
 
1011
                        }
 
1012
                    }
 
1013
                }
 
1014
            }
 
1015
 
 
1016
            if (icon == null) {
 
1017
                // These are only cached per object
 
1018
                cli.System.IntPtr hIcon = extractIcon(getParentIShellFolder(), getRelativePIDL(), getLargeIcon);
 
1019
                icon = makeIcon(hIcon, getLargeIcon);
 
1020
                disposeIcon(hIcon);
 
1021
            }
 
1022
 
 
1023
            if (getLargeIcon) {
 
1024
                largeIcon = icon;
 
1025
            } else {
 
1026
                smallIcon = icon;
 
1027
            }
 
1028
        }
 
1029
        if (icon == null) {
 
1030
            icon = super .getIcon(getLargeIcon);
 
1031
        }
 
1032
        return icon;
 
1033
    }
 
1034
 
 
1035
    /**
 
1036
     * Gets an icon from the Windows system icon list as an <code>Image</code>
 
1037
     */
 
1038
    static Image getShell32Icon(int iconID, boolean getLargeIcon) {
 
1039
        Bitmap bitmap = getShell32IconResourceAsBitmap(iconID, getLargeIcon);
 
1040
        if (bitmap == null) {
 
1041
            return null;
 
1042
        }
 
1043
        return new BufferedImage(bitmap);
 
1044
    }
 
1045
    
 
1046
    private static native Bitmap getShell32IconResourceAsBitmap(int iconID, boolean getLargeIcon);
 
1047
 
 
1048
    /**
 
1049
     * Returns the canonical form of this abstract pathname.  Equivalent to
 
1050
     * <code>new&nbsp;Win32ShellFolder2(getParentFile(), this.{@link java.io.File#getCanonicalPath}())</code>.
 
1051
     *
 
1052
     * @see java.io.File#getCanonicalFile
 
1053
     */
 
1054
    public File getCanonicalFile() throws IOException {
 
1055
        return this;
 
1056
    }
 
1057
 
 
1058
    /*
 
1059
     * Indicates whether this is a special folder (includes My Documents)
 
1060
     */
 
1061
    public boolean isSpecial() {
 
1062
        return isPersonal || !isFileSystem() || (this == getDesktop());
 
1063
    }
 
1064
 
 
1065
    /**
 
1066
     * Compares this object with the specified object for order.
 
1067
     *
 
1068
     * @see sun.awt.shell.ShellFolder#compareTo(File)
 
1069
     */
 
1070
    public int compareTo(File file2) {
 
1071
        if (!(file2 instanceof Win32ShellFolder2)) {
 
1072
            if (isFileSystem() && !isSpecial()) {
 
1073
                return super.compareTo(file2);
 
1074
            } else {
 
1075
                return -1; // Non-file shellfolders sort before files
 
1076
            }
 
1077
        }
 
1078
        return Win32ShellFolderManager2.compareShellFolders(this, (Win32ShellFolder2) file2);
 
1079
    }
 
1080
 
 
1081
    // native constants from commctrl.h
 
1082
    private static final int LVCFMT_LEFT = 0;
 
1083
    private static final int LVCFMT_RIGHT = 1;
 
1084
    private static final int LVCFMT_CENTER = 2;
 
1085
 
 
1086
    @cli.System.Security.SecuritySafeCriticalAttribute.Annotation
 
1087
    public ShellFolderColumnInfo[] getFolderColumns() {
 
1088
        Object o = doGetColumnInfo(getIShellFolder());
 
1089
        ShellFolderColumnInfo[] columns = (ShellFolderColumnInfo[]) o;
 
1090
 
 
1091
        if (columns != null) {
 
1092
            List<ShellFolderColumnInfo> notNullColumns = new ArrayList<ShellFolderColumnInfo>();
 
1093
            for (int i = 0; i < columns.length; i++) {
 
1094
                ShellFolderColumnInfo column = columns[i];
 
1095
                if (column != null) {
 
1096
                    column.setAlignment(column.getAlignment() == LVCFMT_RIGHT ? SwingConstants.RIGHT
 
1097
                                    : column.getAlignment() == LVCFMT_CENTER ? SwingConstants.CENTER
 
1098
                                            : SwingConstants.LEADING);
 
1099
 
 
1100
                    column.setComparator(new ColumnComparator(i));
 
1101
 
 
1102
                    notNullColumns.add(column);
 
1103
                }
 
1104
            }
 
1105
            columns = new ShellFolderColumnInfo[notNullColumns.size()];
 
1106
            notNullColumns.toArray(columns);
 
1107
        }
 
1108
        return columns;
 
1109
    }
 
1110
 
 
1111
    @cli.System.Security.SecuritySafeCriticalAttribute.Annotation
 
1112
    public Object getFolderColumnValue(int column) {
 
1113
        return doGetColumnValue(getParentIShellFolder(), getRelativePIDL(), column);
 
1114
    }
 
1115
 
 
1116
    @cli.System.Security.SecurityCriticalAttribute.Annotation
 
1117
    private static native cli.System.Object /*ShellFolderColumnInfo[]*/ doGetColumnInfo( cli.System.Object iShellFolder2 );
 
1118
 
 
1119
    @cli.System.Security.SecurityCriticalAttribute.Annotation
 
1120
    private static native Object doGetColumnValue(cli.System.Object parentIShellFolder2, cli.System.IntPtr childPIDL, int columnIdx);
 
1121
 
 
1122
    @cli.System.Security.SecurityCriticalAttribute.Annotation
 
1123
    static native int compareIDsByColumn(cli.System.Object pParentIShellFolder, cli.System.IntPtr pidl1, cli.System.IntPtr pidl2, int columnIdx);
 
1124
 
 
1125
    private class ColumnComparator implements Comparator {
 
1126
        private final int columnIdx;
 
1127
 
 
1128
        public ColumnComparator(int columnIdx) {
 
1129
            this.columnIdx = columnIdx;
 
1130
        }
 
1131
 
 
1132
        // compares 2 objects within this folder by the specified column
 
1133
        @cli.System.Security.SecuritySafeCriticalAttribute.Annotation
 
1134
        public int compare(Object o, Object o1) {
 
1135
            if (o instanceof  Win32ShellFolder2 && o1 instanceof  Win32ShellFolder2) {
 
1136
                // delegates comparison to native method
 
1137
                return compareIDsByColumn(getIShellFolder(),
 
1138
                        ((Win32ShellFolder2) o).getRelativePIDL(),
 
1139
                        ((Win32ShellFolder2) o1).getRelativePIDL(),
 
1140
                        columnIdx);
 
1141
            }
 
1142
            return 0;
 
1143
        }
 
1144
    }
 
1145
}
 
 
b'\\ No newline at end of file'