package moviescraper.doctord.model;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.filechooser.FileSystemView;
import org.apache.commons.io.FilenameUtils;
public class IconCache {
/**
* Enumeration of icon providers for the items on the file list view
*/
public enum IconProviderType
{
SYSTEM, /// Icon provider that uses the system shell to get an icon (default)
CONTENT, /// Icon provider that determines icon by file content type
}
// Internal interface used by IconCache
private interface IconProvider
{
// return an icon for the specified file
Icon getIcon(File iconType) throws IOException;
}
// Default icon provider implementation: get shell icons on windows, only folder or file on linux
private static class SystemIconProvider implements IconProvider
{
@Override
public Icon getIcon(File iconType) throws IOException {
return FileSystemView.getFileSystemView().getSystemIcon(iconType);
}
}
// Alternative icon provider implementation: return resource icons based on file content type
private static class ContentIconProvider implements IconProvider
{
private Icon createIcon(String name)
{
return new ImageIcon(getClass().getResource("/res/mime/" + name + ".png"));
}
@Override
public Icon getIcon(File iconType) throws IOException {
// return default icon for folders (no need for a custom png)
if (iconType.isDirectory())
return FileSystemView.getFileSystemView().getSystemIcon(iconType);
// don't probe content type for files without extension as this icon will be cached for all of them,
// skip dot files too (.hidden files on Linux)
String name = FilenameUtils.getName(iconType.getName());
String ext = FilenameUtils.getExtension(iconType.getName());
if (ext != "" && !name.startsWith("."))
{
// determine content type
String mimeType = Files.probeContentType(iconType.toPath());
if (mimeType != null)
{
// take top-level type into account only, this five types should cover the vast majority of cases
for(String type: new String[] { "text", "image", "video", "audio", "application" })
if (mimeType.startsWith(type + "/"))
return createIcon(type);
}
}
// fallback to default file icon
return createIcon("file");
}
}
private static IconProvider iconProvider = new SystemIconProvider();
private static Map<String, Icon> cache = Collections.synchronizedMap(new HashMap<String, Icon>());
/**
* Sets the icon provider for the file list view
* @param type The icon provider type
*/
public static void setIconProvider(IconProviderType type)
{
// determine current provider by class name, set only if necessary
String newType = type.toString() + "IconProvider";
String oldType = iconProvider.getClass().getSimpleName();
if (!newType.equalsIgnoreCase(oldType))
{
// flush cache
cache.clear();
switch(type)
{
case SYSTEM:
iconProvider = new SystemIconProvider();
break;
case CONTENT:
iconProvider = new ContentIconProvider();
break;
default:
break;
}
}
}
public static Icon getIconFromCache(File iconType) throws IOException
{
// use "." as key for folders so we don't get a cached folder icon for files without extension or vice versa
// use "" as key for dot files (hidden files on Linux), to prevent getting a cache entry per file
String name = FilenameUtils.getName(iconType.getName());
String ext = FilenameUtils.getExtension(iconType.getName());
String key = iconType.isDirectory() ? "." : name.startsWith(".") ? "" : ext;
//Cache already contains the item, so just return it
if(cache.containsKey(key))
{
return cache.get(key);
}
//we didn't find it, so read the Icon into the cache and also return it
else
{
Icon iconToCache = iconProvider.getIcon(iconType);
cache.put(key, iconToCache);
// System.err.println("[IconCache] Caching type " + key);
return iconToCache;
}
}
}