diff --git a/src/java.desktop/share/classes/javax/swing/filechooser/FileSystemView.java b/src/java.desktop/share/classes/javax/swing/filechooser/FileSystemView.java index bdcdd8f3545..84b94ceeffe 100644 --- a/src/java.desktop/share/classes/javax/swing/filechooser/FileSystemView.java +++ b/src/java.desktop/share/classes/javax/swing/filechooser/FileSystemView.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2021, 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 @@ -26,6 +26,7 @@ package javax.swing.filechooser; import java.awt.Image; +import java.awt.image.AbstractMultiResolutionImage; import java.beans.PropertyChangeListener; import java.io.File; import java.io.FileNotFoundException; @@ -225,7 +226,7 @@ public abstract class FileSystemView { * 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 @@ -255,6 +256,67 @@ public abstract class FileSystemView { } } + /** + * Returns an icon for a file, directory, or folder as it would be displayed + * in a system file browser for the requested size. + *

+ * Example:

+    *     FileSystemView fsv = FileSystemView.getFileSystemView();
+    *     Icon icon = fsv.getSystemIcon(new File("application.exe"), 64, 64);
+    *     JLabel label = new JLabel(icon);
+    * 
+ * + * @implSpec The available icons may be platform specific and so the + * available sizes determined by the platform. Therefore an exact match + * for the requested size may not be possible. + * + * The icon returned may be a multi-resolution icon image, + * which allows better support for High DPI environments + * with different scaling factors. + * + * @param f a {@code File} object for which the icon will be retrieved + * @param width width of the icon in user coordinate system. + * @param height height of the icon in user coordinate system. + * @return an icon as it would be displayed by a native file chooser + * or null for a non-existent or inaccessible file. + * @throws IllegalArgumentException if an invalid parameter such + * as a negative size or a null file reference is passed. + * @see JFileChooser#getIcon + * @see AbstractMultiResolutionImage + * @see FileSystemView#getSystemIcon(File) + * @since 17 + */ + public Icon getSystemIcon(File f, int width, int height) { + if (height < 1 || width < 1) { + throw new IllegalArgumentException("Icon size can not be below 1"); + } + + if (f == null) { + throw new IllegalArgumentException("The file reference should not be null"); + } + + if(!f.exists()) { + return null; + } + + ShellFolder sf; + + try { + sf = ShellFolder.getShellFolder(f); + } catch (FileNotFoundException e) { + return null; + } + + Image img = sf.getIcon(width, height); + + if (img != null) { + return new ImageIcon(img, sf.getFolderType()); + } else { + return UIManager.getIcon(f.isDirectory() ? "FileView.directoryIcon" + : "FileView.fileIcon"); + } + } + /** * On Windows, a file can appear in multiple folders, other than its * parent directory in the filesystem. Folder could for example be the diff --git a/src/java.desktop/share/classes/sun/awt/shell/ShellFolder.java b/src/java.desktop/share/classes/sun/awt/shell/ShellFolder.java index 3c48e08d319..94402e08807 100644 --- a/src/java.desktop/share/classes/sun/awt/shell/ShellFolder.java +++ b/src/java.desktop/share/classes/sun/awt/shell/ShellFolder.java @@ -207,6 +207,16 @@ public abstract class ShellFolder extends File { return null; } + /** + * Returns the icon of the specified size used to display this shell folder. + * + * @param width width of the icon > 0 + * @param height height of the icon > 0 + * @return The icon of the specified size used to display this shell folder + */ + public Image getIcon(int width, int height) { + return null; + } // Static diff --git a/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolder2.java b/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolder2.java index eebe8e19d2a..b0f1251943d 100644 --- a/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolder2.java +++ b/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolder2.java @@ -82,6 +82,16 @@ import javax.swing.SwingConstants; @SuppressWarnings("serial") // JDK-implementation class final class Win32ShellFolder2 extends ShellFolder { + static final int SMALL_ICON_SIZE = 16; + static final int LARGE_ICON_SIZE = 32; + static final int MIN_QUALITY_ICON = 16; + static final int MAX_QUALITY_ICON = 256; + private final static int[] ICON_RESOLUTIONS + = {16, 24, 32, 48, 64, 72, 96, 128, 256}; + + static final int FILE_ICON_ID = 1; + static final int FOLDER_ICON_ID = 4; + private static native void initIDs(); static { @@ -991,14 +1001,15 @@ final class Win32ShellFolder2 extends ShellFolder { // 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); + + // NOTE: this method uses COM and must be called on the 'COM thread'. See ComInvoker for the details + private static native boolean hiResIconAvailable(long parentIShellFolder, long relativePIDL); // Returns an icon from the Windows system icon list in the form of an HICON private static native long getSystemIcon(int iconID); private static native long getIconResource(String libName, int iconID, - int cxDesired, int cyDesired, - boolean useVGAColors); - // Note: useVGAColors is ignored on XP and later + int cxDesired, int cyDesired); // Return the bits from an HICON. This has a side effect of setting // the imageHash variable for efficient caching / comparing. @@ -1018,20 +1029,17 @@ final class Win32ShellFolder2 extends ShellFolder { return pIShellIcon; } - private static Image makeIcon(long hIcon, boolean getLargeIcon) { + private static Image makeIcon(long hIcon) { 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 int iconSize = (int) Math.sqrt(iconBits.length); final BufferedImage img = - new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB); - img.setRGB(0, 0, size, size, iconBits, 0, size); - return size == baseSize - ? img - : new MultiResolutionIconImage(baseSize, img); + new BufferedImage(iconSize, iconSize, BufferedImage.TYPE_INT_ARGB); + img.setRGB(0, 0, iconSize, iconSize, iconBits, 0, iconSize); + return img; } } return null; @@ -1043,11 +1051,13 @@ final class Win32ShellFolder2 extends ShellFolder { */ public Image getIcon(final boolean getLargeIcon) { Image icon = getLargeIcon ? largeIcon : smallIcon; + int size = getLargeIcon ? LARGE_ICON_SIZE : SMALL_ICON_SIZE; if (icon == null) { icon = invoke(new Callable() { public Image call() { Image newIcon = null; + Image newIcon2 = null; if (isLink()) { Win32ShellFolder2 folder = getLinkLocation(false); if (folder != null && folder.isLibrary()) { @@ -1072,33 +1082,40 @@ final class Win32ShellFolder2 extends ShellFolder { newIcon = imageCache.get(Integer.valueOf(index)); if (newIcon == null) { long hIcon = getIcon(getAbsolutePath(), getLargeIcon); - newIcon = makeIcon(hIcon, getLargeIcon); + newIcon = makeIcon(hIcon); disposeIcon(hIcon); if (newIcon != null) { imageCache.put(Integer.valueOf(index), newIcon); } } + if (newIcon != null) { + if (isLink()) { + imageCache = getLargeIcon ? smallLinkedSystemImages + : largeLinkedSystemImages; + } else { + imageCache = getLargeIcon ? smallSystemImages : largeSystemImages; + } + newIcon2 = imageCache.get(index); + if (newIcon2 == null) { + long hIcon = getIcon(getAbsolutePath(), !getLargeIcon); + newIcon2 = makeIcon(hIcon); + disposeIcon(hIcon); + } + } + + if (newIcon2 != null) { + Map bothIcons = new HashMap<>(2); + bothIcons.put(getLargeIcon ? LARGE_ICON_SIZE : SMALL_ICON_SIZE, newIcon); + bothIcons.put(getLargeIcon ? SMALL_ICON_SIZE : LARGE_ICON_SIZE, newIcon2); + newIcon = new MultiResolutionIconImage(getLargeIcon ? LARGE_ICON_SIZE + : SMALL_ICON_SIZE, bothIcons); + } } } - if (newIcon == null) { - // These are only cached per object - long hIcon = extractIcon(getParentIShellFolder(), - getRelativePIDL(), getLargeIcon, false); - // E_PENDING: loading can take time so get the default - if(hIcon <= 0) { - hIcon = extractIcon(getParentIShellFolder(), - getRelativePIDL(), getLargeIcon, true); - if(hIcon <= 0) { - if (isDirectory()) { - return getShell32Icon(4, getLargeIcon); - } else { - return getShell32Icon(1, getLargeIcon); - } - } - } - newIcon = makeIcon(hIcon, getLargeIcon); - disposeIcon(hIcon); + if (hiResIconAvailable(getParentIShellFolder(), getRelativePIDL()) || newIcon == null) { + int size = getLargeIcon ? LARGE_ICON_SIZE : SMALL_ICON_SIZE; + newIcon = getIcon(size, size); } if (newIcon == null) { @@ -1107,21 +1124,68 @@ final class Win32ShellFolder2 extends ShellFolder { return newIcon; } }); - if (getLargeIcon) { - largeIcon = icon; - } else { - smallIcon = icon; - } } return icon; } + /** + * @return The icon image of specified size used to display this shell folder + */ + public Image getIcon(int width, int height) { + int size = Math.max(width, height); + return invoke(() -> { + Image newIcon = null; + if (isLink()) { + Win32ShellFolder2 folder = getLinkLocation(false); + if (folder != null && folder.isLibrary()) { + return folder.getIcon(size, size); + } + } + Map multiResolutionIcon = new HashMap<>(); + int start = size > MAX_QUALITY_ICON ? ICON_RESOLUTIONS.length - 1 : 0; + int increment = size > MAX_QUALITY_ICON ? -1 : 1; + int end = size > MAX_QUALITY_ICON ? -1 : ICON_RESOLUTIONS.length; + for (int i = start; i != end; i += increment) { + int s = ICON_RESOLUTIONS[i]; + if (size < MIN_QUALITY_ICON || size > MAX_QUALITY_ICON + || (s >= size && s <= size*2)) { + long hIcon = extractIcon(getParentIShellFolder(), + getRelativePIDL(), s, false); + + // E_PENDING: loading can take time so get the default + if (hIcon <= 0) { + hIcon = extractIcon(getParentIShellFolder(), + getRelativePIDL(), s, true); + if (hIcon <= 0) { + if (isDirectory()) { + return getShell32Icon(FOLDER_ICON_ID, size); + } else { + return getShell32Icon(FILE_ICON_ID, size); + } + } + } + newIcon = makeIcon(hIcon); + disposeIcon(hIcon); + + multiResolutionIcon.put(s, newIcon); + if (size < MIN_QUALITY_ICON || size > MAX_QUALITY_ICON) { + break; + } + } + } + return new MultiResolutionIconImage(size, multiResolutionIcon); + }); + } + /** * 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); + if (LARGE_ICON_SIZE != icon.getWidth(null)) { + icon = new MultiResolutionIconImage(LARGE_ICON_SIZE, icon); + } disposeIcon(hIcon); return icon; } @@ -1129,20 +1193,13 @@ final class Win32ShellFolder2 extends ShellFolder { /** * Gets an icon from the Windows system icon list as an {@code Image} */ - static Image getShell32Icon(int iconID, boolean getLargeIcon) { - 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) { - useVGAColors = shellIconBPP.equals("4"); - } - - long hIcon = getIconResource("shell32.dll", iconID, size, size, useVGAColors); + static Image getShell32Icon(int iconID, int size) { + long hIcon = getIconResource("shell32.dll", iconID, size, size); if (hIcon != 0) { - Image icon = makeIcon(hIcon, getLargeIcon); + Image icon = makeIcon(hIcon); + if (size != icon.getWidth(null)) { + icon = new MultiResolutionIconImage(size, icon); + } disposeIcon(hIcon); return icon; } @@ -1325,13 +1382,17 @@ final class Win32ShellFolder2 extends ShellFolder { } static class MultiResolutionIconImage extends AbstractMultiResolutionImage { - final int baseSize; - final Image resolutionVariant; + final Map resolutionVariants = new HashMap<>(); - public MultiResolutionIconImage(int baseSize, Image resolutionVariant) { + public MultiResolutionIconImage(int baseSize, Map resolutionVariants) { this.baseSize = baseSize; - this.resolutionVariant = resolutionVariant; + this.resolutionVariants.putAll(resolutionVariants); + } + + public MultiResolutionIconImage(int baseSize, Image image) { + this.baseSize = baseSize; + this.resolutionVariants.put(baseSize, image); } @Override @@ -1346,17 +1407,34 @@ final class Win32ShellFolder2 extends ShellFolder { @Override protected Image getBaseImage() { - return resolutionVariant; + return getResolutionVariant(baseSize, baseSize); } @Override public Image getResolutionVariant(double width, double height) { - return resolutionVariant; + int dist = 0; + Image retVal = null; + // We only care about width since we don't support non-rectangular icons + int w = (int) width; + int retindex = 0; + for (Integer i : resolutionVariants.keySet()) { + if (retVal == null || dist > Math.abs(i - w) + || (dist == Math.abs(i - w) && i > retindex)) { + retindex = i; + dist = Math.abs(i - w); + retVal = resolutionVariants.get(i); + if (i == w) { + break; + } + } + } + return retVal; } @Override public List getResolutionVariants() { - return Arrays.asList(resolutionVariant); + return Collections.unmodifiableList( + new ArrayList(resolutionVariants.values())); } } } diff --git a/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java b/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java index 8dd6cbbb38b..c9fdfcd4220 100644 --- a/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java +++ b/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2021, 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 @@ -53,10 +53,12 @@ import sun.util.logging.PlatformLogger; import static sun.awt.shell.Win32ShellFolder2.DESKTOP; import static sun.awt.shell.Win32ShellFolder2.DRIVES; import static sun.awt.shell.Win32ShellFolder2.Invoker; +import static sun.awt.shell.Win32ShellFolder2.LARGE_ICON_SIZE; import static sun.awt.shell.Win32ShellFolder2.MultiResolutionIconImage; import static sun.awt.shell.Win32ShellFolder2.NETWORK; import static sun.awt.shell.Win32ShellFolder2.PERSONAL; import static sun.awt.shell.Win32ShellFolder2.RECENT; +import static sun.awt.shell.Win32ShellFolder2.SMALL_ICON_SIZE; // NOTE: This class supersedes Win32ShellFolderManager, which was removed // from distribution after version 1.4.2. @@ -144,9 +146,9 @@ final class Win32ShellFolderManager2 extends ShellFolderManager { new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB); img.setRGB(0, 0, size, size, iconBits, 0, size); - STANDARD_VIEW_BUTTONS[iconIndex] = (size == 16) + STANDARD_VIEW_BUTTONS[iconIndex] = (size == SMALL_ICON_SIZE) ? img - : new MultiResolutionIconImage(16, img); + : new MultiResolutionIconImage(SMALL_ICON_SIZE, img); } return STANDARD_VIEW_BUTTONS[iconIndex]; @@ -408,7 +410,8 @@ final class Win32ShellFolderManager2 extends ShellFolderManager { try { int i = Integer.parseInt(name); if (i >= 0) { - return Win32ShellFolder2.getShell32Icon(i, key.startsWith("shell32LargeIcon ")); + return Win32ShellFolder2.getShell32Icon(i, + key.startsWith("shell32LargeIcon ") ? LARGE_ICON_SIZE : SMALL_ICON_SIZE); } } catch (NumberFormatException ex) { } diff --git a/src/java.desktop/windows/native/libawt/windows/ShellFolder2.cpp b/src/java.desktop/windows/native/libawt/windows/ShellFolder2.cpp index 6e6d5bd0210..bc0c27d069a 100644 --- a/src/java.desktop/windows/native/libawt/windows/ShellFolder2.cpp +++ b/src/java.desktop/windows/native/libawt/windows/ShellFolder2.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2021, 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 @@ -880,7 +880,7 @@ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_getIcon LPCTSTR pathStr = JNU_GetStringPlatformChars(env, absolutePath, NULL); JNU_CHECK_EXCEPTION_RETURN(env, 0); if (fn_SHGetFileInfo(pathStr, 0L, &fileInfo, sizeof(fileInfo), - SHGFI_ICON | (getLargeIcon ? 0 : SHGFI_SMALLICON)) != 0) { + SHGFI_ICON | (getLargeIcon ? SHGFI_LARGEICON : SHGFI_SMALLICON)) != 0) { hIcon = fileInfo.hIcon; } JNU_ReleaseStringPlatformChars(env, absolutePath, pathStr); @@ -912,15 +912,54 @@ JNIEXPORT jint JNICALL Java_sun_awt_shell_Win32ShellFolder2_getIconIndex return (jint)index; } +/* + * Class: sun.awt.shell.Win32ShellFolder2 + * Method: hiResIconAvailable + * Signature: (JJ)Z + */ +JNIEXPORT jboolean JNICALL Java_sun_awt_shell_Win32ShellFolder2_hiResIconAvailable + (JNIEnv* env, jclass cls, jlong pIShellFolderL, jlong relativePIDL) +{ + IShellFolder* pIShellFolder = (IShellFolder*)pIShellFolderL; + LPITEMIDLIST pidl = (LPITEMIDLIST)relativePIDL; + if (pIShellFolder == NULL || pidl == NULL) { + return FALSE; + } + HRESULT hres; + IExtractIconW* pIcon; + hres = pIShellFolder->GetUIObjectOf(NULL, 1, const_cast(&pidl), + IID_IExtractIconW, NULL, (void**)&pIcon); + if (SUCCEEDED(hres)) { + WCHAR szBuf[MAX_PATH]; + INT index; + UINT flags; + UINT uFlags = GIL_FORSHELL | GIL_ASYNC; + hres = pIcon->GetIconLocation(uFlags, szBuf, MAX_PATH, &index, &flags); + if (SUCCEEDED(hres)) { + pIcon->Release(); + return wcscmp(szBuf, L"*") != 0; + } else if (hres == E_PENDING) { + uFlags = GIL_DEFAULTICON; + hres = pIcon->GetIconLocation(uFlags, szBuf, MAX_PATH, &index, &flags); + if (SUCCEEDED(hres)) { + pIcon->Release(); + return wcscmp(szBuf, L"*") != 0; + } + } + pIcon->Release(); + } + return FALSE; +} + /* * Class: sun_awt_shell_Win32ShellFolder2 * Method: extractIcon - * Signature: (JJZZ)J + * Signature: (JJIZ)J */ 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 +980,10 @@ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_extractIcon 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); - } + if (size < 24) { + size = 16; } + hres = pIcon->Extract(szBuf, index, &hIcon, NULL, size); } else if (hres == E_PENDING) { pIcon->Release(); return E_PENDING; @@ -980,7 +1013,7 @@ JNIEXPORT void JNICALL Java_sun_awt_shell_Win32ShellFolder2_disposeIcon JNIEXPORT jintArray JNICALL Java_sun_awt_shell_Win32ShellFolder2_getIconBits (JNIEnv* env, jclass cls, jlong hicon) { - const int MAX_ICON_SIZE = 128; + const int MAX_ICON_SIZE = 256; int iconSize = 0; jintArray iconBits = NULL; @@ -1121,11 +1154,11 @@ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_getSystemIcon /* * Class: sun_awt_shell_Win32ShellFolder2 * Method: getIconResource - * Signature: (Ljava/lang/String;IIIZ)J + * Signature: (Ljava/lang/String;III)J */ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_getIconResource (JNIEnv* env, jclass cls, jstring libName, jint iconID, - jint cxDesired, jint cyDesired, jboolean useVGAColors) + jint cxDesired, jint cyDesired) { const char *pLibName = env->GetStringUTFChars(libName, NULL); JNU_CHECK_EXCEPTION_RETURN(env, 0); @@ -1134,10 +1167,9 @@ JNIEXPORT jlong JNICALL Java_sun_awt_shell_Win32ShellFolder2_getIconResource env->ReleaseStringUTFChars(libName, pLibName); } if (libHandle != NULL) { - UINT fuLoad = (useVGAColors && !IS_WINXP) ? LR_VGACOLOR : 0; return ptr_to_jlong(LoadImage(libHandle, MAKEINTRESOURCE(iconID), IMAGE_ICON, cxDesired, cyDesired, - fuLoad)); + 0)); } return 0; } diff --git a/test/jdk/javax/swing/JFileChooser/FileSystemView/SystemIconTest.java b/test/jdk/javax/swing/JFileChooser/FileSystemView/SystemIconTest.java new file mode 100644 index 00000000000..aeb3b09c3dd --- /dev/null +++ b/test/jdk/javax/swing/JFileChooser/FileSystemView/SystemIconTest.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2021, 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 + * @run main SystemIconTest + */ +import javax.swing.Icon; +import javax.swing.ImageIcon; +import javax.swing.filechooser.FileSystemView; +import java.awt.image.MultiResolutionImage; +import java.io.File; + +public class SystemIconTest { + static final FileSystemView fsv = FileSystemView.getFileSystemView(); + + public static void main(String[] args) { + testSystemIcon(); + negativeTests(); + } + + static void testSystemIcon() { + String os = System.getProperty("os.name"); + if (os.startsWith("Windows")) { + String windir = System.getenv("windir"); + testSystemIcon(new File(windir), true); + testSystemIcon(new File(windir + "/explorer.exe"), + true); + } else { + String homedir = System.getProperty("user.home"); + testSystemIcon(new File(homedir), false); + } + } + + static void negativeTests() { + Icon icon; + try { + icon = fsv.getSystemIcon(new File("."), -1, 16); + throw new RuntimeException("Negative size icon should throw invalid argument exception"); + } catch (IllegalArgumentException iae) { + // Expected + } + + icon = fsv.getSystemIcon(new File("thereisdefinitelynosuchfile.why"), + 16, 16); + if (icon != null) { + throw new RuntimeException("Icons for files with invalid names should be null"); + } + } + + static void testSystemIcon(File file, boolean implComplete) { + 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 == null) { + throw new RuntimeException("icon is null!!!"); + } + + if (implComplete && icon.getIconWidth() != size) { + throw new RuntimeException("Wrong icon size " + + icon.getIconWidth() + " when requested " + size); + } + + if (icon.getImage() instanceof MultiResolutionImage) { + MultiResolutionImage mri = (MultiResolutionImage) icon.getImage(); + if (mri.getResolutionVariant(size, size) == null) { + throw new RuntimeException("There is no suitable variant for the size " + + size + " in the multi resolution icon"); + } + } else { + if (implComplete) { + throw new RuntimeException("icon is supposed to be multi-resolution but it is not"); + } + } + } + } +}