< prev index next >

src/java.desktop/share/classes/sun/swing/FilePane.java

Print this page

        

*** 22,66 **** * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.swing; import java.awt.*; import java.awt.event.*; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.*; import java.text.DateFormat; import java.text.MessageFormat; import java.util.*; import java.util.List; ! import java.util.concurrent.Callable; import javax.accessibility.AccessibleContext; import javax.swing.*; import javax.swing.border.*; ! import javax.swing.event.*; import javax.swing.filechooser.*; import javax.swing.plaf.basic.*; import javax.swing.table.*; import javax.swing.text.*; import sun.awt.shell.*; /** ! * <b>WARNING:</b> This class is an implementation detail and is only ! * public so that it can be used by two packages. You should NOT consider ! * this public API. * <p> * This component is intended to be used in a subclass of * javax.swing.plaf.basic.BasicFileChooserUI. It realies heavily on the * implementation of BasicFileChooserUI, and is intended to be API compatible * with earlier implementations of MetalFileChooserUI and WindowsFileChooserUI. * * @author Leif Samuelsson */ - @SuppressWarnings("serial") // JDK-implementation class public class FilePane extends JPanel implements PropertyChangeListener { // Constants for actions. These are used for the actions' ACTION_COMMAND_KEY // and as keys in the action maps for FilePane and the corresponding UI classes public static final String ACTION_APPROVE_SELECTION = "approveSelection"; --- 22,84 ---- * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.swing; + import com.sun.java.swing.plaf.windows.WindowsFileChooserUI; + import com.sun.java.swing.plaf.windows.WindowsFileChooserUI.WindowsFileListUI; + import static com.sun.java.swing.plaf.windows.WindowsFileChooserUI.WindowsFileListUI.HOVER_CELL_PROPERTY; + import com.sun.java.swing.plaf.windows.WindowsFileChooserUI.WindowsFileTableUI; import java.awt.*; + import static java.awt.Color.BLACK; import java.awt.event.*; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.*; import java.text.DateFormat; import java.text.MessageFormat; import java.util.*; import java.util.List; ! import java.util.concurrent.ConcurrentHashMap; ! import java.util.concurrent.Executor; ! import java.util.concurrent.Executors; ! import java.util.function.Supplier; ! import java.util.stream.IntStream; import javax.accessibility.AccessibleContext; import javax.swing.*; + import static javax.swing.JList.HORIZONTAL_WRAP; + import static javax.swing.SwingConstants.BOTTOM; + import static javax.swing.SwingConstants.CENTER; + import static javax.swing.SwingConstants.LEFT; + import static javax.swing.SwingConstants.RIGHT; import javax.swing.border.*; ! import javax.swing.event.ListDataEvent; ! import javax.swing.event.ListDataListener; ! import javax.swing.event.ListSelectionListener; ! import javax.swing.event.RowSorterEvent; ! import javax.swing.event.RowSorterListener; ! import javax.swing.event.TableModelEvent; ! import javax.swing.event.TableModelListener; import javax.swing.filechooser.*; import javax.swing.plaf.basic.*; import javax.swing.table.*; import javax.swing.text.*; import sun.awt.shell.*; /** ! * <b>WARNING:</b> This class is an implementation detail and is only public so ! * that it can be used by two packages. You should NOT consider this public API. * <p> * This component is intended to be used in a subclass of * javax.swing.plaf.basic.BasicFileChooserUI. It realies heavily on the * implementation of BasicFileChooserUI, and is intended to be API compatible * with earlier implementations of MetalFileChooserUI and WindowsFileChooserUI. * * @author Leif Samuelsson */ public class FilePane extends JPanel implements PropertyChangeListener { // Constants for actions. These are used for the actions' ACTION_COMMAND_KEY // and as keys in the action maps for FilePane and the corresponding UI classes public static final String ACTION_APPROVE_SELECTION = "approveSelection";
*** 70,90 **** public static final String ACTION_CHANGE_TO_PARENT_DIRECTORY = "Go Up"; public static final String ACTION_NEW_FOLDER = "New Folder"; public static final String ACTION_VIEW_LIST = "viewTypeList"; public static final String ACTION_VIEW_DETAILS = "viewTypeDetails"; ! private Action[] actions; ! // "enums" for setViewType() ! public static final int VIEWTYPE_LIST = 0; ! public static final int VIEWTYPE_DETAILS = 1; ! private static final int VIEWTYPE_COUNT = 2; ! private int viewType = -1; ! private JPanel[] viewPanels = new JPanel[VIEWTYPE_COUNT]; private JPanel currentViewPanel; ! private String[] viewTypeActionNames; private String filesListAccessibleName = null; private String filesDetailsAccessibleName = null; private JPopupMenu contextMenu; --- 88,176 ---- public static final String ACTION_CHANGE_TO_PARENT_DIRECTORY = "Go Up"; public static final String ACTION_NEW_FOLDER = "New Folder"; public static final String ACTION_VIEW_LIST = "viewTypeList"; public static final String ACTION_VIEW_DETAILS = "viewTypeDetails"; ! public static enum ViewType { ! MEDIUM_ICONS("mediumIcons", ! /* listOrientation: */ HORIZONTAL_WRAP, ! /* horizTextPos: */ CENTER, ! /* vertTextPos: */ BOTTOM, ! /* prefSize: */ new Dimension(125, 75), ! /* horizAlign: */ CENTER, ! /* wrapFilename: */ true, ! /* largeIcons: */ true, ! /* fileMetaLines: */ false ! ), ! SMALL_ICONS("smallIcons", ! /* listOrientation: */ HORIZONTAL_WRAP, ! /* horizTextPos: */ RIGHT, ! /* vertTextPos: */ CENTER, ! /* prefSize: */ null, ! /* horizAlign: */ LEFT, ! /* wrapFilename: */ true, ! /* largeIcons: */ false, ! /* fileMetaLines: */ false ! ), ! LIST("list", ! /* listOrientation: */ JList.VERTICAL_WRAP, ! /* horizTextPos: */ RIGHT, ! /* vertTextPos: */ CENTER, ! /* prefSize: */ null, ! /* horizAlign: */ LEFT, ! /* wrapFilename: */ false, ! /* largeIcons: */ false, ! /* fileMetaLines: */ false ! ), ! DETAILS("details", null, RIGHT, CENTER, null, LEFT, false, false, false), ! TILES("tiles", ! /* listOrientation: */ JList.HORIZONTAL_WRAP, ! /* horizTextPos: */ RIGHT, ! /* vertTextPos: */ CENTER, ! /* prefSize: */ new Dimension(313, 66), ! /* horizAlign: */ LEFT, ! /* wrapFilename: */ false, ! /* largeIcons: */ true, ! /* fileMetaLines: */ true ! ); ! ! private final String l10nKey; ! private final boolean isTable; ! private final Integer listOrientation; ! private final Integer horizTextPos; ! private final Integer vertTextPos; ! private final Dimension prefSize; ! private final Integer horizAlign; ! private final boolean wrapFilename; ! private final boolean largeIcons; ! private final boolean fileMetaLines; ! ! private ViewType(String l10nKey, Integer listOrientation, ! Integer horizTextPos, Integer vertTextPos, Dimension prefSize, ! Integer horizAlign, boolean wrapFilename, boolean largeIcons, ! boolean fileMetaLines) { ! this.listOrientation = listOrientation; ! this.l10nKey = l10nKey; ! this.isTable = listOrientation == null; ! ! this.horizTextPos = horizTextPos; ! this.vertTextPos = vertTextPos; ! this.prefSize = prefSize; ! this.horizAlign = horizAlign; ! this.wrapFilename = wrapFilename; ! this.largeIcons = largeIcons; ! this.fileMetaLines = fileMetaLines; ! } ! ! } ! private Action[] actions; ! private ViewType viewType; ! private Map<ViewType, JPanel> viewPanels = new EnumMap<>(ViewType.class); private JPanel currentViewPanel; ! private final Map<ViewType, String> viewTypeActionNames = new EnumMap<>(ViewType.class); private String filesListAccessibleName = null; private String filesDetailsAccessibleName = null; private JPopupMenu contextMenu;
*** 117,132 **** timeFactor = (l != null) ? l : 1000L; } /** * Moves the keyboard focus to the first element whose prefix matches ! * the sequence of alphanumeric keys pressed by the user with delay ! * less than value of <code>timeFactor</code>. Subsequent same key ! * presses move the keyboard focus to the next object that starts with ! * the same letter until another key is pressed, then it is treated ! * as the prefix with appropriate number of the same letters followed ! * by first typed another letter. */ public void keyTyped(KeyEvent e) { BasicDirectoryModel model = getModel(); int rowCount = model.getSize(); --- 203,218 ---- timeFactor = (l != null) ? l : 1000L; } /** * Moves the keyboard focus to the first element whose prefix matches ! * the sequence of alphanumeric keys pressed by the user with delay less ! * than value of <code>timeFactor</code>. Subsequent same key presses ! * move the keyboard focus to the next object that starts with the same ! * letter until another key is pressed, then it is treated as the prefix ! * with appropriate number of the same letters followed by first typed ! * another letter. */ public void keyTyped(KeyEvent e) { BasicDirectoryModel model = getModel(); int rowCount = model.getSize();
*** 307,372 **** protected BasicDirectoryModel getModel() { return fileChooserUIAccessor.getModel(); } ! public int getViewType() { return viewType; } ! public void setViewType(int viewType) { if (viewType == this.viewType) { return; } ! int oldValue = this.viewType; this.viewType = viewType; JPanel createdViewPanel = null; Component newFocusOwner = null; ! switch (viewType) { ! case VIEWTYPE_LIST: ! if (viewPanels[viewType] == null) { createdViewPanel = fileChooserUIAccessor.createList(); if (createdViewPanel == null) { createdViewPanel = createList(); } ! list = findChildComponent(createdViewPanel, JList.class); if (listSelectionModel == null) { listSelectionModel = list.getSelectionModel(); if (detailsTable != null) { detailsTable.setSelectionModel(listSelectionModel); } } else { list.setSelectionModel(listSelectionModel); } } ! list.setLayoutOrientation(JList.VERTICAL_WRAP); newFocusOwner = list; - break; - - case VIEWTYPE_DETAILS: - if (viewPanels[viewType] == null) { - createdViewPanel = fileChooserUIAccessor.createDetailsView(); - if (createdViewPanel == null) { - createdViewPanel = createDetailsView(); - } - - detailsTable = findChildComponent(createdViewPanel, JTable.class); - detailsTable.setRowHeight(Math.max(detailsTable.getFont().getSize() + 4, 16 + 1)); - if (listSelectionModel != null) { - detailsTable.setSelectionModel(listSelectionModel); - } - } - newFocusOwner = detailsTable; - break; } if (createdViewPanel != null) { ! viewPanels[viewType] = createdViewPanel; recursivelySetInheritsPopupMenu(createdViewPanel, true); } boolean isFocusOwner = false; --- 393,458 ---- protected BasicDirectoryModel getModel() { return fileChooserUIAccessor.getModel(); } ! public ViewType getViewType() { return viewType; } ! public void setViewType(ViewType viewType) { if (viewType == this.viewType) { return; } ! ViewType oldValue = this.viewType; this.viewType = viewType; JPanel createdViewPanel = null; Component newFocusOwner = null; ! if (viewType.isTable) { ! if (viewPanels.get(viewType) == null) { ! createdViewPanel = fileChooserUIAccessor.createDetailsView(); ! if (createdViewPanel == null) { ! createdViewPanel = createDetailsView(); ! } ! ! detailsTable = (JTable) findChildComponent(createdViewPanel, JTable.class); ! assert detailsTable != null; ! detailsTable.setRowHeight(Math.max(detailsTable.getFont().getSize() + 4, 16 + 5)); ! if(listSelectionModel == null) { ! listSelectionModel = detailsTable.getSelectionModel(); ! if(list != null) ! list.setSelectionModel(listSelectionModel); ! }else ! detailsTable.setSelectionModel(listSelectionModel); ! } ! newFocusOwner = detailsTable; ! } else { ! if (viewPanels.get(viewType) == null) { createdViewPanel = fileChooserUIAccessor.createList(); if (createdViewPanel == null) { createdViewPanel = createList(); } ! list = (JList<?>) findChildComponent(createdViewPanel, JList.class); if (listSelectionModel == null) { listSelectionModel = list.getSelectionModel(); if (detailsTable != null) { detailsTable.setSelectionModel(listSelectionModel); } } else { list.setSelectionModel(listSelectionModel); } } ! list.setLayoutOrientation(viewType.listOrientation); newFocusOwner = list; } if (createdViewPanel != null) { ! viewPanels.put(viewType, createdViewPanel); recursivelySetInheritsPopupMenu(createdViewPanel, true); } boolean isFocusOwner = false;
*** 377,387 **** isFocusOwner = owner == detailsTable || owner == list; remove(currentViewPanel); } ! currentViewPanel = viewPanels[viewType]; add(currentViewPanel, BorderLayout.CENTER); if (isFocusOwner && newFocusOwner != null) { newFocusOwner.requestFocusInWindow(); } --- 463,473 ---- isFocusOwner = owner == detailsTable || owner == list; remove(currentViewPanel); } ! currentViewPanel = viewPanels.get(viewType); add(currentViewPanel, BorderLayout.CENTER); if (isFocusOwner && newFocusOwner != null) { newFocusOwner.requestFocusInWindow(); }
*** 390,422 **** repaint(); updateViewMenu(); firePropertyChange("viewType", oldValue, viewType); } - @SuppressWarnings("serial") // JDK-implementation class class ViewTypeAction extends AbstractAction { - private int viewType; ! ViewTypeAction(int viewType) { ! super(viewTypeActionNames[viewType]); this.viewType = viewType; ! String cmd; ! switch (viewType) { ! case VIEWTYPE_LIST: cmd = ACTION_VIEW_LIST; break; ! case VIEWTYPE_DETAILS: cmd = ACTION_VIEW_DETAILS; break; ! default: cmd = (String)getValue(Action.NAME); ! } ! putValue(Action.ACTION_COMMAND_KEY, cmd); } public void actionPerformed(ActionEvent e) { setViewType(viewType); } } ! public Action getViewTypeAction(int viewType) { return new ViewTypeAction(viewType); } private static void recursivelySetInheritsPopupMenu(Container container, boolean b) { if (container instanceof JComponent) { --- 476,502 ---- repaint(); updateViewMenu(); firePropertyChange("viewType", oldValue, viewType); } class ViewTypeAction extends AbstractAction { ! private final ViewType viewType; ! ! ViewTypeAction(ViewType viewType) { ! super(viewTypeActionNames.get(viewType)); this.viewType = viewType; ! putValue(Action.ACTION_COMMAND_KEY, viewType.l10nKey); } public void actionPerformed(ActionEvent e) { setViewType(viewType); } } ! public Action getViewTypeAction(ViewType viewType) { return new ViewTypeAction(viewType); } private static void recursivelySetInheritsPopupMenu(Container container, boolean b) { if (container instanceof JComponent) {
*** 435,457 **** listViewBackground = UIManager.getColor("FileChooser.listViewBackground"); listViewWindowsStyle = UIManager.getBoolean("FileChooser.listViewWindowsStyle"); readOnly = UIManager.getBoolean("FileChooser.readOnly"); // TODO: On windows, get the following localized strings from the OS ! ! viewMenuLabelText = ! UIManager.getString("FileChooser.viewMenuLabelText", l); ! refreshActionLabelText = ! UIManager.getString("FileChooser.refreshActionLabelText", l); ! newFolderActionLabelText = ! UIManager.getString("FileChooser.newFolderActionLabelText", l); ! ! viewTypeActionNames = new String[VIEWTYPE_COUNT]; ! viewTypeActionNames[VIEWTYPE_LIST] = ! UIManager.getString("FileChooser.listViewActionLabelText", l); ! viewTypeActionNames[VIEWTYPE_DETAILS] = ! UIManager.getString("FileChooser.detailsViewActionLabelText", l); kiloByteString = UIManager.getString("FileChooser.fileSizeKiloBytes", l); megaByteString = UIManager.getString("FileChooser.fileSizeMegaBytes", l); gigaByteString = UIManager.getString("FileChooser.fileSizeGigaBytes", l); fullRowSelection = UIManager.getBoolean("FileView.fullRowSelection"); --- 515,537 ---- listViewBackground = UIManager.getColor("FileChooser.listViewBackground"); listViewWindowsStyle = UIManager.getBoolean("FileChooser.listViewWindowsStyle"); readOnly = UIManager.getBoolean("FileChooser.readOnly"); // TODO: On windows, get the following localized strings from the OS ! viewMenuLabelText ! = UIManager.getString("FileChooser.viewMenuLabelText", l); ! refreshActionLabelText ! = UIManager.getString("FileChooser.refreshActionLabelText", l); ! newFolderActionLabelText ! = UIManager.getString("FileChooser.newFolderActionLabelText", l); ! ! for (ViewType viewType : ViewType.values()) { ! final String key = "FileChooser." + viewType.l10nKey ! + "ViewActionLabel.textAndMnemonic"; ! viewTypeActionNames.put(viewType, ! UIManager.getString(key, l)); ! } kiloByteString = UIManager.getString("FileChooser.fileSizeKiloBytes", l); megaByteString = UIManager.getString("FileChooser.fileSizeMegaBytes", l); gigaByteString = UIManager.getString("FileChooser.fileSizeGigaBytes", l); fullRowSelection = UIManager.getBoolean("FileView.fullRowSelection");
*** 463,474 **** renameErrorText = UIManager.getString("FileChooser.renameErrorText", l); renameErrorFileExistsText = UIManager.getString("FileChooser.renameErrorFileExistsText", l); } /** ! * Fetches the command list for the FilePane. These commands ! * are useful for binding to events, such as in a keymap. * * @return the command list */ public Action[] getActions() { if (actions == null) { --- 543,554 ---- renameErrorText = UIManager.getString("FileChooser.renameErrorText", l); renameErrorFileExistsText = UIManager.getString("FileChooser.renameErrorFileExistsText", l); } /** ! * Fetches the command list for the FilePane. These commands are useful for ! * binding to events, such as in a keymap. * * @return the command list */ public Action[] getActions() { if (actions == null) {
*** 505,515 **** getFileChooser().rescanCurrentDirectory(); } } public boolean isEnabled() { ! String cmd = (String)getValue(Action.ACTION_COMMAND_KEY); if (cmd == ACTION_CANCEL) { return getFileChooser().isEnabled(); } else if (cmd == ACTION_EDIT_FILE_NAME) { return !readOnly && getFileChooser().isEnabled(); } else { --- 585,595 ---- getFileChooser().rescanCurrentDirectory(); } } public boolean isEnabled() { ! String cmd = (String) getValue(Action.ACTION_COMMAND_KEY); if (cmd == ACTION_CANCEL) { return getFileChooser().isEnabled(); } else if (cmd == ACTION_EDIT_FILE_NAME) { return !readOnly && getFileChooser().isEnabled(); } else {
*** 535,549 **** } action = getNewFolderAction(); if (action != null) { actionList.add(action); } ! action = getViewTypeAction(VIEWTYPE_LIST); if (action != null) { actionList.add(action); } ! action = getViewTypeAction(VIEWTYPE_DETAILS); if (action != null) { actionList.add(action); } actions = actionList.toArray(new Action[actionList.size()]); } --- 615,629 ---- } action = getNewFolderAction(); if (action != null) { actionList.add(action); } ! action = getViewTypeAction(ViewType.LIST); if (action != null) { actionList.add(action); } ! action = getViewTypeAction(ViewType.DETAILS); if (action != null) { actionList.add(action); } actions = actionList.toArray(new Action[actionList.size()]); }
*** 553,576 **** protected void createActionMap() { addActionsToMap(super.getActionMap(), getActions()); } - public static void addActionsToMap(ActionMap map, Action[] actions) { if (map != null && actions != null) { for (Action a : actions) { ! String cmd = (String)a.getValue(Action.ACTION_COMMAND_KEY); if (cmd == null) { ! cmd = (String)a.getValue(Action.NAME); } map.put(cmd, a); } } } - private void updateListRowCount(JList<?> list) { if (smallIconsView) { list.setVisibleRowCount(getModel().getSize() / 3); } else { list.setVisibleRowCount(-1); --- 633,654 ---- protected void createActionMap() { addActionsToMap(super.getActionMap(), getActions()); } public static void addActionsToMap(ActionMap map, Action[] actions) { if (map != null && actions != null) { for (Action a : actions) { ! String cmd = (String) a.getValue(Action.ACTION_COMMAND_KEY); if (cmd == null) { ! cmd = (String) a.getValue(Action.NAME); } map.put(cmd, a); } } } private void updateListRowCount(JList<?> list) { if (smallIconsView) { list.setVisibleRowCount(getModel().getSize() / 3); } else { list.setVisibleRowCount(-1);
*** 578,589 **** } public JPanel createList() { JPanel p = new JPanel(new BorderLayout()); final JFileChooser fileChooser = getFileChooser(); - - @SuppressWarnings("serial") // anonymous class final JList<Object> list = new JList<Object>() { public int getNextMatch(String prefix, int startIndex, Position.Bias bias) { ListModel<?> model = getModel(); int max = model.getSize(); if (prefix == null || startIndex < 0 || startIndex >= max) { --- 656,665 ----
*** 597,607 **** --- 673,690 ---- return i; } } return -1; } + + { + if (listViewWindowsStyle) { + setUI(new WindowsFileListUI(getFileChooser())); + } + } }; + list.setCellRenderer(new FileRenderer()); list.setLayoutOrientation(JList.VERTICAL_WRAP); // 4835633 : tell BasicListUI that this is a file list list.putClientProperty("List.isFileList", Boolean.TRUE);
*** 641,651 **** JScrollPane scrollpane = new JScrollPane(list); if (listViewBackground != null) { list.setBackground(listViewBackground); } ! if (listViewBorder != null) { scrollpane.setBorder(listViewBorder); } list.putClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY, filesListAccessibleName); --- 724,736 ---- JScrollPane scrollpane = new JScrollPane(list); if (listViewBackground != null) { list.setBackground(listViewBackground); } ! if (listViewWindowsStyle) { ! scrollpane.setBorder(null); ! } else if (listViewBorder != null) { scrollpane.setBorder(listViewBorder); } list.putClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY, filesListAccessibleName);
*** 654,664 **** } /** * This model allows for sorting JList */ - @SuppressWarnings("serial") // JDK-implementation class private class SortableListModel extends AbstractListModel<Object> implements TableModelListener, RowSorterListener { public SortableListModel() { getDetailsTableModel().addTableModelListener(this); --- 739,748 ----
*** 682,699 **** fireContentsChanged(this, 0, getSize()); } } private DetailsTableModel getDetailsTableModel() { ! if(detailsTableModel == null) { detailsTableModel = new DetailsTableModel(getFileChooser()); } return detailsTableModel; } - @SuppressWarnings("serial") // JDK-implementation class class DetailsTableModel extends AbstractTableModel implements ListDataListener { JFileChooser chooser; BasicDirectoryModel directoryModel; ShellFolderColumnInfo[] columns; int[] columnMap; --- 766,783 ---- fireContentsChanged(this, 0, getSize()); } } private DetailsTableModel getDetailsTableModel() { ! if (detailsTableModel == null) { detailsTableModel = new DetailsTableModel(getFileChooser()); } return detailsTableModel; } class DetailsTableModel extends AbstractTableModel implements ListDataListener { + JFileChooser chooser; BasicDirectoryModel directoryModel; ShellFolderColumnInfo[] columns; int[] columnMap;
*** 716,727 **** } } ShellFolderColumnInfo[] allColumns = ShellFolder.getFolderColumns(dir); ! ArrayList<ShellFolderColumnInfo> visibleColumns = ! new ArrayList<ShellFolderColumnInfo>(); columnMap = new int[allColumns.length]; for (int i = 0; i < allColumns.length; i++) { ShellFolderColumnInfo column = allColumns[i]; if (column.isVisible()) { columnMap[visibleColumns.size()] = i; --- 800,811 ---- } } ShellFolderColumnInfo[] allColumns = ShellFolder.getFolderColumns(dir); ! ArrayList<ShellFolderColumnInfo> visibleColumns ! = new ArrayList<ShellFolderColumnInfo>(); columnMap = new int[allColumns.length]; for (int i = 0; i < allColumns.length; i++) { ShellFolderColumnInfo column = allColumns[i]; if (column.isVisible()) { columnMap[visibleColumns.size()] = i;
*** 807,824 **** if (FilePane.this.getModel().renameFile(f, f2)) { if (fsv.isParent(chooser.getCurrentDirectory(), f2)) { // The setSelectedFile method produces a new setValueAt invocation while the JTable // is editing. Postpone file selection to be sure that edit mode of the JTable // is completed ! SwingUtilities.invokeLater(new Runnable() { ! public void run() { if (chooser.isMultiSelectionEnabled()) { chooser.setSelectedFiles(new File[]{f2}); } else { chooser.setSelectedFile(f2); } - } }); } else { // Could be because of delay in updating Desktop folder // chooser.setSelectedFile(null); } --- 891,906 ---- if (FilePane.this.getModel().renameFile(f, f2)) { if (fsv.isParent(chooser.getCurrentDirectory(), f2)) { // The setSelectedFile method produces a new setValueAt invocation while the JTable // is editing. Postpone file selection to be sure that edit mode of the JTable // is completed ! SwingUtilities.invokeLater(() -> { if (chooser.isMultiSelectionEnabled()) { chooser.setSelectedFiles(new File[]{f2}); } else { chooser.setSelectedFile(f2); } }); } else { // Could be because of delay in updating Desktop folder // chooser.setSelectedFile(null); }
*** 863,873 **** public ShellFolderColumnInfo[] getColumns() { return columns; } } - private void updateDetailsColumnModel(JTable table) { if (table != null) { ShellFolderColumnInfo[] columns = detailsTableModel.getColumns(); TableColumnModel columnModel = new DefaultTableColumnModel(); --- 945,954 ----
*** 898,907 **** --- 979,990 ---- if (!readOnly && columnModel.getColumnCount() > COLUMN_FILENAME) { columnModel.getColumn(COLUMN_FILENAME). setCellEditor(getDetailsTableCellEditor()); } + columnModel.getColumn(0).setPreferredWidth(160); // TODO néha 250 körüli (pl. dl mappa) + table.setColumnModel(columnModel); } } private DetailsTableRowSorter getRowSorter() {
*** 913,928 **** private class DetailsTableRowSorter extends TableRowSorter<TableModel> { public DetailsTableRowSorter() { SorterModelWrapper modelWrapper = new SorterModelWrapper(); setModelWrapper(modelWrapper); ! modelWrapper.getModel().addTableModelListener( ! new TableModelListener() { ! @Override ! public void tableChanged(TableModelEvent e) { modelStructureChanged(); - } }); } public void updateComparators(ShellFolderColumnInfo [] columns) { for (int i = 0; i < columns.length; i++) { --- 996,1007 ---- private class DetailsTableRowSorter extends TableRowSorter<TableModel> { public DetailsTableRowSorter() { SorterModelWrapper modelWrapper = new SorterModelWrapper(); setModelWrapper(modelWrapper); ! modelWrapper.getModel().addTableModelListener(evt -> { modelStructureChanged(); }); } public void updateComparators(ShellFolderColumnInfo [] columns) { for (int i = 0; i < columns.length; i++) {
*** 934,948 **** } } @Override public void sort() { ! ShellFolder.invoke(new Callable<Void>() { ! public Void call() { DetailsTableRowSorter.super.sort(); return null; - } }); } public void modelStructureChanged() { super.modelStructureChanged(); --- 1013,1025 ---- } } @Override public void sort() { ! ShellFolder.invoke(() -> { DetailsTableRowSorter.super.sort(); return null; }); } public void modelStructureChanged() { super.modelStructureChanged();
*** 975,984 **** --- 1052,1062 ---- /** * This class sorts directories before files, comparing directory to * directory and file to file using the wrapped comparator. */ private class DirectoriesFirstComparatorWrapper implements Comparator<File> { + private Comparator<Object> comparator; private int column; @SuppressWarnings("unchecked") public DirectoriesFirstComparatorWrapper(int column, Comparator<?> comparator) {
*** 1068,1092 **** public Insets getInsets(Insets i) { // Provide some space between columns i = super.getInsets(i); i.left += 4; i.right += 4; return i; } public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { ! if ((table.convertColumnIndexToModel(column) != COLUMN_FILENAME || ! (listViewWindowsStyle && !table.isFocusOwner())) && ! !fullRowSelection) { isSelected = false; } super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); setIcon(null); int modelColumn = table.convertColumnIndexToModel(column); ShellFolderColumnInfo columnInfo = detailsTableModel.getColumns()[modelColumn]; --- 1146,1192 ---- public Insets getInsets(Insets i) { // Provide some space between columns i = super.getInsets(i); i.left += 4; i.right += 4; + if (listViewWindowsStyle) { + i.bottom++; + } return i; } public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { ! if ((table.convertColumnIndexToModel(column) != COLUMN_FILENAME ! || (listViewWindowsStyle && !table.isFocusOwner())) ! && !fullRowSelection) { isSelected = false; } super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + Object hoverCelllValue = table.getClientProperty(WindowsFileListUI.HOVER_CELL_PROPERTY); + if(!isSelected) + if(hoverCelllValue instanceof Integer && row == (int) hoverCelllValue) + setBackground(WindowsFileListUI.ITEM_HOVERED_COLOR); + else + setBackground(null); + + if(isSelected) { + Border border = column == 0 ? + WindowsFileTableUI.ITEM_SELECTED_BORDER_LEFT_CELL: + column == table.getModel().getColumnCount()-1? + WindowsFileTableUI.ITEM_SELECTED_BORDER_RIGHT_CELL: + WindowsFileTableUI.ITEM_SELECTED_BORDER_MID_CELL; + + setBorder(border); + } + + setForeground(column == 0 ? BLACK : listViewWindowsStyle ? + SystemColor.controlDkShadow : new Color(150, 150, 150)); setIcon(null); int modelColumn = table.convertColumnIndexToModel(column); ShellFolderColumnInfo columnInfo = detailsTableModel.getColumns()[modelColumn];
*** 1107,1117 **** text = ""; } else if (value instanceof File) { File file = (File)value; text = chooser.getName(file); ! Icon icon = chooser.getIcon(file); setIcon(icon); } else if (value instanceof Long) { long len = ((Long) value) / 1024L; if (listViewWindowsStyle) { --- 1207,1218 ---- text = ""; } else if (value instanceof File) { File file = (File)value; text = chooser.getName(file); ! Icon icon = new FileIcon(file, () -> chooser.getIcon(file), ! table, 16, 16); setIcon(icon); } else if (value instanceof Long) { long len = ((Long) value) / 1024L; if (listViewWindowsStyle) {
*** 1144,1155 **** public JPanel createDetailsView() { final JFileChooser chooser = getFileChooser(); JPanel p = new JPanel(new BorderLayout()); - @SuppressWarnings("serial") // anonymous class final JTable detailsTable = new JTable(getDetailsTableModel()) { // Handle Escape key events here protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) { if (e.getKeyCode() == KeyEvent.VK_ESCAPE && getCellEditor() == null) { // We are not editing, forward to filechooser. chooser.dispatchEvent(e); --- 1245,1261 ---- public JPanel createDetailsView() { final JFileChooser chooser = getFileChooser(); JPanel p = new JPanel(new BorderLayout()); final JTable detailsTable = new JTable(getDetailsTableModel()) { + + { + if(listViewWindowsStyle) + setUI(new WindowsFileChooserUI.WindowsFileTableUI(chooser)); + } + // Handle Escape key events here protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) { if (e.getKeyCode() == KeyEvent.VK_ESCAPE && getCellEditor() == null) { // We are not editing, forward to filechooser. chooser.dispatchEvent(e);
*** 1171,1189 **** detailsTable.setRowSorter(getRowSorter()); detailsTable.setAutoCreateColumnsFromModel(false); detailsTable.setComponentOrientation(chooser.getComponentOrientation()); detailsTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); detailsTable.setShowGrid(false); detailsTable.putClientProperty("JTable.autoStartsEdit", Boolean.FALSE); detailsTable.addKeyListener(detailsKeyListener); ! Font font = list.getFont(); ! detailsTable.setFont(font); ! detailsTable.setIntercellSpacing(new Dimension(0, 0)); TableCellRenderer headerRenderer = new AlignableTableHeaderRenderer(detailsTable.getTableHeader().getDefaultRenderer()); detailsTable.getTableHeader().setDefaultRenderer(headerRenderer); TableCellRenderer cellRenderer = new DetailsTableCellRenderer(chooser); detailsTable.setDefaultRenderer(Object.class, cellRenderer); // So that drag can be started on a mouse press --- 1277,1304 ---- detailsTable.setRowSorter(getRowSorter()); detailsTable.setAutoCreateColumnsFromModel(false); detailsTable.setComponentOrientation(chooser.getComponentOrientation()); detailsTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); detailsTable.setShowGrid(false); + detailsTable.putClientProperty("Table.isFileList", Boolean.TRUE); detailsTable.putClientProperty("JTable.autoStartsEdit", Boolean.FALSE); detailsTable.addKeyListener(detailsKeyListener); + if(listViewWindowsStyle) { + detailsTable.setSelectionBackground(WindowsFileListUI.ITEM_SELECTED_COLOR); + } + detailsTable.getSelectionModel().setSelectionMode( + getFileChooser().isMultiSelectionEnabled()? + ListSelectionModel.MULTIPLE_INTERVAL_SELECTION: + ListSelectionModel.SINGLE_SELECTION); ! detailsTable.setIntercellSpacing(new Dimension(0, ! listViewWindowsStyle ? -1 : 0)); TableCellRenderer headerRenderer = new AlignableTableHeaderRenderer(detailsTable.getTableHeader().getDefaultRenderer()); + if(listViewWindowsStyle) + detailsTable.getTableHeader().setBackground(Color.white); detailsTable.getTableHeader().setDefaultRenderer(headerRenderer); TableCellRenderer cellRenderer = new DetailsTableCellRenderer(chooser); detailsTable.setDefaultRenderer(Object.class, cellRenderer); // So that drag can be started on a mouse press
*** 1192,1204 **** detailsTable.addMouseListener(getMouseHandler()); // No need to addListSelectionListener because selections are forwarded // to our JList. - // 4835633 : tell BasicTableUI that this is a file list - detailsTable.putClientProperty("Table.isFileList", Boolean.TRUE); - if (listViewWindowsStyle) { detailsTable.addFocusListener(repaintListener); } // TAB/SHIFT-TAB should transfer focus and ENTER should select an item. --- 1307,1316 ----
*** 1213,1234 **** detailsTable.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, null); JScrollPane scrollpane = new JScrollPane(detailsTable); scrollpane.setComponentOrientation(chooser.getComponentOrientation()); LookAndFeel.installColors(scrollpane.getViewport(), "Table.background", "Table.foreground"); - // Adjust width of first column so the table fills the viewport when - // first displayed (temporary listener). - scrollpane.addComponentListener(new ComponentAdapter() { - public void componentResized(ComponentEvent e) { - JScrollPane sp = (JScrollPane)e.getComponent(); - fixNameColumnWidth(sp.getViewport().getSize().width); - sp.removeComponentListener(this); - } - }); - // 4835633. // If the mouse is pressed in the area below the Details view table, the // event is not dispatched to the Table MouseListener but to the // scrollpane. Listen for that here so we can clear the selection. scrollpane.addMouseListener(new MouseAdapter() { --- 1325,1338 ---- detailsTable.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, null); JScrollPane scrollpane = new JScrollPane(detailsTable); scrollpane.setComponentOrientation(chooser.getComponentOrientation()); + if(listViewWindowsStyle) + scrollpane.putClientProperty("ScrollPaneLayout.vsbAtTop", "true"); LookAndFeel.installColors(scrollpane.getViewport(), "Table.background", "Table.foreground"); // 4835633. // If the mouse is pressed in the area below the Details view table, the // event is not dispatched to the Table MouseListener but to the // scrollpane. Listen for that here so we can clear the selection. scrollpane.addMouseListener(new MouseAdapter() {
*** 1244,1256 **** } } } }); - detailsTable.setForeground(list.getForeground()); - detailsTable.setBackground(list.getBackground()); - if (listViewBorder != null) { scrollpane.setBorder(listViewBorder); } p.add(scrollpane, BorderLayout.CENTER); --- 1348,1357 ----
*** 1273,1305 **** boolean hasFocus, int row, int column) { Component c = wrappedRenderer.getTableCellRendererComponent( table, value, isSelected, hasFocus, row, column); int modelColumn = table.convertColumnIndexToModel(column); ShellFolderColumnInfo columnInfo = detailsTableModel.getColumns()[modelColumn]; Integer alignment = columnInfo.getAlignment(); if (alignment == null) { alignment = SwingConstants.CENTER; } if (c instanceof JLabel) { ((JLabel) c).setHorizontalAlignment(alignment); } return c; } } - private void fixNameColumnWidth(int viewWidth) { - TableColumn nameCol = detailsTable.getColumnModel().getColumn(COLUMN_FILENAME); - int tableWidth = detailsTable.getPreferredSize().width; - - if (tableWidth < viewWidth) { - nameCol.setPreferredWidth(nameCol.getPreferredWidth() + viewWidth - tableWidth); - } - } private class DelayedSelectionUpdater implements Runnable { File editFile; DelayedSelectionUpdater() { --- 1374,1400 ---- boolean hasFocus, int row, int column) { Component c = wrappedRenderer.getTableCellRendererComponent( table, value, isSelected, hasFocus, row, column); + if(!listViewWindowsStyle) { int modelColumn = table.convertColumnIndexToModel(column); ShellFolderColumnInfo columnInfo = detailsTableModel.getColumns()[modelColumn]; Integer alignment = columnInfo.getAlignment(); if (alignment == null) { alignment = SwingConstants.CENTER; } if (c instanceof JLabel) { ((JLabel) c).setHorizontalAlignment(alignment); } + } return c; } } private class DelayedSelectionUpdater implements Runnable { File editFile; DelayedSelectionUpdater() {
*** 1361,1383 **** JTextField editCell = null; /** * @param index visual index of the file to be edited */ - @SuppressWarnings("deprecation") private void editFileName(int index) { JFileChooser chooser = getFileChooser(); File currentDirectory = chooser.getCurrentDirectory(); if (readOnly || !canWrite(currentDirectory)) { return; } ensureIndexIsVisible(index); ! switch (viewType) { ! case VIEWTYPE_LIST: ! editFile = (File)getModel().getElementAt(getRowSorter().convertRowIndexToModel(index)); Rectangle r = list.getCellBounds(index, index); if (editCell == null) { editCell = new JTextField(); editCell.setName("Tree.cellEditor"); editCell.addActionListener(new EditActionListener()); --- 1456,1478 ---- JTextField editCell = null; /** * @param index visual index of the file to be edited */ private void editFileName(int index) { JFileChooser chooser = getFileChooser(); File currentDirectory = chooser.getCurrentDirectory(); if (readOnly || !canWrite(currentDirectory)) { return; } ensureIndexIsVisible(index); ! if (viewType.isTable) { ! detailsTable.editCellAt(index, COLUMN_FILENAME); ! } else { ! editFile = (File) getModel().getElementAt(getRowSorter().convertRowIndexToModel(index)); Rectangle r = list.getCellBounds(index, index); if (editCell == null) { editCell = new JTextField(); editCell.setName("Tree.cellEditor"); editCell.addActionListener(new EditActionListener());
*** 1399,1413 **** } else { editCell.setBounds(r.x, r.y, r.width - editX, r.height); } editCell.requestFocus(); editCell.selectAll(); - break; - - case VIEWTYPE_DETAILS: - detailsTable.editCellAt(index, COLUMN_FILENAME); - break; } } class EditActionListener implements ActionListener { --- 1494,1503 ----
*** 1464,1474 **** cancelEdit(); } protected Action newFolderAction; - @SuppressWarnings("serial") // anonymous class inside public Action getNewFolderAction() { if (!readOnly && newFolderAction == null) { newFolderAction = new AbstractAction(newFolderActionLabelText) { private Action basicNewFolderAction; --- 1554,1563 ----
*** 1497,1542 **** }; } return newFolderAction; } - @SuppressWarnings("serial") // JDK-implementation class protected class FileRenderer extends DefaultListCellRenderer { ! public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) { if (listViewWindowsStyle && !list.isFocusOwner()) { isSelected = false; } ! super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); File file = (File) value; String fileName = getFileChooser().getName(file); setText(fileName); setFont(list.getFont()); ! Icon icon = getFileChooser().getIcon(file); ! if (icon != null) { ! setIcon(icon); } else { ! if (getFileChooser().getFileSystemView().isTraversable(file)) { ! setText(fileName+File.separator); } } return this; } } - - @SuppressWarnings("deprecation") void setFileSelected() { if (getFileChooser().isMultiSelectionEnabled() && !isDirectorySelected()) { File[] files = getFileChooser().getSelectedFiles(); // Should be selected ! Object[] selectedObjects = list.getSelectedValues(); // Are actually selected listSelectionModel.setValueIsAdjusting(true); try { int lead = listSelectionModel.getLeadSelectionIndex(); int anchor = listSelectionModel.getAnchorSelectionIndex(); --- 1586,1711 ---- }; } return newFolderAction; } protected class FileRenderer extends DefaultListCellRenderer { ! // when the user selects an item then switches window, the item should ! // appear with gray background ! private static final String LAST_SELECTED_PROPERTY = "FilePane.FileRenderer.lastSelected"; ! ! // TODO az új ViewType enumot a többi lafban is használni kéne majd ! ! public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + assert viewType != null; if (listViewWindowsStyle && !list.isFocusOwner()) { isSelected = false; } ! if (listViewWindowsStyle) { ! setOpaque(true); ! setBackground(null); ! } else { ! super.getListCellRendererComponent(list, "", index, isSelected, cellHasFocus); ! } File file = (File) value; String fileName = getFileChooser().getName(file); setText(fileName); setFont(list.getFont()); ! Boolean isTraversable = getFileChooser().getFileSystemView().isTraversable(file); ! setIcon(new FileIcon(file, () -> { ! Icon icon = null; ! if (viewType.largeIcons) { ! try { ! icon = new ImageIcon(ShellFolder.getShellFolder(file).getIcon(true)); ! } catch (FileNotFoundException ex) { ! throw new RuntimeException(ex); ! } ! } ! ! if (icon == null) { ! icon = getFileChooser().getIcon(file); ! } ! return icon; ! }, list, viewType.largeIcons ? 24 : 16, viewType.largeIcons ? 24 : 16)); ! if (isTraversable) { ! setText(fileName + File.separator); ! } ! ! if (viewType.fileMetaLines) { ! String sizeString = ""; ! ! if (!isTraversable) { ! try { ! sizeString += "<br>" + ShellFolder. ! getShellFolder(file).length(); ! } catch (Exception ex) { ! } ! } ! ! setText("<html>" + getText() + "<br><font color=gray>" ! + getFileChooser().getTypeDescription(file) ! + sizeString); ! } ! ! setAlignmentX(RIGHT_ALIGNMENT); ! setHorizontalAlignment(viewType.horizAlign); ! ! setHorizontalTextPosition(viewType.horizTextPos); ! setVerticalTextPosition(viewType.vertTextPos); ! ! setPreferredSize(viewType.prefSize); ! ! if (listViewWindowsStyle) { ! boolean isHovered = false; ! ! { ! Object propertyValue = list.getClientProperty(HOVER_CELL_PROPERTY); ! if (propertyValue != null) { ! int hover = (int) propertyValue; ! if (hover == index) { ! isHovered = true; ! } ! } ! } ! ! setBorder(new EmptyBorder(1, 1, 3, 1)); ! if (isSelected||editFile == file) { ! setBackground(WindowsFileListUI.ITEM_SELECTED_COLOR); ! if (isHovered) { ! setBorder(new CompoundBorder( ! WindowsFileListUI.ITEM_SELECTED_BORDER, ! new EmptyBorder(0, 0, 2, 0) ! )); ! } ! list.putClientProperty(LAST_SELECTED_PROPERTY, value); ! } else if(list.getClientProperty(LAST_SELECTED_PROPERTY) == value) { ! setBackground(WindowsFileListUI.ITEM_SELECTED_UNFOCUSED_COLOR); ! }else if (isHovered) { ! setBackground(WindowsFileListUI.ITEM_HOVERED_COLOR); } else { ! setBackground(null); } } return this; } } void setFileSelected() { if (getFileChooser().isMultiSelectionEnabled() && !isDirectorySelected()) { File[] files = getFileChooser().getSelectedFiles(); // Should be selected ! Object[] selectedObjects = getViewType().isTable? ! IntStream.of(detailsTable.getSelectedRows()). ! mapToObj(i->getModel().getElementAt(i)). ! toArray(): ! list.getSelectedValues(); // Are actually selected listSelectionModel.setValueIsAdjusting(true); try { int lead = listSelectionModel.getLeadSelectionIndex(); int anchor = listSelectionModel.getAnchorSelectionIndex();
*** 1686,1697 **** /* * Listen for filechooser property changes, such as * the selected file changing, or the type of the dialog changing. */ public void propertyChange(PropertyChangeEvent e) { ! if (viewType == -1) { ! setViewType(VIEWTYPE_LIST); } String s = e.getPropertyName(); if (s.equals(JFileChooser.SELECTED_FILE_CHANGED_PROPERTY)) { doSelectedFileChanged(e); --- 1855,1867 ---- /* * Listen for filechooser property changes, such as * the selected file changing, or the type of the dialog changing. */ public void propertyChange(PropertyChangeEvent e) { ! if (viewType == null) { ! setViewType(ViewType.LIST); // BasicFileChooserUI.Handler needs a list to work ! setViewType(ViewType.DETAILS); } String s = e.getPropertyName(); if (s.equals(JFileChooser.SELECTED_FILE_CHANGED_PROPERTY)) { doSelectedFileChanged(e);
*** 1757,1769 **** public JMenu getViewMenu() { if (viewMenu == null) { viewMenu = new JMenu(viewMenuLabelText); ButtonGroup viewButtonGroup = new ButtonGroup(); ! for (int i = 0; i < VIEWTYPE_COUNT; i++) { ! JRadioButtonMenuItem mi = ! new JRadioButtonMenuItem(new ViewTypeAction(i)); viewButtonGroup.add(mi); viewMenu.add(mi); } updateViewMenu(); } --- 1927,1939 ---- public JMenu getViewMenu() { if (viewMenu == null) { viewMenu = new JMenu(viewMenuLabelText); ButtonGroup viewButtonGroup = new ButtonGroup(); ! for (ViewType viewType : ViewType.values()) { ! JRadioButtonMenuItem mi ! = new JRadioButtonMenuItem(new ViewTypeAction(viewType)); viewButtonGroup.add(mi); viewMenu.add(mi); } updateViewMenu(); }
*** 1931,1940 **** --- 2101,2112 ---- } } public void mousePressed(MouseEvent evt) { if (evt.getSource() instanceof JList) { + list.putClientProperty(FileRenderer.LAST_SELECTED_PROPERTY, null); + // Forward event to Basic if (getDoubleClickListener() != null) { getDoubleClickListener().mousePressed(evt); } }
*** 1949,1959 **** } } private MouseListener getDoubleClickListener() { // Lazy creation of Basic's listener ! if (doubleClickListener == null && list != null) { doubleClickListener = fileChooserUIAccessor.createDoubleClickListener(list); } return doubleClickListener; } --- 2121,2131 ---- } } private MouseListener getDoubleClickListener() { // Lazy creation of Basic's listener ! if (doubleClickListener == null) { doubleClickListener = fileChooserUIAccessor.createDoubleClickListener(list); } return doubleClickListener; }
*** 2030,2039 **** --- 2202,2279 ---- return prop == null ? chooser.getFileSystemView().equals(FileSystemView.getFileSystemView()) : prop.booleanValue(); } + /** + * An Icon implementation which loads the real icon in background, so we + * don't need to block the EDT to load an icon of a file. After the icon + * is loaded, the table or list will be refreshed. + */ + public static class FileIcon implements Icon { + + private static final Executor BACKGROUND_LOADER_THREAD = + Executors.newSingleThreadExecutor(runnable->{ + Thread result = new Thread(runnable, "File Icon Loader"); + result.setDaemon(true); + return result; + }); + + private static final Map<File, Icon> CACHE = new ConcurrentHashMap<>(); + private static final Map<Object, FileIcon> FILEICON_CACHE = new WeakHashMap<>(); + + private final File file; + private final Supplier<Icon> supplier; + private final Component component; + private final int width, height; + + private volatile boolean loading; + + public FileIcon(File file, Supplier<Icon> supplier, Component component, + int width, int height) { + this.file = file; + this.supplier = supplier; + this.component = component; + this.width = width; + this.height = height; + } + + @Override + public void paintIcon(Component c, Graphics g, int x, int y) { + if (CACHE.containsKey(file) && + CACHE.get(file).getIconWidth()==width&& + CACHE.get(file).getIconHeight() == height) { + CACHE.get(file).paintIcon(c, g, x, y); + } else if (!loading) { + loading = true; + BACKGROUND_LOADER_THREAD.execute(() -> { + Icon icon; + try { + icon = supplier.get(); + } catch (Exception ex) { + ex.printStackTrace(); + icon = null; + } + CACHE.put(file, icon); + loading = false; + EventQueue.invokeLater(component::repaint); + }); + } + } + + @Override + public int getIconWidth() { + return width; + } + + @Override + public int getIconHeight() { + return height; + } + + } + // This interface is used to access methods in the FileChooserUI // that are not public. public interface FileChooserUIAccessor { public JFileChooser getFileChooser(); public BasicDirectoryModel getModel();
< prev index next >