blob: ffe8464477c2569aa3df940449246224e19b018a [file] [log] [blame]
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.ide;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.INativeFileType;
import com.intellij.openapi.fileTypes.UnknownFileType;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.util.Iconable;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFileSystemItem;
import com.intellij.psi.impl.ElementBase;
import com.intellij.ui.DeferredIconImpl;
import com.intellij.util.Function;
import com.intellij.util.ui.update.ComparableObject;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.io.File;
import java.util.*;
/**
* @author yole
*/
public class NativeIconProvider extends IconProvider implements DumbAware {
private final Map<Ext, Icon> myIconCache = new HashMap<Ext, Icon>();
// on Windows .exe and .ico files provide their own icons which can differ for each file, cache them by full file path
private final Set<Ext> myCustomIconExtensions =
SystemInfo.isWindows ? new HashSet<Ext>(Arrays.asList(new Ext("exe"), new Ext("ico"))) : new HashSet<Ext>();
private final Map<String, Icon> myCustomIconCache = new HashMap<String, Icon>();
private static final Ext NO_EXT = new Ext(null);
private static final Ext CLOSED_DIR = new Ext(null, 0);
@Nullable
@Override
public Icon getIcon(@NotNull PsiElement element, @Iconable.IconFlags int flags) {
if (element instanceof PsiFileSystemItem) {
VirtualFile file = ((PsiFileSystemItem)element).getVirtualFile();
if (file != null) return doGetIcon(file, flags);
}
return null;
}
@Nullable
private Icon doGetIcon(@NotNull VirtualFile file, final int flags) {
if (!isNativeFileType(file)) return null;
final Ext ext = getExtension(file, flags);
final String filePath = file.getPath();
Icon icon;
synchronized (myIconCache) {
if (!myCustomIconExtensions.contains(ext)) {
icon = ext != null ? myIconCache.get(ext) : null;
}
else {
icon = filePath != null ? myCustomIconCache.get(filePath) : null;
}
}
if (icon != null) {
return icon;
}
return new DeferredIconImpl<VirtualFile>(ElementBase.ICON_PLACEHOLDER.getValue(), file, false, new Function<VirtualFile, Icon>() {
@Override
public Icon fun(VirtualFile virtualFile) {
final File f = new File(filePath);
if (!f.exists()) {
return null;
}
Icon icon;
try { // VM will ensure lock to init -static final field--, note we should have no read access here, to avoid deadlock with EDT needed to init component
assert SwingComponentHolder.ourFileChooser != null || !ApplicationManager.getApplication().isReadAccessAllowed();
icon = getNativeIcon(f);
}
catch (Exception e) { // see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4854174
return null;
}
if (ext != null) {
synchronized (myIconCache) {
if (!myCustomIconExtensions.contains(ext)) {
myIconCache.put(ext, icon);
}
else if (filePath != null) {
myCustomIconCache.put(filePath, icon);
}
}
}
return icon;
}
});
}
@Nullable
public static Icon getNativeIcon(@Nullable File file) {
return file == null ? null : SwingComponentHolder.ourFileChooser.getIcon(file);
}
private static Ext getExtension(final VirtualFile file, final int flags) {
if (file.isDirectory()) {
if (file.getExtension() == null) {
return CLOSED_DIR;
} else {
return new Ext(file.getExtension(), flags);
}
}
return file.getExtension() != null ? new Ext(file.getExtension()) : NO_EXT;
}
static class SwingComponentHolder {
private static final JFileChooser ourFileChooser = new JFileChooser();
}
protected boolean isNativeFileType(VirtualFile file) {
FileType type = file.getFileType();
if (type instanceof INativeFileType) return ((INativeFileType)type).useNativeIcon();
return type instanceof UnknownFileType && !file.isDirectory();
}
private static class Ext extends ComparableObject.Impl {
private final Object[] myText;
private Ext(@Nullable String text) {
myText = new Object[] {text};
}
private Ext(@Nullable String text, final int flags) {
myText = new Object[] {text, flags};
}
@Override
@NotNull
public Object[] getEqualityObjects() {
return myText;
}
@Override
public String toString() {
return myText[0] != null ? myText[0].toString() : null;
}
}
}