1 /*
2 * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
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
57 * a series of identifiers and can be either relative to the desktop
58 * (an absolute PIDL), or relative to the shell folder that contains them.
59 * Some Win32 functions can take absolute or relative PIDL values, and
60 * others can only accept relative values.
61 * <BR>
62 * The second data structure is an IShellFolder COM interface. Using
63 * this interface, one can enumerate the relative PIDLs in a shell
64 * folder, get attributes, etc.
65 * <BR>
66 * All Win32ShellFolder2 objects which are folder types (even non-file
67 * system folders) contain an IShellFolder object. Files are named in
68 * directories via relative PIDLs.
69 *
70 * @author Michael Martak
71 * @author Leif Samuelsson
72 * @author Kenneth Russell
73 * @since 1.4 */
74 @SuppressWarnings("serial") // JDK-implementation class
75 final class Win32ShellFolder2 extends ShellFolder {
76
77 private static native void initIDs();
78
79 static {
80 initIDs();
81 }
82
83 // Win32 Shell Folder Constants
84 public static final int DESKTOP = 0x0000;
85 public static final int INTERNET = 0x0001;
86 public static final int PROGRAMS = 0x0002;
87 public static final int CONTROLS = 0x0003;
88 public static final int PRINTERS = 0x0004;
89 public static final int PERSONAL = 0x0005;
90 public static final int FAVORITES = 0x0006;
91 public static final int STARTUP = 0x0007;
92 public static final int RECENT = 0x0008;
93 public static final int SENDTO = 0x0009;
94 public static final int BITBUCKET = 0x000a;
95 public static final int STARTMENU = 0x000b;
96 public static final int DESKTOPDIRECTORY = 0x0010;
960
961
962 // Icons
963
964 private static Map<Integer, Image> smallSystemImages = new HashMap<>();
965 private static Map<Integer, Image> largeSystemImages = new HashMap<>();
966 private static Map<Integer, Image> smallLinkedSystemImages = new HashMap<>();
967 private static Map<Integer, Image> largeLinkedSystemImages = new HashMap<>();
968
969 // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
970 private static native long getIShellIcon(long pIShellFolder);
971
972 // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
973 private static native int getIconIndex(long parentIShellIcon, long relativePIDL);
974
975 // Return the icon of a file system shell folder in the form of an HICON
976 private static native long getIcon(String absolutePath, boolean getLargeIcon);
977
978 // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
979 private static native long extractIcon(long parentIShellFolder, long relativePIDL,
980 boolean getLargeIcon, boolean getDefaultIcon);
981
982 // Returns an icon from the Windows system icon list in the form of an HICON
983 private static native long getSystemIcon(int iconID);
984 private static native long getIconResource(String libName, int iconID,
985 int cxDesired, int cyDesired,
986 boolean useVGAColors);
987 // Note: useVGAColors is ignored on XP and later
988
989 // Return the bits from an HICON. This has a side effect of setting
990 // the imageHash variable for efficient caching / comparing.
991 private static native int[] getIconBits(long hIcon);
992 // Dispose the HICON
993 private static native void disposeIcon(long hIcon);
994
995 // Get buttons from native toolbar implementation.
996 static native int[] getStandardViewButton0(int iconIndex, boolean small);
997
998 // Should be called from the COM thread
999 private long getIShellIcon() {
1000 if (pIShellIcon == -1L) {
1001 pIShellIcon = getIShellIcon(getIShellFolder());
1002 }
1003
1004 return pIShellIcon;
1005 }
1006
1007 private static Image makeIcon(long hIcon, boolean getLargeIcon) {
1008 if (hIcon != 0L && hIcon != -1L) {
1009 // Get the bits. This has the side effect of setting the imageHash value for this object.
1010 final int[] iconBits = getIconBits(hIcon);
1011 if (iconBits != null) {
1012 // icons are always square
1013 final int size = (int) Math.sqrt(iconBits.length);
1014 final int baseSize = getLargeIcon ? 32 : 16;
1015 final BufferedImage img =
1016 new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB);
1017 img.setRGB(0, 0, size, size, iconBits, 0, size);
1018 return size == baseSize
1019 ? img
1020 : new MultiResolutionIconImage(baseSize, img);
1021 }
1022 }
1023 return null;
1024 }
1025
1026
1027 /**
1028 * @return The icon image used to display this shell folder
1029 */
1030 public Image getIcon(final boolean getLargeIcon) {
1031 Image icon = getLargeIcon ? largeIcon : smallIcon;
1032 if (icon == null) {
1033 icon =
1034 invoke(new Callable<Image>() {
1035 public Image call() {
1036 Image newIcon = null;
1037 if (isLink()) {
1038 Win32ShellFolder2 folder = getLinkLocation(false);
1039 if (folder != null && folder.isLibrary()) {
1040 return folder.getIcon(getLargeIcon);
1041 }
1042 }
1043 if (isFileSystem() || isLibrary()) {
1044 long parentIShellIcon = (parent != null)
1045 ? ((Win32ShellFolder2) parent).getIShellIcon()
1046 : 0L;
1047 long relativePIDL = getRelativePIDL();
1048
1049 // These are cached per type (using the index in the system image list)
1050 int index = getIconIndex(parentIShellIcon, relativePIDL);
1051 if (index > 0) {
1052 Map<Integer, Image> imageCache;
1053 if (isLink()) {
1054 imageCache = getLargeIcon ? largeLinkedSystemImages : smallLinkedSystemImages;
1055 } else {
1056 imageCache = getLargeIcon ? largeSystemImages : smallSystemImages;
1057 }
1058 newIcon = imageCache.get(Integer.valueOf(index));
1059 if (newIcon == null) {
1060 long hIcon = getIcon(getAbsolutePath(), getLargeIcon);
1061 newIcon = makeIcon(hIcon, getLargeIcon);
1062 disposeIcon(hIcon);
1063 if (newIcon != null) {
1064 imageCache.put(Integer.valueOf(index), newIcon);
1065 }
1066 }
1067 }
1068 }
1069
1070 if (newIcon == null) {
1071 // These are only cached per object
1072 long hIcon = extractIcon(getParentIShellFolder(),
1073 getRelativePIDL(), getLargeIcon, false);
1074 // E_PENDING: loading can take time so get the default
1075 if(hIcon <= 0) {
1076 hIcon = extractIcon(getParentIShellFolder(),
1077 getRelativePIDL(), getLargeIcon, true);
1078 if(hIcon <= 0) {
1079 if (isDirectory()) {
1080 return getShell32Icon(4, getLargeIcon);
1081 } else {
1082 return getShell32Icon(1, getLargeIcon);
1083 }
1084 }
1085 }
1086 newIcon = makeIcon(hIcon, getLargeIcon);
1087 disposeIcon(hIcon);
1088 }
1089
1090 if (newIcon == null) {
1091 newIcon = Win32ShellFolder2.super.getIcon(getLargeIcon);
1092 }
1093 return newIcon;
1094 }
1095 });
1096 if (getLargeIcon) {
1097 largeIcon = icon;
1098 } else {
1099 smallIcon = icon;
1100 }
1101 }
1102 return icon;
1103 }
1104
1105 /**
1106 * Gets an icon from the Windows system icon list as an {@code Image}
1107 */
1108 static Image getSystemIcon(SystemIcon iconType) {
1109 long hIcon = getSystemIcon(iconType.getIconID());
1110 Image icon = makeIcon(hIcon, true);
1111 disposeIcon(hIcon);
1112 return icon;
1113 }
1114
1115 /**
1116 * Gets an icon from the Windows system icon list as an {@code Image}
1117 */
1118 static Image getShell32Icon(int iconID, boolean getLargeIcon) {
1119 boolean useVGAColors = true; // Will be ignored on XP and later
1120
1121 int size = getLargeIcon ? 32 : 16;
1122
1123 Toolkit toolkit = Toolkit.getDefaultToolkit();
1124 String shellIconBPP = (String)toolkit.getDesktopProperty("win.icon.shellIconBPP");
1125 if (shellIconBPP != null) {
1126 useVGAColors = shellIconBPP.equals("4");
1127 }
1128
1129 long hIcon = getIconResource("shell32.dll", iconID, size, size, useVGAColors);
1130 if (hIcon != 0) {
1131 Image icon = makeIcon(hIcon, getLargeIcon);
1132 disposeIcon(hIcon);
1133 return icon;
1134 }
1135 return null;
1136 }
1137
1138 /**
1139 * Returns the canonical form of this abstract pathname. Equivalent to
1140 * <code>new Win32ShellFolder2(getParentFile(), this.{@link java.io.File#getCanonicalPath}())</code>.
1141 *
1142 * @see java.io.File#getCanonicalFile
1143 */
1144 public File getCanonicalFile() throws IOException {
1145 return this;
1146 }
1147
1148 /*
1149 * Indicates whether this is a special folder (includes My Documents)
1150 */
1151 public boolean isSpecial() {
|
1 /*
2 * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
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
57 * a series of identifiers and can be either relative to the desktop
58 * (an absolute PIDL), or relative to the shell folder that contains them.
59 * Some Win32 functions can take absolute or relative PIDL values, and
60 * others can only accept relative values.
61 * <BR>
62 * The second data structure is an IShellFolder COM interface. Using
63 * this interface, one can enumerate the relative PIDLs in a shell
64 * folder, get attributes, etc.
65 * <BR>
66 * All Win32ShellFolder2 objects which are folder types (even non-file
67 * system folders) contain an IShellFolder object. Files are named in
68 * directories via relative PIDLs.
69 *
70 * @author Michael Martak
71 * @author Leif Samuelsson
72 * @author Kenneth Russell
73 * @since 1.4 */
74 @SuppressWarnings("serial") // JDK-implementation class
75 final class Win32ShellFolder2 extends ShellFolder {
76
77 static final int SMALL_ICON_SIZE = 16;
78 static final int LARGE_ICON_SIZE = 32;
79
80 static final int FILE_ICON_ID = 1;
81 static final int FOLDER_ICON_ID = 4;
82
83 private static native void initIDs();
84
85 static {
86 initIDs();
87 }
88
89 // Win32 Shell Folder Constants
90 public static final int DESKTOP = 0x0000;
91 public static final int INTERNET = 0x0001;
92 public static final int PROGRAMS = 0x0002;
93 public static final int CONTROLS = 0x0003;
94 public static final int PRINTERS = 0x0004;
95 public static final int PERSONAL = 0x0005;
96 public static final int FAVORITES = 0x0006;
97 public static final int STARTUP = 0x0007;
98 public static final int RECENT = 0x0008;
99 public static final int SENDTO = 0x0009;
100 public static final int BITBUCKET = 0x000a;
101 public static final int STARTMENU = 0x000b;
102 public static final int DESKTOPDIRECTORY = 0x0010;
966
967
968 // Icons
969
970 private static Map<Integer, Image> smallSystemImages = new HashMap<>();
971 private static Map<Integer, Image> largeSystemImages = new HashMap<>();
972 private static Map<Integer, Image> smallLinkedSystemImages = new HashMap<>();
973 private static Map<Integer, Image> largeLinkedSystemImages = new HashMap<>();
974
975 // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
976 private static native long getIShellIcon(long pIShellFolder);
977
978 // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
979 private static native int getIconIndex(long parentIShellIcon, long relativePIDL);
980
981 // Return the icon of a file system shell folder in the form of an HICON
982 private static native long getIcon(String absolutePath, boolean getLargeIcon);
983
984 // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
985 private static native long extractIcon(long parentIShellFolder, long relativePIDL,
986 int size, boolean getDefaultIcon);
987
988 // Returns an icon from the Windows system icon list in the form of an HICON
989 private static native long getSystemIcon(int iconID);
990 private static native long getIconResource(String libName, int iconID,
991 int cxDesired, int cyDesired,
992 boolean useVGAColors);
993 // Note: useVGAColors is ignored on XP and later
994
995 // Return the bits from an HICON. This has a side effect of setting
996 // the imageHash variable for efficient caching / comparing.
997 private static native int[] getIconBits(long hIcon);
998 // Dispose the HICON
999 private static native void disposeIcon(long hIcon);
1000
1001 // Get buttons from native toolbar implementation.
1002 static native int[] getStandardViewButton0(int iconIndex, boolean small);
1003
1004 // Should be called from the COM thread
1005 private long getIShellIcon() {
1006 if (pIShellIcon == -1L) {
1007 pIShellIcon = getIShellIcon(getIShellFolder());
1008 }
1009
1010 return pIShellIcon;
1011 }
1012
1013 private static Image makeIcon(long hIcon, int size) {
1014 if (hIcon != 0L && hIcon != -1L) {
1015 // Get the bits. This has the side effect of setting the imageHash value for this object.
1016 final int[] iconBits = getIconBits(hIcon);
1017 if (iconBits != null) {
1018 // icons are always square
1019 final int iconSize = (int) Math.sqrt(iconBits.length);
1020 final BufferedImage img =
1021 new BufferedImage(iconSize, iconSize, BufferedImage.TYPE_INT_ARGB);
1022 img.setRGB(0, 0, iconSize, iconSize, iconBits, 0, iconSize);
1023 return iconSize == size
1024 ? img
1025 : new MultiResolutionIconImage(size, img);
1026 }
1027 }
1028 return null;
1029 }
1030
1031
1032 /**
1033 * @return The icon image used to display this shell folder
1034 */
1035 public Image getIcon(final boolean getLargeIcon) {
1036 Image icon = getLargeIcon ? largeIcon : smallIcon;
1037 int size = getLargeIcon ? LARGE_ICON_SIZE : SMALL_ICON_SIZE;
1038 if (icon == null) {
1039 icon =
1040 invoke(new Callable<Image>() {
1041 public Image call() {
1042 Image newIcon = null;
1043 if (isLink()) {
1044 Win32ShellFolder2 folder = getLinkLocation(false);
1045 if (folder != null && folder.isLibrary()) {
1046 return folder.getIcon(getLargeIcon);
1047 }
1048 }
1049 if (isFileSystem() || isLibrary()) {
1050 long parentIShellIcon = (parent != null)
1051 ? ((Win32ShellFolder2) parent).getIShellIcon()
1052 : 0L;
1053 long relativePIDL = getRelativePIDL();
1054
1055 // These are cached per type (using the index in the system image list)
1056 int index = getIconIndex(parentIShellIcon, relativePIDL);
1057 if (index > 0) {
1058 Map<Integer, Image> imageCache;
1059 if (isLink()) {
1060 imageCache = getLargeIcon ? largeLinkedSystemImages : smallLinkedSystemImages;
1061 } else {
1062 imageCache = getLargeIcon ? largeSystemImages : smallSystemImages;
1063 }
1064 newIcon = imageCache.get(Integer.valueOf(index));
1065 if (newIcon == null) {
1066 long hIcon = getIcon(getAbsolutePath(), getLargeIcon);
1067 newIcon = makeIcon(hIcon, size);
1068 disposeIcon(hIcon);
1069 if (newIcon != null) {
1070 imageCache.put(Integer.valueOf(index), newIcon);
1071 }
1072 }
1073 }
1074 }
1075
1076 if (newIcon == null) {
1077 // These are only cached per object
1078 long hIcon = extractIcon(getParentIShellFolder(),
1079 getRelativePIDL(), size, false);
1080 // E_PENDING: loading can take time so get the default
1081 if(hIcon <= 0) {
1082 hIcon = extractIcon(getParentIShellFolder(),
1083 getRelativePIDL(), size, true);
1084 if(hIcon <= 0) {
1085 if (isDirectory()) {
1086 return getShell32Icon(FOLDER_ICON_ID, size);
1087 } else {
1088 return getShell32Icon(FILE_ICON_ID, size);
1089 }
1090 }
1091 }
1092 newIcon = makeIcon(hIcon, size);
1093 disposeIcon(hIcon);
1094 }
1095
1096 if (newIcon == null) {
1097 newIcon = Win32ShellFolder2.super.getIcon(getLargeIcon);
1098 }
1099 return newIcon;
1100 }
1101 });
1102 }
1103 return icon;
1104 }
1105
1106 public Image getIcon(int size) {
1107 return invoke(() -> {
1108 Image newIcon = null;
1109 if (isLink()) {
1110 Win32ShellFolder2 folder = getLinkLocation(false);
1111 if (folder != null && folder.isLibrary()) {
1112 return folder.getIcon(size);
1113 }
1114 }
1115 long hIcon = extractIcon(getParentIShellFolder(),
1116 getRelativePIDL(), size, false);
1117
1118 // E_PENDING: loading can take time so get the default
1119 if (hIcon <= 0) {
1120 hIcon = extractIcon(getParentIShellFolder(),
1121 getRelativePIDL(), size, true);
1122 if (hIcon <= 0) {
1123 if (isDirectory()) {
1124 return getShell32Icon(FOLDER_ICON_ID, size);
1125 } else {
1126 return getShell32Icon(FILE_ICON_ID, size);
1127 }
1128 }
1129 }
1130 newIcon = makeIcon(hIcon, size);
1131 disposeIcon(hIcon);
1132 return newIcon;
1133 });
1134 }
1135
1136 /**
1137 * Gets an icon from the Windows system icon list as an {@code Image}
1138 */
1139 static Image getSystemIcon(SystemIcon iconType) {
1140 long hIcon = getSystemIcon(iconType.getIconID());
1141 Image icon = makeIcon(hIcon, LARGE_ICON_SIZE);
1142 disposeIcon(hIcon);
1143 return icon;
1144 }
1145
1146 /**
1147 * Gets an icon from the Windows system icon list as an {@code Image}
1148 */
1149 static Image getShell32Icon(int iconID, int size) {
1150 boolean useVGAColors = true; // Will be ignored on XP and later
1151 Toolkit toolkit = Toolkit.getDefaultToolkit();
1152 String shellIconBPP = (String)toolkit.getDesktopProperty("win.icon.shellIconBPP");
1153 if (shellIconBPP != null) {
1154 useVGAColors = shellIconBPP.equals("4");
1155 }
1156
1157 long hIcon = getIconResource("shell32.dll", iconID, size, size, useVGAColors);
1158 if (hIcon != 0) {
1159 Image icon = makeIcon(hIcon, size);
1160 disposeIcon(hIcon);
1161 return icon;
1162 }
1163 return null;
1164 }
1165
1166 /**
1167 * Returns the canonical form of this abstract pathname. Equivalent to
1168 * <code>new Win32ShellFolder2(getParentFile(), this.{@link java.io.File#getCanonicalPath}())</code>.
1169 *
1170 * @see java.io.File#getCanonicalFile
1171 */
1172 public File getCanonicalFile() throws IOException {
1173 return this;
1174 }
1175
1176 /*
1177 * Indicates whether this is a special folder (includes My Documents)
1178 */
1179 public boolean isSpecial() {
|