0N/A/*
2362N/A * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/Apackage sun.swing;
0N/A
0N/Aimport java.awt.*;
0N/Aimport java.awt.event.*;
0N/Aimport java.beans.PropertyChangeEvent;
0N/Aimport java.beans.PropertyChangeListener;
0N/Aimport java.io.*;
0N/Aimport java.text.DateFormat;
0N/Aimport java.text.MessageFormat;
0N/Aimport java.util.*;
0N/Aimport java.util.List;
1083N/Aimport java.util.concurrent.Callable;
0N/A
5202N/Aimport javax.accessibility.AccessibleContext;
0N/Aimport javax.swing.*;
0N/Aimport javax.swing.border.*;
0N/Aimport javax.swing.event.*;
0N/Aimport javax.swing.filechooser.*;
0N/Aimport javax.swing.plaf.basic.*;
0N/Aimport javax.swing.table.*;
0N/Aimport javax.swing.text.*;
0N/A
0N/Aimport sun.awt.shell.*;
0N/A
0N/A/**
0N/A * <b>WARNING:</b> This class is an implementation detail and is only
0N/A * public so that it can be used by two packages. You should NOT consider
0N/A * this public API.
0N/A * <p>
0N/A * This component is intended to be used in a subclass of
0N/A * javax.swing.plaf.basic.BasicFileChooserUI. It realies heavily on the
0N/A * implementation of BasicFileChooserUI, and is intended to be API compatible
0N/A * with earlier implementations of MetalFileChooserUI and WindowsFileChooserUI.
0N/A *
0N/A * @author Leif Samuelsson
0N/A */
0N/Apublic class FilePane extends JPanel implements PropertyChangeListener {
0N/A // Constants for actions. These are used for the actions' ACTION_COMMAND_KEY
0N/A // and as keys in the action maps for FilePane and the corresponding UI classes
0N/A
0N/A public final static String ACTION_APPROVE_SELECTION = "approveSelection";
0N/A public final static String ACTION_CANCEL = "cancelSelection";
0N/A public final static String ACTION_EDIT_FILE_NAME = "editFileName";
0N/A public final static String ACTION_REFRESH = "refresh";
0N/A public final static String ACTION_CHANGE_TO_PARENT_DIRECTORY = "Go Up";
0N/A public final static String ACTION_NEW_FOLDER = "New Folder";
0N/A public final static String ACTION_VIEW_LIST = "viewTypeList";
0N/A public final static String ACTION_VIEW_DETAILS = "viewTypeDetails";
0N/A
0N/A private Action[] actions;
0N/A
0N/A // "enums" for setViewType()
0N/A public static final int VIEWTYPE_LIST = 0;
0N/A public static final int VIEWTYPE_DETAILS = 1;
0N/A private static final int VIEWTYPE_COUNT = 2;
0N/A
0N/A private int viewType = -1;
0N/A private JPanel[] viewPanels = new JPanel[VIEWTYPE_COUNT];
0N/A private JPanel currentViewPanel;
0N/A private String[] viewTypeActionNames;
0N/A
5202N/A private String filesListAccessibleName = null;
5202N/A private String filesDetailsAccessibleName = null;
5202N/A
0N/A private JPopupMenu contextMenu;
0N/A private JMenu viewMenu;
0N/A
0N/A private String viewMenuLabelText;
0N/A private String refreshActionLabelText;
0N/A private String newFolderActionLabelText;
0N/A
0N/A private String kiloByteString;
0N/A private String megaByteString;
0N/A private String gigaByteString;
0N/A
0N/A private String renameErrorTitleText;
0N/A private String renameErrorText;
0N/A private String renameErrorFileExistsText;
0N/A
0N/A private static final Cursor waitCursor =
0N/A Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR);
0N/A
0N/A private final KeyListener detailsKeyListener = new KeyAdapter() {
0N/A private final long timeFactor;
0N/A
0N/A private final StringBuilder typedString = new StringBuilder();
0N/A
0N/A private long lastTime = 1000L;
0N/A
0N/A {
0N/A Long l = (Long) UIManager.get("Table.timeFactor");
0N/A timeFactor = (l != null) ? l : 1000L;
0N/A }
0N/A
0N/A /**
0N/A * Moves the keyboard focus to the first element whose prefix matches
0N/A * the sequence of alphanumeric keys pressed by the user with delay
0N/A * less than value of <code>timeFactor</code>. Subsequent same key
0N/A * presses move the keyboard focus to the next object that starts with
0N/A * the same letter until another key is pressed, then it is treated
0N/A * as the prefix with appropriate number of the same letters followed
0N/A * by first typed another letter.
0N/A */
0N/A public void keyTyped(KeyEvent e) {
0N/A BasicDirectoryModel model = getModel();
0N/A int rowCount = model.getSize();
0N/A
0N/A if (detailsTable == null || rowCount == 0 ||
0N/A e.isAltDown() || e.isControlDown() || e.isMetaDown()) {
0N/A return;
0N/A }
0N/A
0N/A InputMap inputMap = detailsTable.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
0N/A KeyStroke key = KeyStroke.getKeyStrokeForEvent(e);
0N/A
0N/A if (inputMap != null && inputMap.get(key) != null) {
0N/A return;
0N/A }
0N/A
0N/A int startIndex = detailsTable.getSelectionModel().getLeadSelectionIndex();
0N/A
0N/A if (startIndex < 0) {
0N/A startIndex = 0;
0N/A }
0N/A
0N/A if (startIndex >= rowCount) {
0N/A startIndex = rowCount - 1;
0N/A }
0N/A
0N/A char c = e.getKeyChar();
0N/A
0N/A long time = e.getWhen();
0N/A
0N/A if (time - lastTime < timeFactor) {
0N/A if (typedString.length() == 1 && typedString.charAt(0) == c) {
0N/A // Subsequent same key presses move the keyboard focus to the next
0N/A // object that starts with the same letter.
0N/A startIndex++;
0N/A } else {
0N/A typedString.append(c);
0N/A }
0N/A } else {
0N/A startIndex++;
0N/A
0N/A typedString.setLength(0);
0N/A typedString.append(c);
0N/A }
0N/A
0N/A lastTime = time;
0N/A
0N/A if (startIndex >= rowCount) {
0N/A startIndex = 0;
0N/A }
0N/A
0N/A // Find next file
0N/A int index = getNextMatch(startIndex, rowCount - 1);
0N/A
0N/A if (index < 0 && startIndex > 0) { // wrap
0N/A index = getNextMatch(0, startIndex - 1);
0N/A }
0N/A
0N/A if (index >= 0) {
0N/A detailsTable.getSelectionModel().setSelectionInterval(index, index);
0N/A
0N/A Rectangle cellRect = detailsTable.getCellRect(index,
0N/A detailsTable.convertColumnIndexToView(COLUMN_FILENAME), false);
0N/A detailsTable.scrollRectToVisible(cellRect);
0N/A }
0N/A }
0N/A
0N/A private int getNextMatch(int startIndex, int finishIndex) {
0N/A BasicDirectoryModel model = getModel();
0N/A JFileChooser fileChooser = getFileChooser();
0N/A DetailsTableRowSorter rowSorter = getRowSorter();
0N/A
0N/A String prefix = typedString.toString().toLowerCase();
0N/A
0N/A // Search element
0N/A for (int index = startIndex; index <= finishIndex; index++) {
0N/A File file = (File) model.getElementAt(rowSorter.convertRowIndexToModel(index));
0N/A
0N/A String fileName = fileChooser.getName(file).toLowerCase();
0N/A
0N/A if (fileName.startsWith(prefix)) {
0N/A return index;
0N/A }
0N/A }
0N/A
0N/A return -1;
0N/A }
0N/A };
0N/A
0N/A private FocusListener editorFocusListener = new FocusAdapter() {
0N/A public void focusLost(FocusEvent e) {
0N/A if (! e.isTemporary()) {
0N/A applyEdit();
0N/A }
0N/A }
0N/A };
0N/A
0N/A private static FocusListener repaintListener = new FocusListener() {
0N/A public void focusGained(FocusEvent fe) {
0N/A repaintSelection(fe.getSource());
0N/A }
0N/A
0N/A public void focusLost(FocusEvent fe) {
0N/A repaintSelection(fe.getSource());
0N/A }
0N/A
0N/A private void repaintSelection(Object source) {
0N/A if (source instanceof JList) {
0N/A repaintListSelection((JList)source);
0N/A } else if (source instanceof JTable) {
0N/A repaintTableSelection((JTable)source);
0N/A }
0N/A }
0N/A
0N/A private void repaintListSelection(JList list) {
0N/A int[] indices = list.getSelectedIndices();
0N/A for (int i : indices) {
0N/A Rectangle bounds = list.getCellBounds(i, i);
0N/A list.repaint(bounds);
0N/A }
0N/A }
0N/A
0N/A private void repaintTableSelection(JTable table) {
0N/A int minRow = table.getSelectionModel().getMinSelectionIndex();
0N/A int maxRow = table.getSelectionModel().getMaxSelectionIndex();
0N/A if (minRow == -1 || maxRow == -1) {
0N/A return;
0N/A }
0N/A
0N/A int col0 = table.convertColumnIndexToView(COLUMN_FILENAME);
0N/A
0N/A Rectangle first = table.getCellRect(minRow, col0, false);
0N/A Rectangle last = table.getCellRect(maxRow, col0, false);
0N/A Rectangle dirty = first.union(last);
0N/A table.repaint(dirty);
0N/A }
0N/A };
0N/A
0N/A private boolean smallIconsView = false;
0N/A private Border listViewBorder;
0N/A private Color listViewBackground;
0N/A private boolean listViewWindowsStyle;
0N/A private boolean readOnly;
1173N/A private boolean fullRowSelection = false;
0N/A
0N/A private ListSelectionModel listSelectionModel;
0N/A private JList list;
0N/A private JTable detailsTable;
0N/A
0N/A private static final int COLUMN_FILENAME = 0;
0N/A
0N/A // Provides a way to recognize a newly created folder, so it can
0N/A // be selected when it appears in the model.
0N/A private File newFolderFile;
0N/A
0N/A // Used for accessing methods in the corresponding UI class
0N/A private FileChooserUIAccessor fileChooserUIAccessor;
0N/A private DetailsTableModel detailsTableModel;
0N/A private DetailsTableRowSorter rowSorter;
0N/A
0N/A public FilePane(FileChooserUIAccessor fileChooserUIAccessor) {
0N/A super(new BorderLayout());
0N/A
0N/A this.fileChooserUIAccessor = fileChooserUIAccessor;
0N/A
0N/A installDefaults();
0N/A createActionMap();
0N/A }
0N/A
0N/A public void uninstallUI() {
0N/A if (getModel() != null) {
0N/A getModel().removePropertyChangeListener(this);
0N/A }
0N/A }
0N/A
0N/A protected JFileChooser getFileChooser() {
0N/A return fileChooserUIAccessor.getFileChooser();
0N/A }
0N/A
0N/A protected BasicDirectoryModel getModel() {
0N/A return fileChooserUIAccessor.getModel();
0N/A }
0N/A
0N/A public int getViewType() {
0N/A return viewType;
0N/A }
0N/A
0N/A public void setViewType(int viewType) {
629N/A if (viewType == this.viewType) {
0N/A return;
0N/A }
629N/A
629N/A int oldValue = this.viewType;
0N/A this.viewType = viewType;
0N/A
629N/A JPanel createdViewPanel = null;
629N/A Component newFocusOwner = null;
629N/A
0N/A switch (viewType) {
0N/A case VIEWTYPE_LIST:
0N/A if (viewPanels[viewType] == null) {
629N/A createdViewPanel = fileChooserUIAccessor.createList();
629N/A if (createdViewPanel == null) {
629N/A createdViewPanel = createList();
0N/A }
629N/A
629N/A list = (JList) findChildComponent(createdViewPanel, JList.class);
629N/A if (listSelectionModel == null) {
629N/A listSelectionModel = list.getSelectionModel();
629N/A if (detailsTable != null) {
629N/A detailsTable.setSelectionModel(listSelectionModel);
629N/A }
629N/A } else {
629N/A list.setSelectionModel(listSelectionModel);
629N/A }
0N/A }
0N/A list.setLayoutOrientation(JList.VERTICAL_WRAP);
629N/A newFocusOwner = list;
0N/A break;
0N/A
0N/A case VIEWTYPE_DETAILS:
0N/A if (viewPanels[viewType] == null) {
629N/A createdViewPanel = fileChooserUIAccessor.createDetailsView();
629N/A if (createdViewPanel == null) {
629N/A createdViewPanel = createDetailsView();
0N/A }
629N/A
629N/A detailsTable = (JTable) findChildComponent(createdViewPanel, JTable.class);
629N/A detailsTable.setRowHeight(Math.max(detailsTable.getFont().getSize() + 4, 16 + 1));
629N/A if (listSelectionModel != null) {
629N/A detailsTable.setSelectionModel(listSelectionModel);
629N/A }
0N/A }
629N/A newFocusOwner = detailsTable;
0N/A break;
0N/A }
629N/A
629N/A if (createdViewPanel != null) {
629N/A viewPanels[viewType] = createdViewPanel;
629N/A recursivelySetInheritsPopupMenu(createdViewPanel, true);
629N/A }
629N/A
629N/A boolean isFocusOwner = false;
629N/A
629N/A if (currentViewPanel != null) {
629N/A Component owner = DefaultKeyboardFocusManager.
629N/A getCurrentKeyboardFocusManager().getPermanentFocusOwner();
629N/A
629N/A isFocusOwner = owner == detailsTable || owner == list;
629N/A
629N/A remove(currentViewPanel);
629N/A }
629N/A
0N/A currentViewPanel = viewPanels[viewType];
629N/A add(currentViewPanel, BorderLayout.CENTER);
629N/A
629N/A if (isFocusOwner && newFocusOwner != null) {
629N/A newFocusOwner.requestFocusInWindow();
0N/A }
629N/A
629N/A revalidate();
629N/A repaint();
0N/A updateViewMenu();
0N/A firePropertyChange("viewType", oldValue, viewType);
0N/A }
0N/A
0N/A class ViewTypeAction extends AbstractAction {
0N/A private int viewType;
0N/A
0N/A ViewTypeAction(int viewType) {
0N/A super(viewTypeActionNames[viewType]);
0N/A this.viewType = viewType;
0N/A
0N/A String cmd;
0N/A switch (viewType) {
0N/A case VIEWTYPE_LIST: cmd = ACTION_VIEW_LIST; break;
0N/A case VIEWTYPE_DETAILS: cmd = ACTION_VIEW_DETAILS; break;
0N/A default: cmd = (String)getValue(Action.NAME);
0N/A }
0N/A putValue(Action.ACTION_COMMAND_KEY, cmd);
0N/A }
0N/A
0N/A public void actionPerformed(ActionEvent e) {
0N/A setViewType(viewType);
0N/A }
0N/A }
0N/A
0N/A public Action getViewTypeAction(int viewType) {
0N/A return new ViewTypeAction(viewType);
0N/A }
0N/A
0N/A private static void recursivelySetInheritsPopupMenu(Container container, boolean b) {
0N/A if (container instanceof JComponent) {
0N/A ((JComponent)container).setInheritsPopupMenu(b);
0N/A }
0N/A int n = container.getComponentCount();
0N/A for (int i = 0; i < n; i++) {
0N/A recursivelySetInheritsPopupMenu((Container)container.getComponent(i), b);
0N/A }
0N/A }
0N/A
0N/A protected void installDefaults() {
0N/A Locale l = getFileChooser().getLocale();
0N/A
0N/A listViewBorder = UIManager.getBorder("FileChooser.listViewBorder");
0N/A listViewBackground = UIManager.getColor("FileChooser.listViewBackground");
0N/A listViewWindowsStyle = UIManager.getBoolean("FileChooser.listViewWindowsStyle");
0N/A readOnly = UIManager.getBoolean("FileChooser.readOnly");
0N/A
0N/A // TODO: On windows, get the following localized strings from the OS
0N/A
0N/A viewMenuLabelText =
0N/A UIManager.getString("FileChooser.viewMenuLabelText", l);
0N/A refreshActionLabelText =
0N/A UIManager.getString("FileChooser.refreshActionLabelText", l);
0N/A newFolderActionLabelText =
0N/A UIManager.getString("FileChooser.newFolderActionLabelText", l);
0N/A
0N/A viewTypeActionNames = new String[VIEWTYPE_COUNT];
0N/A viewTypeActionNames[VIEWTYPE_LIST] =
0N/A UIManager.getString("FileChooser.listViewActionLabelText", l);
0N/A viewTypeActionNames[VIEWTYPE_DETAILS] =
0N/A UIManager.getString("FileChooser.detailsViewActionLabelText", l);
0N/A
0N/A kiloByteString = UIManager.getString("FileChooser.fileSizeKiloBytes", l);
0N/A megaByteString = UIManager.getString("FileChooser.fileSizeMegaBytes", l);
0N/A gigaByteString = UIManager.getString("FileChooser.fileSizeGigaBytes", l);
1173N/A fullRowSelection = UIManager.getBoolean("FileView.fullRowSelection");
0N/A
5202N/A filesListAccessibleName = UIManager.getString("FileChooser.filesListAccessibleName", l);
5202N/A filesDetailsAccessibleName = UIManager.getString("FileChooser.filesDetailsAccessibleName", l);
5202N/A
0N/A renameErrorTitleText = UIManager.getString("FileChooser.renameErrorTitleText", l);
0N/A renameErrorText = UIManager.getString("FileChooser.renameErrorText", l);
0N/A renameErrorFileExistsText = UIManager.getString("FileChooser.renameErrorFileExistsText", l);
0N/A }
0N/A
0N/A /**
0N/A * Fetches the command list for the FilePane. These commands
0N/A * are useful for binding to events, such as in a keymap.
0N/A *
0N/A * @return the command list
0N/A */
0N/A public Action[] getActions() {
0N/A if (actions == null) {
0N/A class FilePaneAction extends AbstractAction {
0N/A FilePaneAction(String name) {
0N/A this(name, name);
0N/A }
0N/A
0N/A FilePaneAction(String name, String cmd) {
0N/A super(name);
0N/A putValue(Action.ACTION_COMMAND_KEY, cmd);
0N/A }
0N/A
0N/A public void actionPerformed(ActionEvent e) {
0N/A String cmd = (String)getValue(Action.ACTION_COMMAND_KEY);
0N/A
0N/A if (cmd == ACTION_CANCEL) {
0N/A if (editFile != null) {
0N/A cancelEdit();
0N/A } else {
0N/A getFileChooser().cancelSelection();
0N/A }
0N/A } else if (cmd == ACTION_EDIT_FILE_NAME) {
0N/A JFileChooser fc = getFileChooser();
0N/A int index = listSelectionModel.getMinSelectionIndex();
0N/A if (index >= 0 && editFile == null &&
0N/A (!fc.isMultiSelectionEnabled() ||
0N/A fc.getSelectedFiles().length <= 1)) {
0N/A
0N/A editFileName(index);
0N/A }
0N/A } else if (cmd == ACTION_REFRESH) {
0N/A getFileChooser().rescanCurrentDirectory();
0N/A }
0N/A }
0N/A
0N/A public boolean isEnabled() {
0N/A String cmd = (String)getValue(Action.ACTION_COMMAND_KEY);
0N/A if (cmd == ACTION_CANCEL) {
0N/A return getFileChooser().isEnabled();
0N/A } else if (cmd == ACTION_EDIT_FILE_NAME) {
0N/A return !readOnly && getFileChooser().isEnabled();
0N/A } else {
0N/A return true;
0N/A }
0N/A }
0N/A }
0N/A
0N/A ArrayList<Action> actionList = new ArrayList<Action>(8);
0N/A Action action;
0N/A
0N/A actionList.add(new FilePaneAction(ACTION_CANCEL));
0N/A actionList.add(new FilePaneAction(ACTION_EDIT_FILE_NAME));
0N/A actionList.add(new FilePaneAction(refreshActionLabelText, ACTION_REFRESH));
0N/A
0N/A action = fileChooserUIAccessor.getApproveSelectionAction();
0N/A if (action != null) {
0N/A actionList.add(action);
0N/A }
0N/A action = fileChooserUIAccessor.getChangeToParentDirectoryAction();
0N/A if (action != null) {
0N/A actionList.add(action);
0N/A }
0N/A action = getNewFolderAction();
0N/A if (action != null) {
0N/A actionList.add(action);
0N/A }
0N/A action = getViewTypeAction(VIEWTYPE_LIST);
0N/A if (action != null) {
0N/A actionList.add(action);
0N/A }
0N/A action = getViewTypeAction(VIEWTYPE_DETAILS);
0N/A if (action != null) {
0N/A actionList.add(action);
0N/A }
0N/A actions = actionList.toArray(new Action[actionList.size()]);
0N/A }
0N/A
0N/A return actions;
0N/A }
0N/A
0N/A protected void createActionMap() {
0N/A addActionsToMap(super.getActionMap(), getActions());
0N/A }
0N/A
0N/A
0N/A public static void addActionsToMap(ActionMap map, Action[] actions) {
0N/A if (map != null && actions != null) {
625N/A for (Action a : actions) {
0N/A String cmd = (String)a.getValue(Action.ACTION_COMMAND_KEY);
0N/A if (cmd == null) {
0N/A cmd = (String)a.getValue(Action.NAME);
0N/A }
0N/A map.put(cmd, a);
0N/A }
0N/A }
0N/A }
0N/A
0N/A
0N/A private void updateListRowCount(JList list) {
0N/A if (smallIconsView) {
0N/A list.setVisibleRowCount(getModel().getSize() / 3);
0N/A } else {
0N/A list.setVisibleRowCount(-1);
0N/A }
0N/A }
0N/A
0N/A public JPanel createList() {
0N/A JPanel p = new JPanel(new BorderLayout());
0N/A final JFileChooser fileChooser = getFileChooser();
0N/A final JList list = new JList() {
0N/A public int getNextMatch(String prefix, int startIndex, Position.Bias bias) {
0N/A ListModel model = getModel();
0N/A int max = model.getSize();
0N/A if (prefix == null || startIndex < 0 || startIndex >= max) {
0N/A throw new IllegalArgumentException();
0N/A }
0N/A // start search from the next element before/after the selected element
0N/A boolean backwards = (bias == Position.Bias.Backward);
0N/A for (int i = startIndex; backwards ? i >= 0 : i < max; i += (backwards ? -1 : 1)) {
0N/A String filename = fileChooser.getName((File)model.getElementAt(i));
0N/A if (filename.regionMatches(true, 0, prefix, 0, prefix.length())) {
0N/A return i;
0N/A }
0N/A }
0N/A return -1;
0N/A }
0N/A };
0N/A list.setCellRenderer(new FileRenderer());
0N/A list.setLayoutOrientation(JList.VERTICAL_WRAP);
0N/A
0N/A // 4835633 : tell BasicListUI that this is a file list
0N/A list.putClientProperty("List.isFileList", Boolean.TRUE);
0N/A
0N/A if (listViewWindowsStyle) {
0N/A list.addFocusListener(repaintListener);
0N/A }
0N/A
0N/A updateListRowCount(list);
0N/A
0N/A getModel().addListDataListener(new ListDataListener() {
0N/A public void intervalAdded(ListDataEvent e) {
0N/A updateListRowCount(list);
0N/A }
0N/A public void intervalRemoved(ListDataEvent e) {
0N/A updateListRowCount(list);
0N/A }
0N/A public void contentsChanged(ListDataEvent e) {
0N/A if (isShowing()) {
0N/A clearSelection();
0N/A }
0N/A updateListRowCount(list);
0N/A }
0N/A });
0N/A
0N/A getModel().addPropertyChangeListener(this);
0N/A
0N/A if (fileChooser.isMultiSelectionEnabled()) {
0N/A list.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
0N/A } else {
0N/A list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
0N/A }
0N/A list.setModel(new SortableListModel());
0N/A
0N/A list.addListSelectionListener(createListSelectionListener());
0N/A list.addMouseListener(getMouseHandler());
0N/A
0N/A JScrollPane scrollpane = new JScrollPane(list);
0N/A if (listViewBackground != null) {
0N/A list.setBackground(listViewBackground);
0N/A }
0N/A if (listViewBorder != null) {
0N/A scrollpane.setBorder(listViewBorder);
0N/A }
5202N/A
5202N/A list.putClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY, filesListAccessibleName);
5202N/A
0N/A p.add(scrollpane, BorderLayout.CENTER);
0N/A return p;
0N/A }
0N/A
0N/A /**
0N/A * This model allows for sorting JList
0N/A */
0N/A private class SortableListModel extends AbstractListModel
0N/A implements TableModelListener, RowSorterListener {
0N/A
0N/A public SortableListModel() {
0N/A getDetailsTableModel().addTableModelListener(this);
0N/A getRowSorter().addRowSorterListener(this);
0N/A }
0N/A
0N/A public int getSize() {
0N/A return getModel().getSize();
0N/A }
0N/A
0N/A public Object getElementAt(int index) {
0N/A // JList doesn't support RowSorter so far, so we put it into the list model
0N/A return getModel().getElementAt(getRowSorter().convertRowIndexToModel(index));
0N/A }
0N/A
0N/A public void tableChanged(TableModelEvent e) {
0N/A fireContentsChanged(this, 0, getSize());
0N/A }
0N/A
0N/A public void sorterChanged(RowSorterEvent e) {
0N/A fireContentsChanged(this, 0, getSize());
0N/A }
0N/A }
0N/A
0N/A private DetailsTableModel getDetailsTableModel() {
0N/A if(detailsTableModel == null) {
0N/A detailsTableModel = new DetailsTableModel(getFileChooser());
0N/A }
0N/A return detailsTableModel;
0N/A }
0N/A
0N/A class DetailsTableModel extends AbstractTableModel implements ListDataListener {
0N/A JFileChooser chooser;
0N/A BasicDirectoryModel directoryModel;
0N/A
0N/A ShellFolderColumnInfo[] columns;
0N/A int[] columnMap;
0N/A
0N/A DetailsTableModel(JFileChooser fc) {
0N/A this.chooser = fc;
0N/A directoryModel = getModel();
0N/A directoryModel.addListDataListener(this);
0N/A
0N/A updateColumnInfo();
0N/A }
0N/A
0N/A void updateColumnInfo() {
0N/A File dir = chooser.getCurrentDirectory();
825N/A if (dir != null && usesShellFolder(chooser)) {
0N/A try {
0N/A dir = ShellFolder.getShellFolder(dir);
0N/A } catch (FileNotFoundException e) {
0N/A // Leave dir without changing
0N/A }
0N/A }
0N/A
0N/A ShellFolderColumnInfo[] allColumns = ShellFolder.getFolderColumns(dir);
0N/A
0N/A ArrayList<ShellFolderColumnInfo> visibleColumns =
0N/A new ArrayList<ShellFolderColumnInfo>();
0N/A columnMap = new int[allColumns.length];
0N/A for (int i = 0; i < allColumns.length; i++) {
0N/A ShellFolderColumnInfo column = allColumns[i];
0N/A if (column.isVisible()) {
0N/A columnMap[visibleColumns.size()] = i;
0N/A visibleColumns.add(column);
0N/A }
0N/A }
0N/A
0N/A columns = new ShellFolderColumnInfo[visibleColumns.size()];
0N/A visibleColumns.toArray(columns);
0N/A columnMap = Arrays.copyOf(columnMap, columns.length);
0N/A
625N/A List<? extends RowSorter.SortKey> sortKeys =
0N/A (rowSorter == null) ? null : rowSorter.getSortKeys();
0N/A fireTableStructureChanged();
0N/A restoreSortKeys(sortKeys);
0N/A }
0N/A
625N/A private void restoreSortKeys(List<? extends RowSorter.SortKey> sortKeys) {
0N/A if (sortKeys != null) {
0N/A // check if preserved sortKeys are valid for this folder
0N/A for (int i = 0; i < sortKeys.size(); i++) {
0N/A RowSorter.SortKey sortKey = sortKeys.get(i);
0N/A if (sortKey.getColumn() >= columns.length) {
0N/A sortKeys = null;
0N/A break;
0N/A }
0N/A }
0N/A if (sortKeys != null) {
0N/A rowSorter.setSortKeys(sortKeys);
0N/A }
0N/A }
0N/A }
0N/A
0N/A public int getRowCount() {
0N/A return directoryModel.getSize();
0N/A }
0N/A
0N/A public int getColumnCount() {
0N/A return columns.length;
0N/A }
0N/A
0N/A public Object getValueAt(int row, int col) {
0N/A // Note: It is very important to avoid getting info on drives, as
0N/A // this will trigger "No disk in A:" and similar dialogs.
0N/A //
0N/A // Use (f.exists() && !chooser.getFileSystemView().isFileSystemRoot(f)) to
0N/A // determine if it is safe to call methods directly on f.
0N/A return getFileColumnValue((File)directoryModel.getElementAt(row), col);
0N/A }
0N/A
0N/A private Object getFileColumnValue(File f, int col) {
0N/A return (col == COLUMN_FILENAME)
0N/A ? f // always return the file itself for the 1st column
0N/A : ShellFolder.getFolderColumnValue(f, columnMap[col]);
0N/A }
0N/A
0N/A public void setValueAt(Object value, int row, int col) {
0N/A if (col == COLUMN_FILENAME) {
4091N/A final JFileChooser chooser = getFileChooser();
0N/A File f = (File)getValueAt(row, col);
0N/A if (f != null) {
0N/A String oldDisplayName = chooser.getName(f);
0N/A String oldFileName = f.getName();
0N/A String newDisplayName = ((String)value).trim();
0N/A String newFileName;
0N/A
0N/A if (!newDisplayName.equals(oldDisplayName)) {
0N/A newFileName = newDisplayName;
0N/A //Check if extension is hidden from user
0N/A int i1 = oldFileName.length();
0N/A int i2 = oldDisplayName.length();
0N/A if (i1 > i2 && oldFileName.charAt(i2) == '.') {
0N/A newFileName = newDisplayName + oldFileName.substring(i2);
0N/A }
0N/A
0N/A // rename
0N/A FileSystemView fsv = chooser.getFileSystemView();
4091N/A final File f2 = fsv.createFileObject(f.getParentFile(), newFileName);
0N/A if (f2.exists()) {
0N/A JOptionPane.showMessageDialog(chooser, MessageFormat.format(renameErrorFileExistsText,
0N/A oldFileName), renameErrorTitleText, JOptionPane.ERROR_MESSAGE);
0N/A } else {
0N/A if (FilePane.this.getModel().renameFile(f, f2)) {
0N/A if (fsv.isParent(chooser.getCurrentDirectory(), f2)) {
4091N/A // The setSelectedFile method produces a new setValueAt invocation while the JTable
4091N/A // is editing. Postpone file selection to be sure that edit mode of the JTable
4091N/A // is completed
4091N/A SwingUtilities.invokeLater(new Runnable() {
4091N/A public void run() {
4091N/A if (chooser.isMultiSelectionEnabled()) {
4091N/A chooser.setSelectedFiles(new File[]{f2});
4091N/A } else {
4091N/A chooser.setSelectedFile(f2);
4091N/A }
4091N/A }
4091N/A });
0N/A } else {
0N/A // Could be because of delay in updating Desktop folder
0N/A // chooser.setSelectedFile(null);
0N/A }
0N/A } else {
0N/A JOptionPane.showMessageDialog(chooser, MessageFormat.format(renameErrorText, oldFileName),
0N/A renameErrorTitleText, JOptionPane.ERROR_MESSAGE);
0N/A }
0N/A }
0N/A }
0N/A }
0N/A }
0N/A }
0N/A
0N/A public boolean isCellEditable(int row, int column) {
0N/A File currentDirectory = getFileChooser().getCurrentDirectory();
0N/A return (!readOnly && column == COLUMN_FILENAME && canWrite(currentDirectory));
0N/A }
0N/A
0N/A public void contentsChanged(ListDataEvent e) {
0N/A // Update the selection after the model has been updated
0N/A new DelayedSelectionUpdater();
0N/A fireTableDataChanged();
0N/A }
0N/A
0N/A public void intervalAdded(ListDataEvent e) {
0N/A int i0 = e.getIndex0();
0N/A int i1 = e.getIndex1();
0N/A if (i0 == i1) {
0N/A File file = (File)getModel().getElementAt(i0);
0N/A if (file.equals(newFolderFile)) {
0N/A new DelayedSelectionUpdater(file);
0N/A newFolderFile = null;
0N/A }
0N/A }
0N/A
0N/A fireTableRowsInserted(e.getIndex0(), e.getIndex1());
0N/A }
0N/A public void intervalRemoved(ListDataEvent e) {
0N/A fireTableRowsDeleted(e.getIndex0(), e.getIndex1());
0N/A }
0N/A
0N/A public ShellFolderColumnInfo[] getColumns() {
0N/A return columns;
0N/A }
0N/A }
0N/A
0N/A
0N/A private void updateDetailsColumnModel(JTable table) {
0N/A if (table != null) {
0N/A ShellFolderColumnInfo[] columns = detailsTableModel.getColumns();
0N/A
0N/A TableColumnModel columnModel = new DefaultTableColumnModel();
0N/A for (int i = 0; i < columns.length; i++) {
0N/A ShellFolderColumnInfo dataItem = columns[i];
0N/A TableColumn column = new TableColumn(i);
0N/A
0N/A String title = dataItem.getTitle();
0N/A if (title != null && title.startsWith("FileChooser.") && title.endsWith("HeaderText")) {
0N/A // the column must have a string resource that we try to get
0N/A String uiTitle = UIManager.getString(title, table.getLocale());
0N/A if (uiTitle != null) {
0N/A title = uiTitle;
0N/A }
0N/A }
0N/A column.setHeaderValue(title);
0N/A
0N/A Integer width = dataItem.getWidth();
0N/A if (width != null) {
0N/A column.setPreferredWidth(width);
0N/A // otherwise we let JTable to decide the actual width
0N/A }
0N/A
0N/A columnModel.addColumn(column);
0N/A }
0N/A
0N/A // Install cell editor for editing file name
0N/A if (!readOnly && columnModel.getColumnCount() > COLUMN_FILENAME) {
0N/A columnModel.getColumn(COLUMN_FILENAME).
0N/A setCellEditor(getDetailsTableCellEditor());
0N/A }
0N/A
0N/A table.setColumnModel(columnModel);
0N/A }
0N/A }
0N/A
0N/A private DetailsTableRowSorter getRowSorter() {
0N/A if (rowSorter == null) {
0N/A rowSorter = new DetailsTableRowSorter();
0N/A }
0N/A return rowSorter;
0N/A }
0N/A
625N/A private class DetailsTableRowSorter extends TableRowSorter<TableModel> {
0N/A public DetailsTableRowSorter() {
0N/A setModelWrapper(new SorterModelWrapper());
0N/A }
0N/A
0N/A public void updateComparators(ShellFolderColumnInfo [] columns) {
0N/A for (int i = 0; i < columns.length; i++) {
0N/A Comparator c = columns[i].getComparator();
0N/A if (c != null) {
0N/A c = new DirectoriesFirstComparatorWrapper(i, c);
0N/A }
0N/A setComparator(i, c);
0N/A }
0N/A }
0N/A
1083N/A @Override
1083N/A public void sort() {
1453N/A ShellFolder.invoke(new Callable<Void>() {
1453N/A public Void call() {
1083N/A DetailsTableRowSorter.super.sort();
1083N/A return null;
1083N/A }
1083N/A });
1083N/A }
1083N/A
0N/A public void modelStructureChanged() {
0N/A super.modelStructureChanged();
0N/A updateComparators(detailsTableModel.getColumns());
0N/A }
0N/A
625N/A private class SorterModelWrapper extends ModelWrapper<TableModel, Integer> {
625N/A public TableModel getModel() {
0N/A return getDetailsTableModel();
0N/A }
0N/A
0N/A public int getColumnCount() {
0N/A return getDetailsTableModel().getColumnCount();
0N/A }
0N/A
0N/A public int getRowCount() {
0N/A return getDetailsTableModel().getRowCount();
0N/A }
0N/A
0N/A public Object getValueAt(int row, int column) {
0N/A return FilePane.this.getModel().getElementAt(row);
0N/A }
0N/A
625N/A public Integer getIdentifier(int row) {
0N/A return row;
0N/A }
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * This class sorts directories before files, comparing directory to
0N/A * directory and file to file using the wrapped comparator.
0N/A */
0N/A private class DirectoriesFirstComparatorWrapper implements Comparator<File> {
0N/A private Comparator comparator;
0N/A private int column;
0N/A
0N/A public DirectoriesFirstComparatorWrapper(int column, Comparator comparator) {
0N/A this.column = column;
0N/A this.comparator = comparator;
0N/A }
0N/A
0N/A public int compare(File f1, File f2) {
0N/A if (f1 != null && f2 != null) {
0N/A boolean traversable1 = getFileChooser().isTraversable(f1);
0N/A boolean traversable2 = getFileChooser().isTraversable(f2);
0N/A // directories go first
0N/A if (traversable1 && !traversable2) {
0N/A return -1;
0N/A }
0N/A if (!traversable1 && traversable2) {
0N/A return 1;
0N/A }
0N/A }
0N/A if (detailsTableModel.getColumns()[column].isCompareByColumn()) {
0N/A return comparator.compare(
0N/A getDetailsTableModel().getFileColumnValue(f1, column),
0N/A getDetailsTableModel().getFileColumnValue(f2, column)
0N/A );
0N/A }
0N/A // For this column we need to pass the file itself (not a
0N/A // column value) to the comparator
0N/A return comparator.compare(f1, f2);
0N/A }
0N/A }
0N/A
0N/A private DetailsTableCellEditor tableCellEditor;
0N/A
0N/A private DetailsTableCellEditor getDetailsTableCellEditor() {
0N/A if (tableCellEditor == null) {
0N/A tableCellEditor = new DetailsTableCellEditor(new JTextField());
0N/A }
0N/A return tableCellEditor;
0N/A }
0N/A
0N/A private class DetailsTableCellEditor extends DefaultCellEditor {
0N/A private final JTextField tf;
0N/A
0N/A public DetailsTableCellEditor(JTextField tf) {
0N/A super(tf);
0N/A this.tf = tf;
1173N/A tf.setName("Table.editor");
0N/A tf.addFocusListener(editorFocusListener);
0N/A }
0N/A
0N/A public Component getTableCellEditorComponent(JTable table, Object value,
0N/A boolean isSelected, int row, int column) {
0N/A Component comp = super.getTableCellEditorComponent(table, value,
0N/A isSelected, row, column);
0N/A if (value instanceof File) {
0N/A tf.setText(getFileChooser().getName((File) value));
0N/A tf.selectAll();
0N/A }
0N/A return comp;
0N/A }
0N/A }
0N/A
0N/A
0N/A class DetailsTableCellRenderer extends DefaultTableCellRenderer {
0N/A JFileChooser chooser;
0N/A DateFormat df;
0N/A
0N/A DetailsTableCellRenderer(JFileChooser chooser) {
0N/A this.chooser = chooser;
0N/A df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT,
0N/A chooser.getLocale());
0N/A }
0N/A
0N/A public void setBounds(int x, int y, int width, int height) {
1173N/A if (getHorizontalAlignment() == SwingConstants.LEADING &&
1173N/A !fullRowSelection) {
0N/A // Restrict width to actual text
0N/A width = Math.min(width, this.getPreferredSize().width+4);
0N/A } else {
0N/A x -= 4;
0N/A }
0N/A super.setBounds(x, y, width, height);
0N/A }
0N/A
0N/A
0N/A public Insets getInsets(Insets i) {
0N/A // Provide some space between columns
0N/A i = super.getInsets(i);
0N/A i.left += 4;
0N/A i.right += 4;
0N/A return i;
0N/A }
0N/A
0N/A public Component getTableCellRendererComponent(JTable table, Object value,
0N/A boolean isSelected, boolean hasFocus, int row, int column) {
0N/A
1173N/A if ((table.convertColumnIndexToModel(column) != COLUMN_FILENAME ||
1173N/A (listViewWindowsStyle && !table.isFocusOwner())) &&
1173N/A !fullRowSelection) {
0N/A isSelected = false;
0N/A }
0N/A
0N/A super.getTableCellRendererComponent(table, value, isSelected,
0N/A hasFocus, row, column);
0N/A
0N/A setIcon(null);
0N/A
0N/A int modelColumn = table.convertColumnIndexToModel(column);
0N/A ShellFolderColumnInfo columnInfo = detailsTableModel.getColumns()[modelColumn];
0N/A
0N/A Integer alignment = columnInfo.getAlignment();
0N/A if (alignment == null) {
0N/A alignment = (value instanceof Number)
0N/A ? SwingConstants.RIGHT
0N/A : SwingConstants.LEADING;
0N/A }
0N/A
0N/A setHorizontalAlignment(alignment);
0N/A
0N/A // formatting cell text
0N/A // TODO: it's rather a temporary trick, to be revised
0N/A String text;
0N/A
0N/A if (value == null) {
0N/A text = "";
0N/A
0N/A } else if (value instanceof File) {
0N/A File file = (File)value;
0N/A text = chooser.getName(file);
0N/A Icon icon = chooser.getIcon(file);
0N/A setIcon(icon);
0N/A
0N/A } else if (value instanceof Long) {
0N/A long len = ((Long) value) / 1024L;
0N/A if (listViewWindowsStyle) {
0N/A text = MessageFormat.format(kiloByteString, len + 1);
0N/A } else if (len < 1024L) {
0N/A text = MessageFormat.format(kiloByteString, (len == 0L) ? 1L : len);
0N/A } else {
0N/A len /= 1024L;
0N/A if (len < 1024L) {
0N/A text = MessageFormat.format(megaByteString, len);
0N/A } else {
0N/A len /= 1024L;
0N/A text = MessageFormat.format(gigaByteString, len);
0N/A }
0N/A }
0N/A
0N/A } else if (value instanceof Date) {
0N/A text = df.format((Date)value);
0N/A
0N/A } else {
0N/A text = value.toString();
0N/A }
0N/A
0N/A setText(text);
0N/A
0N/A return this;
0N/A }
0N/A }
0N/A
0N/A public JPanel createDetailsView() {
0N/A final JFileChooser chooser = getFileChooser();
0N/A
0N/A JPanel p = new JPanel(new BorderLayout());
0N/A
0N/A final JTable detailsTable = new JTable(getDetailsTableModel()) {
0N/A // Handle Escape key events here
0N/A protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) {
0N/A if (e.getKeyCode() == KeyEvent.VK_ESCAPE && getCellEditor() == null) {
0N/A // We are not editing, forward to filechooser.
0N/A chooser.dispatchEvent(e);
0N/A return true;
0N/A }
0N/A return super.processKeyBinding(ks, e, condition, pressed);
0N/A }
0N/A
0N/A public void tableChanged(TableModelEvent e) {
0N/A super.tableChanged(e);
0N/A
0N/A if (e.getFirstRow() == TableModelEvent.HEADER_ROW) {
0N/A // update header with possibly changed column set
0N/A updateDetailsColumnModel(this);
0N/A }
0N/A }
0N/A };
0N/A
0N/A detailsTable.setRowSorter(getRowSorter());
0N/A detailsTable.setAutoCreateColumnsFromModel(false);
0N/A detailsTable.setComponentOrientation(chooser.getComponentOrientation());
0N/A detailsTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
0N/A detailsTable.setShowGrid(false);
0N/A detailsTable.putClientProperty("JTable.autoStartsEdit", Boolean.FALSE);
0N/A detailsTable.addKeyListener(detailsKeyListener);
0N/A
0N/A Font font = list.getFont();
0N/A detailsTable.setFont(font);
0N/A detailsTable.setIntercellSpacing(new Dimension(0, 0));
0N/A
0N/A TableCellRenderer headerRenderer =
0N/A new AlignableTableHeaderRenderer(detailsTable.getTableHeader().getDefaultRenderer());
0N/A detailsTable.getTableHeader().setDefaultRenderer(headerRenderer);
0N/A TableCellRenderer cellRenderer = new DetailsTableCellRenderer(chooser);
0N/A detailsTable.setDefaultRenderer(Object.class, cellRenderer);
0N/A
0N/A // So that drag can be started on a mouse press
0N/A detailsTable.getColumnModel().getSelectionModel().
0N/A setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
0N/A
0N/A detailsTable.addMouseListener(getMouseHandler());
0N/A // No need to addListSelectionListener because selections are forwarded
0N/A // to our JList.
0N/A
0N/A // 4835633 : tell BasicTableUI that this is a file list
0N/A detailsTable.putClientProperty("Table.isFileList", Boolean.TRUE);
0N/A
0N/A if (listViewWindowsStyle) {
0N/A detailsTable.addFocusListener(repaintListener);
0N/A }
0N/A
0N/A // TAB/SHIFT-TAB should transfer focus and ENTER should select an item.
0N/A // We don't want them to navigate within the table
0N/A ActionMap am = SwingUtilities.getUIActionMap(detailsTable);
0N/A am.remove("selectNextRowCell");
0N/A am.remove("selectPreviousRowCell");
0N/A am.remove("selectNextColumnCell");
0N/A am.remove("selectPreviousColumnCell");
0N/A detailsTable.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
0N/A null);
0N/A detailsTable.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
0N/A null);
0N/A
0N/A JScrollPane scrollpane = new JScrollPane(detailsTable);
0N/A scrollpane.setComponentOrientation(chooser.getComponentOrientation());
0N/A LookAndFeel.installColors(scrollpane.getViewport(), "Table.background", "Table.foreground");
0N/A
0N/A // Adjust width of first column so the table fills the viewport when
0N/A // first displayed (temporary listener).
0N/A scrollpane.addComponentListener(new ComponentAdapter() {
0N/A public void componentResized(ComponentEvent e) {
0N/A JScrollPane sp = (JScrollPane)e.getComponent();
0N/A fixNameColumnWidth(sp.getViewport().getSize().width);
0N/A sp.removeComponentListener(this);
0N/A }
0N/A });
0N/A
0N/A // 4835633.
0N/A // If the mouse is pressed in the area below the Details view table, the
0N/A // event is not dispatched to the Table MouseListener but to the
0N/A // scrollpane. Listen for that here so we can clear the selection.
0N/A scrollpane.addMouseListener(new MouseAdapter() {
0N/A public void mousePressed(MouseEvent e) {
0N/A JScrollPane jsp = ((JScrollPane)e.getComponent());
0N/A JTable table = (JTable)jsp.getViewport().getView();
0N/A
0N/A if (!e.isShiftDown() || table.getSelectionModel().getSelectionMode() == ListSelectionModel.SINGLE_SELECTION) {
0N/A clearSelection();
0N/A TableCellEditor tce = table.getCellEditor();
0N/A if (tce != null) {
0N/A tce.stopCellEditing();
0N/A }
0N/A }
0N/A }
0N/A });
0N/A
0N/A detailsTable.setForeground(list.getForeground());
0N/A detailsTable.setBackground(list.getBackground());
0N/A
0N/A if (listViewBorder != null) {
0N/A scrollpane.setBorder(listViewBorder);
0N/A }
0N/A p.add(scrollpane, BorderLayout.CENTER);
0N/A
0N/A detailsTableModel.fireTableStructureChanged();
0N/A
5202N/A detailsTable.putClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY, filesDetailsAccessibleName);
5202N/A
0N/A return p;
0N/A } // createDetailsView
0N/A
0N/A private class AlignableTableHeaderRenderer implements TableCellRenderer {
0N/A TableCellRenderer wrappedRenderer;
0N/A
0N/A public AlignableTableHeaderRenderer(TableCellRenderer wrappedRenderer) {
0N/A this.wrappedRenderer = wrappedRenderer;
0N/A }
0N/A
0N/A public Component getTableCellRendererComponent(
0N/A JTable table, Object value, boolean isSelected,
0N/A boolean hasFocus, int row, int column) {
0N/A
0N/A Component c = wrappedRenderer.getTableCellRendererComponent(
0N/A table, value, isSelected, hasFocus, row, column);
0N/A
0N/A int modelColumn = table.convertColumnIndexToModel(column);
0N/A ShellFolderColumnInfo columnInfo = detailsTableModel.getColumns()[modelColumn];
0N/A
0N/A Integer alignment = columnInfo.getAlignment();
0N/A if (alignment == null) {
0N/A alignment = SwingConstants.CENTER;
0N/A }
0N/A if (c instanceof JLabel) {
0N/A ((JLabel) c).setHorizontalAlignment(alignment);
0N/A }
0N/A
0N/A return c;
0N/A }
0N/A }
0N/A
0N/A private void fixNameColumnWidth(int viewWidth) {
0N/A TableColumn nameCol = detailsTable.getColumnModel().getColumn(COLUMN_FILENAME);
0N/A int tableWidth = detailsTable.getPreferredSize().width;
0N/A
0N/A if (tableWidth < viewWidth) {
0N/A nameCol.setPreferredWidth(nameCol.getPreferredWidth() + viewWidth - tableWidth);
0N/A }
0N/A }
0N/A
0N/A private class DelayedSelectionUpdater implements Runnable {
0N/A File editFile;
0N/A
0N/A DelayedSelectionUpdater() {
0N/A this(null);
0N/A }
0N/A
0N/A DelayedSelectionUpdater(File editFile) {
0N/A this.editFile = editFile;
0N/A if (isShowing()) {
0N/A SwingUtilities.invokeLater(this);
0N/A }
0N/A }
0N/A
0N/A public void run() {
0N/A setFileSelected();
0N/A if (editFile != null) {
0N/A editFileName(getRowSorter().convertRowIndexToView(
0N/A getModel().indexOf(editFile)));
0N/A editFile = null;
0N/A }
0N/A }
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Creates a selection listener for the list of files and directories.
0N/A *
0N/A * @return a <code>ListSelectionListener</code>
0N/A */
0N/A public ListSelectionListener createListSelectionListener() {
0N/A return fileChooserUIAccessor.createListSelectionListener();
0N/A }
0N/A
0N/A int lastIndex = -1;
0N/A File editFile = null;
0N/A
0N/A private int getEditIndex() {
0N/A return lastIndex;
0N/A }
0N/A
0N/A private void setEditIndex(int i) {
0N/A lastIndex = i;
0N/A }
0N/A
0N/A private void resetEditIndex() {
0N/A lastIndex = -1;
0N/A }
0N/A
0N/A private void cancelEdit() {
0N/A if (editFile != null) {
0N/A editFile = null;
0N/A list.remove(editCell);
0N/A repaint();
0N/A } else if (detailsTable != null && detailsTable.isEditing()) {
0N/A detailsTable.getCellEditor().cancelCellEditing();
0N/A }
0N/A }
0N/A
0N/A JTextField editCell = null;
0N/A
0N/A /**
0N/A * @param index visual index of the file to be edited
0N/A */
0N/A private void editFileName(int index) {
241N/A JFileChooser chooser = getFileChooser();
241N/A File currentDirectory = chooser.getCurrentDirectory();
241N/A
0N/A if (readOnly || !canWrite(currentDirectory)) {
0N/A return;
0N/A }
0N/A
0N/A ensureIndexIsVisible(index);
0N/A switch (viewType) {
0N/A case VIEWTYPE_LIST:
0N/A editFile = (File)getModel().getElementAt(getRowSorter().convertRowIndexToModel(index));
0N/A Rectangle r = list.getCellBounds(index, index);
0N/A if (editCell == null) {
0N/A editCell = new JTextField();
1173N/A editCell.setName("Tree.cellEditor");
0N/A editCell.addActionListener(new EditActionListener());
0N/A editCell.addFocusListener(editorFocusListener);
0N/A editCell.setNextFocusableComponent(list);
0N/A }
0N/A list.add(editCell);
241N/A editCell.setText(chooser.getName(editFile));
0N/A ComponentOrientation orientation = list.getComponentOrientation();
0N/A editCell.setComponentOrientation(orientation);
241N/A
241N/A Icon icon = chooser.getIcon(editFile);
241N/A
241N/A // PENDING - grab padding (4) below from defaults table.
241N/A int editX = icon == null ? 20 : icon.getIconWidth() + 4;
241N/A
0N/A if (orientation.isLeftToRight()) {
0N/A editCell.setBounds(editX + r.x, r.y, r.width - editX, r.height);
0N/A } else {
0N/A editCell.setBounds(r.x, r.y, r.width - editX, r.height);
0N/A }
0N/A editCell.requestFocus();
0N/A editCell.selectAll();
0N/A break;
0N/A
0N/A case VIEWTYPE_DETAILS:
0N/A detailsTable.editCellAt(index, COLUMN_FILENAME);
0N/A break;
0N/A }
0N/A }
0N/A
0N/A
0N/A class EditActionListener implements ActionListener {
0N/A public void actionPerformed(ActionEvent e) {
0N/A applyEdit();
0N/A }
0N/A }
0N/A
0N/A private void applyEdit() {
0N/A if (editFile != null && editFile.exists()) {
0N/A JFileChooser chooser = getFileChooser();
0N/A String oldDisplayName = chooser.getName(editFile);
0N/A String oldFileName = editFile.getName();
0N/A String newDisplayName = editCell.getText().trim();
0N/A String newFileName;
0N/A
0N/A if (!newDisplayName.equals(oldDisplayName)) {
0N/A newFileName = newDisplayName;
0N/A //Check if extension is hidden from user
0N/A int i1 = oldFileName.length();
0N/A int i2 = oldDisplayName.length();
0N/A if (i1 > i2 && oldFileName.charAt(i2) == '.') {
0N/A newFileName = newDisplayName + oldFileName.substring(i2);
0N/A }
0N/A
0N/A // rename
0N/A FileSystemView fsv = chooser.getFileSystemView();
0N/A File f2 = fsv.createFileObject(editFile.getParentFile(), newFileName);
0N/A if (f2.exists()) {
0N/A JOptionPane.showMessageDialog(chooser, MessageFormat.format(renameErrorFileExistsText, oldFileName),
0N/A renameErrorTitleText, JOptionPane.ERROR_MESSAGE);
0N/A } else {
0N/A if (getModel().renameFile(editFile, f2)) {
0N/A if (fsv.isParent(chooser.getCurrentDirectory(), f2)) {
0N/A if (chooser.isMultiSelectionEnabled()) {
0N/A chooser.setSelectedFiles(new File[]{f2});
0N/A } else {
0N/A chooser.setSelectedFile(f2);
0N/A }
0N/A } else {
0N/A //Could be because of delay in updating Desktop folder
0N/A //chooser.setSelectedFile(null);
0N/A }
0N/A } else {
0N/A JOptionPane.showMessageDialog(chooser, MessageFormat.format(renameErrorText, oldFileName),
0N/A renameErrorTitleText, JOptionPane.ERROR_MESSAGE);
0N/A }
0N/A }
0N/A }
0N/A }
0N/A if (detailsTable != null && detailsTable.isEditing()) {
0N/A detailsTable.getCellEditor().stopCellEditing();
0N/A }
0N/A cancelEdit();
0N/A }
0N/A
0N/A protected Action newFolderAction;
0N/A
0N/A public Action getNewFolderAction() {
0N/A if (!readOnly && newFolderAction == null) {
0N/A newFolderAction = new AbstractAction(newFolderActionLabelText) {
0N/A private Action basicNewFolderAction;
0N/A
0N/A // Initializer
0N/A {
0N/A putValue(Action.ACTION_COMMAND_KEY, FilePane.ACTION_NEW_FOLDER);
0N/A
0N/A File currentDirectory = getFileChooser().getCurrentDirectory();
0N/A if (currentDirectory != null) {
0N/A setEnabled(canWrite(currentDirectory));
0N/A }
0N/A }
0N/A
0N/A public void actionPerformed(ActionEvent ev) {
0N/A if (basicNewFolderAction == null) {
0N/A basicNewFolderAction = fileChooserUIAccessor.getNewFolderAction();
0N/A }
0N/A JFileChooser fc = getFileChooser();
0N/A File oldFile = fc.getSelectedFile();
0N/A basicNewFolderAction.actionPerformed(ev);
0N/A File newFile = fc.getSelectedFile();
0N/A if (newFile != null && !newFile.equals(oldFile) && newFile.isDirectory()) {
0N/A newFolderFile = newFile;
0N/A }
0N/A }
0N/A };
0N/A }
0N/A return newFolderAction;
0N/A }
0N/A
0N/A protected class FileRenderer extends DefaultListCellRenderer {
0N/A
0N/A public Component getListCellRendererComponent(JList list, Object value,
0N/A int index, boolean isSelected,
0N/A boolean cellHasFocus) {
0N/A
0N/A if (listViewWindowsStyle && !list.isFocusOwner()) {
0N/A isSelected = false;
0N/A }
0N/A
0N/A super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
0N/A File file = (File) value;
0N/A String fileName = getFileChooser().getName(file);
0N/A setText(fileName);
0N/A setFont(list.getFont());
0N/A
0N/A Icon icon = getFileChooser().getIcon(file);
0N/A if (icon != null) {
0N/A setIcon(icon);
0N/A } else {
0N/A if (getFileChooser().getFileSystemView().isTraversable(file)) {
0N/A setText(fileName+File.separator);
0N/A }
0N/A }
0N/A
0N/A return this;
0N/A }
0N/A }
0N/A
0N/A
0N/A void setFileSelected() {
0N/A if (getFileChooser().isMultiSelectionEnabled() && !isDirectorySelected()) {
0N/A File[] files = getFileChooser().getSelectedFiles(); // Should be selected
0N/A Object[] selectedObjects = list.getSelectedValues(); // Are actually selected
0N/A
0N/A listSelectionModel.setValueIsAdjusting(true);
0N/A try {
0N/A int lead = listSelectionModel.getLeadSelectionIndex();
0N/A int anchor = listSelectionModel.getAnchorSelectionIndex();
0N/A
0N/A Arrays.sort(files);
0N/A Arrays.sort(selectedObjects);
0N/A
0N/A int shouldIndex = 0;
0N/A int actuallyIndex = 0;
0N/A
0N/A // Remove files that shouldn't be selected and add files which should be selected
0N/A // Note: Assume files are already sorted in compareTo order.
0N/A while (shouldIndex < files.length &&
0N/A actuallyIndex < selectedObjects.length) {
0N/A int comparison = files[shouldIndex].compareTo((File)selectedObjects[actuallyIndex]);
0N/A if (comparison < 0) {
0N/A doSelectFile(files[shouldIndex++]);
0N/A } else if (comparison > 0) {
0N/A doDeselectFile(selectedObjects[actuallyIndex++]);
0N/A } else {
0N/A // Do nothing
0N/A shouldIndex++;
0N/A actuallyIndex++;
0N/A }
0N/A
0N/A }
0N/A
0N/A while (shouldIndex < files.length) {
0N/A doSelectFile(files[shouldIndex++]);
0N/A }
0N/A
0N/A while (actuallyIndex < selectedObjects.length) {
0N/A doDeselectFile(selectedObjects[actuallyIndex++]);
0N/A }
0N/A
0N/A // restore the anchor and lead
0N/A if (listSelectionModel instanceof DefaultListSelectionModel) {
0N/A ((DefaultListSelectionModel)listSelectionModel).
0N/A moveLeadSelectionIndex(lead);
0N/A listSelectionModel.setAnchorSelectionIndex(anchor);
0N/A }
0N/A } finally {
0N/A listSelectionModel.setValueIsAdjusting(false);
0N/A }
0N/A } else {
0N/A JFileChooser chooser = getFileChooser();
0N/A File f;
0N/A if (isDirectorySelected()) {
0N/A f = getDirectory();
0N/A } else {
0N/A f = chooser.getSelectedFile();
0N/A }
0N/A int i;
0N/A if (f != null && (i = getModel().indexOf(f)) >= 0) {
0N/A int viewIndex = getRowSorter().convertRowIndexToView(i);
0N/A listSelectionModel.setSelectionInterval(viewIndex, viewIndex);
0N/A ensureIndexIsVisible(viewIndex);
0N/A } else {
0N/A clearSelection();
0N/A }
0N/A }
0N/A }
0N/A
0N/A private void doSelectFile(File fileToSelect) {
0N/A int index = getModel().indexOf(fileToSelect);
0N/A // could be missed in the current directory if it changed
0N/A if (index >= 0) {
0N/A index = getRowSorter().convertRowIndexToView(index);
0N/A listSelectionModel.addSelectionInterval(index, index);
0N/A }
0N/A }
0N/A
0N/A private void doDeselectFile(Object fileToDeselect) {
0N/A int index = getRowSorter().convertRowIndexToView(
0N/A getModel().indexOf(fileToDeselect));
0N/A listSelectionModel.removeSelectionInterval(index, index);
0N/A }
0N/A
0N/A /* The following methods are used by the PropertyChange Listener */
0N/A
0N/A private void doSelectedFileChanged(PropertyChangeEvent e) {
0N/A applyEdit();
0N/A File f = (File) e.getNewValue();
0N/A JFileChooser fc = getFileChooser();
0N/A if (f != null
0N/A && ((fc.isFileSelectionEnabled() && !f.isDirectory())
0N/A || (f.isDirectory() && fc.isDirectorySelectionEnabled()))) {
0N/A
0N/A setFileSelected();
0N/A }
0N/A }
0N/A
0N/A private void doSelectedFilesChanged(PropertyChangeEvent e) {
0N/A applyEdit();
0N/A File[] files = (File[]) e.getNewValue();
0N/A JFileChooser fc = getFileChooser();
0N/A if (files != null
0N/A && files.length > 0
0N/A && (files.length > 1 || fc.isDirectorySelectionEnabled() || !files[0].isDirectory())) {
0N/A setFileSelected();
0N/A }
0N/A }
0N/A
0N/A private void doDirectoryChanged(PropertyChangeEvent e) {
0N/A getDetailsTableModel().updateColumnInfo();
0N/A
0N/A JFileChooser fc = getFileChooser();
0N/A FileSystemView fsv = fc.getFileSystemView();
0N/A
0N/A applyEdit();
0N/A resetEditIndex();
0N/A ensureIndexIsVisible(0);
0N/A File currentDirectory = fc.getCurrentDirectory();
0N/A if (currentDirectory != null) {
0N/A if (!readOnly) {
0N/A getNewFolderAction().setEnabled(canWrite(currentDirectory));
0N/A }
0N/A fileChooserUIAccessor.getChangeToParentDirectoryAction().setEnabled(!fsv.isRoot(currentDirectory));
0N/A }
0N/A if (list != null) {
0N/A list.clearSelection();
0N/A }
0N/A }
0N/A
0N/A private void doFilterChanged(PropertyChangeEvent e) {
0N/A applyEdit();
0N/A resetEditIndex();
0N/A clearSelection();
0N/A }
0N/A
0N/A private void doFileSelectionModeChanged(PropertyChangeEvent e) {
0N/A applyEdit();
0N/A resetEditIndex();
0N/A clearSelection();
0N/A }
0N/A
0N/A private void doMultiSelectionChanged(PropertyChangeEvent e) {
0N/A if (getFileChooser().isMultiSelectionEnabled()) {
0N/A listSelectionModel.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
0N/A } else {
0N/A listSelectionModel.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
0N/A clearSelection();
0N/A getFileChooser().setSelectedFiles(null);
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * Listen for filechooser property changes, such as
0N/A * the selected file changing, or the type of the dialog changing.
0N/A */
0N/A public void propertyChange(PropertyChangeEvent e) {
0N/A if (viewType == -1) {
0N/A setViewType(VIEWTYPE_LIST);
0N/A }
0N/A
0N/A String s = e.getPropertyName();
0N/A if (s.equals(JFileChooser.SELECTED_FILE_CHANGED_PROPERTY)) {
0N/A doSelectedFileChanged(e);
0N/A } else if (s.equals(JFileChooser.SELECTED_FILES_CHANGED_PROPERTY)) {
0N/A doSelectedFilesChanged(e);
0N/A } else if (s.equals(JFileChooser.DIRECTORY_CHANGED_PROPERTY)) {
0N/A doDirectoryChanged(e);
0N/A } else if (s.equals(JFileChooser.FILE_FILTER_CHANGED_PROPERTY)) {
0N/A doFilterChanged(e);
0N/A } else if (s.equals(JFileChooser.FILE_SELECTION_MODE_CHANGED_PROPERTY)) {
0N/A doFileSelectionModeChanged(e);
0N/A } else if (s.equals(JFileChooser.MULTI_SELECTION_ENABLED_CHANGED_PROPERTY)) {
0N/A doMultiSelectionChanged(e);
0N/A } else if (s.equals(JFileChooser.CANCEL_SELECTION)) {
0N/A applyEdit();
0N/A } else if (s.equals("busy")) {
0N/A setCursor((Boolean)e.getNewValue() ? waitCursor : null);
0N/A } else if (s.equals("componentOrientation")) {
0N/A ComponentOrientation o = (ComponentOrientation)e.getNewValue();
0N/A JFileChooser cc = (JFileChooser)e.getSource();
0N/A if (o != e.getOldValue()) {
0N/A cc.applyComponentOrientation(o);
0N/A }
0N/A if (detailsTable != null) {
0N/A detailsTable.setComponentOrientation(o);
0N/A detailsTable.getParent().getParent().setComponentOrientation(o);
0N/A }
0N/A }
0N/A }
0N/A
0N/A private void ensureIndexIsVisible(int i) {
0N/A if (i >= 0) {
0N/A if (list != null) {
0N/A list.ensureIndexIsVisible(i);
0N/A }
0N/A if (detailsTable != null) {
0N/A detailsTable.scrollRectToVisible(detailsTable.getCellRect(i, COLUMN_FILENAME, true));
0N/A }
0N/A }
0N/A }
0N/A
0N/A public void ensureFileIsVisible(JFileChooser fc, File f) {
0N/A int modelIndex = getModel().indexOf(f);
0N/A if (modelIndex >= 0) {
0N/A ensureIndexIsVisible(getRowSorter().convertRowIndexToView(modelIndex));
0N/A }
0N/A }
0N/A
0N/A public void rescanCurrentDirectory() {
0N/A getModel().validateFileCache();
0N/A }
0N/A
0N/A public void clearSelection() {
0N/A if (listSelectionModel != null) {
0N/A listSelectionModel.clearSelection();
0N/A if (listSelectionModel instanceof DefaultListSelectionModel) {
0N/A ((DefaultListSelectionModel)listSelectionModel).moveLeadSelectionIndex(0);
0N/A listSelectionModel.setAnchorSelectionIndex(0);
0N/A }
0N/A }
0N/A }
0N/A
0N/A public JMenu getViewMenu() {
0N/A if (viewMenu == null) {
0N/A viewMenu = new JMenu(viewMenuLabelText);
0N/A ButtonGroup viewButtonGroup = new ButtonGroup();
0N/A
0N/A for (int i = 0; i < VIEWTYPE_COUNT; i++) {
0N/A JRadioButtonMenuItem mi =
0N/A new JRadioButtonMenuItem(new ViewTypeAction(i));
0N/A viewButtonGroup.add(mi);
0N/A viewMenu.add(mi);
0N/A }
0N/A updateViewMenu();
0N/A }
0N/A return viewMenu;
0N/A }
0N/A
0N/A private void updateViewMenu() {
0N/A if (viewMenu != null) {
0N/A Component[] comps = viewMenu.getMenuComponents();
625N/A for (Component comp : comps) {
625N/A if (comp instanceof JRadioButtonMenuItem) {
625N/A JRadioButtonMenuItem mi = (JRadioButtonMenuItem) comp;
0N/A if (((ViewTypeAction)mi.getAction()).viewType == viewType) {
0N/A mi.setSelected(true);
0N/A }
0N/A }
0N/A }
0N/A }
0N/A }
0N/A
0N/A public JPopupMenu getComponentPopupMenu() {
0N/A JPopupMenu popupMenu = getFileChooser().getComponentPopupMenu();
0N/A if (popupMenu != null) {
0N/A return popupMenu;
0N/A }
0N/A
0N/A JMenu viewMenu = getViewMenu();
0N/A if (contextMenu == null) {
0N/A contextMenu = new JPopupMenu();
0N/A if (viewMenu != null) {
0N/A contextMenu.add(viewMenu);
0N/A if (listViewWindowsStyle) {
0N/A contextMenu.addSeparator();
0N/A }
0N/A }
0N/A ActionMap actionMap = getActionMap();
0N/A Action refreshAction = actionMap.get(ACTION_REFRESH);
0N/A Action newFolderAction = actionMap.get(ACTION_NEW_FOLDER);
0N/A if (refreshAction != null) {
0N/A contextMenu.add(refreshAction);
0N/A if (listViewWindowsStyle && newFolderAction != null) {
0N/A contextMenu.addSeparator();
0N/A }
0N/A }
0N/A if (newFolderAction != null) {
0N/A contextMenu.add(newFolderAction);
0N/A }
0N/A }
0N/A if (viewMenu != null) {
0N/A viewMenu.getPopupMenu().setInvoker(viewMenu);
0N/A }
0N/A return contextMenu;
0N/A }
0N/A
0N/A
0N/A private Handler handler;
0N/A
0N/A protected Handler getMouseHandler() {
0N/A if (handler == null) {
0N/A handler = new Handler();
0N/A }
0N/A return handler;
0N/A }
0N/A
0N/A private class Handler implements MouseListener {
0N/A private MouseListener doubleClickListener;
0N/A
0N/A public void mouseClicked(MouseEvent evt) {
0N/A JComponent source = (JComponent)evt.getSource();
0N/A
0N/A int index;
0N/A if (source instanceof JList) {
0N/A index = SwingUtilities2.loc2IndexFileList(list, evt.getPoint());
0N/A } else if (source instanceof JTable) {
0N/A JTable table = (JTable)source;
0N/A Point p = evt.getPoint();
0N/A index = table.rowAtPoint(p);
0N/A
1173N/A boolean pointOutsidePrefSize =
1173N/A SwingUtilities2.pointOutsidePrefSize(
1173N/A table, index, table.columnAtPoint(p), p);
0N/A
1173N/A if (pointOutsidePrefSize && !fullRowSelection) {
0N/A return;
0N/A }
0N/A
0N/A // Translate point from table to list
0N/A if (index >= 0 && list != null &&
0N/A listSelectionModel.isSelectedIndex(index)) {
0N/A
0N/A // Make a new event with the list as source, placing the
0N/A // click in the corresponding list cell.
0N/A Rectangle r = list.getCellBounds(index, index);
0N/A evt = new MouseEvent(list, evt.getID(),
0N/A evt.getWhen(), evt.getModifiers(),
0N/A r.x + 1, r.y + r.height/2,
0N/A evt.getXOnScreen(),
0N/A evt.getYOnScreen(),
0N/A evt.getClickCount(), evt.isPopupTrigger(),
0N/A evt.getButton());
0N/A }
0N/A } else {
0N/A return;
0N/A }
0N/A
0N/A if (index >= 0 && SwingUtilities.isLeftMouseButton(evt)) {
0N/A JFileChooser fc = getFileChooser();
0N/A
0N/A // For single click, we handle editing file name
0N/A if (evt.getClickCount() == 1 && source instanceof JList) {
0N/A if ((!fc.isMultiSelectionEnabled() || fc.getSelectedFiles().length <= 1)
0N/A && index >= 0 && listSelectionModel.isSelectedIndex(index)
0N/A && getEditIndex() == index && editFile == null) {
0N/A
0N/A editFileName(index);
0N/A } else {
0N/A if (index >= 0) {
0N/A setEditIndex(index);
0N/A } else {
0N/A resetEditIndex();
0N/A }
0N/A }
0N/A } else if (evt.getClickCount() == 2) {
0N/A // on double click (open or drill down one directory) be
0N/A // sure to clear the edit index
0N/A resetEditIndex();
0N/A }
0N/A }
0N/A
0N/A // Forward event to Basic
0N/A if (getDoubleClickListener() != null) {
0N/A getDoubleClickListener().mouseClicked(evt);
0N/A }
0N/A }
0N/A
0N/A public void mouseEntered(MouseEvent evt) {
0N/A JComponent source = (JComponent)evt.getSource();
0N/A if (source instanceof JTable) {
0N/A JTable table = (JTable)evt.getSource();
0N/A
0N/A TransferHandler th1 = getFileChooser().getTransferHandler();
0N/A TransferHandler th2 = table.getTransferHandler();
0N/A if (th1 != th2) {
0N/A table.setTransferHandler(th1);
0N/A }
0N/A
0N/A boolean dragEnabled = getFileChooser().getDragEnabled();
0N/A if (dragEnabled != table.getDragEnabled()) {
0N/A table.setDragEnabled(dragEnabled);
0N/A }
0N/A } else if (source instanceof JList) {
0N/A // Forward event to Basic
0N/A if (getDoubleClickListener() != null) {
0N/A getDoubleClickListener().mouseEntered(evt);
0N/A }
0N/A }
0N/A }
0N/A
0N/A public void mouseExited(MouseEvent evt) {
0N/A if (evt.getSource() instanceof JList) {
0N/A // Forward event to Basic
0N/A if (getDoubleClickListener() != null) {
0N/A getDoubleClickListener().mouseExited(evt);
0N/A }
0N/A }
0N/A }
0N/A
0N/A public void mousePressed(MouseEvent evt) {
0N/A if (evt.getSource() instanceof JList) {
0N/A // Forward event to Basic
0N/A if (getDoubleClickListener() != null) {
0N/A getDoubleClickListener().mousePressed(evt);
0N/A }
0N/A }
0N/A }
0N/A
0N/A public void mouseReleased(MouseEvent evt) {
0N/A if (evt.getSource() instanceof JList) {
0N/A // Forward event to Basic
0N/A if (getDoubleClickListener() != null) {
0N/A getDoubleClickListener().mouseReleased(evt);
0N/A }
0N/A }
0N/A }
0N/A
0N/A private MouseListener getDoubleClickListener() {
0N/A // Lazy creation of Basic's listener
0N/A if (doubleClickListener == null && list != null) {
0N/A doubleClickListener =
0N/A fileChooserUIAccessor.createDoubleClickListener(list);
0N/A }
0N/A return doubleClickListener;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Property to remember whether a directory is currently selected in the UI.
0N/A *
0N/A * @return <code>true</code> iff a directory is currently selected.
0N/A */
0N/A protected boolean isDirectorySelected() {
0N/A return fileChooserUIAccessor.isDirectorySelected();
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Property to remember the directory that is currently selected in the UI.
0N/A *
0N/A * @return the value of the <code>directory</code> property
0N/A * @see javax.swing.plaf.basic.BasicFileChooserUI#setDirectory
0N/A */
0N/A protected File getDirectory() {
0N/A return fileChooserUIAccessor.getDirectory();
0N/A }
0N/A
0N/A private Component findChildComponent(Container container, Class cls) {
0N/A int n = container.getComponentCount();
0N/A for (int i = 0; i < n; i++) {
0N/A Component comp = container.getComponent(i);
0N/A if (cls.isInstance(comp)) {
0N/A return comp;
0N/A } else if (comp instanceof Container) {
0N/A Component c = findChildComponent((Container)comp, cls);
0N/A if (c != null) {
0N/A return c;
0N/A }
0N/A }
0N/A }
0N/A return null;
0N/A }
0N/A
0N/A public boolean canWrite(File f) {
0N/A // Return false for non FileSystem files or if file doesn't exist.
0N/A if (!f.exists()) {
0N/A return false;
0N/A }
0N/A
0N/A if (f instanceof ShellFolder) {
0N/A return ((ShellFolder) f).isFileSystem();
0N/A } else {
825N/A if (usesShellFolder(getFileChooser())) {
0N/A try {
0N/A return ShellFolder.getShellFolder(f).isFileSystem();
0N/A } catch (FileNotFoundException ex) {
0N/A // File doesn't exist
0N/A return false;
0N/A }
0N/A } else {
0N/A // Ordinary file
0N/A return true;
0N/A }
0N/A }
0N/A }
0N/A
823N/A /**
823N/A * Returns true if specified FileChooser should use ShellFolder
823N/A */
823N/A public static boolean usesShellFolder(JFileChooser chooser) {
823N/A Boolean prop = (Boolean) chooser.getClientProperty("FileChooser.useShellFolder");
823N/A
823N/A return prop == null ? chooser.getFileSystemView().equals(FileSystemView.getFileSystemView())
823N/A : prop.booleanValue();
823N/A }
823N/A
0N/A // This interface is used to access methods in the FileChooserUI
0N/A // that are not public.
0N/A public interface FileChooserUIAccessor {
0N/A public JFileChooser getFileChooser();
0N/A public BasicDirectoryModel getModel();
0N/A public JPanel createList();
0N/A public JPanel createDetailsView();
0N/A public boolean isDirectorySelected();
0N/A public File getDirectory();
0N/A public Action getApproveSelectionAction();
0N/A public Action getChangeToParentDirectoryAction();
0N/A public Action getNewFolderAction();
0N/A public MouseListener createDoubleClickListener(JList list);
0N/A public ListSelectionListener createListSelectionListener();
0N/A }
0N/A}