Save This Page
Home » openjdk-7 » sun » swing » [javadoc | source]
    1   /*
    2    * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   package sun.swing;
   26   
   27   import java.awt;
   28   import java.awt.event;
   29   import java.beans.PropertyChangeEvent;
   30   import java.beans.PropertyChangeListener;
   31   import java.io;
   32   import java.text.DateFormat;
   33   import java.text.MessageFormat;
   34   import java.util;
   35   import java.util.List;
   36   import java.util.concurrent.Callable;
   37   
   38   import javax.swing;
   39   import javax.swing.border;
   40   import javax.swing.event;
   41   import javax.swing.filechooser;
   42   import javax.swing.plaf.basic;
   43   import javax.swing.table;
   44   import javax.swing.text;
   45   
   46   import sun.awt.shell;
   47   
   48   /**
   49    * <b>WARNING:</b> This class is an implementation detail and is only
   50    * public so that it can be used by two packages. You should NOT consider
   51    * this public API.
   52    * <p>
   53    * This component is intended to be used in a subclass of
   54    * javax.swing.plaf.basic.BasicFileChooserUI. It realies heavily on the
   55    * implementation of BasicFileChooserUI, and is intended to be API compatible
   56    * with earlier implementations of MetalFileChooserUI and WindowsFileChooserUI.
   57    *
   58    * @author Leif Samuelsson
   59    */
   60   public class FilePane extends JPanel implements PropertyChangeListener {
   61       // Constants for actions. These are used for the actions' ACTION_COMMAND_KEY
   62       // and as keys in the action maps for FilePane and the corresponding UI classes
   63   
   64       public final static String ACTION_APPROVE_SELECTION = "approveSelection";
   65       public final static String ACTION_CANCEL            = "cancelSelection";
   66       public final static String ACTION_EDIT_FILE_NAME    = "editFileName";
   67       public final static String ACTION_REFRESH           = "refresh";
   68       public final static String ACTION_CHANGE_TO_PARENT_DIRECTORY = "Go Up";
   69       public final static String ACTION_NEW_FOLDER        = "New Folder";
   70       public final static String ACTION_VIEW_LIST         = "viewTypeList";
   71       public final static String ACTION_VIEW_DETAILS      = "viewTypeDetails";
   72   
   73       private Action[] actions;
   74   
   75       // "enums" for setViewType()
   76       public  static final int VIEWTYPE_LIST     = 0;
   77       public  static final int VIEWTYPE_DETAILS  = 1;
   78       private static final int VIEWTYPE_COUNT    = 2;
   79   
   80       private int viewType = -1;
   81       private JPanel[] viewPanels = new JPanel[VIEWTYPE_COUNT];
   82       private JPanel currentViewPanel;
   83       private String[] viewTypeActionNames;
   84   
   85       private JPopupMenu contextMenu;
   86       private JMenu viewMenu;
   87   
   88       private String viewMenuLabelText;
   89       private String refreshActionLabelText;
   90       private String newFolderActionLabelText;
   91   
   92       private String kiloByteString;
   93       private String megaByteString;
   94       private String gigaByteString;
   95   
   96       private String renameErrorTitleText;
   97       private String renameErrorText;
   98       private String renameErrorFileExistsText;
   99   
  100       private static final Cursor waitCursor =
  101           Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR);
  102   
  103       private final KeyListener detailsKeyListener = new KeyAdapter() {
  104           private final long timeFactor;
  105   
  106           private final StringBuilder typedString = new StringBuilder();
  107   
  108           private long lastTime = 1000L;
  109   
  110           {
  111               Long l = (Long) UIManager.get("Table.timeFactor");
  112               timeFactor = (l != null) ? l : 1000L;
  113           }
  114   
  115           /**
  116            * Moves the keyboard focus to the first element whose prefix matches
  117            * the sequence of alphanumeric keys pressed by the user with delay
  118            * less than value of <code>timeFactor</code>. Subsequent same key
  119            * presses move the keyboard focus to the next object that starts with
  120            * the same letter until another key is pressed, then it is treated
  121            * as the prefix with appropriate number of the same letters followed
  122            * by first typed another letter.
  123            */
  124           public void keyTyped(KeyEvent e) {
  125               BasicDirectoryModel model = getModel();
  126               int rowCount = model.getSize();
  127   
  128               if (detailsTable == null || rowCount == 0 ||
  129                       e.isAltDown() || e.isControlDown() || e.isMetaDown()) {
  130                   return;
  131               }
  132   
  133               InputMap inputMap = detailsTable.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
  134               KeyStroke key = KeyStroke.getKeyStrokeForEvent(e);
  135   
  136               if (inputMap != null && inputMap.get(key) != null) {
  137                   return;
  138               }
  139   
  140               int startIndex = detailsTable.getSelectionModel().getLeadSelectionIndex();
  141   
  142               if (startIndex < 0) {
  143                   startIndex = 0;
  144               }
  145   
  146               if (startIndex >= rowCount) {
  147                   startIndex = rowCount - 1;
  148               }
  149   
  150               char c = e.getKeyChar();
  151   
  152               long time = e.getWhen();
  153   
  154               if (time - lastTime < timeFactor) {
  155                   if (typedString.length() == 1 && typedString.charAt(0) == c) {
  156                       // Subsequent same key presses move the keyboard focus to the next
  157                       // object that starts with the same letter.
  158                       startIndex++;
  159                   } else {
  160                       typedString.append(c);
  161                   }
  162               } else {
  163                   startIndex++;
  164   
  165                   typedString.setLength(0);
  166                   typedString.append(c);
  167               }
  168   
  169               lastTime = time;
  170   
  171               if (startIndex >= rowCount) {
  172                   startIndex = 0;
  173               }
  174   
  175               // Find next file
  176               int index = getNextMatch(startIndex, rowCount - 1);
  177   
  178               if (index < 0 && startIndex > 0) { // wrap
  179                   index = getNextMatch(0, startIndex - 1);
  180               }
  181   
  182               if (index >= 0) {
  183                   detailsTable.getSelectionModel().setSelectionInterval(index, index);
  184   
  185                   Rectangle cellRect = detailsTable.getCellRect(index,
  186                           detailsTable.convertColumnIndexToView(COLUMN_FILENAME), false);
  187                   detailsTable.scrollRectToVisible(cellRect);
  188               }
  189           }
  190   
  191           private int getNextMatch(int startIndex, int finishIndex) {
  192               BasicDirectoryModel model = getModel();
  193               JFileChooser fileChooser = getFileChooser();
  194               DetailsTableRowSorter rowSorter = getRowSorter();
  195   
  196               String prefix = typedString.toString().toLowerCase();
  197   
  198               // Search element
  199               for (int index = startIndex; index <= finishIndex; index++) {
  200                   File file = (File) model.getElementAt(rowSorter.convertRowIndexToModel(index));
  201   
  202                   String fileName = fileChooser.getName(file).toLowerCase();
  203   
  204                   if (fileName.startsWith(prefix)) {
  205                       return index;
  206                   }
  207               }
  208   
  209               return -1;
  210           }
  211       };
  212   
  213       private FocusListener editorFocusListener = new FocusAdapter() {
  214           public void focusLost(FocusEvent e) {
  215               if (! e.isTemporary()) {
  216                   applyEdit();
  217               }
  218           }
  219       };
  220   
  221       private static FocusListener repaintListener = new FocusListener() {
  222           public void focusGained(FocusEvent fe) {
  223               repaintSelection(fe.getSource());
  224           }
  225   
  226           public void focusLost(FocusEvent fe) {
  227               repaintSelection(fe.getSource());
  228           }
  229   
  230           private void repaintSelection(Object source) {
  231               if (source instanceof JList) {
  232                   repaintListSelection((JList)source);
  233               } else if (source instanceof JTable) {
  234                   repaintTableSelection((JTable)source);
  235               }
  236           }
  237   
  238           private void repaintListSelection(JList list) {
  239               int[] indices = list.getSelectedIndices();
  240               for (int i : indices) {
  241                   Rectangle bounds = list.getCellBounds(i, i);
  242                   list.repaint(bounds);
  243               }
  244           }
  245   
  246           private void repaintTableSelection(JTable table) {
  247               int minRow = table.getSelectionModel().getMinSelectionIndex();
  248               int maxRow = table.getSelectionModel().getMaxSelectionIndex();
  249               if (minRow == -1 || maxRow == -1) {
  250                   return;
  251               }
  252   
  253               int col0 = table.convertColumnIndexToView(COLUMN_FILENAME);
  254   
  255               Rectangle first = table.getCellRect(minRow, col0, false);
  256               Rectangle last = table.getCellRect(maxRow, col0, false);
  257               Rectangle dirty = first.union(last);
  258               table.repaint(dirty);
  259           }
  260       };
  261   
  262       private boolean smallIconsView = false;
  263       private Border  listViewBorder;
  264       private Color   listViewBackground;
  265       private boolean listViewWindowsStyle;
  266       private boolean readOnly;
  267       private boolean fullRowSelection = false;
  268   
  269       private ListSelectionModel listSelectionModel;
  270       private JList list;
  271       private JTable detailsTable;
  272   
  273       private static final int COLUMN_FILENAME = 0;
  274   
  275       // Provides a way to recognize a newly created folder, so it can
  276       // be selected when it appears in the model.
  277       private File newFolderFile;
  278   
  279       // Used for accessing methods in the corresponding UI class
  280       private FileChooserUIAccessor fileChooserUIAccessor;
  281       private DetailsTableModel detailsTableModel;
  282       private DetailsTableRowSorter rowSorter;
  283   
  284       public FilePane(FileChooserUIAccessor fileChooserUIAccessor) {
  285           super(new BorderLayout());
  286   
  287           this.fileChooserUIAccessor = fileChooserUIAccessor;
  288   
  289           installDefaults();
  290           createActionMap();
  291       }
  292   
  293       public void uninstallUI() {
  294           if (getModel() != null) {
  295               getModel().removePropertyChangeListener(this);
  296           }
  297       }
  298   
  299       protected JFileChooser getFileChooser() {
  300           return fileChooserUIAccessor.getFileChooser();
  301       }
  302   
  303       protected BasicDirectoryModel getModel() {
  304           return fileChooserUIAccessor.getModel();
  305       }
  306   
  307       public int getViewType() {
  308           return viewType;
  309       }
  310   
  311       public void setViewType(int viewType) {
  312           if (viewType == this.viewType) {
  313               return;
  314           }
  315   
  316           int oldValue = this.viewType;
  317           this.viewType = viewType;
  318   
  319           JPanel createdViewPanel = null;
  320           Component newFocusOwner = null;
  321   
  322           switch (viewType) {
  323             case VIEWTYPE_LIST:
  324               if (viewPanels[viewType] == null) {
  325                   createdViewPanel = fileChooserUIAccessor.createList();
  326                   if (createdViewPanel == null) {
  327                       createdViewPanel = createList();
  328                   }
  329   
  330                   list = (JList) findChildComponent(createdViewPanel, JList.class);
  331                   if (listSelectionModel == null) {
  332                       listSelectionModel = list.getSelectionModel();
  333                       if (detailsTable != null) {
  334                           detailsTable.setSelectionModel(listSelectionModel);
  335                       }
  336                   } else {
  337                       list.setSelectionModel(listSelectionModel);
  338                   }
  339               }
  340               list.setLayoutOrientation(JList.VERTICAL_WRAP);
  341               newFocusOwner = list;
  342               break;
  343   
  344             case VIEWTYPE_DETAILS:
  345               if (viewPanels[viewType] == null) {
  346                   createdViewPanel = fileChooserUIAccessor.createDetailsView();
  347                   if (createdViewPanel == null) {
  348                       createdViewPanel = createDetailsView();
  349                   }
  350   
  351                   detailsTable = (JTable) findChildComponent(createdViewPanel, JTable.class);
  352                   detailsTable.setRowHeight(Math.max(detailsTable.getFont().getSize() + 4, 16 + 1));
  353                   if (listSelectionModel != null) {
  354                       detailsTable.setSelectionModel(listSelectionModel);
  355                   }
  356               }
  357               newFocusOwner = detailsTable;
  358               break;
  359           }
  360   
  361           if (createdViewPanel != null) {
  362               viewPanels[viewType] = createdViewPanel;
  363               recursivelySetInheritsPopupMenu(createdViewPanel, true);
  364           }
  365   
  366           boolean isFocusOwner = false;
  367   
  368           if (currentViewPanel != null) {
  369               Component owner = DefaultKeyboardFocusManager.
  370                       getCurrentKeyboardFocusManager().getPermanentFocusOwner();
  371   
  372               isFocusOwner = owner == detailsTable || owner == list;
  373   
  374               remove(currentViewPanel);
  375           }
  376   
  377           currentViewPanel = viewPanels[viewType];
  378           add(currentViewPanel, BorderLayout.CENTER);
  379   
  380           if (isFocusOwner && newFocusOwner != null) {
  381               newFocusOwner.requestFocusInWindow();
  382           }
  383   
  384           revalidate();
  385           repaint();
  386           updateViewMenu();
  387           firePropertyChange("viewType", oldValue, viewType);
  388       }
  389   
  390       class ViewTypeAction extends AbstractAction {
  391           private int viewType;
  392   
  393           ViewTypeAction(int viewType) {
  394               super(viewTypeActionNames[viewType]);
  395               this.viewType = viewType;
  396   
  397               String cmd;
  398               switch (viewType) {
  399                   case VIEWTYPE_LIST:    cmd = ACTION_VIEW_LIST;    break;
  400                   case VIEWTYPE_DETAILS: cmd = ACTION_VIEW_DETAILS; break;
  401                   default:               cmd = (String)getValue(Action.NAME);
  402               }
  403               putValue(Action.ACTION_COMMAND_KEY, cmd);
  404           }
  405   
  406           public void actionPerformed(ActionEvent e) {
  407               setViewType(viewType);
  408           }
  409       }
  410   
  411       public Action getViewTypeAction(int viewType) {
  412           return new ViewTypeAction(viewType);
  413       }
  414   
  415       private static void recursivelySetInheritsPopupMenu(Container container, boolean b) {
  416           if (container instanceof JComponent) {
  417               ((JComponent)container).setInheritsPopupMenu(b);
  418           }
  419           int n = container.getComponentCount();
  420           for (int i = 0; i < n; i++) {
  421               recursivelySetInheritsPopupMenu((Container)container.getComponent(i), b);
  422           }
  423       }
  424   
  425       protected void installDefaults() {
  426           Locale l = getFileChooser().getLocale();
  427   
  428           listViewBorder       = UIManager.getBorder("FileChooser.listViewBorder");
  429           listViewBackground   = UIManager.getColor("FileChooser.listViewBackground");
  430           listViewWindowsStyle = UIManager.getBoolean("FileChooser.listViewWindowsStyle");
  431           readOnly             = UIManager.getBoolean("FileChooser.readOnly");
  432   
  433           // TODO: On windows, get the following localized strings from the OS
  434   
  435           viewMenuLabelText =
  436                           UIManager.getString("FileChooser.viewMenuLabelText", l);
  437           refreshActionLabelText =
  438                           UIManager.getString("FileChooser.refreshActionLabelText", l);
  439           newFolderActionLabelText =
  440                           UIManager.getString("FileChooser.newFolderActionLabelText", l);
  441   
  442           viewTypeActionNames = new String[VIEWTYPE_COUNT];
  443           viewTypeActionNames[VIEWTYPE_LIST] =
  444                           UIManager.getString("FileChooser.listViewActionLabelText", l);
  445           viewTypeActionNames[VIEWTYPE_DETAILS] =
  446                           UIManager.getString("FileChooser.detailsViewActionLabelText", l);
  447   
  448           kiloByteString = UIManager.getString("FileChooser.fileSizeKiloBytes", l);
  449           megaByteString = UIManager.getString("FileChooser.fileSizeMegaBytes", l);
  450           gigaByteString = UIManager.getString("FileChooser.fileSizeGigaBytes", l);
  451           fullRowSelection = UIManager.getBoolean("FileView.fullRowSelection");
  452   
  453           renameErrorTitleText = UIManager.getString("FileChooser.renameErrorTitleText", l);
  454           renameErrorText = UIManager.getString("FileChooser.renameErrorText", l);
  455           renameErrorFileExistsText = UIManager.getString("FileChooser.renameErrorFileExistsText", l);
  456       }
  457   
  458       /**
  459        * Fetches the command list for the FilePane. These commands
  460        * are useful for binding to events, such as in a keymap.
  461        *
  462        * @return the command list
  463        */
  464       public Action[] getActions() {
  465           if (actions == null) {
  466               class FilePaneAction extends AbstractAction {
  467                   FilePaneAction(String name) {
  468                       this(name, name);
  469                   }
  470   
  471                   FilePaneAction(String name, String cmd) {
  472                       super(name);
  473                       putValue(Action.ACTION_COMMAND_KEY, cmd);
  474                   }
  475   
  476                   public void actionPerformed(ActionEvent e) {
  477                       String cmd = (String)getValue(Action.ACTION_COMMAND_KEY);
  478   
  479                       if (cmd == ACTION_CANCEL) {
  480                           if (editFile != null) {
  481                              cancelEdit();
  482                           } else {
  483                              getFileChooser().cancelSelection();
  484                           }
  485                       } else if (cmd == ACTION_EDIT_FILE_NAME) {
  486                           JFileChooser fc = getFileChooser();
  487                           int index = listSelectionModel.getMinSelectionIndex();
  488                           if (index >= 0 && editFile == null &&
  489                               (!fc.isMultiSelectionEnabled() ||
  490                                fc.getSelectedFiles().length <= 1)) {
  491   
  492                               editFileName(index);
  493                           }
  494                       } else if (cmd == ACTION_REFRESH) {
  495                           getFileChooser().rescanCurrentDirectory();
  496                       }
  497                   }
  498   
  499                   public boolean isEnabled() {
  500                       String cmd = (String)getValue(Action.ACTION_COMMAND_KEY);
  501                       if (cmd == ACTION_CANCEL) {
  502                           return getFileChooser().isEnabled();
  503                       } else if (cmd == ACTION_EDIT_FILE_NAME) {
  504                           return !readOnly && getFileChooser().isEnabled();
  505                       } else {
  506                           return true;
  507                       }
  508                   }
  509               }
  510   
  511               ArrayList<Action> actionList = new ArrayList<Action>(8);
  512               Action action;
  513   
  514               actionList.add(new FilePaneAction(ACTION_CANCEL));
  515               actionList.add(new FilePaneAction(ACTION_EDIT_FILE_NAME));
  516               actionList.add(new FilePaneAction(refreshActionLabelText, ACTION_REFRESH));
  517   
  518               action = fileChooserUIAccessor.getApproveSelectionAction();
  519               if (action != null) {
  520                   actionList.add(action);
  521               }
  522               action = fileChooserUIAccessor.getChangeToParentDirectoryAction();
  523               if (action != null) {
  524                   actionList.add(action);
  525               }
  526               action = getNewFolderAction();
  527               if (action != null) {
  528                   actionList.add(action);
  529               }
  530               action = getViewTypeAction(VIEWTYPE_LIST);
  531               if (action != null) {
  532                   actionList.add(action);
  533               }
  534               action = getViewTypeAction(VIEWTYPE_DETAILS);
  535               if (action != null) {
  536                   actionList.add(action);
  537               }
  538               actions = actionList.toArray(new Action[actionList.size()]);
  539           }
  540   
  541           return actions;
  542       }
  543   
  544       protected void createActionMap() {
  545           addActionsToMap(super.getActionMap(), getActions());
  546       }
  547   
  548   
  549       public static void addActionsToMap(ActionMap map, Action[] actions) {
  550           if (map != null && actions != null) {
  551               for (Action a : actions) {
  552                   String cmd = (String)a.getValue(Action.ACTION_COMMAND_KEY);
  553                   if (cmd == null) {
  554                       cmd = (String)a.getValue(Action.NAME);
  555                   }
  556                   map.put(cmd, a);
  557               }
  558           }
  559       }
  560   
  561   
  562       private void updateListRowCount(JList list) {
  563           if (smallIconsView) {
  564               list.setVisibleRowCount(getModel().getSize() / 3);
  565           } else {
  566               list.setVisibleRowCount(-1);
  567           }
  568       }
  569   
  570       public JPanel createList() {
  571           JPanel p = new JPanel(new BorderLayout());
  572           final JFileChooser fileChooser = getFileChooser();
  573           final JList list = new JList() {
  574               public int getNextMatch(String prefix, int startIndex, Position.Bias bias) {
  575                   ListModel model = getModel();
  576                   int max = model.getSize();
  577                   if (prefix == null || startIndex < 0 || startIndex >= max) {
  578                       throw new IllegalArgumentException();
  579                   }
  580                   // start search from the next element before/after the selected element
  581                   boolean backwards = (bias == Position.Bias.Backward);
  582                   for (int i = startIndex; backwards ? i >= 0 : i < max; i += (backwards ?  -1 : 1)) {
  583                       String filename = fileChooser.getName((File)model.getElementAt(i));
  584                       if (filename.regionMatches(true, 0, prefix, 0, prefix.length())) {
  585                           return i;
  586                       }
  587                   }
  588                   return -1;
  589               }
  590           };
  591           list.setCellRenderer(new FileRenderer());
  592           list.setLayoutOrientation(JList.VERTICAL_WRAP);
  593   
  594           // 4835633 : tell BasicListUI that this is a file list
  595           list.putClientProperty("List.isFileList", Boolean.TRUE);
  596   
  597           if (listViewWindowsStyle) {
  598               list.addFocusListener(repaintListener);
  599           }
  600   
  601           updateListRowCount(list);
  602   
  603           getModel().addListDataListener(new ListDataListener() {
  604               public void intervalAdded(ListDataEvent e) {
  605                   updateListRowCount(list);
  606               }
  607               public void intervalRemoved(ListDataEvent e) {
  608                   updateListRowCount(list);
  609               }
  610               public void contentsChanged(ListDataEvent e) {
  611                   if (isShowing()) {
  612                       clearSelection();
  613                   }
  614                   updateListRowCount(list);
  615               }
  616           });
  617   
  618           getModel().addPropertyChangeListener(this);
  619   
  620           if (fileChooser.isMultiSelectionEnabled()) {
  621               list.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
  622           } else {
  623               list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
  624           }
  625           list.setModel(new SortableListModel());
  626   
  627           list.addListSelectionListener(createListSelectionListener());
  628           list.addMouseListener(getMouseHandler());
  629   
  630           JScrollPane scrollpane = new JScrollPane(list);
  631           if (listViewBackground != null) {
  632               list.setBackground(listViewBackground);
  633           }
  634           if (listViewBorder != null) {
  635               scrollpane.setBorder(listViewBorder);
  636           }
  637           p.add(scrollpane, BorderLayout.CENTER);
  638           return p;
  639       }
  640   
  641       /**
  642        * This model allows for sorting JList
  643        */
  644       private class SortableListModel extends AbstractListModel
  645               implements TableModelListener, RowSorterListener {
  646   
  647           public SortableListModel() {
  648               getDetailsTableModel().addTableModelListener(this);
  649               getRowSorter().addRowSorterListener(this);
  650           }
  651   
  652           public int getSize() {
  653               return getModel().getSize();
  654           }
  655   
  656           public Object getElementAt(int index) {
  657               // JList doesn't support RowSorter so far, so we put it into the list model
  658               return getModel().getElementAt(getRowSorter().convertRowIndexToModel(index));
  659           }
  660   
  661           public void tableChanged(TableModelEvent e) {
  662               fireContentsChanged(this, 0, getSize());
  663           }
  664   
  665           public void sorterChanged(RowSorterEvent e) {
  666               fireContentsChanged(this, 0, getSize());
  667           }
  668       }
  669   
  670       private DetailsTableModel getDetailsTableModel() {
  671           if(detailsTableModel == null) {
  672               detailsTableModel = new DetailsTableModel(getFileChooser());
  673           }
  674           return detailsTableModel;
  675       }
  676   
  677       class DetailsTableModel extends AbstractTableModel implements ListDataListener {
  678           JFileChooser chooser;
  679           BasicDirectoryModel directoryModel;
  680   
  681           ShellFolderColumnInfo[] columns;
  682           int[] columnMap;
  683   
  684           DetailsTableModel(JFileChooser fc) {
  685               this.chooser = fc;
  686               directoryModel = getModel();
  687               directoryModel.addListDataListener(this);
  688   
  689               updateColumnInfo();
  690           }
  691   
  692           void updateColumnInfo() {
  693               File dir = chooser.getCurrentDirectory();
  694               if (dir != null && usesShellFolder(chooser)) {
  695                   try {
  696                       dir = ShellFolder.getShellFolder(dir);
  697                   } catch (FileNotFoundException e) {
  698                       // Leave dir without changing
  699                   }
  700               }
  701   
  702               ShellFolderColumnInfo[] allColumns = ShellFolder.getFolderColumns(dir);
  703   
  704               ArrayList<ShellFolderColumnInfo> visibleColumns =
  705                       new ArrayList<ShellFolderColumnInfo>();
  706               columnMap = new int[allColumns.length];
  707               for (int i = 0; i < allColumns.length; i++) {
  708                   ShellFolderColumnInfo column = allColumns[i];
  709                   if (column.isVisible()) {
  710                       columnMap[visibleColumns.size()] = i;
  711                       visibleColumns.add(column);
  712                   }
  713               }
  714   
  715               columns = new ShellFolderColumnInfo[visibleColumns.size()];
  716               visibleColumns.toArray(columns);
  717               columnMap = Arrays.copyOf(columnMap, columns.length);
  718   
  719               List<? extends RowSorter.SortKey> sortKeys =
  720                       (rowSorter == null) ? null : rowSorter.getSortKeys();
  721               fireTableStructureChanged();
  722               restoreSortKeys(sortKeys);
  723           }
  724   
  725           private void restoreSortKeys(List<? extends RowSorter.SortKey> sortKeys) {
  726               if (sortKeys != null) {
  727                   // check if preserved sortKeys are valid for this folder
  728                   for (int i = 0; i < sortKeys.size(); i++) {
  729                       RowSorter.SortKey sortKey = sortKeys.get(i);
  730                       if (sortKey.getColumn() >= columns.length) {
  731                           sortKeys = null;
  732                           break;
  733                       }
  734                   }
  735                   if (sortKeys != null) {
  736                       rowSorter.setSortKeys(sortKeys);
  737                   }
  738               }
  739           }
  740   
  741           public int getRowCount() {
  742               return directoryModel.getSize();
  743           }
  744   
  745           public int getColumnCount() {
  746               return columns.length;
  747           }
  748   
  749           public Object getValueAt(int row, int col) {
  750               // Note: It is very important to avoid getting info on drives, as
  751               // this will trigger "No disk in A:" and similar dialogs.
  752               //
  753               // Use (f.exists() && !chooser.getFileSystemView().isFileSystemRoot(f)) to
  754               // determine if it is safe to call methods directly on f.
  755               return getFileColumnValue((File)directoryModel.getElementAt(row), col);
  756           }
  757   
  758           private Object getFileColumnValue(File f, int col) {
  759               return (col == COLUMN_FILENAME)
  760                       ? f // always return the file itself for the 1st column
  761                       : ShellFolder.getFolderColumnValue(f, columnMap[col]);
  762           }
  763   
  764           public void setValueAt(Object value, int row, int col) {
  765               if (col == COLUMN_FILENAME) {
  766                   final JFileChooser chooser = getFileChooser();
  767                   File f = (File)getValueAt(row, col);
  768                   if (f != null) {
  769                       String oldDisplayName = chooser.getName(f);
  770                       String oldFileName = f.getName();
  771                       String newDisplayName = ((String)value).trim();
  772                       String newFileName;
  773   
  774                       if (!newDisplayName.equals(oldDisplayName)) {
  775                           newFileName = newDisplayName;
  776                           //Check if extension is hidden from user
  777                           int i1 = oldFileName.length();
  778                           int i2 = oldDisplayName.length();
  779                           if (i1 > i2 && oldFileName.charAt(i2) == '.') {
  780                               newFileName = newDisplayName + oldFileName.substring(i2);
  781                           }
  782   
  783                           // rename
  784                           FileSystemView fsv = chooser.getFileSystemView();
  785                           final File f2 = fsv.createFileObject(f.getParentFile(), newFileName);
  786                           if (f2.exists()) {
  787                               JOptionPane.showMessageDialog(chooser, MessageFormat.format(renameErrorFileExistsText,
  788                                       oldFileName), renameErrorTitleText, JOptionPane.ERROR_MESSAGE);
  789                           } else {
  790                               if (FilePane.this.getModel().renameFile(f, f2)) {
  791                                   if (fsv.isParent(chooser.getCurrentDirectory(), f2)) {
  792                                       // The setSelectedFile method produces a new setValueAt invocation while the JTable
  793                                       // is editing. Postpone file selection to be sure that edit mode of the JTable
  794                                       // is completed
  795                                       SwingUtilities.invokeLater(new Runnable() {
  796                                           public void run() {
  797                                               if (chooser.isMultiSelectionEnabled()) {
  798                                                   chooser.setSelectedFiles(new File[]{f2});
  799                                               } else {
  800                                                   chooser.setSelectedFile(f2);
  801                                               }
  802                                           }
  803                                       });
  804                                   } else {
  805                                       // Could be because of delay in updating Desktop folder
  806                                       // chooser.setSelectedFile(null);
  807                                   }
  808                               } else {
  809                                   JOptionPane.showMessageDialog(chooser, MessageFormat.format(renameErrorText, oldFileName),
  810                                           renameErrorTitleText, JOptionPane.ERROR_MESSAGE);
  811                               }
  812                           }
  813                       }
  814                   }
  815               }
  816           }
  817   
  818           public boolean isCellEditable(int row, int column) {
  819               File currentDirectory = getFileChooser().getCurrentDirectory();
  820               return (!readOnly && column == COLUMN_FILENAME && canWrite(currentDirectory));
  821           }
  822   
  823           public void contentsChanged(ListDataEvent e) {
  824               // Update the selection after the model has been updated
  825               new DelayedSelectionUpdater();
  826               fireTableDataChanged();
  827           }
  828   
  829           public void intervalAdded(ListDataEvent e) {
  830               int i0 = e.getIndex0();
  831               int i1 = e.getIndex1();
  832               if (i0 == i1) {
  833                   File file = (File)getModel().getElementAt(i0);
  834                   if (file.equals(newFolderFile)) {
  835                       new DelayedSelectionUpdater(file);
  836                       newFolderFile = null;
  837                   }
  838               }
  839   
  840               fireTableRowsInserted(e.getIndex0(), e.getIndex1());
  841           }
  842           public void intervalRemoved(ListDataEvent e) {
  843               fireTableRowsDeleted(e.getIndex0(), e.getIndex1());
  844           }
  845   
  846           public ShellFolderColumnInfo[] getColumns() {
  847               return columns;
  848           }
  849       }
  850   
  851   
  852       private void updateDetailsColumnModel(JTable table) {
  853           if (table != null) {
  854               ShellFolderColumnInfo[] columns = detailsTableModel.getColumns();
  855   
  856               TableColumnModel columnModel = new DefaultTableColumnModel();
  857               for (int i = 0; i < columns.length; i++) {
  858                   ShellFolderColumnInfo dataItem = columns[i];
  859                   TableColumn column = new TableColumn(i);
  860   
  861                   String title = dataItem.getTitle();
  862                   if (title != null && title.startsWith("FileChooser.") && title.endsWith("HeaderText")) {
  863                       // the column must have a string resource that we try to get
  864                       String uiTitle = UIManager.getString(title, table.getLocale());
  865                       if (uiTitle != null) {
  866                           title = uiTitle;
  867                       }
  868                   }
  869                   column.setHeaderValue(title);
  870   
  871                   Integer width = dataItem.getWidth();
  872                   if (width != null) {
  873                       column.setPreferredWidth(width);
  874                       // otherwise we let JTable to decide the actual width
  875                   }
  876   
  877                   columnModel.addColumn(column);
  878               }
  879   
  880               // Install cell editor for editing file name
  881               if (!readOnly && columnModel.getColumnCount() > COLUMN_FILENAME) {
  882                   columnModel.getColumn(COLUMN_FILENAME).
  883                           setCellEditor(getDetailsTableCellEditor());
  884               }
  885   
  886               table.setColumnModel(columnModel);
  887           }
  888       }
  889   
  890       private DetailsTableRowSorter getRowSorter() {
  891           if (rowSorter == null) {
  892               rowSorter = new DetailsTableRowSorter();
  893           }
  894           return rowSorter;
  895       }
  896   
  897       private class DetailsTableRowSorter extends TableRowSorter<TableModel> {
  898           public DetailsTableRowSorter() {
  899               setModelWrapper(new SorterModelWrapper());
  900           }
  901   
  902           public void updateComparators(ShellFolderColumnInfo [] columns) {
  903               for (int i = 0; i < columns.length; i++) {
  904                   Comparator c = columns[i].getComparator();
  905                   if (c != null) {
  906                       c = new DirectoriesFirstComparatorWrapper(i, c);
  907                   }
  908                   setComparator(i, c);
  909               }
  910           }
  911   
  912           @Override
  913           public void sort() {
  914               ShellFolder.invoke(new Callable<Void>() {
  915                   public Void call() {
  916                       DetailsTableRowSorter.super.sort();
  917                       return null;
  918                   }
  919               });
  920           }
  921   
  922           public void modelStructureChanged() {
  923               super.modelStructureChanged();
  924               updateComparators(detailsTableModel.getColumns());
  925           }
  926   
  927           private class SorterModelWrapper extends ModelWrapper<TableModel, Integer> {
  928               public TableModel getModel() {
  929                   return getDetailsTableModel();
  930               }
  931   
  932               public int getColumnCount() {
  933                   return getDetailsTableModel().getColumnCount();
  934               }
  935   
  936               public int getRowCount() {
  937                   return getDetailsTableModel().getRowCount();
  938               }
  939   
  940               public Object getValueAt(int row, int column) {
  941                   return FilePane.this.getModel().getElementAt(row);
  942               }
  943   
  944               public Integer getIdentifier(int row) {
  945                   return row;
  946               }
  947           }
  948       }
  949   
  950       /**
  951        * This class sorts directories before files, comparing directory to
  952        * directory and file to file using the wrapped comparator.
  953        */
  954       private class DirectoriesFirstComparatorWrapper implements Comparator<File> {
  955           private Comparator comparator;
  956           private int column;
  957   
  958           public DirectoriesFirstComparatorWrapper(int column, Comparator comparator) {
  959               this.column = column;
  960               this.comparator = comparator;
  961           }
  962   
  963           public int compare(File f1, File f2) {
  964               if (f1 != null && f2 != null) {
  965                   boolean traversable1 = getFileChooser().isTraversable(f1);
  966                   boolean traversable2 = getFileChooser().isTraversable(f2);
  967                   // directories go first
  968                   if (traversable1 && !traversable2) {
  969                       return -1;
  970                   }
  971                   if (!traversable1 && traversable2) {
  972                       return 1;
  973                   }
  974               }
  975               if (detailsTableModel.getColumns()[column].isCompareByColumn()) {
  976                   return comparator.compare(
  977                           getDetailsTableModel().getFileColumnValue(f1, column),
  978                           getDetailsTableModel().getFileColumnValue(f2, column)
  979                   );
  980               }
  981               // For this column we need to pass the file itself (not a
  982               // column value) to the comparator
  983               return comparator.compare(f1, f2);
  984           }
  985       }
  986   
  987       private DetailsTableCellEditor tableCellEditor;
  988   
  989       private DetailsTableCellEditor getDetailsTableCellEditor() {
  990           if (tableCellEditor == null) {
  991               tableCellEditor = new DetailsTableCellEditor(new JTextField());
  992           }
  993           return tableCellEditor;
  994       }
  995   
  996       private class DetailsTableCellEditor extends DefaultCellEditor {
  997           private final JTextField tf;
  998   
  999           public DetailsTableCellEditor(JTextField tf) {
 1000               super(tf);
 1001               this.tf = tf;
 1002               tf.setName("Table.editor");
 1003               tf.addFocusListener(editorFocusListener);
 1004           }
 1005   
 1006           public Component getTableCellEditorComponent(JTable table, Object value,
 1007                                                        boolean isSelected, int row, int column) {
 1008               Component comp = super.getTableCellEditorComponent(table, value,
 1009                       isSelected, row, column);
 1010               if (value instanceof File) {
 1011                   tf.setText(getFileChooser().getName((File) value));
 1012                   tf.selectAll();
 1013               }
 1014               return comp;
 1015           }
 1016       }
 1017   
 1018   
 1019       class DetailsTableCellRenderer extends DefaultTableCellRenderer {
 1020           JFileChooser chooser;
 1021           DateFormat df;
 1022   
 1023           DetailsTableCellRenderer(JFileChooser chooser) {
 1024               this.chooser = chooser;
 1025               df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT,
 1026                                                   chooser.getLocale());
 1027           }
 1028   
 1029           public void setBounds(int x, int y, int width, int height) {
 1030           if (getHorizontalAlignment() == SwingConstants.LEADING &&
 1031                       !fullRowSelection) {
 1032                   // Restrict width to actual text
 1033                   width = Math.min(width, this.getPreferredSize().width+4);
 1034               } else {
 1035                   x -= 4;
 1036               }
 1037               super.setBounds(x, y, width, height);
 1038           }
 1039   
 1040   
 1041           public Insets getInsets(Insets i) {
 1042               // Provide some space between columns
 1043               i = super.getInsets(i);
 1044               i.left  += 4;
 1045               i.right += 4;
 1046               return i;
 1047           }
 1048   
 1049           public Component getTableCellRendererComponent(JTable table, Object value,
 1050                                 boolean isSelected, boolean hasFocus, int row, int column) {
 1051   
 1052               if ((table.convertColumnIndexToModel(column) != COLUMN_FILENAME ||
 1053                       (listViewWindowsStyle && !table.isFocusOwner())) &&
 1054                       !fullRowSelection) {
 1055                   isSelected = false;
 1056               }
 1057   
 1058               super.getTableCellRendererComponent(table, value, isSelected,
 1059                                                          hasFocus, row, column);
 1060   
 1061               setIcon(null);
 1062   
 1063               int modelColumn = table.convertColumnIndexToModel(column);
 1064               ShellFolderColumnInfo columnInfo = detailsTableModel.getColumns()[modelColumn];
 1065   
 1066               Integer alignment = columnInfo.getAlignment();
 1067               if (alignment == null) {
 1068                   alignment = (value instanceof Number)
 1069                           ? SwingConstants.RIGHT
 1070                           : SwingConstants.LEADING;
 1071               }
 1072   
 1073               setHorizontalAlignment(alignment);
 1074   
 1075               // formatting cell text
 1076               // TODO: it's rather a temporary trick, to be revised
 1077               String text;
 1078   
 1079               if (value == null) {
 1080                   text = "";
 1081   
 1082               } else if (value instanceof File) {
 1083                   File file = (File)value;
 1084                   text = chooser.getName(file);
 1085                   Icon icon = chooser.getIcon(file);
 1086                   setIcon(icon);
 1087   
 1088               } else if (value instanceof Long) {
 1089                   long len = ((Long) value) / 1024L;
 1090                   if (listViewWindowsStyle) {
 1091                       text = MessageFormat.format(kiloByteString, len + 1);
 1092                   } else if (len < 1024L) {
 1093                       text = MessageFormat.format(kiloByteString, (len == 0L) ? 1L : len);
 1094                   } else {
 1095                       len /= 1024L;
 1096                       if (len < 1024L) {
 1097                           text = MessageFormat.format(megaByteString, len);
 1098                       } else {
 1099                           len /= 1024L;
 1100                           text = MessageFormat.format(gigaByteString, len);
 1101                       }
 1102                   }
 1103   
 1104               } else if (value instanceof Date) {
 1105                   text = df.format((Date)value);
 1106   
 1107               } else {
 1108                   text = value.toString();
 1109               }
 1110   
 1111               setText(text);
 1112   
 1113               return this;
 1114           }
 1115       }
 1116   
 1117       public JPanel createDetailsView() {
 1118           final JFileChooser chooser = getFileChooser();
 1119   
 1120           JPanel p = new JPanel(new BorderLayout());
 1121   
 1122           final JTable detailsTable = new JTable(getDetailsTableModel()) {
 1123               // Handle Escape key events here
 1124               protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) {
 1125                   if (e.getKeyCode() == KeyEvent.VK_ESCAPE && getCellEditor() == null) {
 1126                       // We are not editing, forward to filechooser.
 1127                       chooser.dispatchEvent(e);
 1128                       return true;
 1129                   }
 1130                   return super.processKeyBinding(ks, e, condition, pressed);
 1131               }
 1132   
 1133               public void tableChanged(TableModelEvent e) {
 1134                   super.tableChanged(e);
 1135   
 1136                   if (e.getFirstRow() == TableModelEvent.HEADER_ROW) {
 1137                       // update header with possibly changed column set
 1138                       updateDetailsColumnModel(this);
 1139                   }
 1140               }
 1141           };
 1142   
 1143           detailsTable.setRowSorter(getRowSorter());
 1144           detailsTable.setAutoCreateColumnsFromModel(false);
 1145           detailsTable.setComponentOrientation(chooser.getComponentOrientation());
 1146           detailsTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
 1147           detailsTable.setShowGrid(false);
 1148           detailsTable.putClientProperty("JTable.autoStartsEdit", Boolean.FALSE);
 1149           detailsTable.addKeyListener(detailsKeyListener);
 1150   
 1151           Font font = list.getFont();
 1152           detailsTable.setFont(font);
 1153           detailsTable.setIntercellSpacing(new Dimension(0, 0));
 1154   
 1155           TableCellRenderer headerRenderer =
 1156                   new AlignableTableHeaderRenderer(detailsTable.getTableHeader().getDefaultRenderer());
 1157           detailsTable.getTableHeader().setDefaultRenderer(headerRenderer);
 1158           TableCellRenderer cellRenderer = new DetailsTableCellRenderer(chooser);
 1159           detailsTable.setDefaultRenderer(Object.class, cellRenderer);
 1160   
 1161           // So that drag can be started on a mouse press
 1162           detailsTable.getColumnModel().getSelectionModel().
 1163               setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
 1164   
 1165           detailsTable.addMouseListener(getMouseHandler());
 1166           // No need to addListSelectionListener because selections are forwarded
 1167           // to our JList.
 1168   
 1169           // 4835633 : tell BasicTableUI that this is a file list
 1170           detailsTable.putClientProperty("Table.isFileList", Boolean.TRUE);
 1171   
 1172           if (listViewWindowsStyle) {
 1173               detailsTable.addFocusListener(repaintListener);
 1174           }
 1175   
 1176           // TAB/SHIFT-TAB should transfer focus and ENTER should select an item.
 1177           // We don't want them to navigate within the table
 1178           ActionMap am = SwingUtilities.getUIActionMap(detailsTable);
 1179           am.remove("selectNextRowCell");
 1180           am.remove("selectPreviousRowCell");
 1181           am.remove("selectNextColumnCell");
 1182           am.remove("selectPreviousColumnCell");
 1183           detailsTable.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
 1184                        null);
 1185           detailsTable.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
 1186                        null);
 1187   
 1188           JScrollPane scrollpane = new JScrollPane(detailsTable);
 1189           scrollpane.setComponentOrientation(chooser.getComponentOrientation());
 1190           LookAndFeel.installColors(scrollpane.getViewport(), "Table.background", "Table.foreground");
 1191   
 1192           // Adjust width of first column so the table fills the viewport when
 1193           // first displayed (temporary listener).
 1194           scrollpane.addComponentListener(new ComponentAdapter() {
 1195               public void componentResized(ComponentEvent e) {
 1196                   JScrollPane sp = (JScrollPane)e.getComponent();
 1197                   fixNameColumnWidth(sp.getViewport().getSize().width);
 1198                   sp.removeComponentListener(this);
 1199               }
 1200           });
 1201   
 1202           // 4835633.
 1203           // If the mouse is pressed in the area below the Details view table, the
 1204           // event is not dispatched to the Table MouseListener but to the
 1205           // scrollpane.  Listen for that here so we can clear the selection.
 1206           scrollpane.addMouseListener(new MouseAdapter() {
 1207               public void mousePressed(MouseEvent e) {
 1208                   JScrollPane jsp = ((JScrollPane)e.getComponent());
 1209                   JTable table = (JTable)jsp.getViewport().getView();
 1210   
 1211                   if (!e.isShiftDown() || table.getSelectionModel().getSelectionMode() == ListSelectionModel.SINGLE_SELECTION) {
 1212                       clearSelection();
 1213                       TableCellEditor tce = table.getCellEditor();
 1214                       if (tce != null) {
 1215                           tce.stopCellEditing();
 1216                       }
 1217                   }
 1218               }
 1219           });
 1220   
 1221           detailsTable.setForeground(list.getForeground());
 1222           detailsTable.setBackground(list.getBackground());
 1223   
 1224           if (listViewBorder != null) {
 1225               scrollpane.setBorder(listViewBorder);
 1226           }
 1227           p.add(scrollpane, BorderLayout.CENTER);
 1228   
 1229           detailsTableModel.fireTableStructureChanged();
 1230   
 1231           return p;
 1232       } // createDetailsView
 1233   
 1234       private class AlignableTableHeaderRenderer implements TableCellRenderer {
 1235           TableCellRenderer wrappedRenderer;
 1236   
 1237           public AlignableTableHeaderRenderer(TableCellRenderer wrappedRenderer) {
 1238               this.wrappedRenderer = wrappedRenderer;
 1239           }
 1240   
 1241           public Component getTableCellRendererComponent(
 1242                                   JTable table, Object value, boolean isSelected,
 1243                                   boolean hasFocus, int row, int column) {
 1244   
 1245               Component c = wrappedRenderer.getTableCellRendererComponent(
 1246                                   table, value, isSelected, hasFocus, row, column);
 1247   
 1248               int modelColumn = table.convertColumnIndexToModel(column);
 1249               ShellFolderColumnInfo columnInfo = detailsTableModel.getColumns()[modelColumn];
 1250   
 1251               Integer alignment = columnInfo.getAlignment();
 1252               if (alignment == null) {
 1253                   alignment = SwingConstants.CENTER;
 1254               }
 1255               if (c instanceof JLabel) {
 1256                   ((JLabel) c).setHorizontalAlignment(alignment);
 1257               }
 1258   
 1259               return c;
 1260           }
 1261       }
 1262   
 1263       private void fixNameColumnWidth(int viewWidth) {
 1264           TableColumn nameCol = detailsTable.getColumnModel().getColumn(COLUMN_FILENAME);
 1265           int tableWidth = detailsTable.getPreferredSize().width;
 1266   
 1267           if (tableWidth < viewWidth) {
 1268               nameCol.setPreferredWidth(nameCol.getPreferredWidth() + viewWidth - tableWidth);
 1269           }
 1270       }
 1271   
 1272       private class DelayedSelectionUpdater implements Runnable {
 1273           File editFile;
 1274   
 1275           DelayedSelectionUpdater() {
 1276               this(null);
 1277           }
 1278   
 1279           DelayedSelectionUpdater(File editFile) {
 1280               this.editFile = editFile;
 1281               if (isShowing()) {
 1282                   SwingUtilities.invokeLater(this);
 1283               }
 1284           }
 1285   
 1286           public void run() {
 1287               setFileSelected();
 1288               if (editFile != null) {
 1289                   editFileName(getRowSorter().convertRowIndexToView(
 1290                           getModel().indexOf(editFile)));
 1291                   editFile = null;
 1292               }
 1293           }
 1294       }
 1295   
 1296   
 1297       /**
 1298        * Creates a selection listener for the list of files and directories.
 1299        *
 1300        * @return a <code>ListSelectionListener</code>
 1301        */
 1302       public ListSelectionListener createListSelectionListener() {
 1303           return fileChooserUIAccessor.createListSelectionListener();
 1304       }
 1305   
 1306       int lastIndex = -1;
 1307       File editFile = null;
 1308   
 1309       private int getEditIndex() {
 1310           return lastIndex;
 1311       }
 1312   
 1313       private void setEditIndex(int i) {
 1314           lastIndex = i;
 1315       }
 1316   
 1317       private void resetEditIndex() {
 1318           lastIndex = -1;
 1319       }
 1320   
 1321       private void cancelEdit() {
 1322           if (editFile != null) {
 1323               editFile = null;
 1324               list.remove(editCell);
 1325               repaint();
 1326           } else if (detailsTable != null && detailsTable.isEditing()) {
 1327               detailsTable.getCellEditor().cancelCellEditing();
 1328           }
 1329       }
 1330   
 1331       JTextField editCell = null;
 1332   
 1333       /**
 1334        * @param index visual index of the file to be edited
 1335        */
 1336       private void editFileName(int index) {
 1337           JFileChooser chooser = getFileChooser();
 1338           File currentDirectory = chooser.getCurrentDirectory();
 1339   
 1340           if (readOnly || !canWrite(currentDirectory)) {
 1341               return;
 1342           }
 1343   
 1344           ensureIndexIsVisible(index);
 1345           switch (viewType) {
 1346             case VIEWTYPE_LIST:
 1347               editFile = (File)getModel().getElementAt(getRowSorter().convertRowIndexToModel(index));
 1348               Rectangle r = list.getCellBounds(index, index);
 1349               if (editCell == null) {
 1350                   editCell = new JTextField();
 1351                   editCell.setName("Tree.cellEditor");
 1352                   editCell.addActionListener(new EditActionListener());
 1353                   editCell.addFocusListener(editorFocusListener);
 1354                   editCell.setNextFocusableComponent(list);
 1355               }
 1356               list.add(editCell);
 1357               editCell.setText(chooser.getName(editFile));
 1358               ComponentOrientation orientation = list.getComponentOrientation();
 1359               editCell.setComponentOrientation(orientation);
 1360   
 1361               Icon icon = chooser.getIcon(editFile);
 1362   
 1363               // PENDING - grab padding (4) below from defaults table.
 1364               int editX = icon == null ? 20 : icon.getIconWidth() + 4;
 1365   
 1366               if (orientation.isLeftToRight()) {
 1367                   editCell.setBounds(editX + r.x, r.y, r.width - editX, r.height);
 1368               } else {
 1369                   editCell.setBounds(r.x, r.y, r.width - editX, r.height);
 1370               }
 1371               editCell.requestFocus();
 1372               editCell.selectAll();
 1373               break;
 1374   
 1375             case VIEWTYPE_DETAILS:
 1376               detailsTable.editCellAt(index, COLUMN_FILENAME);
 1377               break;
 1378           }
 1379       }
 1380   
 1381   
 1382       class EditActionListener implements ActionListener {
 1383           public void actionPerformed(ActionEvent e) {
 1384               applyEdit();
 1385           }
 1386       }
 1387   
 1388       private void applyEdit() {
 1389           if (editFile != null && editFile.exists()) {
 1390               JFileChooser chooser = getFileChooser();
 1391               String oldDisplayName = chooser.getName(editFile);
 1392               String oldFileName = editFile.getName();
 1393               String newDisplayName = editCell.getText().trim();
 1394               String newFileName;
 1395   
 1396               if (!newDisplayName.equals(oldDisplayName)) {
 1397                   newFileName = newDisplayName;
 1398                   //Check if extension is hidden from user
 1399                   int i1 = oldFileName.length();
 1400                   int i2 = oldDisplayName.length();
 1401                   if (i1 > i2 && oldFileName.charAt(i2) == '.') {
 1402                       newFileName = newDisplayName + oldFileName.substring(i2);
 1403                   }
 1404   
 1405                   // rename
 1406                   FileSystemView fsv = chooser.getFileSystemView();
 1407                   File f2 = fsv.createFileObject(editFile.getParentFile(), newFileName);
 1408                   if (f2.exists()) {
 1409                       JOptionPane.showMessageDialog(chooser, MessageFormat.format(renameErrorFileExistsText, oldFileName),
 1410                               renameErrorTitleText, JOptionPane.ERROR_MESSAGE);
 1411                   } else {
 1412                       if (getModel().renameFile(editFile, f2)) {
 1413                           if (fsv.isParent(chooser.getCurrentDirectory(), f2)) {
 1414                               if (chooser.isMultiSelectionEnabled()) {
 1415                                   chooser.setSelectedFiles(new File[]{f2});
 1416                               } else {
 1417                                   chooser.setSelectedFile(f2);
 1418                               }
 1419                           } else {
 1420                               //Could be because of delay in updating Desktop folder
 1421                               //chooser.setSelectedFile(null);
 1422                           }
 1423                       } else {
 1424                           JOptionPane.showMessageDialog(chooser, MessageFormat.format(renameErrorText, oldFileName),
 1425                                   renameErrorTitleText, JOptionPane.ERROR_MESSAGE);
 1426                       }
 1427                   }
 1428               }
 1429           }
 1430           if (detailsTable != null && detailsTable.isEditing()) {
 1431               detailsTable.getCellEditor().stopCellEditing();
 1432           }
 1433           cancelEdit();
 1434       }
 1435   
 1436       protected Action newFolderAction;
 1437   
 1438       public Action getNewFolderAction() {
 1439           if (!readOnly && newFolderAction == null) {
 1440               newFolderAction = new AbstractAction(newFolderActionLabelText) {
 1441                   private Action basicNewFolderAction;
 1442   
 1443                   // Initializer
 1444                   {
 1445                       putValue(Action.ACTION_COMMAND_KEY, FilePane.ACTION_NEW_FOLDER);
 1446   
 1447                       File currentDirectory = getFileChooser().getCurrentDirectory();
 1448                       if (currentDirectory != null) {
 1449                           setEnabled(canWrite(currentDirectory));
 1450                       }
 1451                   }
 1452   
 1453                   public void actionPerformed(ActionEvent ev) {
 1454                       if (basicNewFolderAction == null) {
 1455                           basicNewFolderAction = fileChooserUIAccessor.getNewFolderAction();
 1456                       }
 1457                       JFileChooser fc = getFileChooser();
 1458                       File oldFile = fc.getSelectedFile();
 1459                       basicNewFolderAction.actionPerformed(ev);
 1460                       File newFile = fc.getSelectedFile();
 1461                       if (newFile != null && !newFile.equals(oldFile) && newFile.isDirectory()) {
 1462                           newFolderFile = newFile;
 1463                       }
 1464                   }
 1465               };
 1466           }
 1467           return newFolderAction;
 1468       }
 1469   
 1470       protected class FileRenderer extends DefaultListCellRenderer  {
 1471   
 1472           public Component getListCellRendererComponent(JList list, Object value,
 1473                                                         int index, boolean isSelected,
 1474                                                         boolean cellHasFocus) {
 1475   
 1476               if (listViewWindowsStyle && !list.isFocusOwner()) {
 1477                   isSelected = false;
 1478               }
 1479   
 1480               super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
 1481               File file = (File) value;
 1482               String fileName = getFileChooser().getName(file);
 1483               setText(fileName);
 1484               setFont(list.getFont());
 1485   
 1486               Icon icon = getFileChooser().getIcon(file);
 1487               if (icon != null) {
 1488                   setIcon(icon);
 1489               } else {
 1490                   if (getFileChooser().getFileSystemView().isTraversable(file)) {
 1491                       setText(fileName+File.separator);
 1492                   }
 1493               }
 1494   
 1495               return this;
 1496           }
 1497       }
 1498   
 1499   
 1500       void setFileSelected() {
 1501           if (getFileChooser().isMultiSelectionEnabled() && !isDirectorySelected()) {
 1502               File[] files = getFileChooser().getSelectedFiles(); // Should be selected
 1503               Object[] selectedObjects = list.getSelectedValues(); // Are actually selected
 1504   
 1505               listSelectionModel.setValueIsAdjusting(true);
 1506               try {
 1507                   int lead = listSelectionModel.getLeadSelectionIndex();
 1508                   int anchor = listSelectionModel.getAnchorSelectionIndex();
 1509   
 1510                   Arrays.sort(files);
 1511                   Arrays.sort(selectedObjects);
 1512   
 1513                   int shouldIndex = 0;
 1514                   int actuallyIndex = 0;
 1515   
 1516                   // Remove files that shouldn't be selected and add files which should be selected
 1517                   // Note: Assume files are already sorted in compareTo order.
 1518                   while (shouldIndex < files.length &&
 1519                          actuallyIndex < selectedObjects.length) {
 1520                       int comparison = files[shouldIndex].compareTo((File)selectedObjects[actuallyIndex]);
 1521                       if (comparison < 0) {
 1522                           doSelectFile(files[shouldIndex++]);
 1523                       } else if (comparison > 0) {
 1524                           doDeselectFile(selectedObjects[actuallyIndex++]);
 1525                       } else {
 1526                           // Do nothing
 1527                           shouldIndex++;
 1528                           actuallyIndex++;
 1529                       }
 1530   
 1531                   }
 1532   
 1533                   while (shouldIndex < files.length) {
 1534                       doSelectFile(files[shouldIndex++]);
 1535                   }
 1536   
 1537                   while (actuallyIndex < selectedObjects.length) {
 1538                       doDeselectFile(selectedObjects[actuallyIndex++]);
 1539                   }
 1540   
 1541                   // restore the anchor and lead
 1542                   if (listSelectionModel instanceof DefaultListSelectionModel) {
 1543                       ((DefaultListSelectionModel)listSelectionModel).
 1544                           moveLeadSelectionIndex(lead);
 1545                       listSelectionModel.setAnchorSelectionIndex(anchor);
 1546                   }
 1547               } finally {
 1548                   listSelectionModel.setValueIsAdjusting(false);
 1549               }
 1550           } else {
 1551               JFileChooser chooser = getFileChooser();
 1552               File f;
 1553               if (isDirectorySelected()) {
 1554                   f = getDirectory();
 1555               } else {
 1556                   f = chooser.getSelectedFile();
 1557               }
 1558               int i;
 1559               if (f != null && (i = getModel().indexOf(f)) >= 0) {
 1560                   int viewIndex = getRowSorter().convertRowIndexToView(i);
 1561                   listSelectionModel.setSelectionInterval(viewIndex, viewIndex);
 1562                   ensureIndexIsVisible(viewIndex);
 1563               } else {
 1564                   clearSelection();
 1565               }
 1566           }
 1567       }
 1568   
 1569       private void doSelectFile(File fileToSelect) {
 1570           int index = getModel().indexOf(fileToSelect);
 1571           // could be missed in the current directory if it changed
 1572           if (index >= 0) {
 1573               index = getRowSorter().convertRowIndexToView(index);
 1574               listSelectionModel.addSelectionInterval(index, index);
 1575           }
 1576       }
 1577   
 1578       private void doDeselectFile(Object fileToDeselect) {
 1579           int index = getRowSorter().convertRowIndexToView(
 1580                                   getModel().indexOf(fileToDeselect));
 1581           listSelectionModel.removeSelectionInterval(index, index);
 1582       }
 1583   
 1584       /* The following methods are used by the PropertyChange Listener */
 1585   
 1586       private void doSelectedFileChanged(PropertyChangeEvent e) {
 1587           applyEdit();
 1588           File f = (File) e.getNewValue();
 1589           JFileChooser fc = getFileChooser();
 1590           if (f != null
 1591               && ((fc.isFileSelectionEnabled() && !f.isDirectory())
 1592                   || (f.isDirectory() && fc.isDirectorySelectionEnabled()))) {
 1593   
 1594               setFileSelected();
 1595           }
 1596       }
 1597   
 1598       private void doSelectedFilesChanged(PropertyChangeEvent e) {
 1599           applyEdit();
 1600           File[] files = (File[]) e.getNewValue();
 1601           JFileChooser fc = getFileChooser();
 1602           if (files != null
 1603               && files.length > 0
 1604               && (files.length > 1 || fc.isDirectorySelectionEnabled() || !files[0].isDirectory())) {
 1605               setFileSelected();
 1606           }
 1607       }
 1608   
 1609       private void doDirectoryChanged(PropertyChangeEvent e) {
 1610           getDetailsTableModel().updateColumnInfo();
 1611   
 1612           JFileChooser fc = getFileChooser();
 1613           FileSystemView fsv = fc.getFileSystemView();
 1614   
 1615           applyEdit();
 1616           resetEditIndex();
 1617           ensureIndexIsVisible(0);
 1618           File currentDirectory = fc.getCurrentDirectory();
 1619           if (currentDirectory != null) {
 1620               if (!readOnly) {
 1621                   getNewFolderAction().setEnabled(canWrite(currentDirectory));
 1622               }
 1623               fileChooserUIAccessor.getChangeToParentDirectoryAction().setEnabled(!fsv.isRoot(currentDirectory));
 1624           }
 1625           if (list != null) {
 1626               list.clearSelection();
 1627           }
 1628       }
 1629   
 1630       private void doFilterChanged(PropertyChangeEvent e) {
 1631           applyEdit();
 1632           resetEditIndex();
 1633           clearSelection();
 1634       }
 1635   
 1636       private void doFileSelectionModeChanged(PropertyChangeEvent e) {
 1637           applyEdit();
 1638           resetEditIndex();
 1639           clearSelection();
 1640       }
 1641   
 1642       private void doMultiSelectionChanged(PropertyChangeEvent e) {
 1643           if (getFileChooser().isMultiSelectionEnabled()) {
 1644               listSelectionModel.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
 1645           } else {
 1646               listSelectionModel.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
 1647               clearSelection();
 1648               getFileChooser().setSelectedFiles(null);
 1649           }
 1650       }
 1651   
 1652       /*
 1653        * Listen for filechooser property changes, such as
 1654        * the selected file changing, or the type of the dialog changing.
 1655        */
 1656       public void propertyChange(PropertyChangeEvent e) {
 1657               if (viewType == -1) {
 1658                   setViewType(VIEWTYPE_LIST);
 1659               }
 1660   
 1661           String s = e.getPropertyName();
 1662           if (s.equals(JFileChooser.SELECTED_FILE_CHANGED_PROPERTY)) {
 1663               doSelectedFileChanged(e);
 1664           } else if (s.equals(JFileChooser.SELECTED_FILES_CHANGED_PROPERTY)) {
 1665               doSelectedFilesChanged(e);
 1666           } else if (s.equals(JFileChooser.DIRECTORY_CHANGED_PROPERTY)) {
 1667               doDirectoryChanged(e);
 1668           } else if (s.equals(JFileChooser.FILE_FILTER_CHANGED_PROPERTY)) {
 1669               doFilterChanged(e);
 1670           } else if (s.equals(JFileChooser.FILE_SELECTION_MODE_CHANGED_PROPERTY)) {
 1671               doFileSelectionModeChanged(e);
 1672           } else if (s.equals(JFileChooser.MULTI_SELECTION_ENABLED_CHANGED_PROPERTY)) {
 1673               doMultiSelectionChanged(e);
 1674           } else if (s.equals(JFileChooser.CANCEL_SELECTION)) {
 1675               applyEdit();
 1676           } else if (s.equals("busy")) {
 1677               setCursor((Boolean)e.getNewValue() ? waitCursor : null);
 1678           } else if (s.equals("componentOrientation")) {
 1679               ComponentOrientation o = (ComponentOrientation)e.getNewValue();
 1680               JFileChooser cc = (JFileChooser)e.getSource();
 1681               if (o != e.getOldValue()) {
 1682                   cc.applyComponentOrientation(o);
 1683               }
 1684               if (detailsTable != null) {
 1685                   detailsTable.setComponentOrientation(o);
 1686                   detailsTable.getParent().getParent().setComponentOrientation(o);
 1687               }
 1688           }
 1689       }
 1690   
 1691       private void ensureIndexIsVisible(int i) {
 1692           if (i >= 0) {
 1693               if (list != null) {
 1694                   list.ensureIndexIsVisible(i);
 1695               }
 1696               if (detailsTable != null) {
 1697                   detailsTable.scrollRectToVisible(detailsTable.getCellRect(i, COLUMN_FILENAME, true));
 1698               }
 1699           }
 1700       }
 1701   
 1702       public void ensureFileIsVisible(JFileChooser fc, File f) {
 1703           int modelIndex = getModel().indexOf(f);
 1704           if (modelIndex >= 0) {
 1705               ensureIndexIsVisible(getRowSorter().convertRowIndexToView(modelIndex));
 1706           }
 1707       }
 1708   
 1709       public void rescanCurrentDirectory() {
 1710           getModel().validateFileCache();
 1711       }
 1712   
 1713       public void clearSelection() {
 1714           if (listSelectionModel != null) {
 1715               listSelectionModel.clearSelection();
 1716               if (listSelectionModel instanceof DefaultListSelectionModel) {
 1717                   ((DefaultListSelectionModel)listSelectionModel).moveLeadSelectionIndex(0);
 1718                   listSelectionModel.setAnchorSelectionIndex(0);
 1719               }
 1720           }
 1721       }
 1722   
 1723       public JMenu getViewMenu() {
 1724           if (viewMenu == null) {
 1725               viewMenu = new JMenu(viewMenuLabelText);
 1726               ButtonGroup viewButtonGroup = new ButtonGroup();
 1727   
 1728               for (int i = 0; i < VIEWTYPE_COUNT; i++) {
 1729                   JRadioButtonMenuItem mi =
 1730                       new JRadioButtonMenuItem(new ViewTypeAction(i));
 1731                   viewButtonGroup.add(mi);
 1732                   viewMenu.add(mi);
 1733               }
 1734               updateViewMenu();
 1735           }
 1736           return viewMenu;
 1737       }
 1738   
 1739       private void updateViewMenu() {
 1740           if (viewMenu != null) {
 1741               Component[] comps = viewMenu.getMenuComponents();
 1742               for (Component comp : comps) {
 1743                   if (comp instanceof JRadioButtonMenuItem) {
 1744                       JRadioButtonMenuItem mi = (JRadioButtonMenuItem) comp;
 1745                       if (((ViewTypeAction)mi.getAction()).viewType == viewType) {
 1746                           mi.setSelected(true);
 1747                       }
 1748                   }
 1749               }
 1750           }
 1751       }
 1752   
 1753       public JPopupMenu getComponentPopupMenu() {
 1754           JPopupMenu popupMenu = getFileChooser().getComponentPopupMenu();
 1755           if (popupMenu != null) {
 1756               return popupMenu;
 1757           }
 1758   
 1759           JMenu viewMenu = getViewMenu();
 1760           if (contextMenu == null) {
 1761               contextMenu = new JPopupMenu();
 1762               if (viewMenu != null) {
 1763                   contextMenu.add(viewMenu);
 1764                   if (listViewWindowsStyle) {
 1765                       contextMenu.addSeparator();
 1766                   }
 1767               }
 1768               ActionMap actionMap = getActionMap();
 1769               Action refreshAction   = actionMap.get(ACTION_REFRESH);
 1770               Action newFolderAction = actionMap.get(ACTION_NEW_FOLDER);
 1771               if (refreshAction != null) {
 1772                   contextMenu.add(refreshAction);
 1773                   if (listViewWindowsStyle && newFolderAction != null) {
 1774                       contextMenu.addSeparator();
 1775                   }
 1776               }
 1777               if (newFolderAction != null) {
 1778                   contextMenu.add(newFolderAction);
 1779               }
 1780           }
 1781           if (viewMenu != null) {
 1782               viewMenu.getPopupMenu().setInvoker(viewMenu);
 1783           }
 1784           return contextMenu;
 1785       }
 1786   
 1787   
 1788       private Handler handler;
 1789   
 1790       protected Handler getMouseHandler() {
 1791           if (handler == null) {
 1792               handler = new Handler();
 1793           }
 1794           return handler;
 1795       }
 1796   
 1797       private class Handler implements MouseListener {
 1798           private MouseListener doubleClickListener;
 1799   
 1800           public void mouseClicked(MouseEvent evt) {
 1801               JComponent source = (JComponent)evt.getSource();
 1802   
 1803               int index;
 1804               if (source instanceof JList) {
 1805                   index = SwingUtilities2.loc2IndexFileList(list, evt.getPoint());
 1806               } else if (source instanceof JTable) {
 1807                   JTable table = (JTable)source;
 1808                   Point p = evt.getPoint();
 1809                   index = table.rowAtPoint(p);
 1810   
 1811                   boolean pointOutsidePrefSize =
 1812                           SwingUtilities2.pointOutsidePrefSize(
 1813                               table, index, table.columnAtPoint(p), p);
 1814   
 1815                   if (pointOutsidePrefSize && !fullRowSelection) {
 1816                       return;
 1817                   }
 1818   
 1819                   // Translate point from table to list
 1820                   if (index >= 0 && list != null &&
 1821                       listSelectionModel.isSelectedIndex(index)) {
 1822   
 1823                       // Make a new event with the list as source, placing the
 1824                       // click in the corresponding list cell.
 1825                       Rectangle r = list.getCellBounds(index, index);
 1826                       evt = new MouseEvent(list, evt.getID(),
 1827                                            evt.getWhen(), evt.getModifiers(),
 1828                                            r.x + 1, r.y + r.height/2,
 1829                                            evt.getXOnScreen(),
 1830                                            evt.getYOnScreen(),
 1831                                            evt.getClickCount(), evt.isPopupTrigger(),
 1832                                            evt.getButton());
 1833                   }
 1834               } else {
 1835                   return;
 1836               }
 1837   
 1838               if (index >= 0 && SwingUtilities.isLeftMouseButton(evt)) {
 1839                   JFileChooser fc = getFileChooser();
 1840   
 1841                   // For single click, we handle editing file name
 1842                   if (evt.getClickCount() == 1 && source instanceof JList) {
 1843                       if ((!fc.isMultiSelectionEnabled() || fc.getSelectedFiles().length <= 1)
 1844                           && index >= 0 && listSelectionModel.isSelectedIndex(index)
 1845                           && getEditIndex() == index && editFile == null) {
 1846   
 1847                           editFileName(index);
 1848                       } else {
 1849                           if (index >= 0) {
 1850                               setEditIndex(index);
 1851                           } else {
 1852                               resetEditIndex();
 1853                           }
 1854                       }
 1855                   } else if (evt.getClickCount() == 2) {
 1856                       // on double click (open or drill down one directory) be
 1857                       // sure to clear the edit index
 1858                       resetEditIndex();
 1859                   }
 1860               }
 1861   
 1862               // Forward event to Basic
 1863               if (getDoubleClickListener() != null) {
 1864                   getDoubleClickListener().mouseClicked(evt);
 1865               }
 1866           }
 1867   
 1868           public void mouseEntered(MouseEvent evt) {
 1869               JComponent source = (JComponent)evt.getSource();
 1870               if (source instanceof JTable) {
 1871                   JTable table = (JTable)evt.getSource();
 1872   
 1873                   TransferHandler th1 = getFileChooser().getTransferHandler();
 1874                   TransferHandler th2 = table.getTransferHandler();
 1875                   if (th1 != th2) {
 1876                       table.setTransferHandler(th1);
 1877                   }
 1878   
 1879                   boolean dragEnabled = getFileChooser().getDragEnabled();
 1880                   if (dragEnabled != table.getDragEnabled()) {
 1881                       table.setDragEnabled(dragEnabled);
 1882                   }
 1883               } else if (source instanceof JList) {
 1884                   // Forward event to Basic
 1885                   if (getDoubleClickListener() != null) {
 1886                       getDoubleClickListener().mouseEntered(evt);
 1887                   }
 1888               }
 1889           }
 1890   
 1891           public void mouseExited(MouseEvent evt) {
 1892               if (evt.getSource() instanceof JList) {
 1893                   // Forward event to Basic
 1894                   if (getDoubleClickListener() != null) {
 1895                       getDoubleClickListener().mouseExited(evt);
 1896                   }
 1897               }
 1898           }
 1899   
 1900           public void mousePressed(MouseEvent evt) {
 1901               if (evt.getSource() instanceof JList) {
 1902                   // Forward event to Basic
 1903                   if (getDoubleClickListener() != null) {
 1904                       getDoubleClickListener().mousePressed(evt);
 1905                   }
 1906               }
 1907           }
 1908   
 1909           public void mouseReleased(MouseEvent evt) {
 1910               if (evt.getSource() instanceof JList) {
 1911                   // Forward event to Basic
 1912                   if (getDoubleClickListener() != null) {
 1913                       getDoubleClickListener().mouseReleased(evt);
 1914                   }
 1915               }
 1916           }
 1917   
 1918           private MouseListener getDoubleClickListener() {
 1919               // Lazy creation of Basic's listener
 1920               if (doubleClickListener == null && list != null) {
 1921                   doubleClickListener =
 1922                       fileChooserUIAccessor.createDoubleClickListener(list);
 1923               }
 1924               return doubleClickListener;
 1925           }
 1926       }
 1927   
 1928       /**
 1929        * Property to remember whether a directory is currently selected in the UI.
 1930        *
 1931        * @return <code>true</code> iff a directory is currently selected.
 1932        */
 1933       protected boolean isDirectorySelected() {
 1934           return fileChooserUIAccessor.isDirectorySelected();
 1935       }
 1936   
 1937   
 1938       /**
 1939        * Property to remember the directory that is currently selected in the UI.
 1940        *
 1941        * @return the value of the <code>directory</code> property
 1942        * @see javax.swing.plaf.basic.BasicFileChooserUI#setDirectory
 1943        */
 1944       protected File getDirectory() {
 1945           return fileChooserUIAccessor.getDirectory();
 1946       }
 1947   
 1948       private Component findChildComponent(Container container, Class cls) {
 1949           int n = container.getComponentCount();
 1950           for (int i = 0; i < n; i++) {
 1951               Component comp = container.getComponent(i);
 1952               if (cls.isInstance(comp)) {
 1953                   return comp;
 1954               } else if (comp instanceof Container) {
 1955                   Component c = findChildComponent((Container)comp, cls);
 1956                   if (c != null) {
 1957                       return c;
 1958                   }
 1959               }
 1960           }
 1961           return null;
 1962       }
 1963   
 1964       public boolean canWrite(File f) {
 1965           // Return false for non FileSystem files or if file doesn't exist.
 1966           if (!f.exists()) {
 1967               return false;
 1968           }
 1969   
 1970           if (f instanceof ShellFolder) {
 1971               return ((ShellFolder) f).isFileSystem();
 1972           } else {
 1973               if (usesShellFolder(getFileChooser())) {
 1974                   try {
 1975                       return ShellFolder.getShellFolder(f).isFileSystem();
 1976                   } catch (FileNotFoundException ex) {
 1977                       // File doesn't exist
 1978                       return false;
 1979                   }
 1980               } else {
 1981                   // Ordinary file
 1982                   return true;
 1983               }
 1984           }
 1985       }
 1986   
 1987       /**
 1988        * Returns true if specified FileChooser should use ShellFolder
 1989        */
 1990       public static boolean usesShellFolder(JFileChooser chooser) {
 1991           Boolean prop = (Boolean) chooser.getClientProperty("FileChooser.useShellFolder");
 1992   
 1993           return prop == null ? chooser.getFileSystemView().equals(FileSystemView.getFileSystemView())
 1994                   : prop.booleanValue();
 1995       }
 1996   
 1997       // This interface is used to access methods in the FileChooserUI
 1998       // that are not public.
 1999       public interface FileChooserUIAccessor {
 2000           public JFileChooser getFileChooser();
 2001           public BasicDirectoryModel getModel();
 2002           public JPanel createList();
 2003           public JPanel createDetailsView();
 2004           public boolean isDirectorySelected();
 2005           public File getDirectory();
 2006           public Action getApproveSelectionAction();
 2007           public Action getChangeToParentDirectoryAction();
 2008           public Action getNewFolderAction();
 2009           public MouseListener createDoubleClickListener(JList list);
 2010           public ListSelectionListener createListSelectionListener();
 2011       }
 2012   }

Save This Page
Home » openjdk-7 » sun » swing » [javadoc | source]