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

Print this page


   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


  41 import javax.swing.event.*;
  42 import javax.swing.filechooser.*;
  43 import javax.swing.plaf.basic.*;
  44 import javax.swing.table.*;
  45 import javax.swing.text.*;
  46 
  47 import sun.awt.shell.*;
  48 
  49 /**
  50  * <b>WARNING:</b> This class is an implementation detail and is only
  51  * public so that it can be used by two packages. You should NOT consider
  52  * this public API.
  53  * <p>
  54  * This component is intended to be used in a subclass of
  55  * javax.swing.plaf.basic.BasicFileChooserUI. It realies heavily on the
  56  * implementation of BasicFileChooserUI, and is intended to be API compatible
  57  * with earlier implementations of MetalFileChooserUI and WindowsFileChooserUI.
  58  *
  59  * @author Leif Samuelsson
  60  */

  61 public class FilePane extends JPanel implements PropertyChangeListener {
  62     // Constants for actions. These are used for the actions' ACTION_COMMAND_KEY
  63     // and as keys in the action maps for FilePane and the corresponding UI classes
  64 
  65     public final static String ACTION_APPROVE_SELECTION = "approveSelection";
  66     public final static String ACTION_CANCEL            = "cancelSelection";
  67     public final static String ACTION_EDIT_FILE_NAME    = "editFileName";
  68     public final static String ACTION_REFRESH           = "refresh";
  69     public final static String ACTION_CHANGE_TO_PARENT_DIRECTORY = "Go Up";
  70     public final static String ACTION_NEW_FOLDER        = "New Folder";
  71     public final static String ACTION_VIEW_LIST         = "viewTypeList";
  72     public final static String ACTION_VIEW_DETAILS      = "viewTypeDetails";
  73 
  74     private Action[] actions;
  75 
  76     // "enums" for setViewType()
  77     public  static final int VIEWTYPE_LIST     = 0;
  78     public  static final int VIEWTYPE_DETAILS  = 1;
  79     private static final int VIEWTYPE_COUNT    = 2;
  80 


 374                     getCurrentKeyboardFocusManager().getPermanentFocusOwner();
 375 
 376             isFocusOwner = owner == detailsTable || owner == list;
 377 
 378             remove(currentViewPanel);
 379         }
 380 
 381         currentViewPanel = viewPanels[viewType];
 382         add(currentViewPanel, BorderLayout.CENTER);
 383 
 384         if (isFocusOwner && newFocusOwner != null) {
 385             newFocusOwner.requestFocusInWindow();
 386         }
 387 
 388         revalidate();
 389         repaint();
 390         updateViewMenu();
 391         firePropertyChange("viewType", oldValue, viewType);
 392     }
 393 

 394     class ViewTypeAction extends AbstractAction {
 395         private int viewType;
 396 
 397         ViewTypeAction(int viewType) {
 398             super(viewTypeActionNames[viewType]);
 399             this.viewType = viewType;
 400 
 401             String cmd;
 402             switch (viewType) {
 403                 case VIEWTYPE_LIST:    cmd = ACTION_VIEW_LIST;    break;
 404                 case VIEWTYPE_DETAILS: cmd = ACTION_VIEW_DETAILS; break;
 405                 default:               cmd = (String)getValue(Action.NAME);
 406             }
 407             putValue(Action.ACTION_COMMAND_KEY, cmd);
 408         }
 409 
 410         public void actionPerformed(ActionEvent e) {
 411             setViewType(viewType);
 412         }
 413     }


 453         megaByteString = UIManager.getString("FileChooser.fileSizeMegaBytes", l);
 454         gigaByteString = UIManager.getString("FileChooser.fileSizeGigaBytes", l);
 455         fullRowSelection = UIManager.getBoolean("FileView.fullRowSelection");
 456 
 457         filesListAccessibleName = UIManager.getString("FileChooser.filesListAccessibleName", l);
 458         filesDetailsAccessibleName = UIManager.getString("FileChooser.filesDetailsAccessibleName", l);
 459 
 460         renameErrorTitleText = UIManager.getString("FileChooser.renameErrorTitleText", l);
 461         renameErrorText = UIManager.getString("FileChooser.renameErrorText", l);
 462         renameErrorFileExistsText = UIManager.getString("FileChooser.renameErrorFileExistsText", l);
 463     }
 464 
 465     /**
 466      * Fetches the command list for the FilePane. These commands
 467      * are useful for binding to events, such as in a keymap.
 468      *
 469      * @return the command list
 470      */
 471     public Action[] getActions() {
 472         if (actions == null) {

 473             class FilePaneAction extends AbstractAction {
 474                 FilePaneAction(String name) {
 475                     this(name, name);
 476                 }
 477 
 478                 FilePaneAction(String name, String cmd) {
 479                     super(name);
 480                     putValue(Action.ACTION_COMMAND_KEY, cmd);
 481                 }
 482 
 483                 public void actionPerformed(ActionEvent e) {
 484                     String cmd = (String)getValue(Action.ACTION_COMMAND_KEY);
 485 
 486                     if (cmd == ACTION_CANCEL) {
 487                         if (editFile != null) {
 488                            cancelEdit();
 489                         } else {
 490                            getFileChooser().cancelSelection();
 491                         }
 492                     } else if (cmd == ACTION_EDIT_FILE_NAME) {


 560                 if (cmd == null) {
 561                     cmd = (String)a.getValue(Action.NAME);
 562                 }
 563                 map.put(cmd, a);
 564             }
 565         }
 566     }
 567 
 568 
 569     private void updateListRowCount(JList list) {
 570         if (smallIconsView) {
 571             list.setVisibleRowCount(getModel().getSize() / 3);
 572         } else {
 573             list.setVisibleRowCount(-1);
 574         }
 575     }
 576 
 577     public JPanel createList() {
 578         JPanel p = new JPanel(new BorderLayout());
 579         final JFileChooser fileChooser = getFileChooser();


 580         final JList<Object> list = new JList<Object>() {
 581             public int getNextMatch(String prefix, int startIndex, Position.Bias bias) {
 582                 ListModel model = getModel();
 583                 int max = model.getSize();
 584                 if (prefix == null || startIndex < 0 || startIndex >= max) {
 585                     throw new IllegalArgumentException();
 586                 }
 587                 // start search from the next element before/after the selected element
 588                 boolean backwards = (bias == Position.Bias.Backward);
 589                 for (int i = startIndex; backwards ? i >= 0 : i < max; i += (backwards ?  -1 : 1)) {
 590                     String filename = fileChooser.getName((File)model.getElementAt(i));
 591                     if (filename.regionMatches(true, 0, prefix, 0, prefix.length())) {
 592                         return i;
 593                     }
 594                 }
 595                 return -1;
 596             }
 597         };
 598         list.setCellRenderer(new FileRenderer());
 599         list.setLayoutOrientation(JList.VERTICAL_WRAP);


 634         list.addListSelectionListener(createListSelectionListener());
 635         list.addMouseListener(getMouseHandler());
 636 
 637         JScrollPane scrollpane = new JScrollPane(list);
 638         if (listViewBackground != null) {
 639             list.setBackground(listViewBackground);
 640         }
 641         if (listViewBorder != null) {
 642             scrollpane.setBorder(listViewBorder);
 643         }
 644 
 645         list.putClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY, filesListAccessibleName);
 646 
 647         p.add(scrollpane, BorderLayout.CENTER);
 648         return p;
 649     }
 650 
 651     /**
 652      * This model allows for sorting JList
 653      */

 654     private class SortableListModel extends AbstractListModel<Object>
 655             implements TableModelListener, RowSorterListener {
 656 
 657         public SortableListModel() {
 658             getDetailsTableModel().addTableModelListener(this);
 659             getRowSorter().addRowSorterListener(this);
 660         }
 661 
 662         public int getSize() {
 663             return getModel().getSize();
 664         }
 665 
 666         public Object getElementAt(int index) {
 667             // JList doesn't support RowSorter so far, so we put it into the list model
 668             return getModel().getElementAt(getRowSorter().convertRowIndexToModel(index));
 669         }
 670 
 671         public void tableChanged(TableModelEvent e) {
 672             fireContentsChanged(this, 0, getSize());
 673         }
 674 
 675         public void sorterChanged(RowSorterEvent e) {
 676             fireContentsChanged(this, 0, getSize());
 677         }
 678     }
 679 
 680     private DetailsTableModel getDetailsTableModel() {
 681         if(detailsTableModel == null) {
 682             detailsTableModel = new DetailsTableModel(getFileChooser());
 683         }
 684         return detailsTableModel;
 685     }
 686 

 687     class DetailsTableModel extends AbstractTableModel implements ListDataListener {
 688         JFileChooser chooser;
 689         BasicDirectoryModel directoryModel;
 690 
 691         ShellFolderColumnInfo[] columns;
 692         int[] columnMap;
 693 
 694         DetailsTableModel(JFileChooser fc) {
 695             this.chooser = fc;
 696             directoryModel = getModel();
 697             directoryModel.addListDataListener(this);
 698 
 699             updateColumnInfo();
 700         }
 701 
 702         void updateColumnInfo() {
 703             File dir = chooser.getCurrentDirectory();
 704             if (dir != null && usesShellFolder(chooser)) {
 705                 try {
 706                     dir = ShellFolder.getShellFolder(dir);


 986                 return comparator.compare(
 987                         getDetailsTableModel().getFileColumnValue(f1, column),
 988                         getDetailsTableModel().getFileColumnValue(f2, column)
 989                 );
 990             }
 991             // For this column we need to pass the file itself (not a
 992             // column value) to the comparator
 993             return comparator.compare(f1, f2);
 994         }
 995     }
 996 
 997     private DetailsTableCellEditor tableCellEditor;
 998 
 999     private DetailsTableCellEditor getDetailsTableCellEditor() {
1000         if (tableCellEditor == null) {
1001             tableCellEditor = new DetailsTableCellEditor(new JTextField());
1002         }
1003         return tableCellEditor;
1004     }
1005 

1006     private class DetailsTableCellEditor extends DefaultCellEditor {
1007         private final JTextField tf;
1008 
1009         public DetailsTableCellEditor(JTextField tf) {
1010             super(tf);
1011             this.tf = tf;
1012             tf.setName("Table.editor");
1013             tf.addFocusListener(editorFocusListener);
1014         }
1015 
1016         public Component getTableCellEditorComponent(JTable table, Object value,
1017                                                      boolean isSelected, int row, int column) {
1018             Component comp = super.getTableCellEditorComponent(table, value,
1019                     isSelected, row, column);
1020             if (value instanceof File) {
1021                 tf.setText(getFileChooser().getName((File) value));
1022                 tf.selectAll();
1023             }
1024             return comp;
1025         }
1026     }
1027 
1028 
1029     class DetailsTableCellRenderer extends DefaultTableCellRenderer {
1030         JFileChooser chooser;
1031         DateFormat df;
1032 
1033         DetailsTableCellRenderer(JFileChooser chooser) {
1034             this.chooser = chooser;
1035             df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT,
1036                                                 chooser.getLocale());
1037         }
1038 
1039         public void setBounds(int x, int y, int width, int height) {
1040         if (getHorizontalAlignment() == SwingConstants.LEADING &&
1041                     !fullRowSelection) {
1042                 // Restrict width to actual text
1043                 width = Math.min(width, this.getPreferredSize().width+4);
1044             } else {
1045                 x -= 4;
1046             }
1047             super.setBounds(x, y, width, height);
1048         }


1112                 }
1113 
1114             } else if (value instanceof Date) {
1115                 text = df.format((Date)value);
1116 
1117             } else {
1118                 text = value.toString();
1119             }
1120 
1121             setText(text);
1122 
1123             return this;
1124         }
1125     }
1126 
1127     public JPanel createDetailsView() {
1128         final JFileChooser chooser = getFileChooser();
1129 
1130         JPanel p = new JPanel(new BorderLayout());
1131 

1132         final JTable detailsTable = new JTable(getDetailsTableModel()) {
1133             // Handle Escape key events here
1134             protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) {
1135                 if (e.getKeyCode() == KeyEvent.VK_ESCAPE && getCellEditor() == null) {
1136                     // We are not editing, forward to filechooser.
1137                     chooser.dispatchEvent(e);
1138                     return true;
1139                 }
1140                 return super.processKeyBinding(ks, e, condition, pressed);
1141             }
1142 
1143             public void tableChanged(TableModelEvent e) {
1144                 super.tableChanged(e);
1145 
1146                 if (e.getFirstRow() == TableModelEvent.HEADER_ROW) {
1147                     // update header with possibly changed column set
1148                     updateDetailsColumnModel(this);
1149                 }
1150             }
1151         };


1430                             }
1431                         } else {
1432                             //Could be because of delay in updating Desktop folder
1433                             //chooser.setSelectedFile(null);
1434                         }
1435                     } else {
1436                         JOptionPane.showMessageDialog(chooser, MessageFormat.format(renameErrorText, oldFileName),
1437                                 renameErrorTitleText, JOptionPane.ERROR_MESSAGE);
1438                     }
1439                 }
1440             }
1441         }
1442         if (detailsTable != null && detailsTable.isEditing()) {
1443             detailsTable.getCellEditor().stopCellEditing();
1444         }
1445         cancelEdit();
1446     }
1447 
1448     protected Action newFolderAction;
1449 

1450     public Action getNewFolderAction() {
1451         if (!readOnly && newFolderAction == null) {
1452             newFolderAction = new AbstractAction(newFolderActionLabelText) {
1453                 private Action basicNewFolderAction;
1454 
1455                 // Initializer
1456                 {
1457                     putValue(Action.ACTION_COMMAND_KEY, FilePane.ACTION_NEW_FOLDER);
1458 
1459                     File currentDirectory = getFileChooser().getCurrentDirectory();
1460                     if (currentDirectory != null) {
1461                         setEnabled(canWrite(currentDirectory));
1462                     }
1463                 }
1464 
1465                 public void actionPerformed(ActionEvent ev) {
1466                     if (basicNewFolderAction == null) {
1467                         basicNewFolderAction = fileChooserUIAccessor.getNewFolderAction();
1468                     }
1469                     JFileChooser fc = getFileChooser();
1470                     File oldFile = fc.getSelectedFile();
1471                     basicNewFolderAction.actionPerformed(ev);
1472                     File newFile = fc.getSelectedFile();
1473                     if (newFile != null && !newFile.equals(oldFile) && newFile.isDirectory()) {
1474                         newFolderFile = newFile;
1475                     }
1476                 }
1477             };
1478         }
1479         return newFolderAction;
1480     }
1481 

1482     protected class FileRenderer extends DefaultListCellRenderer  {
1483 
1484         public Component getListCellRendererComponent(JList list, Object value,
1485                                                       int index, boolean isSelected,
1486                                                       boolean cellHasFocus) {
1487 
1488             if (listViewWindowsStyle && !list.isFocusOwner()) {
1489                 isSelected = false;
1490             }
1491 
1492             super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
1493             File file = (File) value;
1494             String fileName = getFileChooser().getName(file);
1495             setText(fileName);
1496             setFont(list.getFont());
1497 
1498             Icon icon = getFileChooser().getIcon(file);
1499             if (icon != null) {
1500                 setIcon(icon);
1501             } else {


   1 /*
   2  * Copyright (c) 2003, 2014, 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


  41 import javax.swing.event.*;
  42 import javax.swing.filechooser.*;
  43 import javax.swing.plaf.basic.*;
  44 import javax.swing.table.*;
  45 import javax.swing.text.*;
  46 
  47 import sun.awt.shell.*;
  48 
  49 /**
  50  * <b>WARNING:</b> This class is an implementation detail and is only
  51  * public so that it can be used by two packages. You should NOT consider
  52  * this public API.
  53  * <p>
  54  * This component is intended to be used in a subclass of
  55  * javax.swing.plaf.basic.BasicFileChooserUI. It realies heavily on the
  56  * implementation of BasicFileChooserUI, and is intended to be API compatible
  57  * with earlier implementations of MetalFileChooserUI and WindowsFileChooserUI.
  58  *
  59  * @author Leif Samuelsson
  60  */
  61 @SuppressWarnings("serial") // JDK-implementation class
  62 public class FilePane extends JPanel implements PropertyChangeListener {
  63     // Constants for actions. These are used for the actions' ACTION_COMMAND_KEY
  64     // and as keys in the action maps for FilePane and the corresponding UI classes
  65 
  66     public final static String ACTION_APPROVE_SELECTION = "approveSelection";
  67     public final static String ACTION_CANCEL            = "cancelSelection";
  68     public final static String ACTION_EDIT_FILE_NAME    = "editFileName";
  69     public final static String ACTION_REFRESH           = "refresh";
  70     public final static String ACTION_CHANGE_TO_PARENT_DIRECTORY = "Go Up";
  71     public final static String ACTION_NEW_FOLDER        = "New Folder";
  72     public final static String ACTION_VIEW_LIST         = "viewTypeList";
  73     public final static String ACTION_VIEW_DETAILS      = "viewTypeDetails";
  74 
  75     private Action[] actions;
  76 
  77     // "enums" for setViewType()
  78     public  static final int VIEWTYPE_LIST     = 0;
  79     public  static final int VIEWTYPE_DETAILS  = 1;
  80     private static final int VIEWTYPE_COUNT    = 2;
  81 


 375                     getCurrentKeyboardFocusManager().getPermanentFocusOwner();
 376 
 377             isFocusOwner = owner == detailsTable || owner == list;
 378 
 379             remove(currentViewPanel);
 380         }
 381 
 382         currentViewPanel = viewPanels[viewType];
 383         add(currentViewPanel, BorderLayout.CENTER);
 384 
 385         if (isFocusOwner && newFocusOwner != null) {
 386             newFocusOwner.requestFocusInWindow();
 387         }
 388 
 389         revalidate();
 390         repaint();
 391         updateViewMenu();
 392         firePropertyChange("viewType", oldValue, viewType);
 393     }
 394 
 395     @SuppressWarnings("serial") // JDK-implementation class
 396     class ViewTypeAction extends AbstractAction {
 397         private int viewType;
 398 
 399         ViewTypeAction(int viewType) {
 400             super(viewTypeActionNames[viewType]);
 401             this.viewType = viewType;
 402 
 403             String cmd;
 404             switch (viewType) {
 405                 case VIEWTYPE_LIST:    cmd = ACTION_VIEW_LIST;    break;
 406                 case VIEWTYPE_DETAILS: cmd = ACTION_VIEW_DETAILS; break;
 407                 default:               cmd = (String)getValue(Action.NAME);
 408             }
 409             putValue(Action.ACTION_COMMAND_KEY, cmd);
 410         }
 411 
 412         public void actionPerformed(ActionEvent e) {
 413             setViewType(viewType);
 414         }
 415     }


 455         megaByteString = UIManager.getString("FileChooser.fileSizeMegaBytes", l);
 456         gigaByteString = UIManager.getString("FileChooser.fileSizeGigaBytes", l);
 457         fullRowSelection = UIManager.getBoolean("FileView.fullRowSelection");
 458 
 459         filesListAccessibleName = UIManager.getString("FileChooser.filesListAccessibleName", l);
 460         filesDetailsAccessibleName = UIManager.getString("FileChooser.filesDetailsAccessibleName", l);
 461 
 462         renameErrorTitleText = UIManager.getString("FileChooser.renameErrorTitleText", l);
 463         renameErrorText = UIManager.getString("FileChooser.renameErrorText", l);
 464         renameErrorFileExistsText = UIManager.getString("FileChooser.renameErrorFileExistsText", l);
 465     }
 466 
 467     /**
 468      * Fetches the command list for the FilePane. These commands
 469      * are useful for binding to events, such as in a keymap.
 470      *
 471      * @return the command list
 472      */
 473     public Action[] getActions() {
 474         if (actions == null) {
 475             @SuppressWarnings("serial") // JDK-implementation class
 476             class FilePaneAction extends AbstractAction {
 477                 FilePaneAction(String name) {
 478                     this(name, name);
 479                 }
 480 
 481                 FilePaneAction(String name, String cmd) {
 482                     super(name);
 483                     putValue(Action.ACTION_COMMAND_KEY, cmd);
 484                 }
 485 
 486                 public void actionPerformed(ActionEvent e) {
 487                     String cmd = (String)getValue(Action.ACTION_COMMAND_KEY);
 488 
 489                     if (cmd == ACTION_CANCEL) {
 490                         if (editFile != null) {
 491                            cancelEdit();
 492                         } else {
 493                            getFileChooser().cancelSelection();
 494                         }
 495                     } else if (cmd == ACTION_EDIT_FILE_NAME) {


 563                 if (cmd == null) {
 564                     cmd = (String)a.getValue(Action.NAME);
 565                 }
 566                 map.put(cmd, a);
 567             }
 568         }
 569     }
 570 
 571 
 572     private void updateListRowCount(JList list) {
 573         if (smallIconsView) {
 574             list.setVisibleRowCount(getModel().getSize() / 3);
 575         } else {
 576             list.setVisibleRowCount(-1);
 577         }
 578     }
 579 
 580     public JPanel createList() {
 581         JPanel p = new JPanel(new BorderLayout());
 582         final JFileChooser fileChooser = getFileChooser();
 583         
 584         @SuppressWarnings("serial") // anonymous class
 585         final JList<Object> list = new JList<Object>() {
 586             public int getNextMatch(String prefix, int startIndex, Position.Bias bias) {
 587                 ListModel model = getModel();
 588                 int max = model.getSize();
 589                 if (prefix == null || startIndex < 0 || startIndex >= max) {
 590                     throw new IllegalArgumentException();
 591                 }
 592                 // start search from the next element before/after the selected element
 593                 boolean backwards = (bias == Position.Bias.Backward);
 594                 for (int i = startIndex; backwards ? i >= 0 : i < max; i += (backwards ?  -1 : 1)) {
 595                     String filename = fileChooser.getName((File)model.getElementAt(i));
 596                     if (filename.regionMatches(true, 0, prefix, 0, prefix.length())) {
 597                         return i;
 598                     }
 599                 }
 600                 return -1;
 601             }
 602         };
 603         list.setCellRenderer(new FileRenderer());
 604         list.setLayoutOrientation(JList.VERTICAL_WRAP);


 639         list.addListSelectionListener(createListSelectionListener());
 640         list.addMouseListener(getMouseHandler());
 641 
 642         JScrollPane scrollpane = new JScrollPane(list);
 643         if (listViewBackground != null) {
 644             list.setBackground(listViewBackground);
 645         }
 646         if (listViewBorder != null) {
 647             scrollpane.setBorder(listViewBorder);
 648         }
 649 
 650         list.putClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY, filesListAccessibleName);
 651 
 652         p.add(scrollpane, BorderLayout.CENTER);
 653         return p;
 654     }
 655 
 656     /**
 657      * This model allows for sorting JList
 658      */
 659     @SuppressWarnings("serial") // JDK-implementation class
 660     private class SortableListModel extends AbstractListModel<Object>
 661             implements TableModelListener, RowSorterListener {
 662 
 663         public SortableListModel() {
 664             getDetailsTableModel().addTableModelListener(this);
 665             getRowSorter().addRowSorterListener(this);
 666         }
 667 
 668         public int getSize() {
 669             return getModel().getSize();
 670         }
 671 
 672         public Object getElementAt(int index) {
 673             // JList doesn't support RowSorter so far, so we put it into the list model
 674             return getModel().getElementAt(getRowSorter().convertRowIndexToModel(index));
 675         }
 676 
 677         public void tableChanged(TableModelEvent e) {
 678             fireContentsChanged(this, 0, getSize());
 679         }
 680 
 681         public void sorterChanged(RowSorterEvent e) {
 682             fireContentsChanged(this, 0, getSize());
 683         }
 684     }
 685 
 686     private DetailsTableModel getDetailsTableModel() {
 687         if(detailsTableModel == null) {
 688             detailsTableModel = new DetailsTableModel(getFileChooser());
 689         }
 690         return detailsTableModel;
 691     }
 692 
 693     @SuppressWarnings("serial") // JDK-implementation class
 694     class DetailsTableModel extends AbstractTableModel implements ListDataListener {
 695         JFileChooser chooser;
 696         BasicDirectoryModel directoryModel;
 697 
 698         ShellFolderColumnInfo[] columns;
 699         int[] columnMap;
 700 
 701         DetailsTableModel(JFileChooser fc) {
 702             this.chooser = fc;
 703             directoryModel = getModel();
 704             directoryModel.addListDataListener(this);
 705 
 706             updateColumnInfo();
 707         }
 708 
 709         void updateColumnInfo() {
 710             File dir = chooser.getCurrentDirectory();
 711             if (dir != null && usesShellFolder(chooser)) {
 712                 try {
 713                     dir = ShellFolder.getShellFolder(dir);


 993                 return comparator.compare(
 994                         getDetailsTableModel().getFileColumnValue(f1, column),
 995                         getDetailsTableModel().getFileColumnValue(f2, column)
 996                 );
 997             }
 998             // For this column we need to pass the file itself (not a
 999             // column value) to the comparator
1000             return comparator.compare(f1, f2);
1001         }
1002     }
1003 
1004     private DetailsTableCellEditor tableCellEditor;
1005 
1006     private DetailsTableCellEditor getDetailsTableCellEditor() {
1007         if (tableCellEditor == null) {
1008             tableCellEditor = new DetailsTableCellEditor(new JTextField());
1009         }
1010         return tableCellEditor;
1011     }
1012 
1013     @SuppressWarnings("serial") // JDK-implementation class
1014     private class DetailsTableCellEditor extends DefaultCellEditor {
1015         private final JTextField tf;
1016 
1017         public DetailsTableCellEditor(JTextField tf) {
1018             super(tf);
1019             this.tf = tf;
1020             tf.setName("Table.editor");
1021             tf.addFocusListener(editorFocusListener);
1022         }
1023 
1024         public Component getTableCellEditorComponent(JTable table, Object value,
1025                                                      boolean isSelected, int row, int column) {
1026             Component comp = super.getTableCellEditorComponent(table, value,
1027                     isSelected, row, column);
1028             if (value instanceof File) {
1029                 tf.setText(getFileChooser().getName((File) value));
1030                 tf.selectAll();
1031             }
1032             return comp;
1033         }
1034     }
1035 
1036     @SuppressWarnings("serial") // JDK-implementation class
1037     class DetailsTableCellRenderer extends DefaultTableCellRenderer {
1038         JFileChooser chooser;
1039         DateFormat df;
1040 
1041         DetailsTableCellRenderer(JFileChooser chooser) {
1042             this.chooser = chooser;
1043             df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT,
1044                                                 chooser.getLocale());
1045         }
1046 
1047         public void setBounds(int x, int y, int width, int height) {
1048         if (getHorizontalAlignment() == SwingConstants.LEADING &&
1049                     !fullRowSelection) {
1050                 // Restrict width to actual text
1051                 width = Math.min(width, this.getPreferredSize().width+4);
1052             } else {
1053                 x -= 4;
1054             }
1055             super.setBounds(x, y, width, height);
1056         }


1120                 }
1121 
1122             } else if (value instanceof Date) {
1123                 text = df.format((Date)value);
1124 
1125             } else {
1126                 text = value.toString();
1127             }
1128 
1129             setText(text);
1130 
1131             return this;
1132         }
1133     }
1134 
1135     public JPanel createDetailsView() {
1136         final JFileChooser chooser = getFileChooser();
1137 
1138         JPanel p = new JPanel(new BorderLayout());
1139 
1140         @SuppressWarnings("serial") // anonymous class
1141         final JTable detailsTable = new JTable(getDetailsTableModel()) {
1142             // Handle Escape key events here
1143             protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) {
1144                 if (e.getKeyCode() == KeyEvent.VK_ESCAPE && getCellEditor() == null) {
1145                     // We are not editing, forward to filechooser.
1146                     chooser.dispatchEvent(e);
1147                     return true;
1148                 }
1149                 return super.processKeyBinding(ks, e, condition, pressed);
1150             }
1151 
1152             public void tableChanged(TableModelEvent e) {
1153                 super.tableChanged(e);
1154 
1155                 if (e.getFirstRow() == TableModelEvent.HEADER_ROW) {
1156                     // update header with possibly changed column set
1157                     updateDetailsColumnModel(this);
1158                 }
1159             }
1160         };


1439                             }
1440                         } else {
1441                             //Could be because of delay in updating Desktop folder
1442                             //chooser.setSelectedFile(null);
1443                         }
1444                     } else {
1445                         JOptionPane.showMessageDialog(chooser, MessageFormat.format(renameErrorText, oldFileName),
1446                                 renameErrorTitleText, JOptionPane.ERROR_MESSAGE);
1447                     }
1448                 }
1449             }
1450         }
1451         if (detailsTable != null && detailsTable.isEditing()) {
1452             detailsTable.getCellEditor().stopCellEditing();
1453         }
1454         cancelEdit();
1455     }
1456 
1457     protected Action newFolderAction;
1458 
1459     @SuppressWarnings("serial") // anonymous class inside
1460     public Action getNewFolderAction() {
1461         if (!readOnly && newFolderAction == null) {
1462             newFolderAction = new AbstractAction(newFolderActionLabelText) {
1463                 private Action basicNewFolderAction;
1464 
1465                 // Initializer
1466                 {
1467                     putValue(Action.ACTION_COMMAND_KEY, FilePane.ACTION_NEW_FOLDER);
1468 
1469                     File currentDirectory = getFileChooser().getCurrentDirectory();
1470                     if (currentDirectory != null) {
1471                         setEnabled(canWrite(currentDirectory));
1472                     }
1473                 }
1474 
1475                 public void actionPerformed(ActionEvent ev) {
1476                     if (basicNewFolderAction == null) {
1477                         basicNewFolderAction = fileChooserUIAccessor.getNewFolderAction();
1478                     }
1479                     JFileChooser fc = getFileChooser();
1480                     File oldFile = fc.getSelectedFile();
1481                     basicNewFolderAction.actionPerformed(ev);
1482                     File newFile = fc.getSelectedFile();
1483                     if (newFile != null && !newFile.equals(oldFile) && newFile.isDirectory()) {
1484                         newFolderFile = newFile;
1485                     }
1486                 }
1487             };
1488         }
1489         return newFolderAction;
1490     }
1491 
1492     @SuppressWarnings("serial") // JDK-implementation class
1493     protected class FileRenderer extends DefaultListCellRenderer  {
1494         
1495         public Component getListCellRendererComponent(JList list, Object value,
1496                                                       int index, boolean isSelected,
1497                                                       boolean cellHasFocus) {
1498 
1499             if (listViewWindowsStyle && !list.isFocusOwner()) {
1500                 isSelected = false;
1501             }
1502 
1503             super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
1504             File file = (File) value;
1505             String fileName = getFileChooser().getName(file);
1506             setText(fileName);
1507             setFont(list.getFont());
1508 
1509             Icon icon = getFileChooser().getIcon(file);
1510             if (icon != null) {
1511                 setIcon(icon);
1512             } else {