/*
 * Copyright (c) 2003, 2013, Oracle and/or its affiliates. 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.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * 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.AWTAccessor;
import sun.awt.AWTAccessor.MouseEventAccessor;
import sun.awt.shell.*;

WARNING: 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.

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
/** * <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 final static String ACTION_APPROVE_SELECTION = "approveSelection"; public final static String ACTION_CANCEL = "cancelSelection"; public final static String ACTION_EDIT_FILE_NAME = "editFileName"; public final static String ACTION_REFRESH = "refresh"; public final static String ACTION_CHANGE_TO_PARENT_DIRECTORY = "Go Up"; public final static String ACTION_NEW_FOLDER = "New Folder"; public final static String ACTION_VIEW_LIST = "viewTypeList"; public final static 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; private JMenu viewMenu; private String viewMenuLabelText; private String refreshActionLabelText; private String newFolderActionLabelText; private String kiloByteString; private String megaByteString; private String gigaByteString; private String renameErrorTitleText; private String renameErrorText; private String renameErrorFileExistsText; private static final Cursor waitCursor = Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR); private final KeyListener detailsKeyListener = new KeyAdapter() { private final long timeFactor; private final StringBuilder typedString = new StringBuilder(); private long lastTime = 1000L; { Long l = (Long) UIManager.get("Table.timeFactor"); 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 timeFactor. 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.
/** * 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(); if (detailsTable == null || rowCount == 0 || e.isAltDown() || e.isControlDown() || e.isMetaDown()) { return; } InputMap inputMap = detailsTable.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); KeyStroke key = KeyStroke.getKeyStrokeForEvent(e); if (inputMap != null && inputMap.get(key) != null) { return; } int startIndex = detailsTable.getSelectionModel().getLeadSelectionIndex(); if (startIndex < 0) { startIndex = 0; } if (startIndex >= rowCount) { startIndex = rowCount - 1; } char c = e.getKeyChar(); long time = e.getWhen(); if (time - lastTime < timeFactor) { if (typedString.length() == 1 && typedString.charAt(0) == c) { // Subsequent same key presses move the keyboard focus to the next // object that starts with the same letter. startIndex++; } else { typedString.append(c); } } else { startIndex++; typedString.setLength(0); typedString.append(c); } lastTime = time; if (startIndex >= rowCount) { startIndex = 0; } // Find next file int index = getNextMatch(startIndex, rowCount - 1); if (index < 0 && startIndex > 0) { // wrap index = getNextMatch(0, startIndex - 1); } if (index >= 0) { detailsTable.getSelectionModel().setSelectionInterval(index, index); Rectangle cellRect = detailsTable.getCellRect(index, detailsTable.convertColumnIndexToView(COLUMN_FILENAME), false); detailsTable.scrollRectToVisible(cellRect); } } private int getNextMatch(int startIndex, int finishIndex) { BasicDirectoryModel model = getModel(); JFileChooser fileChooser = getFileChooser(); DetailsTableRowSorter rowSorter = getRowSorter(); String prefix = typedString.toString().toLowerCase(); // Search element for (int index = startIndex; index <= finishIndex; index++) { File file = (File) model.getElementAt(rowSorter.convertRowIndexToModel(index)); String fileName = fileChooser.getName(file).toLowerCase(); if (fileName.startsWith(prefix)) { return index; } } return -1; } }; private FocusListener editorFocusListener = new FocusAdapter() { public void focusLost(FocusEvent e) { if (! e.isTemporary()) { applyEdit(); } } }; private static FocusListener repaintListener = new FocusListener() { public void focusGained(FocusEvent fe) { repaintSelection(fe.getSource()); } public void focusLost(FocusEvent fe) { repaintSelection(fe.getSource()); } private void repaintSelection(Object source) { if (source instanceof JList) { repaintListSelection((JList)source); } else if (source instanceof JTable) { repaintTableSelection((JTable)source); } } private void repaintListSelection(JList list) { int[] indices = list.getSelectedIndices(); for (int i : indices) { Rectangle bounds = list.getCellBounds(i, i); list.repaint(bounds); } } private void repaintTableSelection(JTable table) { int minRow = table.getSelectionModel().getMinSelectionIndex(); int maxRow = table.getSelectionModel().getMaxSelectionIndex(); if (minRow == -1 || maxRow == -1) { return; } int col0 = table.convertColumnIndexToView(COLUMN_FILENAME); Rectangle first = table.getCellRect(minRow, col0, false); Rectangle last = table.getCellRect(maxRow, col0, false); Rectangle dirty = first.union(last); table.repaint(dirty); } }; private boolean smallIconsView = false; private Border listViewBorder; private Color listViewBackground; private boolean listViewWindowsStyle; private boolean readOnly; private boolean fullRowSelection = false; private ListSelectionModel listSelectionModel; private JList list; private JTable detailsTable; private static final int COLUMN_FILENAME = 0; // Provides a way to recognize a newly created folder, so it can // be selected when it appears in the model. private File newFolderFile; // Used for accessing methods in the corresponding UI class private FileChooserUIAccessor fileChooserUIAccessor; private DetailsTableModel detailsTableModel; private DetailsTableRowSorter rowSorter; public FilePane(FileChooserUIAccessor fileChooserUIAccessor) { super(new BorderLayout()); this.fileChooserUIAccessor = fileChooserUIAccessor; installDefaults(); createActionMap(); } public void uninstallUI() { if (getModel() != null) { getModel().removePropertyChangeListener(this); } } protected JFileChooser getFileChooser() { return fileChooserUIAccessor.getFileChooser(); } 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 = (JList) 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 = (JTable) 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; if (currentViewPanel != null) { Component owner = DefaultKeyboardFocusManager. getCurrentKeyboardFocusManager().getPermanentFocusOwner(); isFocusOwner = owner == detailsTable || owner == list; remove(currentViewPanel); } currentViewPanel = viewPanels[viewType]; add(currentViewPanel, BorderLayout.CENTER); if (isFocusOwner && newFocusOwner != null) { newFocusOwner.requestFocusInWindow(); } revalidate(); repaint(); updateViewMenu(); firePropertyChange("viewType", oldValue, viewType); } 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) { ((JComponent)container).setInheritsPopupMenu(b); } int n = container.getComponentCount(); for (int i = 0; i < n; i++) { recursivelySetInheritsPopupMenu((Container)container.getComponent(i), b); } } protected void installDefaults() { Locale l = getFileChooser().getLocale(); listViewBorder = UIManager.getBorder("FileChooser.listViewBorder"); 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"); filesListAccessibleName = UIManager.getString("FileChooser.filesListAccessibleName", l); filesDetailsAccessibleName = UIManager.getString("FileChooser.filesDetailsAccessibleName", l); renameErrorTitleText = UIManager.getString("FileChooser.renameErrorTitleText", l); 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.
Returns:the command list
/** * 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) { class FilePaneAction extends AbstractAction { FilePaneAction(String name) { this(name, name); } FilePaneAction(String name, String cmd) { super(name); putValue(Action.ACTION_COMMAND_KEY, cmd); } public void actionPerformed(ActionEvent e) { String cmd = (String)getValue(Action.ACTION_COMMAND_KEY); if (cmd == ACTION_CANCEL) { if (editFile != null) { cancelEdit(); } else { getFileChooser().cancelSelection(); } } else if (cmd == ACTION_EDIT_FILE_NAME) { JFileChooser fc = getFileChooser(); int index = listSelectionModel.getMinSelectionIndex(); if (index >= 0 && editFile == null && (!fc.isMultiSelectionEnabled() || fc.getSelectedFiles().length <= 1)) { editFileName(index); } } else if (cmd == ACTION_REFRESH) { 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 { return true; } } } ArrayList<Action> actionList = new ArrayList<Action>(8); Action action; actionList.add(new FilePaneAction(ACTION_CANCEL)); actionList.add(new FilePaneAction(ACTION_EDIT_FILE_NAME)); actionList.add(new FilePaneAction(refreshActionLabelText, ACTION_REFRESH)); action = fileChooserUIAccessor.getApproveSelectionAction(); if (action != null) { actionList.add(action); } action = fileChooserUIAccessor.getChangeToParentDirectoryAction(); if (action != null) { actionList.add(action); } 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()]); } return actions; } 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); } } public JPanel createList() { JPanel p = new JPanel(new BorderLayout()); final JFileChooser fileChooser = getFileChooser(); 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) { throw new IllegalArgumentException(); } // start search from the next element before/after the selected element boolean backwards = (bias == Position.Bias.Backward); for (int i = startIndex; backwards ? i >= 0 : i < max; i += (backwards ? -1 : 1)) { String filename = fileChooser.getName((File)model.getElementAt(i)); if (filename.regionMatches(true, 0, prefix, 0, prefix.length())) { return i; } } return -1; } }; list.setCellRenderer(new FileRenderer()); list.setLayoutOrientation(JList.VERTICAL_WRAP); // 4835633 : tell BasicListUI that this is a file list list.putClientProperty("List.isFileList", Boolean.TRUE); if (listViewWindowsStyle) { list.addFocusListener(repaintListener); } updateListRowCount(list); getModel().addListDataListener(new ListDataListener() { public void intervalAdded(ListDataEvent e) { updateListRowCount(list); } public void intervalRemoved(ListDataEvent e) { updateListRowCount(list); } public void contentsChanged(ListDataEvent e) { if (isShowing()) { clearSelection(); } updateListRowCount(list); } }); getModel().addPropertyChangeListener(this); if (fileChooser.isMultiSelectionEnabled()) { list.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); } else { list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); } list.setModel(new SortableListModel()); list.addListSelectionListener(createListSelectionListener()); list.addMouseListener(getMouseHandler()); JScrollPane scrollpane = new JScrollPane(list); if (listViewBackground != null) { list.setBackground(listViewBackground); } if (listViewBorder != null) { scrollpane.setBorder(listViewBorder); } list.putClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY, filesListAccessibleName); p.add(scrollpane, BorderLayout.CENTER); return p; }
This model allows for sorting JList
/** * This model allows for sorting JList */
private class SortableListModel extends AbstractListModel<Object> implements TableModelListener, RowSorterListener { public SortableListModel() { getDetailsTableModel().addTableModelListener(this); getRowSorter().addRowSorterListener(this); } public int getSize() { return getModel().getSize(); } public Object getElementAt(int index) { // JList doesn't support RowSorter so far, so we put it into the list model return getModel().getElementAt(getRowSorter().convertRowIndexToModel(index)); } public void tableChanged(TableModelEvent e) { fireContentsChanged(this, 0, getSize()); } public void sorterChanged(RowSorterEvent e) { 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; DetailsTableModel(JFileChooser fc) { this.chooser = fc; directoryModel = getModel(); directoryModel.addListDataListener(this); updateColumnInfo(); } void updateColumnInfo() { File dir = chooser.getCurrentDirectory(); if (dir != null && usesShellFolder(chooser)) { try { dir = ShellFolder.getShellFolder(dir); } catch (FileNotFoundException e) { // Leave dir without changing } } 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; visibleColumns.add(column); } } columns = new ShellFolderColumnInfo[visibleColumns.size()]; visibleColumns.toArray(columns); columnMap = Arrays.copyOf(columnMap, columns.length); List<? extends RowSorter.SortKey> sortKeys = (rowSorter == null) ? null : rowSorter.getSortKeys(); fireTableStructureChanged(); restoreSortKeys(sortKeys); } private void restoreSortKeys(List<? extends RowSorter.SortKey> sortKeys) { if (sortKeys != null) { // check if preserved sortKeys are valid for this folder for (int i = 0; i < sortKeys.size(); i++) { RowSorter.SortKey sortKey = sortKeys.get(i); if (sortKey.getColumn() >= columns.length) { sortKeys = null; break; } } if (sortKeys != null) { rowSorter.setSortKeys(sortKeys); } } } public int getRowCount() { return directoryModel.getSize(); } public int getColumnCount() { return columns.length; } public Object getValueAt(int row, int col) { // Note: It is very important to avoid getting info on drives, as // this will trigger "No disk in A:" and similar dialogs. // // Use (f.exists() && !chooser.getFileSystemView().isFileSystemRoot(f)) to // determine if it is safe to call methods directly on f. return getFileColumnValue((File)directoryModel.getElementAt(row), col); } private Object getFileColumnValue(File f, int col) { return (col == COLUMN_FILENAME) ? f // always return the file itself for the 1st column : ShellFolder.getFolderColumnValue(f, columnMap[col]); } public void setValueAt(Object value, int row, int col) { if (col == COLUMN_FILENAME) { final JFileChooser chooser = getFileChooser(); File f = (File)getValueAt(row, col); if (f != null) { String oldDisplayName = chooser.getName(f); String oldFileName = f.getName(); String newDisplayName = ((String)value).trim(); String newFileName; if (!newDisplayName.equals(oldDisplayName)) { newFileName = newDisplayName; //Check if extension is hidden from user int i1 = oldFileName.length(); int i2 = oldDisplayName.length(); if (i1 > i2 && oldFileName.charAt(i2) == '.') { newFileName = newDisplayName + oldFileName.substring(i2); } // rename FileSystemView fsv = chooser.getFileSystemView(); final File f2 = fsv.createFileObject(f.getParentFile(), newFileName); if (f2.exists()) { JOptionPane.showMessageDialog(chooser, MessageFormat.format(renameErrorFileExistsText, oldFileName), renameErrorTitleText, JOptionPane.ERROR_MESSAGE); } else { 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); } } else { JOptionPane.showMessageDialog(chooser, MessageFormat.format(renameErrorText, oldFileName), renameErrorTitleText, JOptionPane.ERROR_MESSAGE); } } } } } } public boolean isCellEditable(int row, int column) { File currentDirectory = getFileChooser().getCurrentDirectory(); return (!readOnly && column == COLUMN_FILENAME && canWrite(currentDirectory)); } public void contentsChanged(ListDataEvent e) { // Update the selection after the model has been updated new DelayedSelectionUpdater(); fireTableDataChanged(); } public void intervalAdded(ListDataEvent e) { int i0 = e.getIndex0(); int i1 = e.getIndex1(); if (i0 == i1) { File file = (File)getModel().getElementAt(i0); if (file.equals(newFolderFile)) { new DelayedSelectionUpdater(file); newFolderFile = null; } } fireTableRowsInserted(e.getIndex0(), e.getIndex1()); } public void intervalRemoved(ListDataEvent e) { fireTableRowsDeleted(e.getIndex0(), e.getIndex1()); } public ShellFolderColumnInfo[] getColumns() { return columns; } } private void updateDetailsColumnModel(JTable table) { if (table != null) { ShellFolderColumnInfo[] columns = detailsTableModel.getColumns(); TableColumnModel columnModel = new DefaultTableColumnModel(); for (int i = 0; i < columns.length; i++) { ShellFolderColumnInfo dataItem = columns[i]; TableColumn column = new TableColumn(i); String title = dataItem.getTitle(); if (title != null && title.startsWith("FileChooser.") && title.endsWith("HeaderText")) { // the column must have a string resource that we try to get String uiTitle = UIManager.getString(title, table.getLocale()); if (uiTitle != null) { title = uiTitle; } } column.setHeaderValue(title); Integer width = dataItem.getWidth(); if (width != null) { column.setPreferredWidth(width); // otherwise we let JTable to decide the actual width } columnModel.addColumn(column); } // Install cell editor for editing file name if (!readOnly && columnModel.getColumnCount() > COLUMN_FILENAME) { columnModel.getColumn(COLUMN_FILENAME). setCellEditor(getDetailsTableCellEditor()); } table.setColumnModel(columnModel); } } private DetailsTableRowSorter getRowSorter() { if (rowSorter == null) { rowSorter = new DetailsTableRowSorter(); } return rowSorter; } private class DetailsTableRowSorter extends TableRowSorter<TableModel> { public DetailsTableRowSorter() { setModelWrapper(new SorterModelWrapper()); } public void updateComparators(ShellFolderColumnInfo [] columns) { for (int i = 0; i < columns.length; i++) { Comparator c = columns[i].getComparator(); if (c != null) { c = new DirectoriesFirstComparatorWrapper(i, c); } setComparator(i, c); } } @Override public void sort() { ShellFolder.invoke(new Callable<Void>() { public Void call() { DetailsTableRowSorter.super.sort(); return null; } }); } public void modelStructureChanged() { super.modelStructureChanged(); updateComparators(detailsTableModel.getColumns()); } private class SorterModelWrapper extends ModelWrapper<TableModel, Integer> { public TableModel getModel() { return getDetailsTableModel(); } public int getColumnCount() { return getDetailsTableModel().getColumnCount(); } public int getRowCount() { return getDetailsTableModel().getRowCount(); } public Object getValueAt(int row, int column) { return FilePane.this.getModel().getElementAt(row); } public Integer getIdentifier(int row) { return row; } } }
This class sorts directories before files, comparing directory to directory and file to file using the wrapped comparator.
/** * 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 comparator; private int column; public DirectoriesFirstComparatorWrapper(int column, Comparator comparator) { this.column = column; this.comparator = comparator; } public int compare(File f1, File f2) { if (f1 != null && f2 != null) { boolean traversable1 = getFileChooser().isTraversable(f1); boolean traversable2 = getFileChooser().isTraversable(f2); // directories go first if (traversable1 && !traversable2) { return -1; } if (!traversable1 && traversable2) { return 1; } } if (detailsTableModel.getColumns()[column].isCompareByColumn()) { return comparator.compare( getDetailsTableModel().getFileColumnValue(f1, column), getDetailsTableModel().getFileColumnValue(f2, column) ); } // For this column we need to pass the file itself (not a // column value) to the comparator return comparator.compare(f1, f2); } } private DetailsTableCellEditor tableCellEditor; private DetailsTableCellEditor getDetailsTableCellEditor() { if (tableCellEditor == null) { tableCellEditor = new DetailsTableCellEditor(new JTextField()); } return tableCellEditor; } private class DetailsTableCellEditor extends DefaultCellEditor { private final JTextField tf; public DetailsTableCellEditor(JTextField tf) { super(tf); this.tf = tf; tf.setName("Table.editor"); tf.addFocusListener(editorFocusListener); } public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { Component comp = super.getTableCellEditorComponent(table, value, isSelected, row, column); if (value instanceof File) { tf.setText(getFileChooser().getName((File) value)); tf.selectAll(); } return comp; } } class DetailsTableCellRenderer extends DefaultTableCellRenderer { JFileChooser chooser; DateFormat df; DetailsTableCellRenderer(JFileChooser chooser) { this.chooser = chooser; df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, chooser.getLocale()); } public void setBounds(int x, int y, int width, int height) { if (getHorizontalAlignment() == SwingConstants.LEADING && !fullRowSelection) { // Restrict width to actual text width = Math.min(width, this.getPreferredSize().width+4); } else { x -= 4; } super.setBounds(x, y, width, height); } 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]; Integer alignment = columnInfo.getAlignment(); if (alignment == null) { alignment = (value instanceof Number) ? SwingConstants.RIGHT : SwingConstants.LEADING; } setHorizontalAlignment(alignment); // formatting cell text // TODO: it's rather a temporary trick, to be revised String text; if (value == null) { 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) { text = MessageFormat.format(kiloByteString, len + 1); } else if (len < 1024L) { text = MessageFormat.format(kiloByteString, (len == 0L) ? 1L : len); } else { len /= 1024L; if (len < 1024L) { text = MessageFormat.format(megaByteString, len); } else { len /= 1024L; text = MessageFormat.format(gigaByteString, len); } } } else if (value instanceof Date) { text = df.format((Date)value); } else { text = value.toString(); } setText(text); return this; } } public JPanel createDetailsView() { final JFileChooser chooser = getFileChooser(); JPanel p = new JPanel(new BorderLayout()); 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); return true; } return super.processKeyBinding(ks, e, condition, pressed); } public void tableChanged(TableModelEvent e) { super.tableChanged(e); if (e.getFirstRow() == TableModelEvent.HEADER_ROW) { // update header with possibly changed column set updateDetailsColumnModel(this); } } }; 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 detailsTable.getColumnModel().getSelectionModel(). setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 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. // We don't want them to navigate within the table ActionMap am = SwingUtilities.getUIActionMap(detailsTable); am.remove("selectNextRowCell"); am.remove("selectPreviousRowCell"); am.remove("selectNextColumnCell"); am.remove("selectPreviousColumnCell"); detailsTable.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, null); 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() { public void mousePressed(MouseEvent e) { JScrollPane jsp = ((JScrollPane)e.getComponent()); JTable table = (JTable)jsp.getViewport().getView(); if (!e.isShiftDown() || table.getSelectionModel().getSelectionMode() == ListSelectionModel.SINGLE_SELECTION) { clearSelection(); TableCellEditor tce = table.getCellEditor(); if (tce != null) { tce.stopCellEditing(); } } } }); detailsTable.setForeground(list.getForeground()); detailsTable.setBackground(list.getBackground()); if (listViewBorder != null) { scrollpane.setBorder(listViewBorder); } p.add(scrollpane, BorderLayout.CENTER); detailsTableModel.fireTableStructureChanged(); detailsTable.putClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY, filesDetailsAccessibleName); return p; } // createDetailsView private class AlignableTableHeaderRenderer implements TableCellRenderer { TableCellRenderer wrappedRenderer; public AlignableTableHeaderRenderer(TableCellRenderer wrappedRenderer) { this.wrappedRenderer = wrappedRenderer; } public Component getTableCellRendererComponent( JTable table, Object value, boolean isSelected, 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() { this(null); } DelayedSelectionUpdater(File editFile) { this.editFile = editFile; if (isShowing()) { SwingUtilities.invokeLater(this); } } public void run() { setFileSelected(); if (editFile != null) { editFileName(getRowSorter().convertRowIndexToView( getModel().indexOf(editFile))); editFile = null; } } }
Creates a selection listener for the list of files and directories.
Returns:a ListSelectionListener
/** * Creates a selection listener for the list of files and directories. * * @return a <code>ListSelectionListener</code> */
public ListSelectionListener createListSelectionListener() { return fileChooserUIAccessor.createListSelectionListener(); } int lastIndex = -1; File editFile = null; private int getEditIndex() { return lastIndex; } private void setEditIndex(int i) { lastIndex = i; } private void resetEditIndex() { lastIndex = -1; } private void cancelEdit() { if (editFile != null) { editFile = null; list.remove(editCell); repaint(); } else if (detailsTable != null && detailsTable.isEditing()) { detailsTable.getCellEditor().cancelCellEditing(); } } JTextField editCell = null;
Params:
  • index – visual index of the file to be edited
/** * @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); 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()); editCell.addFocusListener(editorFocusListener); editCell.setNextFocusableComponent(list); } list.add(editCell); editCell.setText(chooser.getName(editFile)); ComponentOrientation orientation = list.getComponentOrientation(); editCell.setComponentOrientation(orientation); Icon icon = chooser.getIcon(editFile); // PENDING - grab padding (4) below from defaults table. int editX = icon == null ? 20 : icon.getIconWidth() + 4; if (orientation.isLeftToRight()) { editCell.setBounds(editX + r.x, r.y, r.width - editX, r.height); } 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 { public void actionPerformed(ActionEvent e) { applyEdit(); } } private void applyEdit() { if (editFile != null && editFile.exists()) { JFileChooser chooser = getFileChooser(); String oldDisplayName = chooser.getName(editFile); String oldFileName = editFile.getName(); String newDisplayName = editCell.getText().trim(); String newFileName; if (!newDisplayName.equals(oldDisplayName)) { newFileName = newDisplayName; //Check if extension is hidden from user int i1 = oldFileName.length(); int i2 = oldDisplayName.length(); if (i1 > i2 && oldFileName.charAt(i2) == '.') { newFileName = newDisplayName + oldFileName.substring(i2); } // rename FileSystemView fsv = chooser.getFileSystemView(); File f2 = fsv.createFileObject(editFile.getParentFile(), newFileName); if (f2.exists()) { JOptionPane.showMessageDialog(chooser, MessageFormat.format(renameErrorFileExistsText, oldFileName), renameErrorTitleText, JOptionPane.ERROR_MESSAGE); } else { if (getModel().renameFile(editFile, f2)) { if (fsv.isParent(chooser.getCurrentDirectory(), f2)) { 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); } } else { JOptionPane.showMessageDialog(chooser, MessageFormat.format(renameErrorText, oldFileName), renameErrorTitleText, JOptionPane.ERROR_MESSAGE); } } } } if (detailsTable != null && detailsTable.isEditing()) { detailsTable.getCellEditor().stopCellEditing(); } cancelEdit(); } protected Action newFolderAction; public Action getNewFolderAction() { if (!readOnly && newFolderAction == null) { newFolderAction = new AbstractAction(newFolderActionLabelText) { private Action basicNewFolderAction; // Initializer { putValue(Action.ACTION_COMMAND_KEY, FilePane.ACTION_NEW_FOLDER); File currentDirectory = getFileChooser().getCurrentDirectory(); if (currentDirectory != null) { setEnabled(canWrite(currentDirectory)); } } public void actionPerformed(ActionEvent ev) { if (basicNewFolderAction == null) { basicNewFolderAction = fileChooserUIAccessor.getNewFolderAction(); } JFileChooser fc = getFileChooser(); File oldFile = fc.getSelectedFile(); basicNewFolderAction.actionPerformed(ev); File newFile = fc.getSelectedFile(); if (newFile != null && !newFile.equals(oldFile) && newFile.isDirectory()) { newFolderFile = newFile; } } }; } return newFolderAction; } 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; } } 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(); Arrays.sort(files); Arrays.sort(selectedObjects); int shouldIndex = 0; int actuallyIndex = 0; // Remove files that shouldn't be selected and add files which should be selected // Note: Assume files are already sorted in compareTo order. while (shouldIndex < files.length && actuallyIndex < selectedObjects.length) { int comparison = files[shouldIndex].compareTo((File)selectedObjects[actuallyIndex]); if (comparison < 0) { doSelectFile(files[shouldIndex++]); } else if (comparison > 0) { doDeselectFile(selectedObjects[actuallyIndex++]); } else { // Do nothing shouldIndex++; actuallyIndex++; } } while (shouldIndex < files.length) { doSelectFile(files[shouldIndex++]); } while (actuallyIndex < selectedObjects.length) { doDeselectFile(selectedObjects[actuallyIndex++]); } // restore the anchor and lead if (listSelectionModel instanceof DefaultListSelectionModel) { ((DefaultListSelectionModel)listSelectionModel). moveLeadSelectionIndex(lead); listSelectionModel.setAnchorSelectionIndex(anchor); } } finally { listSelectionModel.setValueIsAdjusting(false); } } else { JFileChooser chooser = getFileChooser(); File f; if (isDirectorySelected()) { f = getDirectory(); } else { f = chooser.getSelectedFile(); } int i; if (f != null && (i = getModel().indexOf(f)) >= 0) { int viewIndex = getRowSorter().convertRowIndexToView(i); listSelectionModel.setSelectionInterval(viewIndex, viewIndex); ensureIndexIsVisible(viewIndex); } else { clearSelection(); } } } private void doSelectFile(File fileToSelect) { int index = getModel().indexOf(fileToSelect); // could be missed in the current directory if it changed if (index >= 0) { index = getRowSorter().convertRowIndexToView(index); listSelectionModel.addSelectionInterval(index, index); } } private void doDeselectFile(Object fileToDeselect) { int index = getRowSorter().convertRowIndexToView( getModel().indexOf(fileToDeselect)); listSelectionModel.removeSelectionInterval(index, index); } /* The following methods are used by the PropertyChange Listener */ private void doSelectedFileChanged(PropertyChangeEvent e) { applyEdit(); File f = (File) e.getNewValue(); JFileChooser fc = getFileChooser(); if (f != null && ((fc.isFileSelectionEnabled() && !f.isDirectory()) || (f.isDirectory() && fc.isDirectorySelectionEnabled()))) { setFileSelected(); } } private void doSelectedFilesChanged(PropertyChangeEvent e) { applyEdit(); File[] files = (File[]) e.getNewValue(); JFileChooser fc = getFileChooser(); if (files != null && files.length > 0 && (files.length > 1 || fc.isDirectorySelectionEnabled() || !files[0].isDirectory())) { setFileSelected(); } } private void doDirectoryChanged(PropertyChangeEvent e) { getDetailsTableModel().updateColumnInfo(); JFileChooser fc = getFileChooser(); FileSystemView fsv = fc.getFileSystemView(); applyEdit(); resetEditIndex(); ensureIndexIsVisible(0); File currentDirectory = fc.getCurrentDirectory(); if (currentDirectory != null) { if (!readOnly) { getNewFolderAction().setEnabled(canWrite(currentDirectory)); } fileChooserUIAccessor.getChangeToParentDirectoryAction().setEnabled(!fsv.isRoot(currentDirectory)); } if (list != null) { list.clearSelection(); } } private void doFilterChanged(PropertyChangeEvent e) { applyEdit(); resetEditIndex(); clearSelection(); } private void doFileSelectionModeChanged(PropertyChangeEvent e) { applyEdit(); resetEditIndex(); clearSelection(); } private void doMultiSelectionChanged(PropertyChangeEvent e) { if (getFileChooser().isMultiSelectionEnabled()) { listSelectionModel.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); } else { listSelectionModel.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); clearSelection(); getFileChooser().setSelectedFiles(null); } } /* * 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); } else if (s.equals(JFileChooser.SELECTED_FILES_CHANGED_PROPERTY)) { doSelectedFilesChanged(e); } else if (s.equals(JFileChooser.DIRECTORY_CHANGED_PROPERTY)) { doDirectoryChanged(e); } else if (s.equals(JFileChooser.FILE_FILTER_CHANGED_PROPERTY)) { doFilterChanged(e); } else if (s.equals(JFileChooser.FILE_SELECTION_MODE_CHANGED_PROPERTY)) { doFileSelectionModeChanged(e); } else if (s.equals(JFileChooser.MULTI_SELECTION_ENABLED_CHANGED_PROPERTY)) { doMultiSelectionChanged(e); } else if (s.equals(JFileChooser.CANCEL_SELECTION)) { applyEdit(); } else if (s.equals("busy")) { setCursor((Boolean)e.getNewValue() ? waitCursor : null); } else if (s.equals("componentOrientation")) { ComponentOrientation o = (ComponentOrientation)e.getNewValue(); JFileChooser cc = (JFileChooser)e.getSource(); if (o != e.getOldValue()) { cc.applyComponentOrientation(o); } if (detailsTable != null) { detailsTable.setComponentOrientation(o); detailsTable.getParent().getParent().setComponentOrientation(o); } } } private void ensureIndexIsVisible(int i) { if (i >= 0) { if (list != null) { list.ensureIndexIsVisible(i); } if (detailsTable != null) { detailsTable.scrollRectToVisible(detailsTable.getCellRect(i, COLUMN_FILENAME, true)); } } } public void ensureFileIsVisible(JFileChooser fc, File f) { int modelIndex = getModel().indexOf(f); if (modelIndex >= 0) { ensureIndexIsVisible(getRowSorter().convertRowIndexToView(modelIndex)); } } public void rescanCurrentDirectory() { getModel().validateFileCache(); } public void clearSelection() { if (listSelectionModel != null) { listSelectionModel.clearSelection(); if (listSelectionModel instanceof DefaultListSelectionModel) { ((DefaultListSelectionModel)listSelectionModel).moveLeadSelectionIndex(0); listSelectionModel.setAnchorSelectionIndex(0); } } } 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(); } return viewMenu; } private void updateViewMenu() { if (viewMenu != null) { Component[] comps = viewMenu.getMenuComponents(); for (Component comp : comps) { if (comp instanceof JRadioButtonMenuItem) { JRadioButtonMenuItem mi = (JRadioButtonMenuItem) comp; if (((ViewTypeAction)mi.getAction()).viewType == viewType) { mi.setSelected(true); } } } } } public JPopupMenu getComponentPopupMenu() { JPopupMenu popupMenu = getFileChooser().getComponentPopupMenu(); if (popupMenu != null) { return popupMenu; } JMenu viewMenu = getViewMenu(); if (contextMenu == null) { contextMenu = new JPopupMenu(); if (viewMenu != null) { contextMenu.add(viewMenu); if (listViewWindowsStyle) { contextMenu.addSeparator(); } } ActionMap actionMap = getActionMap(); Action refreshAction = actionMap.get(ACTION_REFRESH); Action newFolderAction = actionMap.get(ACTION_NEW_FOLDER); if (refreshAction != null) { contextMenu.add(refreshAction); if (listViewWindowsStyle && newFolderAction != null) { contextMenu.addSeparator(); } } if (newFolderAction != null) { contextMenu.add(newFolderAction); } } if (viewMenu != null) { viewMenu.getPopupMenu().setInvoker(viewMenu); } return contextMenu; } private Handler handler; protected Handler getMouseHandler() { if (handler == null) { handler = new Handler(); } return handler; } private class Handler implements MouseListener { private MouseListener doubleClickListener; public void mouseClicked(MouseEvent evt) { JComponent source = (JComponent)evt.getSource(); int index; if (source instanceof JList) { index = SwingUtilities2.loc2IndexFileList(list, evt.getPoint()); } else if (source instanceof JTable) { JTable table = (JTable)source; Point p = evt.getPoint(); index = table.rowAtPoint(p); boolean pointOutsidePrefSize = SwingUtilities2.pointOutsidePrefSize( table, index, table.columnAtPoint(p), p); if (pointOutsidePrefSize && !fullRowSelection) { return; } // Translate point from table to list if (index >= 0 && list != null && listSelectionModel.isSelectedIndex(index)) { // Make a new event with the list as source, placing the // click in the corresponding list cell. Rectangle r = list.getCellBounds(index, index); MouseEvent newEvent = new MouseEvent(list, evt.getID(), evt.getWhen(), evt.getModifiers(), r.x + 1, r.y + r.height/2, evt.getXOnScreen(), evt.getYOnScreen(), evt.getClickCount(), evt.isPopupTrigger(), evt.getButton()); MouseEventAccessor meAccessor = AWTAccessor.getMouseEventAccessor(); meAccessor.setCausedByTouchEvent(newEvent, meAccessor.isCausedByTouchEvent(evt)); evt = newEvent; } } else { return; } if (index >= 0 && SwingUtilities.isLeftMouseButton(evt)) { JFileChooser fc = getFileChooser(); // For single click, we handle editing file name if (evt.getClickCount() == 1 && source instanceof JList) { if ((!fc.isMultiSelectionEnabled() || fc.getSelectedFiles().length <= 1) && index >= 0 && listSelectionModel.isSelectedIndex(index) && getEditIndex() == index && editFile == null) { editFileName(index); } else { if (index >= 0) { setEditIndex(index); } else { resetEditIndex(); } } } else if (evt.getClickCount() == 2) { // on double click (open or drill down one directory) be // sure to clear the edit index resetEditIndex(); } } // Forward event to Basic if (getDoubleClickListener() != null) { getDoubleClickListener().mouseClicked(evt); } } public void mouseEntered(MouseEvent evt) { JComponent source = (JComponent)evt.getSource(); if (source instanceof JTable) { JTable table = (JTable)evt.getSource(); TransferHandler th1 = getFileChooser().getTransferHandler(); TransferHandler th2 = table.getTransferHandler(); if (th1 != th2) { table.setTransferHandler(th1); } boolean dragEnabled = getFileChooser().getDragEnabled(); if (dragEnabled != table.getDragEnabled()) { table.setDragEnabled(dragEnabled); } } else if (source instanceof JList) { // Forward event to Basic if (getDoubleClickListener() != null) { getDoubleClickListener().mouseEntered(evt); } } } public void mouseExited(MouseEvent evt) { if (evt.getSource() instanceof JList) { // Forward event to Basic if (getDoubleClickListener() != null) { getDoubleClickListener().mouseExited(evt); } } } public void mousePressed(MouseEvent evt) { if (evt.getSource() instanceof JList) { // Forward event to Basic if (getDoubleClickListener() != null) { getDoubleClickListener().mousePressed(evt); } } } public void mouseReleased(MouseEvent evt) { if (evt.getSource() instanceof JList) { // Forward event to Basic if (getDoubleClickListener() != null) { getDoubleClickListener().mouseReleased(evt); } } } private MouseListener getDoubleClickListener() { // Lazy creation of Basic's listener if (doubleClickListener == null && list != null) { doubleClickListener = fileChooserUIAccessor.createDoubleClickListener(list); } return doubleClickListener; } }
Property to remember whether a directory is currently selected in the UI.
Returns:true iff a directory is currently selected.
/** * Property to remember whether a directory is currently selected in the UI. * * @return <code>true</code> iff a directory is currently selected. */
protected boolean isDirectorySelected() { return fileChooserUIAccessor.isDirectorySelected(); }
Property to remember the directory that is currently selected in the UI.
See Also:
Returns:the value of the directory property
/** * Property to remember the directory that is currently selected in the UI. * * @return the value of the <code>directory</code> property * @see javax.swing.plaf.basic.BasicFileChooserUI#setDirectory */
protected File getDirectory() { return fileChooserUIAccessor.getDirectory(); } private Component findChildComponent(Container container, Class cls) { int n = container.getComponentCount(); for (int i = 0; i < n; i++) { Component comp = container.getComponent(i); if (cls.isInstance(comp)) { return comp; } else if (comp instanceof Container) { Component c = findChildComponent((Container)comp, cls); if (c != null) { return c; } } } return null; } public boolean canWrite(File f) { // Return false for non FileSystem files or if file doesn't exist. if (!f.exists()) { return false; } try { if (f instanceof ShellFolder) { return f.canWrite(); } else { if (usesShellFolder(getFileChooser())) { try { return ShellFolder.getShellFolder(f).canWrite(); } catch (FileNotFoundException ex) { // File doesn't exist return false; } } else { // Ordinary file return f.canWrite(); } } } catch (SecurityException e) { return false; } }
Returns true if specified FileChooser should use ShellFolder
/** * Returns true if specified FileChooser should use ShellFolder */
public static boolean usesShellFolder(JFileChooser chooser) { Boolean prop = (Boolean) chooser.getClientProperty("FileChooser.useShellFolder"); return prop == null ? chooser.getFileSystemView().equals(FileSystemView.getFileSystemView()) : prop.booleanValue(); } // This interface is used to access methods in the FileChooserUI // that are not public. public interface FileChooserUIAccessor { public JFileChooser getFileChooser(); public BasicDirectoryModel getModel(); public JPanel createList(); public JPanel createDetailsView(); public boolean isDirectorySelected(); public File getDirectory(); public Action getApproveSelectionAction(); public Action getChangeToParentDirectoryAction(); public Action getNewFolderAction(); public MouseListener createDoubleClickListener(JList list); public ListSelectionListener createListSelectionListener(); } }