/* * This file is part of muCommander, http://www.mucommander.com * Copyright (C) 2002-2010 Maxence Bernard * * muCommander is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * muCommander 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 for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.mucommander.ui.quicklist; import com.mucommander.commons.file.AbstractFile; import com.mucommander.ui.icon.CustomFileIconProvider; import com.mucommander.ui.icon.FileIcons; import com.mucommander.ui.icon.IconManager; import com.mucommander.ui.icon.SpinningDial; import com.mucommander.ui.quicklist.item.DataList; import javax.swing.*; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; import java.util.HashMap; /** * FileTablePopupWithIcons is a FileTablePopupWithDataList in which the data list * contains icons. * * @author Arik Hadas */ public abstract class QuickListWithIcons extends QuickListWithDataList { // This HashMap's keys are items and its objects are the corresponding icon. private final HashMap<Object, Icon> itemToIconCacheMap = new HashMap<Object, Icon>(); // This SpinningDial will appear until the icon fetching of an item is over. private static final SpinningDial waitingIcon = new SpinningDial(); // If the icon fetching fails for some item, the following icon will appear for it. private static final Icon notAvailableIcon = IconManager.getIcon(IconManager.FILE_ICON_SET, CustomFileIconProvider.NOT_ACCESSIBLE_FILE); // Saves the number of waiting-icons (SpinningDials) appearing in the list. private int numOfWaitingIconInList; public QuickListWithIcons(String header, String emptyPopupHeader) { super(header, emptyPopupHeader); numOfWaitingIconInList = 0; addPopupMenuListener(new PopupMenuListener() { public void popupMenuCanceled(PopupMenuEvent e) {} public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {} public void popupMenuWillBecomeVisible(PopupMenuEvent e) { // Clear icon-caching before opening popup-list in order to let the icons be fetched again. itemToIconCacheMap.clear(); } }); } /** * Called when waitingIcon is added to the list. */ private synchronized void waitingIconAddedToList() { // If there was no other waitingIcon in the list before current addition - start the spinning dial. if (numOfWaitingIconInList++ == 0) waitingIcon.setAnimated(true); } /** * Called when waitingIcon is removed from the list. */ private synchronized void waitingIconRemovedFromList() { // If after current remove operation, there will be no waitingIcon in the list - stop the spinning dial. if (--numOfWaitingIconInList == 0) waitingIcon.setAnimated(false); } @Override protected DataList getList() { return new GenericPopupDataListWithIcons() { @Override public Icon getImageIconOfItem(Object item) { return getImageIconOfItemImp(item); } }; } /** * This function gets an item from the data list and return its icon. * * @param item a list item * @return an icon for the specified item */ protected abstract Icon itemToIcon(Object item); /** * This function return an icon for the specified file. * * @param file the file for which to return an icon * @return the specified file's icon. null is returned if the file does not exist */ protected Icon getIconOfFile(AbstractFile file) { return (file != null && file.exists()) ? IconManager.getImageIcon(FileIcons.getFileIcon(file)) : null; } private Icon getImageIconOfItemImp(final Object item) { boolean found; synchronized(itemToIconCacheMap) { if (!(found = itemToIconCacheMap.containsKey(item))) { itemToIconCacheMap.put(item, waitingIcon); waitingIconAddedToList(); } } if (!found) new Thread() { @Override public void run() { Icon icon = itemToIcon(item); synchronized(itemToIconCacheMap) { // If the item does not exist or is not accessible, show notAvailableIcon for it. itemToIconCacheMap.put(item, icon != null ? icon : notAvailableIcon); } waitingIconRemovedFromList(); repaint(); } }.start(); Icon result; synchronized(itemToIconCacheMap) { result = itemToIconCacheMap.get(item); } return result; } }