< prev index next >

src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolder2.java

Print this page




  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.awt.shell;
  27 
  28 import java.awt.Image;
  29 import java.awt.Toolkit;
  30 import java.awt.image.BufferedImage;
  31 import java.io.File;

  32 import java.io.IOException;
  33 import java.util.*;
  34 import java.util.concurrent.*;
  35 import javax.swing.SwingConstants;
  36 
  37 // NOTE: This class supersedes Win32ShellFolder, which was removed from
  38 //       distribution after version 1.4.2.
  39 
  40 /**
  41  * Win32 Shell Folders
  42  * <P>
  43  * <BR>
  44  * There are two fundamental types of shell folders : file system folders
  45  * and non-file system folders.  File system folders are relatively easy
  46  * to deal with.  Non-file system folders are items such as My Computer,
  47  * Network Neighborhood, and the desktop.  Some of these non-file system
  48  * folders have special values and properties.
  49  * <P>
  50  * <BR>
  51  * Win32 keeps two basic data structures for shell folders.  The first


 216             });
 217             disposed = true;
 218         }
 219     }
 220     FolderDisposer disposer = new FolderDisposer();
 221     private void setIShellFolder(long pIShellFolder) {
 222         disposer.pIShellFolder = pIShellFolder;
 223     }
 224     private void setRelativePIDL(long relativePIDL) {
 225         disposer.relativePIDL = relativePIDL;
 226     }
 227     /*
 228      * The following are for caching various shell folder properties.
 229      */
 230     private long pIShellIcon = -1L;
 231     private String folderType = null;
 232     private String displayName = null;
 233     private Image smallIcon = null;
 234     private Image largeIcon = null;
 235     private Boolean isDir = null;

 236 
 237     /*
 238      * The following is to identify the My Documents folder as being special
 239      */
 240     private boolean isPersonal;
 241 
 242     private static String composePathForCsidl(int csidl) throws IOException, InterruptedException {
 243         String path = getFileSystemPath(csidl);
 244         return path == null
 245                 ? ("ShellFolder: 0x" + Integer.toHexString(csidl))
 246                 : path;
 247     }
 248 
 249     /**
 250      * Create a system special shell folder, such as the
 251      * desktop or Network Neighborhood.
 252      */
 253     Win32ShellFolder2(final int csidl) throws IOException, InterruptedException {
 254         // Desktop is parent of DRIVES and NETWORK, not necessarily
 255         // other special shell folders.
 256         super(null, composePathForCsidl(csidl));

 257 
 258         invoke(new Callable<Void>() {
 259             public Void call() throws InterruptedException {
 260                 if (csidl == DESKTOP) {
 261                     initDesktop();
 262                 } else {
 263                     initSpecial(getDesktop().getIShellFolder(), csidl);
 264                     // At this point, the native method initSpecial() has set our relativePIDL
 265                     // relative to the Desktop, which may not be our immediate parent. We need
 266                     // to traverse this ID list and break it into a chain of shell folders from
 267                     // the top, with each one having an immediate parent and a relativePIDL
 268                     // relative to that parent.
 269                     long pIDL = disposer.relativePIDL;
 270                     parent = getDesktop();
 271                     while (pIDL != 0) {
 272                         // Get a child pidl relative to 'parent'
 273                         long childPIDL = copyFirstPIDLEntry(pIDL);
 274                         if (childPIDL != 0) {
 275                             // Get a handle to the rest of the ID list
 276                             // i,e, parent's grandchilren and down
 277                             pIDL = getNextPIDLEntry(pIDL);
 278                             if (pIDL != 0) {
 279                                 // Now we know that parent isn't immediate to 'this' because it
 280                                 // has a continued ID list. Create a shell folder for this child
 281                                 // pidl and make it the new 'parent'.
 282                                 parent = new Win32ShellFolder2((Win32ShellFolder2) parent, childPIDL);
 283                             } else {
 284                                 // No grandchildren means we have arrived at the parent of 'this',
 285                                 // and childPIDL is directly relative to parent.
 286                                 disposer.relativePIDL = childPIDL;
 287                             }
 288                         } else {
 289                             break;
 290                         }
 291                     }
 292                 }
 293                 return null;
 294             }
 295         }, InterruptedException.class);
 296 
 297         sun.java2d.Disposer.addRecord(this, disposer);
 298     }
 299 
 300 
 301     /**
 302      * Create a system shell folder
 303      */
 304     Win32ShellFolder2(Win32ShellFolder2 parent, long pIShellFolder, long relativePIDL, String path) {
 305         super(parent, (path != null) ? path : "ShellFolder: ");

 306         this.disposer.pIShellFolder = pIShellFolder;
 307         this.disposer.relativePIDL = relativePIDL;
 308         sun.java2d.Disposer.addRecord(this, disposer);
 309     }
 310 
 311 
 312     /**
 313      * Creates a shell folder with a parent and relative PIDL
 314      */
 315     Win32ShellFolder2(final Win32ShellFolder2 parent, final long relativePIDL) throws InterruptedException {
 316         super(parent,
 317             invoke(new Callable<String>() {
 318                 public String call() {
 319                     return getFileSystemPath(parent.getIShellFolder(), relativePIDL);







 320                 }
 321             }, RuntimeException.class)
 322         );
 323         this.disposer.relativePIDL = relativePIDL;
 324         sun.java2d.Disposer.addRecord(this, disposer);
 325     }
 326 
 327     // Initializes the desktop shell folder
 328     // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
 329     private native void initDesktop();
 330 
 331     // Initializes a special, non-file system shell folder
 332     // from one of the above constants
 333     // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
 334     private native void initSpecial(long desktopIShellFolder, int csidl);
 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


 584      */
 585 
 586     private static native int getAttributes0(long pParentIShellFolder, long pIDL, int attrsMask);
 587 
 588     // Return the path to the underlying file system object
 589     // Should be called from the COM thread
 590     private static String getFileSystemPath(final long parentIShellFolder, final long relativePIDL) {
 591         int linkedFolder = ATTRIB_LINK | ATTRIB_FOLDER;
 592         if (parentIShellFolder == Win32ShellFolderManager2.getNetwork().getIShellFolder() &&
 593                 getAttributes0(parentIShellFolder, relativePIDL, linkedFolder) == linkedFolder) {
 594 
 595             String s =
 596                     getFileSystemPath(Win32ShellFolderManager2.getDesktop().getIShellFolder(),
 597                             getLinkLocation(parentIShellFolder, relativePIDL, false));
 598             if (s != null && s.startsWith("\\\\")) {
 599                 return s;
 600             }
 601         }
 602         String path = getDisplayNameOf(parentIShellFolder, relativePIDL,
 603                         SHGDN_FORPARSING);




 604         // if this is a library its default save location is taken as a path
 605         // this is a temp fix until java.io starts support Libraries
 606         if( path != null && path.startsWith("::{") &&
 607                 path.toLowerCase().endsWith(".library-ms")) {
 608             for (KnownFolderDefinition kf : KnownFolderDefinition.libraries) {
 609                 if( path.toLowerCase().endsWith(
 610                             kf.relativePath.toLowerCase()) &&
 611                             path.toUpperCase().startsWith(
 612                             kf.parsingName.substring(0, 40).toUpperCase()) ) {
 613                     return kf.saveLocation;
 614                 }
 615             }
 616         }
 617         return path;
 618     }
 619 
 620     // Needs to be accessible to Win32ShellFolderManager2
 621     static String getFileSystemPath(final int csidl) throws IOException, InterruptedException {
 622         String path = invoke(new Callable<String>() {
 623             public String call() throws IOException {
 624                 return getFileSystemPath0(csidl);
 625             }
 626         }, IOException.class);
 627         if (path != null) {
 628             SecurityManager security = System.getSecurityManager();
 629             if (security != null) {
 630                 security.checkRead(path);
 631             }
 632         }
 633         return path;
 634     }
 635 
 636     // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
 637     private static native String getFileSystemPath0(int csidl) throws IOException;


 733                     // parent so we have an IShellFolder to query.
 734                     long pIShellFolder = getIShellFolder();
 735                     // Now we can enumerate the objects in this folder.
 736                     ArrayList<Win32ShellFolder2> list = new ArrayList<Win32ShellFolder2>();
 737                     long pEnumObjects = getEnumObjects(includeHiddenFiles);
 738                     if (pEnumObjects != 0) {
 739                         try {
 740                             long childPIDL;
 741                             int testedAttrs = ATTRIB_FILESYSTEM | ATTRIB_FILESYSANCESTOR;
 742                             do {
 743                                 childPIDL = getNextChild(pEnumObjects);
 744                                 boolean releasePIDL = true;
 745                                 if (childPIDL != 0 &&
 746                                         (getAttributes0(pIShellFolder, childPIDL, testedAttrs) & testedAttrs) != 0) {
 747                                     Win32ShellFolder2 childFolder;
 748                                     if (Win32ShellFolder2.this.equals(desktop)
 749                                             && personal != null
 750                                             && pidlsEqual(pIShellFolder, childPIDL, personal.disposer.relativePIDL)) {
 751                                         childFolder = personal;
 752                                     } else {
 753                                         childFolder = new Win32ShellFolder2(Win32ShellFolder2.this, childPIDL);
 754                                         releasePIDL = false;
 755                                     }
 756                                     list.add(childFolder);
 757                                 }
 758                                 if (releasePIDL) {
 759                                     releasePIDL(childPIDL);
 760                                 }
 761                             } while (childPIDL != 0 && !Thread.currentThread().isInterrupted());
 762                         } finally {
 763                             releaseEnumObjects(pEnumObjects);
 764                         }
 765                     }
 766                     return Thread.currentThread().isInterrupted()
 767                         ? new File[0]
 768                         : list.toArray(new ShellFolder[list.size()]);
 769                 }
 770             }, InterruptedException.class);
 771         } catch (InterruptedException e) {
 772             return new File[0];
 773         }
 774     }
 775 
 776 
 777     /**
 778      * Look for (possibly special) child folder by it's path
 779      *
 780      * @return The child shellfolder, or null if not found.
 781      */
 782     Win32ShellFolder2 getChildByPath(final String filePath) throws InterruptedException {
 783         return invoke(new Callable<Win32ShellFolder2>() {
 784             public Win32ShellFolder2 call() throws InterruptedException {
 785                 long pIShellFolder = getIShellFolder();
 786                 long pEnumObjects = getEnumObjects(true);
 787                 Win32ShellFolder2 child = null;
 788                 long childPIDL;
 789 
 790                 while ((childPIDL = getNextChild(pEnumObjects)) != 0) {
 791                     if (getAttributes0(pIShellFolder, childPIDL, ATTRIB_FILESYSTEM) != 0) {
 792                         String path = getFileSystemPath(pIShellFolder, childPIDL);

 793                         if (path != null && path.equalsIgnoreCase(filePath)) {
 794                             long childIShellFolder = bindToObject(pIShellFolder, childPIDL);
 795                             child = new Win32ShellFolder2(Win32ShellFolder2.this,
 796                                     childIShellFolder, childPIDL, path);
 797                             break;
 798                         }
 799                     }
 800                     releasePIDL(childPIDL);
 801                 }
 802                 releaseEnumObjects(pEnumObjects);
 803                 return child;
 804             }
 805         }, InterruptedException.class);
 806     }
 807 
 808     private volatile Boolean cachedIsLink;
 809 
 810     /**
 811      * @return Whether this shell folder is a link
 812      */
 813     public boolean isLink() {
 814         if (cachedIsLink == null) {
 815             cachedIsLink = hasAttribute(ATTRIB_LINK);
 816         }


1112      *
1113      * @see sun.awt.shell.ShellFolder#compareTo(File)
1114      */
1115     public int compareTo(File file2) {
1116         if (!(file2 instanceof Win32ShellFolder2)) {
1117             if (isFileSystem() && !isSpecial()) {
1118                 return super.compareTo(file2);
1119             } else {
1120                 return -1; // Non-file shellfolders sort before files
1121             }
1122         }
1123         return Win32ShellFolderManager2.compareShellFolders(this, (Win32ShellFolder2) file2);
1124     }
1125 
1126     // native constants from commctrl.h
1127     private static final int LVCFMT_LEFT = 0;
1128     private static final int LVCFMT_RIGHT = 1;
1129     private static final int LVCFMT_CENTER = 2;
1130 
1131     public ShellFolderColumnInfo[] getFolderColumns() {


1132         return invoke(new Callable<ShellFolderColumnInfo[]>() {
1133             public ShellFolderColumnInfo[] call() {
1134                 ShellFolderColumnInfo[] columns = doGetColumnInfo(getIShellFolder());
1135 
1136                 if (columns != null) {
1137                     List<ShellFolderColumnInfo> notNullColumns =
1138                             new ArrayList<ShellFolderColumnInfo>();
1139                     for (int i = 0; i < columns.length; i++) {
1140                         ShellFolderColumnInfo column = columns[i];
1141                         if (column != null) {
1142                             column.setAlignment(column.getAlignment() == LVCFMT_RIGHT
1143                                     ? SwingConstants.RIGHT
1144                                     : column.getAlignment() == LVCFMT_CENTER
1145                                     ? SwingConstants.CENTER
1146                                     : SwingConstants.LEADING);
1147 
1148                             column.setComparator(new ColumnComparator(Win32ShellFolder2.this, i));
1149 
1150                             notNullColumns.add(column);
1151                         }
1152                     }
1153                     columns = new ShellFolderColumnInfo[notNullColumns.size()];
1154                     notNullColumns.toArray(columns);
1155                 }
1156                 return columns;
1157             }
1158         });
1159     }
1160 
1161     public Object getFolderColumnValue(final int column) {




1162         return invoke(new Callable<Object>() {
1163             public Object call() {
1164                 return doGetColumnValue(getParentIShellFolder(), getRelativePIDL(), column);
1165             }
1166         });




















1167     }
1168 
1169     // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
1170     private native ShellFolderColumnInfo[] doGetColumnInfo(long iShellFolder2);
1171 
1172     // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
1173     private native Object doGetColumnValue(long parentIShellFolder2, long childPIDL, int columnIdx);
1174 
1175     // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
1176     private static native int compareIDsByColumn(long pParentIShellFolder, long pidl1, long pidl2, int columnIdx);
1177 
1178 
1179     public void sortChildren(final List<? extends File> files) {
1180         // To avoid loads of synchronizations with Invoker and improve performance we
1181         // synchronize the whole code of the sort method once
1182         invoke(new Callable<Void>() {
1183             public Void call() {
1184                 Collections.sort(files, new ColumnComparator(Win32ShellFolder2.this, 0));
1185 
1186                 return null;




  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.awt.shell;
  27 
  28 import java.awt.Image;
  29 import java.awt.Toolkit;
  30 import java.awt.image.BufferedImage;
  31 import java.io.File;
  32 import java.io.FileNotFoundException;
  33 import java.io.IOException;
  34 import java.util.*;
  35 import java.util.concurrent.*;
  36 import javax.swing.SwingConstants;
  37 
  38 // NOTE: This class supersedes Win32ShellFolder, which was removed from
  39 //       distribution after version 1.4.2.
  40 
  41 /**
  42  * Win32 Shell Folders
  43  * <P>
  44  * <BR>
  45  * There are two fundamental types of shell folders : file system folders
  46  * and non-file system folders.  File system folders are relatively easy
  47  * to deal with.  Non-file system folders are items such as My Computer,
  48  * Network Neighborhood, and the desktop.  Some of these non-file system
  49  * folders have special values and properties.
  50  * <P>
  51  * <BR>
  52  * Win32 keeps two basic data structures for shell folders.  The first


 217             });
 218             disposed = true;
 219         }
 220     }
 221     FolderDisposer disposer = new FolderDisposer();
 222     private void setIShellFolder(long pIShellFolder) {
 223         disposer.pIShellFolder = pIShellFolder;
 224     }
 225     private void setRelativePIDL(long relativePIDL) {
 226         disposer.relativePIDL = relativePIDL;
 227     }
 228     /*
 229      * The following are for caching various shell folder properties.
 230      */
 231     private long pIShellIcon = -1L;
 232     private String folderType = null;
 233     private String displayName = null;
 234     private Image smallIcon = null;
 235     private Image largeIcon = null;
 236     private Boolean isDir = null;
 237     private final boolean isLib;
 238 
 239     /*
 240      * The following is to identify the My Documents folder as being special
 241      */
 242     private boolean isPersonal;
 243 
 244     private static String composePathForCsidl(int csidl) throws IOException, InterruptedException {
 245         String path = getFileSystemPath(csidl);
 246         return path == null
 247                 ? ("ShellFolder: 0x" + Integer.toHexString(csidl))
 248                 : path;
 249     }
 250 
 251     /**
 252      * Create a system special shell folder, such as the
 253      * desktop or Network Neighborhood.
 254      */
 255     Win32ShellFolder2(final int csidl) throws IOException, InterruptedException {
 256         // Desktop is parent of DRIVES and NETWORK, not necessarily
 257         // other special shell folders.
 258         super(null, composePathForCsidl(csidl));
 259         isLib = false;
 260 
 261         invoke(new Callable<Void>() {
 262             public Void call() throws InterruptedException {
 263                 if (csidl == DESKTOP) {
 264                     initDesktop();
 265                 } else {
 266                     initSpecial(getDesktop().getIShellFolder(), csidl);
 267                     // At this point, the native method initSpecial() has set our relativePIDL
 268                     // relative to the Desktop, which may not be our immediate parent. We need
 269                     // to traverse this ID list and break it into a chain of shell folders from
 270                     // the top, with each one having an immediate parent and a relativePIDL
 271                     // relative to that parent.
 272                     long pIDL = disposer.relativePIDL;
 273                     parent = getDesktop();
 274                     while (pIDL != 0) {
 275                         // Get a child pidl relative to 'parent'
 276                         long childPIDL = copyFirstPIDLEntry(pIDL);
 277                         if (childPIDL != 0) {
 278                             // Get a handle to the rest of the ID list
 279                             // i,e, parent's grandchilren and down
 280                             pIDL = getNextPIDLEntry(pIDL);
 281                             if (pIDL != 0) {
 282                                 // Now we know that parent isn't immediate to 'this' because it
 283                                 // has a continued ID list. Create a shell folder for this child
 284                                 // pidl and make it the new 'parent'.
 285                                 parent = createShellFolder((Win32ShellFolder2) parent, childPIDL);
 286                             } else {
 287                                 // No grandchildren means we have arrived at the parent of 'this',
 288                                 // and childPIDL is directly relative to parent.
 289                                 disposer.relativePIDL = childPIDL;
 290                             }
 291                         } else {
 292                             break;
 293                         }
 294                     }
 295                 }
 296                 return null;
 297             }
 298         }, InterruptedException.class);
 299 
 300         sun.java2d.Disposer.addRecord(this, disposer);
 301     }
 302 
 303 
 304     /**
 305      * Create a system shell folder
 306      */
 307     Win32ShellFolder2(Win32ShellFolder2 parent, long pIShellFolder, long relativePIDL, String path, boolean isLib) {
 308         super(parent, (path != null) ? path : "ShellFolder: ");
 309         this.isLib = isLib;
 310         this.disposer.pIShellFolder = pIShellFolder;
 311         this.disposer.relativePIDL = relativePIDL;
 312         sun.java2d.Disposer.addRecord(this, disposer);
 313     }
 314 
 315 
 316     /**
 317      * Creates a shell folder with a parent and relative PIDL
 318      */
 319     static Win32ShellFolder2 createShellFolder(Win32ShellFolder2 parent, long pIDL)
 320             throws InterruptedException {
 321         String path = invoke(new Callable<String>() {
 322             public String call() {
 323                 return getFileSystemPath(parent.getIShellFolder(), pIDL);
 324             }
 325         }, RuntimeException.class);
 326         String libPath = resolveLibrary(path);
 327         if (libPath == null) {
 328             return new Win32ShellFolder2(parent, 0, pIDL, path, false);
 329         } else {
 330             return new Win32ShellFolder2(parent, 0, pIDL, libPath, true);
 331         }




 332     }
 333 
 334     // Initializes the desktop shell folder
 335     // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
 336     private native void initDesktop();
 337 
 338     // Initializes a special, non-file system shell folder
 339     // from one of the above constants
 340     // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
 341     private native void initSpecial(long desktopIShellFolder, int csidl);
 342 
 343     /** Marks this folder as being the My Documents (Personal) folder */
 344     public void setIsPersonal() {
 345         isPersonal = true;
 346     }
 347 
 348     /**
 349      * This method is implemented to make sure that no instances
 350      * of <code>ShellFolder</code> are ever serialized. If <code>isFileSystem()</code> returns
 351      * <code>true</code>, then the object is representable with an instance of


 591      */
 592 
 593     private static native int getAttributes0(long pParentIShellFolder, long pIDL, int attrsMask);
 594 
 595     // Return the path to the underlying file system object
 596     // Should be called from the COM thread
 597     private static String getFileSystemPath(final long parentIShellFolder, final long relativePIDL) {
 598         int linkedFolder = ATTRIB_LINK | ATTRIB_FOLDER;
 599         if (parentIShellFolder == Win32ShellFolderManager2.getNetwork().getIShellFolder() &&
 600                 getAttributes0(parentIShellFolder, relativePIDL, linkedFolder) == linkedFolder) {
 601 
 602             String s =
 603                     getFileSystemPath(Win32ShellFolderManager2.getDesktop().getIShellFolder(),
 604                             getLinkLocation(parentIShellFolder, relativePIDL, false));
 605             if (s != null && s.startsWith("\\\\")) {
 606                 return s;
 607             }
 608         }
 609         String path = getDisplayNameOf(parentIShellFolder, relativePIDL,
 610                         SHGDN_FORPARSING);
 611         return path;
 612     }
 613 
 614     private static String resolveLibrary(String path) {
 615         // if this is a library its default save location is taken as a path
 616         // this is a temp fix until java.io starts support Libraries
 617         if( path != null && path.startsWith("::{") &&
 618                 path.toLowerCase().endsWith(".library-ms")) {
 619             for (KnownFolderDefinition kf : KnownFolderDefinition.libraries) {
 620                 if (path.toLowerCase().endsWith(
 621                         "\\" + kf.relativePath.toLowerCase()) &&
 622                         path.toUpperCase().startsWith(
 623                         kf.parsingName.substring(0, 40).toUpperCase())) {
 624                     return kf.saveLocation;
 625                 }
 626             }
 627         }
 628         return null;
 629     }
 630 
 631     // Needs to be accessible to Win32ShellFolderManager2
 632     static String getFileSystemPath(final int csidl) throws IOException, InterruptedException {
 633         String path = invoke(new Callable<String>() {
 634             public String call() throws IOException {
 635                 return getFileSystemPath0(csidl);
 636             }
 637         }, IOException.class);
 638         if (path != null) {
 639             SecurityManager security = System.getSecurityManager();
 640             if (security != null) {
 641                 security.checkRead(path);
 642             }
 643         }
 644         return path;
 645     }
 646 
 647     // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
 648     private static native String getFileSystemPath0(int csidl) throws IOException;


 744                     // parent so we have an IShellFolder to query.
 745                     long pIShellFolder = getIShellFolder();
 746                     // Now we can enumerate the objects in this folder.
 747                     ArrayList<Win32ShellFolder2> list = new ArrayList<Win32ShellFolder2>();
 748                     long pEnumObjects = getEnumObjects(includeHiddenFiles);
 749                     if (pEnumObjects != 0) {
 750                         try {
 751                             long childPIDL;
 752                             int testedAttrs = ATTRIB_FILESYSTEM | ATTRIB_FILESYSANCESTOR;
 753                             do {
 754                                 childPIDL = getNextChild(pEnumObjects);
 755                                 boolean releasePIDL = true;
 756                                 if (childPIDL != 0 &&
 757                                         (getAttributes0(pIShellFolder, childPIDL, testedAttrs) & testedAttrs) != 0) {
 758                                     Win32ShellFolder2 childFolder;
 759                                     if (Win32ShellFolder2.this.equals(desktop)
 760                                             && personal != null
 761                                             && pidlsEqual(pIShellFolder, childPIDL, personal.disposer.relativePIDL)) {
 762                                         childFolder = personal;
 763                                     } else {
 764                                         childFolder = createShellFolder(Win32ShellFolder2.this, childPIDL);
 765                                         releasePIDL = false;
 766                                     }
 767                                     list.add(childFolder);
 768                                 }
 769                                 if (releasePIDL) {
 770                                     releasePIDL(childPIDL);
 771                                 }
 772                             } while (childPIDL != 0 && !Thread.currentThread().isInterrupted());
 773                         } finally {
 774                             releaseEnumObjects(pEnumObjects);
 775                         }
 776                     }
 777                     return Thread.currentThread().isInterrupted()
 778                         ? new File[0]
 779                         : list.toArray(new ShellFolder[list.size()]);
 780                 }
 781             }, InterruptedException.class);
 782         } catch (InterruptedException e) {
 783             return new File[0];
 784         }
 785     }
 786 
 787 
 788     /**
 789      * Look for (possibly special) child folder by it's path
 790      *
 791      * @return The child shellfolder, or null if not found.
 792      */
 793     Win32ShellFolder2 getChildByPath(final String filePath) throws InterruptedException {
 794         return invoke(new Callable<Win32ShellFolder2>() {
 795             public Win32ShellFolder2 call() throws InterruptedException {
 796                 long pIShellFolder = getIShellFolder();
 797                 long pEnumObjects = getEnumObjects(true);
 798                 Win32ShellFolder2 child = null;
 799                 long childPIDL;
 800 
 801                 while ((childPIDL = getNextChild(pEnumObjects)) != 0) {
 802                     if (getAttributes0(pIShellFolder, childPIDL, ATTRIB_FILESYSTEM) != 0) {
 803                         String path = getFileSystemPath(pIShellFolder, childPIDL);
 804                         if(isLib) path = resolveLibrary( path );
 805                         if (path != null && path.equalsIgnoreCase(filePath)) {
 806                             long childIShellFolder = bindToObject(pIShellFolder, childPIDL);
 807                             child = new Win32ShellFolder2(Win32ShellFolder2.this,
 808                                     childIShellFolder, childPIDL, path, isLib);
 809                             break;
 810                         }
 811                     }
 812                     releasePIDL(childPIDL);
 813                 }
 814                 releaseEnumObjects(pEnumObjects);
 815                 return child;
 816             }
 817         }, InterruptedException.class);
 818     }
 819 
 820     private volatile Boolean cachedIsLink;
 821 
 822     /**
 823      * @return Whether this shell folder is a link
 824      */
 825     public boolean isLink() {
 826         if (cachedIsLink == null) {
 827             cachedIsLink = hasAttribute(ATTRIB_LINK);
 828         }


1124      *
1125      * @see sun.awt.shell.ShellFolder#compareTo(File)
1126      */
1127     public int compareTo(File file2) {
1128         if (!(file2 instanceof Win32ShellFolder2)) {
1129             if (isFileSystem() && !isSpecial()) {
1130                 return super.compareTo(file2);
1131             } else {
1132                 return -1; // Non-file shellfolders sort before files
1133             }
1134         }
1135         return Win32ShellFolderManager2.compareShellFolders(this, (Win32ShellFolder2) file2);
1136     }
1137 
1138     // native constants from commctrl.h
1139     private static final int LVCFMT_LEFT = 0;
1140     private static final int LVCFMT_RIGHT = 1;
1141     private static final int LVCFMT_CENTER = 2;
1142 
1143     public ShellFolderColumnInfo[] getFolderColumns() {
1144         ShellFolder library = resolveLibrary();
1145         if (library != null) return library.getFolderColumns();
1146         return invoke(new Callable<ShellFolderColumnInfo[]>() {
1147             public ShellFolderColumnInfo[] call() {
1148                 ShellFolderColumnInfo[] columns = doGetColumnInfo(getIShellFolder());
1149 
1150                 if (columns != null) {
1151                     List<ShellFolderColumnInfo> notNullColumns =
1152                             new ArrayList<ShellFolderColumnInfo>();
1153                     for (int i = 0; i < columns.length; i++) {
1154                         ShellFolderColumnInfo column = columns[i];
1155                         if (column != null) {
1156                             column.setAlignment(column.getAlignment() == LVCFMT_RIGHT
1157                                     ? SwingConstants.RIGHT
1158                                     : column.getAlignment() == LVCFMT_CENTER
1159                                     ? SwingConstants.CENTER
1160                                     : SwingConstants.LEADING);
1161 
1162                             column.setComparator(new ColumnComparator(Win32ShellFolder2.this, i));
1163 
1164                             notNullColumns.add(column);
1165                         }
1166                     }
1167                     columns = new ShellFolderColumnInfo[notNullColumns.size()];
1168                     notNullColumns.toArray(columns);
1169                 }
1170                 return columns;
1171             }
1172         });
1173     }
1174 
1175     public Object getFolderColumnValue(final int column) {
1176         if(!isLibrary()) {
1177             ShellFolder library = resolveLibrary();
1178             if (library != null) return library.getFolderColumnValue(column);
1179         }
1180         return invoke(new Callable<Object>() {
1181             public Object call() {
1182                 return doGetColumnValue(getParentIShellFolder(), getRelativePIDL(), column);
1183             }
1184         });
1185     }
1186 
1187     boolean isLibrary() {
1188         return isLib;
1189     }
1190 
1191     private ShellFolder resolveLibrary() {
1192         for (ShellFolder f = this; f != null; f = f.parent) {
1193             if (!f.isFileSystem()) {
1194                 if (f instanceof Win32ShellFolder2 &&
1195                                            ((Win32ShellFolder2)f).isLibrary()) {
1196                     try {
1197                         return getShellFolder(new File(getPath()));
1198                     } catch (FileNotFoundException e) {
1199                     }
1200                 }
1201                 break;
1202             }
1203         }
1204         return null;
1205     }
1206 
1207     // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
1208     private native ShellFolderColumnInfo[] doGetColumnInfo(long iShellFolder2);
1209 
1210     // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
1211     private native Object doGetColumnValue(long parentIShellFolder2, long childPIDL, int columnIdx);
1212 
1213     // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
1214     private static native int compareIDsByColumn(long pParentIShellFolder, long pidl1, long pidl2, int columnIdx);
1215 
1216 
1217     public void sortChildren(final List<? extends File> files) {
1218         // To avoid loads of synchronizations with Invoker and improve performance we
1219         // synchronize the whole code of the sort method once
1220         invoke(new Callable<Void>() {
1221             public Void call() {
1222                 Collections.sort(files, new ColumnComparator(Win32ShellFolder2.this, 0));
1223 
1224                 return null;


< prev index next >