6840086: JFileChooser lacks icons on top right when running on Windows 7
authorrupashka
Fri, 18 Sep 2009 15:11:28 +0400
changeset 3978 b024e01b947a
parent 3977 0da8e3baf0b5
child 3979 66f32a866212
6840086: JFileChooser lacks icons on top right when running on Windows 7 Reviewed-by: peterz, uta
jdk/src/share/classes/sun/awt/shell/ShellFolderManager.java
jdk/src/windows/classes/sun/awt/shell/Win32ShellFolder2.java
jdk/src/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java
jdk/src/windows/native/sun/windows/ShellFolder2.cpp
jdk/test/javax/swing/JFileChooser/6840086/bug6840086.java
--- a/jdk/src/share/classes/sun/awt/shell/ShellFolderManager.java	Thu Sep 17 19:08:15 2009 +0400
+++ b/jdk/src/share/classes/sun/awt/shell/ShellFolderManager.java	Fri Sep 18 15:11:28 2009 +0400
@@ -57,8 +57,9 @@
      *    folders, such as Desktop, Documents, History, Network, Home, etc.
      *    This is used in the shortcut panel of the filechooser on Windows 2000
      *    and Windows Me.
-     *  "fileChooserIcon nn":
-     *    Returns an <code>Image</code> - icon nn from resource 124 in comctl32.dll (Windows only).
+     *  "fileChooserIcon <icon>":
+     *    Returns an <code>Image</code> - icon can be ListView, DetailsView, UpFolder, NewFolder or
+     *    ViewMenu (Windows only).
      *
      * @return An Object matching the key string.
      */
--- a/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolder2.java	Thu Sep 17 19:08:15 2009 +0400
+++ b/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolder2.java	Fri Sep 18 15:11:28 2009 +0400
@@ -922,7 +922,7 @@
     // Dispose the HICON
     private static native void disposeIcon(long hIcon);
 
-    public static native int[] getFileChooserBitmapBits();
+    static native int[] getStandardViewButton0(int iconIndex);
 
     // Should be called from the COM thread
     private long getIShellIcon() {
@@ -933,34 +933,6 @@
         return pIShellIcon;
     }
 
-
-    static int[] fileChooserBitmapBits = null;
-    static Image[] fileChooserIcons = new Image[47];
-
-    static Image getFileChooserIcon(int i) {
-        if (fileChooserIcons[i] != null) {
-            return fileChooserIcons[i];
-        } else {
-            if (fileChooserBitmapBits == null) {
-                fileChooserBitmapBits = getFileChooserBitmapBits();
-            }
-            if (fileChooserBitmapBits != null) {
-                int nImages = fileChooserBitmapBits.length / (16*16);
-                int[] bitmapBits = new int[16 * 16];
-                for (int y = 0; y < 16; y++) {
-                    for (int x = 0; x < 16; x++) {
-                        bitmapBits[y * 16 + x] = fileChooserBitmapBits[y * (nImages * 16) + (i * 16) + x];
-                    }
-                }
-                BufferedImage img = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);
-                img.setRGB(0, 0, 16, 16, bitmapBits, 0, 16);
-                fileChooserIcons[i] = img;
-            }
-        }
-        return fileChooserIcons[i];
-    }
-
-
     private static Image makeIcon(long hIcon, boolean getLargeIcon) {
         if (hIcon != 0L && hIcon != -1L) {
             // Get the bits.  This has the side effect of setting the imageHash value for this object.
--- a/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java	Thu Sep 17 19:08:15 2009 +0400
+++ b/jdk/src/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java	Fri Sep 18 15:11:28 2009 +0400
@@ -25,7 +25,8 @@
 
 package sun.awt.shell;
 
-import java.awt.Toolkit;
+import java.awt.*;
+import java.awt.image.BufferedImage;
 
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -33,6 +34,7 @@
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.*;
+import java.util.List;
 import java.util.concurrent.*;
 
 import sun.security.action.LoadLibraryAction;
@@ -98,6 +100,29 @@
         return parent;
     }
 
+    private static final int VIEW_LIST = 2;
+    private static final int VIEW_DETAILS = 3;
+    private static final int VIEW_PARENTFOLDER = 8;
+    private static final int VIEW_NEWFOLDER = 11;
+
+    private static final Image[] STANDARD_VIEW_BUTTONS = new Image[12];
+
+    private static Image getStandardViewButton(int iconIndex) {
+        Image result = STANDARD_VIEW_BUTTONS[iconIndex];
+
+        if (result != null) {
+            return result;
+        }
+
+        BufferedImage img = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);
+
+        img.setRGB(0, 0, 16, 16, Win32ShellFolder2.getStandardViewButton0(iconIndex), 0, 16);
+
+        STANDARD_VIEW_BUTTONS[iconIndex] = img;
+
+        return img;
+    }
+
     // Special folders
     private static Win32ShellFolder2 desktop;
     private static Win32ShellFolder2 drives;
@@ -105,12 +130,6 @@
     private static Win32ShellFolder2 network;
     private static Win32ShellFolder2 personal;
 
-    private static final boolean USE_SHELL32_ICONS = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
-        public Boolean run() {
-            return OSInfo.getWindowsVersion().compareTo(OSInfo.WINDOWS_XP) >= 0;
-        }
-    });
-
     static Win32ShellFolder2 getDesktop() {
         if (desktop == null) {
             try {
@@ -206,9 +225,9 @@
      *    folders, such as Desktop, Documents, History, Network, Home, etc.
      *    This is used in the shortcut panel of the filechooser on Windows 2000
      *    and Windows Me.
-     *  "fileChooserIcon nn":
-     *    Returns an <code>Image</code> - icon nn from resource 216 in shell32.dll,
-     *      or if not found there from resource 124 in comctl32.dll (Windows only).
+     *  "fileChooserIcon <icon>":
+     *    Returns an <code>Image</code> - icon can be ListView, DetailsView, UpFolder, NewFolder or
+     *    ViewMenu (Windows only).
      *  "optionPaneIcon iconName":
      *    Returns an <code>Image</code> - icon from the system icon list
      *
@@ -303,26 +322,23 @@
             }
             return folders.toArray(new File[folders.size()]);
         } else if (key.startsWith("fileChooserIcon ")) {
-            int i = -1;
-            String name = key.substring(key.indexOf(" ")+1);
-            try {
-                i = Integer.parseInt(name);
-            } catch (NumberFormatException ex) {
-                if (name.equals("ListView")) {
-                    i = (USE_SHELL32_ICONS) ? 21 : 2;
-                } else if (name.equals("DetailsView")) {
-                    i = (USE_SHELL32_ICONS) ? 23 : 3;
-                } else if (name.equals("UpFolder")) {
-                    i = (USE_SHELL32_ICONS) ? 28 : 8;
-                } else if (name.equals("NewFolder")) {
-                    i = (USE_SHELL32_ICONS) ? 31 : 11;
-                } else if (name.equals("ViewMenu")) {
-                    i = (USE_SHELL32_ICONS) ? 21 : 2;
-                }
+            String name = key.substring(key.indexOf(" ") + 1);
+
+            int iconIndex;
+
+            if (name.equals("ListView") || name.equals("ViewMenu")) {
+                iconIndex = VIEW_LIST;
+            } else if (name.equals("DetailsView")) {
+                iconIndex = VIEW_DETAILS;
+            } else if (name.equals("UpFolder")) {
+                iconIndex = VIEW_PARENTFOLDER;
+            } else if (name.equals("NewFolder")) {
+                iconIndex = VIEW_NEWFOLDER;
+            } else {
+                return null;
             }
-            if (i >= 0) {
-                return Win32ShellFolder2.getFileChooserIcon(i);
-            }
+
+            return getStandardViewButton(iconIndex);
         } else if (key.startsWith("optionPaneIcon ")) {
             Win32ShellFolder2.SystemIcon iconType;
             if (key == "optionPaneIcon Error") {
--- a/jdk/src/windows/native/sun/windows/ShellFolder2.cpp	Thu Sep 17 19:08:15 2009 +0400
+++ b/jdk/src/windows/native/sun/windows/ShellFolder2.cpp	Fri Sep 18 15:11:28 2009 +0400
@@ -256,7 +256,6 @@
 static IShellIcon* getIShellIcon(IShellFolder* pIShellFolder) {
     // http://msdn.microsoft.com/library/en-us/shellcc/platform/Shell/programmersguide/shell_int/shell_int_programming/std_ifaces.asp
     HRESULT hres;
-    HICON hIcon = NULL;
     IShellIcon* pIShellIcon;
     if (pIShellFolder != NULL) {
         hres = pIShellFolder->QueryInterface(IID_IShellIcon, (void**)&pIShellIcon);
@@ -965,89 +964,40 @@
 
 /*
  * Class:     sun_awt_shell_Win32ShellFolder2
- * Method:    getFileChooserBitmapBits
- * Signature: ()[I
+ * Method:    getStandardViewButton0
+ * Signature: (I)[I
  */
-JNIEXPORT jintArray JNICALL Java_sun_awt_shell_Win32ShellFolder2_getFileChooserBitmapBits
-    (JNIEnv* env, jclass cls)
+JNIEXPORT jintArray JNICALL Java_sun_awt_shell_Win32ShellFolder2_getStandardViewButton0
+    (JNIEnv* env, jclass cls, jint iconIndex)
 {
-    HBITMAP hBitmap = NULL;
-    BITMAP bm;
-    HINSTANCE libComCtl32;
-    HINSTANCE libShell32;
+    jintArray result = NULL;
 
-    libShell32 = LoadLibrary(TEXT("shell32.dll"));
-    if (libShell32 != NULL) {
-        hBitmap = (HBITMAP)LoadImage(libShell32,
-                    IS_WINVISTA ? TEXT("IDB_TB_SH_DEF_16") : MAKEINTRESOURCE(216),
-                    IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
+    // Create a toolbar
+    HWND hWndToolbar = ::CreateWindowEx(0, TOOLBARCLASSNAME, NULL,
+        0, 0, 0, 0, 0,
+        NULL, NULL, NULL, NULL);
+
+    if (hWndToolbar != NULL) {
+        SendMessage(hWndToolbar, TB_LOADIMAGES, (WPARAM)IDB_VIEW_SMALL_COLOR, (LPARAM)HINST_COMMCTRL);
 
-        if (hBitmap == NULL) {
-            // version of shell32.dll doesn't match OS version.
-            // So we either are in a Vista Compatibility Mode
-            // or shell32.dll was copied from OS of another version
-            hBitmap = (HBITMAP)LoadImage(libShell32,
-                    IS_WINVISTA ? MAKEINTRESOURCE(216) : TEXT("IDB_TB_SH_DEF_16"),
-                    IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
+        HIMAGELIST hImageList = (HIMAGELIST) SendMessage(hWndToolbar, TB_GETIMAGELIST, 0, 0);
+
+        if (hImageList != NULL) {
+            HICON hIcon = ImageList_GetIcon(hImageList, iconIndex, ILD_TRANSPARENT);
+
+            if (hIcon != NULL) {
+                result = Java_sun_awt_shell_Win32ShellFolder2_getIconBits(env, cls, ptr_to_jlong(hIcon), 16);
+
+                DestroyIcon(hIcon);
+            }
+
+            ImageList_Destroy(hImageList);
         }
-    }
-    if (hBitmap == NULL) {
-        libComCtl32 = LoadLibrary(TEXT("comctl32.dll"));
-        if (libComCtl32 != NULL) {
-            hBitmap = (HBITMAP)LoadImage(libComCtl32, MAKEINTRESOURCE(124),
-                                         IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
-        }
-    }
-    if (hBitmap == NULL) {
-        return NULL;
+
+        DestroyWindow(hWndToolbar);
     }
 
-    GetObject(hBitmap, sizeof(bm), (LPSTR)&bm);
-
-    // Get the screen DC
-    HDC dc = GetDC(NULL);
-    if (dc == NULL) {
-        return NULL;
-    }
-
-    // Set up BITMAPINFO
-    BITMAPINFO bmi;
-    memset(&bmi, 0, sizeof(BITMAPINFO));
-    bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
-    bmi.bmiHeader.biWidth = bm.bmWidth;
-    bmi.bmiHeader.biHeight = -bm.bmHeight;
-    bmi.bmiHeader.biPlanes = 1;
-    bmi.bmiHeader.biBitCount = 32;
-    bmi.bmiHeader.biCompression = BI_RGB;
-    // Extract the color bitmap
-    int numPixels = bm.bmWidth * bm.bmHeight;
-    //long colorBits[192 * 16];
-    long *colorBits = (long*)safe_Malloc(numPixels * sizeof(long));
-    if (GetDIBits(dc, hBitmap, 0, bm.bmHeight, colorBits, &bmi, DIB_RGB_COLORS) == 0) {
-        return NULL;
-    }
-
-    // Release DC
-    ReleaseDC(NULL, dc);
-
-    // The color of the first pixel defines the transparency, according
-    // to the documentation for LR_LOADTRANSPARENT at
-    // http://msdn.microsoft.com/library/psdk/winui/resource_9fhi.htm
-    long transparent = colorBits[0];
-    for (int i=0; i < numPixels; i++) {
-        if (colorBits[i] != transparent) {
-            colorBits[i] |= 0xff000000;
-        }
-    }
-
-    // Create java array
-    jintArray bits = env->NewIntArray(numPixels);
-    // Copy values to java array
-    env->SetIntArrayRegion(bits, 0, numPixels, colorBits);
-    // Fix 4745575 GDI Resource Leak
-    ::DeleteObject(hBitmap);
-    ::FreeLibrary(libComCtl32);
-    return bits;
+    return result;
 }
 
 /*
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/JFileChooser/6840086/bug6840086.java	Fri Sep 18 15:11:28 2009 +0400
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+   @bug 6840086
+   @summary JFileChooser lacks icons on top right when running on Windows 7
+   @author Pavel Porvatov
+   @run main bug6840086
+*/
+
+import sun.awt.OSInfo;
+import sun.awt.shell.ShellFolder;
+
+import java.awt.*;
+
+public class bug6840086 {
+    private static final String[] KEYS = {
+        "fileChooserIcon ListView",
+        "fileChooserIcon ViewMenu",
+        "fileChooserIcon DetailsView",
+        "fileChooserIcon UpFolder",
+        "fileChooserIcon NewFolder",
+    };
+
+    public static void main(String[] args) {
+        if (OSInfo.getOSType() != OSInfo.OSType.WINDOWS) {
+            System.out.println("The test was skipped because it is sensible only for Windows.");
+
+            return;
+        }
+
+        for (String key : KEYS) {
+            Image image = (Image) ShellFolder.get(key);
+
+            if (image == null) {
+                throw new RuntimeException("The image '" + key + "' not found.");
+            }
+
+            if (image != ShellFolder.get(key)) {
+                throw new RuntimeException("The image '" + key + "' is not cached.");
+            }
+        }
+
+        System.out.println("The test passed.");
+    }
+}