--- old/src/java.desktop/share/classes/javax/swing/filechooser/FileSystemView.java 2018-07-30 12:17:24.218779400 +0530
+++ new/src/java.desktop/share/classes/javax/swing/filechooser/FileSystemView.java 2018-07-30 12:17:20.755754200 +0530
@@ -45,6 +45,14 @@
import jdk.internal.ref.CleanerFactory;
import sun.awt.shell.ShellFolder;
+import java.awt.image.BufferedImage;
+import java.awt.Graphics2D;
+import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsDevice;
+import java.awt.GraphicsEnvironment;
+import java.awt.RenderingHints;
+import java.awt.Transparency;
+
/**
* FileSystemView is JFileChooser's gateway to the
* file system. Since the JDK1.1 File API doesn't allow
@@ -256,6 +264,123 @@
}
/**
+ * Scaled icon for a file, directory, or folder as it would be displayed in
+ * a system file browser. Example from Windows: the "M:\" directory
+ * displays a CD-ROM icon.
+ *
+ * The default implementation gets information from the ShellFolder class.
+ *
+ * @param f a File
object
+ * @param width width of the icon in pixels to be scaled(valid range: 1 to 256)
+ * @param height height of the icon in pixels to be scaled(valid range: 1 to 256)
+ * @return an icon as it would be displayed by a native file chooser
+ * @see JFileChooser#getIcon
+ * @since 12
+ */
+ public Icon getSystemIcon(File f, int width, int height) {
+ if (f == null) {
+ return null;
+ }
+
+ if((width > 256 || width < 1) || (height > 256 || height < 1)) {
+ return null;
+ }
+
+ ShellFolder sf;
+ try {
+ sf = getShellFolder(f);
+ } catch (FileNotFoundException e) {
+ return null;
+ }
+
+ int size;
+ if(width > height) {
+ size = width;
+ } else {
+ size = height;
+ }
+
+ Image img = sf.getIcon(size);
+
+ // scale the icon in case the width/height does not match the requested
+ if (img != null) {
+ if((img.getWidth(null) != width) || (img.getHeight(null) != height)) {
+ Image scaledImg = scaleIconImage(img, null, width, height);
+
+ // set the scaled icon
+ if(scaledImg != null) {
+ img = scaledImg;
+ } else {
+ return null;
+ }
+ }
+ } else {
+ Icon icon = UIManager.getIcon(f.isDirectory() ? "FileView.directoryIcon" : "FileView.fileIcon");
+
+ if((icon != null) && ((icon.getIconWidth() != width) || (icon.getIconHeight() != height))) {
+ Image scaledImg = scaleIconImage(null, icon, width, height);
+
+ // set the scaled icon
+ if(scaledImg != null) {
+ img = scaledImg;
+ } else {
+ return null;
+ }
+ }
+ }
+
+ if (img != null) {
+ return new ImageIcon(img, sf.getFolderType());
+ }
+
+ return null;
+ }
+
+ private static Image scaleIconImage(Image srcImage, Icon srcIcon, int scaledW, int scaledH) {
+ if (srcImage == null && srcIcon == null) {
+ return null;
+ }
+
+ int w;
+ int h;
+
+ if(srcImage != null) {
+ w = srcImage.getWidth(null);
+ h = srcImage.getHeight(null);
+ } else {
+ w = srcIcon.getIconWidth();
+ h = srcIcon.getIconHeight();
+ }
+
+ GraphicsEnvironment ge =
+ GraphicsEnvironment.getLocalGraphicsEnvironment();
+ GraphicsDevice gd = ge.getDefaultScreenDevice();
+ GraphicsConfiguration gc = gd.getDefaultConfiguration();
+
+ // convert to image
+ BufferedImage iconImage = gc.createCompatibleImage(w, h,
+ Transparency.TRANSLUCENT);
+ Graphics2D g = iconImage.createGraphics();
+ if(srcImage != null) {
+ g.drawImage(srcImage, 0, 0, w, h, null);
+ } else {
+ srcIcon.paintIcon(null, g, 0, 0);
+ }
+ g.dispose();
+
+ // and scale it nicely
+ BufferedImage scaledImage = gc.createCompatibleImage(scaledW, scaledH,
+ Transparency.TRANSLUCENT);
+ g = scaledImage.createGraphics();
+ g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
+ RenderingHints.VALUE_INTERPOLATION_BILINEAR);
+ g.drawImage(iconImage, 0, 0, scaledW, scaledH, null);
+ g.dispose();
+
+ return (Image)scaledImage;
+ }
+
+ /**
* On Windows, a file can appear in multiple folders, other than its
* parent directory in the filesystem. Folder could for example be the
* "Desktop" folder which is not the same as file.getParentFile().
--- old/src/java.desktop/share/classes/sun/awt/shell/ShellFolder.java 2018-07-30 12:18:00.561049700 +0530
+++ new/src/java.desktop/share/classes/sun/awt/shell/ShellFolder.java 2018-07-30 12:17:57.384009300 +0530
@@ -199,6 +199,13 @@
return null;
}
+ /**
+ * @param size size of the icon > 0
+ * @return The icon used to display this shell folder
+ */
+ public Image getIcon(int size) {
+ return null;
+ }
// Static
--- old/src/java.desktop/windows/native/libawt/windows/ShellFolder2.cpp 2018-07-30 12:18:27.405218000 +0530
+++ new/src/java.desktop/windows/native/libawt/windows/ShellFolder2.cpp 2018-07-30 12:18:24.286198100 +0530
@@ -920,7 +920,7 @@
*/
JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_extractIcon
(JNIEnv* env, jclass cls, jlong pIShellFolderL, jlong relativePIDL,
- jboolean getLargeIcon, jboolean getDefaultIcon)
+ jint size, jboolean getDefaultIcon)
{
IShellFolder* pIShellFolder = (IShellFolder*)pIShellFolderL;
LPITEMIDLIST pidl = (LPITEMIDLIST)relativePIDL;
@@ -941,16 +941,7 @@
UINT uFlags = getDefaultIcon ? GIL_DEFAULTICON : GIL_FORSHELL | GIL_ASYNC;
hres = pIcon->GetIconLocation(uFlags, szBuf, MAX_PATH, &index, &flags);
if (SUCCEEDED(hres)) {
- HICON hIconLarge;
- hres = pIcon->Extract(szBuf, index, &hIconLarge, &hIcon, (16 << 16) + 32);
- if (SUCCEEDED(hres)) {
- if (getLargeIcon) {
- fn_DestroyIcon((HICON)hIcon);
- hIcon = hIconLarge;
- } else {
- fn_DestroyIcon((HICON)hIconLarge);
- }
- }
+ hres = pIcon->Extract(szBuf, index, &hIcon, 0, size);
} else if (hres == E_PENDING) {
pIcon->Release();
return E_PENDING;
--- old/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolder2.java 2018-07-30 12:19:00.394451200 +0530
+++ new/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolder2.java 2018-07-30 12:18:57.073426200 +0530
@@ -977,7 +977,7 @@
// NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details
private static native long extractIcon(long parentIShellFolder, long relativePIDL,
- boolean getLargeIcon, boolean getDefaultIcon);
+ int size, boolean getDefaultIcon);
// Returns an icon from the Windows system icon list in the form of an HICON
private static native long getSystemIcon(int iconID);
@@ -1004,20 +1004,19 @@
return pIShellIcon;
}
- private static Image makeIcon(long hIcon, boolean getLargeIcon) {
+ private static Image makeIcon(long hIcon, int bsize) {
if (hIcon != 0L && hIcon != -1L) {
// Get the bits. This has the side effect of setting the imageHash value for this object.
final int[] iconBits = getIconBits(hIcon);
if (iconBits != null) {
// icons are always square
final int size = (int) Math.sqrt(iconBits.length);
- final int baseSize = getLargeIcon ? 32 : 16;
final BufferedImage img =
new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB);
img.setRGB(0, 0, size, size, iconBits, 0, size);
- return size == baseSize
+ return size == bsize
? img
- : new MultiResolutionIconImage(baseSize, img);
+ : new MultiResolutionIconImage(bsize, img);
}
}
return null;
@@ -1029,6 +1028,7 @@
*/
public Image getIcon(final boolean getLargeIcon) {
Image icon = getLargeIcon ? largeIcon : smallIcon;
+ int size = getLargeIcon ? 32 : 16; // large icon is 32 pixels else 16 pixels
if (icon == null) {
icon =
invoke(new Callable() {
@@ -1058,7 +1058,7 @@
newIcon = imageCache.get(Integer.valueOf(index));
if (newIcon == null) {
long hIcon = getIcon(getAbsolutePath(), getLargeIcon);
- newIcon = makeIcon(hIcon, getLargeIcon);
+ newIcon = makeIcon(hIcon, size);
disposeIcon(hIcon);
if (newIcon != null) {
imageCache.put(Integer.valueOf(index), newIcon);
@@ -1070,20 +1070,20 @@
if (newIcon == null) {
// These are only cached per object
long hIcon = extractIcon(getParentIShellFolder(),
- getRelativePIDL(), getLargeIcon, false);
+ getRelativePIDL(), size, false);
// E_PENDING: loading can take time so get the default
if(hIcon <= 0) {
hIcon = extractIcon(getParentIShellFolder(),
- getRelativePIDL(), getLargeIcon, true);
+ getRelativePIDL(), size, true);
if(hIcon <= 0) {
if (isDirectory()) {
- return getShell32Icon(4, getLargeIcon);
+ return getShell32Icon(4, size); // pick folder icon
} else {
- return getShell32Icon(1, getLargeIcon);
+ return getShell32Icon(1, size); // pick file icon
}
}
}
- newIcon = makeIcon(hIcon, getLargeIcon);
+ newIcon = makeIcon(hIcon, size);
disposeIcon(hIcon);
}
@@ -1093,21 +1093,46 @@
return newIcon;
}
});
- if (getLargeIcon) {
- largeIcon = icon;
- } else {
- smallIcon = icon;
- }
}
return icon;
}
+ public Image getIcon(int size) {
+ return invoke(() -> {
+ Image newIcon = null;
+ if (isLink()) {
+ Win32ShellFolder2 folder = getLinkLocation(false);
+ if (folder != null && folder.isLibrary()) {
+ return folder.getIcon(size);
+ }
+ }
+ long hIcon = extractIcon(getParentIShellFolder(),
+ getRelativePIDL(), size, false);
+
+ // E_PENDING: loading can take time so get the default
+ if(hIcon <= 0) {
+ hIcon = extractIcon(getParentIShellFolder(),
+ getRelativePIDL(), size, true);
+ if(hIcon <= 0) {
+ if (isDirectory()) {
+ return getShell32Icon(4, size);
+ } else {
+ return getShell32Icon(1, size);
+ }
+ }
+ }
+ newIcon = makeIcon(hIcon, size);
+ disposeIcon(hIcon);
+ return newIcon;
+ });
+ }
+
/**
* Gets an icon from the Windows system icon list as an {@code Image}
*/
static Image getSystemIcon(SystemIcon iconType) {
long hIcon = getSystemIcon(iconType.getIconID());
- Image icon = makeIcon(hIcon, true);
+ Image icon = makeIcon(hIcon, 32);
disposeIcon(hIcon);
return icon;
}
@@ -1115,11 +1140,8 @@
/**
* Gets an icon from the Windows system icon list as an {@code Image}
*/
- static Image getShell32Icon(int iconID, boolean getLargeIcon) {
+ static Image getShell32Icon(int iconID, int size) {
boolean useVGAColors = true; // Will be ignored on XP and later
-
- int size = getLargeIcon ? 32 : 16;
-
Toolkit toolkit = Toolkit.getDefaultToolkit();
String shellIconBPP = (String)toolkit.getDesktopProperty("win.icon.shellIconBPP");
if (shellIconBPP != null) {
@@ -1128,7 +1150,7 @@
long hIcon = getIconResource("shell32.dll", iconID, size, size, useVGAColors);
if (hIcon != 0) {
- Image icon = makeIcon(hIcon, getLargeIcon);
+ Image icon = makeIcon(hIcon, size);
disposeIcon(hIcon);
return icon;
}
--- old/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java 2018-07-30 12:19:41.046733900 +0530
+++ new/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java 2018-07-30 12:19:37.932706400 +0530
@@ -379,7 +379,8 @@
try {
int i = Integer.parseInt(name);
if (i >= 0) {
- return Win32ShellFolder2.getShell32Icon(i, key.startsWith("shell32LargeIcon "));
+ return Win32ShellFolder2.getShell32Icon(i, key.startsWith("shell32LargeIcon ")?
+ 32 : 16);
}
} catch (NumberFormatException ex) {
}
--- /dev/null 2018-07-30 12:20:13.000000000 +0530
+++ new/test/jdk/javax/swing/JFileChooser/FileSystemView/SystemIconTest.java 2018-07-30 12:20:07.704913200 +0530
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8182043
+ * @summary Access to Windows Large Icons
+ * sun.awt.shell.ShellFolder
+ * @run main SystemIconTest
+ */
+
+import javax.swing.ImageIcon;
+import javax.swing.filechooser.FileSystemView;
+import java.io.File;
+
+public class SystemIconTest {
+ static final FileSystemView fsv = FileSystemView.getFileSystemView();
+
+ public static void main(String[] args) {
+ if(System.getProperty("os.name").toLowerCase().contains("windows")) {
+ System.out.println("Windows detected: will run sytem icons test");
+ testSystemIcon();
+ }
+
+ System.out.println("ok");
+ }
+
+ static void testSystemIcon() {
+ String windir = System.getenv("windir");
+ testSystemIcon(new File(windir));
+ testSystemIcon(new File(windir + "/explorer.exe"));
+ return;
+ }
+
+ static void testSystemIcon(File file) {
+ int[] sizes = new int[] {16, 32, 48, 64, 128};
+ for (int size : sizes) {
+ ImageIcon icon = (ImageIcon)fsv.getSystemIcon(file, size, size);
+
+ //Enable below to see the icon
+ //JLabel label = new JLabel(icon);
+ //JOptionPane.showMessageDialog(null, label);
+
+ if (icon.getIconWidth() != size) {
+ throw new RuntimeException("Wrong icon size " +
+ icon.getIconWidth() + " when requested " + size);
+ }
+ }
+ }
+}