src/macosx/classes/com/apple/laf/AquaFileChooserUI.java

Print this page


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


 840         File selectedFile = null;
 841         // whitespace is legal on Macs, even on beginning and end of filename
 842         if (filename != null && !filename.equals("")) {
 843             final FileSystemView fs = fc.getFileSystemView();
 844             selectedFile = fs.createFileObject(filename);
 845             if (!selectedFile.isAbsolute()) {
 846                 selectedFile = fs.createFileObject(fc.getCurrentDirectory(), filename);
 847             }
 848         }
 849         return selectedFile;
 850     }
 851 
 852     // Utility to tell if the textfield has anything in it
 853     boolean textfieldIsValid() {
 854         final String s = getFileName();
 855         return (s != null && !s.equals(""));
 856     }
 857 
 858     // Action to attach to the file list so we can override the default action
 859     // of the table for the return key, which is to select the next line.

 860     protected class DefaultButtonAction extends AbstractAction {
 861         public void actionPerformed(final ActionEvent e) {
 862             final JRootPane root = AquaFileChooserUI.this.getFileChooser().getRootPane();
 863             final JFileChooser fc = AquaFileChooserUI.this.getFileChooser();
 864             final JButton owner = root.getDefaultButton();
 865             if (owner != null && SwingUtilities.getRootPane(owner) == root && owner.isEnabled()) {
 866                 owner.doClick(20);
 867             } else if (!fc.getControlButtonsAreShown()) {
 868                 final JButton defaultButton = AquaFileChooserUI.this.fSubPanel.getDefaultButton(fc);
 869 
 870                 if (defaultButton != null) {
 871                     defaultButton.doClick(20);
 872                 }
 873             } else {
 874                 Toolkit.getDefaultToolkit().beep();
 875             }
 876         }
 877 
 878         public boolean isEnabled() {
 879             return true;
 880         }
 881     }
 882 
 883     /**
 884      * Creates a new folder.
 885      */

 886     protected class NewFolderAction extends AbstractAction {
 887         protected NewFolderAction() {
 888             super(newFolderAccessibleName);
 889         }
 890 
 891         // Muchlike showInputDialog, but we give it options instead of selectionValues
 892         private Object showNewFolderDialog(final Component parentComponent, final Object message, final String title, final int messageType, final Icon icon, final Object[] options, final Object initialSelectionValue) {
 893             final JOptionPane pane = new JOptionPane(message, messageType, JOptionPane.OK_CANCEL_OPTION, icon, options, null);
 894 
 895             pane.setWantsInput(true);
 896             pane.setInitialSelectionValue(initialSelectionValue);
 897 
 898             final JDialog dialog = pane.createDialog(parentComponent, title);
 899 
 900             pane.selectInitialValue();
 901             dialog.setVisible(true);
 902             dialog.dispose();
 903 
 904             final Object value = pane.getValue();
 905 


 927                     newFolder = fc.getFileSystemView().createFileObject(currentDirectory, filename);
 928                     if (newFolder.exists()) {
 929                         JOptionPane.showMessageDialog(fc, newFolderExistsErrorText, "", JOptionPane.ERROR_MESSAGE);
 930                         return;
 931                     }
 932 
 933                     newFolder.mkdirs();
 934                 } catch(final Exception exc) {
 935                     JOptionPane.showMessageDialog(fc, newFolderErrorText, "", JOptionPane.ERROR_MESSAGE);
 936                     return;
 937                 }
 938 
 939                 openDirectory(newFolder);
 940             }
 941         }
 942     }
 943 
 944     /**
 945      * Responds to an Open, Save, or Choose request
 946      */

 947     protected class ApproveSelectionAction extends AbstractAction {
 948         public void actionPerformed(final ActionEvent e) {
 949             fSubPanel.approveSelection(getFileChooser());
 950         }
 951     }
 952 
 953     /**
 954      * Responds to an OpenDirectory request
 955      */

 956     protected class OpenSelectionAction extends AbstractAction {
 957         public void actionPerformed(final ActionEvent e) {
 958             final int index = fFileList.getSelectedRow();
 959             if (index >= 0) {
 960                 final File selectedFile = (File)((AquaFileSystemModel)fFileList.getModel()).getElementAt(index);
 961                 if (selectedFile != null) openDirectory(selectedFile);
 962             }
 963         }
 964     }
 965 
 966     /**
 967      * Responds to a cancel request.
 968      */

 969     protected class CancelSelectionAction extends AbstractAction {
 970         public void actionPerformed(final ActionEvent e) {
 971             getFileChooser().cancelSelection();
 972         }
 973 
 974         public boolean isEnabled() {
 975             return getFileChooser().isEnabled();
 976         }
 977     }
 978 
 979     /**
 980      * Rescans the files in the current directory
 981      */

 982     protected class UpdateAction extends AbstractAction {
 983         public void actionPerformed(final ActionEvent e) {
 984             final JFileChooser fc = getFileChooser();
 985             fc.setCurrentDirectory(fc.getFileSystemView().createFileObject(getDirectoryName()));
 986             fc.rescanCurrentDirectory();
 987         }
 988     }
 989 
 990     // *****************************************
 991     // ***** default AcceptAll file filter *****
 992     // *****************************************
 993     protected class AcceptAllFileFilter extends FileFilter {
 994         public AcceptAllFileFilter() {
 995         }
 996 
 997         public boolean accept(final File f) {
 998             return true;
 999         }
1000 
1001         public String getDescription() {
1002             return UIManager.getString("FileChooser.acceptAllFileFilterText");
1003         }
1004     }
1005 
1006     // Penultimate superclass is JLabel

1007     protected class MacFCTableCellRenderer extends DefaultTableCellRenderer {
1008         boolean fIsSelected = false;
1009 
1010         public MacFCTableCellRenderer(final Font f) {
1011             super();
1012             setFont(f);
1013             setIconTextGap(10);
1014         }
1015 
1016         public Component getTableCellRendererComponent(final JTable list, final Object value, final boolean isSelected, final boolean cellHasFocus, final int index, final int col) {
1017             super.getTableCellRendererComponent(list, value, isSelected, false, index, col); // No focus border, thanks
1018             fIsSelected = isSelected;
1019             return this;
1020         }
1021 
1022         public boolean isSelected() {
1023             return fIsSelected && isEnabled();
1024         }
1025 
1026         protected String layoutCL(final JLabel label, final FontMetrics fontMetrics, final String text, final Icon icon, final Rectangle viewR, final Rectangle iconR, final Rectangle textR) {


1067                     g.setColor(background);
1068                     g.fillRect(textX - 1, paintTextR.y, paintTextR.width + 2, fm.getAscent() + 2);
1069 
1070                     g.setColor(getForeground());
1071                     SwingUtilities2.drawString(filechooser, g, clippedText, textX, textY);
1072                 } else {
1073                     final Color background = getBackground();
1074                     g.setColor(background);
1075                     g.fillRect(textX - 1, paintTextR.y, paintTextR.width + 2, fm.getAscent() + 2);
1076 
1077                     g.setColor(background.brighter());
1078                     SwingUtilities2.drawString(filechooser, g, clippedText, textX, textY);
1079                     g.setColor(background.darker());
1080                     SwingUtilities2.drawString(filechooser, g, clippedText, textX + 1, textY + 1);
1081                 }
1082             }
1083         }
1084 
1085     }
1086 

1087     protected class FileRenderer extends MacFCTableCellRenderer {
1088         public FileRenderer(final Font f) {
1089             super(f);
1090         }
1091 
1092         public Component getTableCellRendererComponent(final JTable list, final Object value, final boolean isSelected, final boolean cellHasFocus, final int index, final int col) {
1093             super.getTableCellRendererComponent(list, value, isSelected, false, index, col); // No focus border, thanks
1094             final File file = (File)value;
1095             final JFileChooser fc = getFileChooser();
1096             setText(fc.getName(file));
1097             setIcon(fc.getIcon(file));
1098             setEnabled(isSelectableInList(file));
1099             return this;
1100         }
1101     }
1102 

1103     protected class DateRenderer extends MacFCTableCellRenderer {
1104         public DateRenderer(final Font f) {
1105             super(f);
1106         }
1107 
1108         public Component getTableCellRendererComponent(final JTable list, final Object value, final boolean isSelected, final boolean cellHasFocus, final int index, final int col) {
1109             super.getTableCellRendererComponent(list, value, isSelected, false, index, col);
1110             final File file = (File)fFileList.getValueAt(index, 0);
1111             setEnabled(isSelectableInList(file));
1112             final DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.SHORT);
1113             final Date date = (Date)value;
1114 
1115             if (date != null) {
1116                 setText(formatter.format(date));
1117             } else {
1118                 setText("");
1119             }
1120 
1121             return this;
1122         }
1123     }
1124 
1125     public Dimension getPreferredSize(final JComponent c) {
1126         return PREF_SIZE;
1127     }
1128 
1129     public Dimension getMinimumSize(final JComponent c) {
1130         return MIN_SIZE;
1131     }
1132 
1133     public Dimension getMaximumSize(final JComponent c) {
1134         return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
1135     }
1136 

1137     protected ListCellRenderer createDirectoryComboBoxRenderer(final JFileChooser fc) {
1138         return new AquaComboBoxRendererInternal(directoryComboBox) {
1139             public Component getListCellRendererComponent(final JList list, final Object value, final int index, final boolean isSelected, final boolean cellHasFocus) {
1140                 super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
1141                 final File directory = (File)value;
1142                 if (directory == null) {
1143                     setText("");
1144                     return this;
1145                 }
1146 
1147                 final JFileChooser chooser = getFileChooser();
1148                 setText(chooser.getName(directory));
1149                 setIcon(chooser.getIcon(directory));
1150                 return this;
1151             }
1152         };
1153     }
1154 
1155     //
1156     // DataModel for DirectoryComboxbox
1157     //
1158     protected DirectoryComboBoxModel createDirectoryComboBoxModel(final JFileChooser fc) {
1159         return new DirectoryComboBoxModel();
1160     }
1161 
1162     /**
1163      * Data model for a type-face selection combo-box.
1164      */

1165     protected class DirectoryComboBoxModel extends AbstractListModel implements ComboBoxModel {
1166         Vector<File> fDirectories = new Vector<File>();
1167         int topIndex = -1;
1168         int fPathCount = 0;
1169 
1170         File fSelectedDirectory = null;
1171 
1172         public DirectoryComboBoxModel() {
1173             super();
1174             // Add the current directory to the model, and make it the
1175             // selectedDirectory
1176             addItem(getFileChooser().getCurrentDirectory());
1177         }
1178 
1179         /**
1180          * Removes the selected directory, and clears out the
1181          * path file entries leading up to that directory.
1182          */
1183         private void removeSelectedDirectory() {
1184             fDirectories.removeAllElements();


1228             this.fSelectedDirectory = (File)selectedDirectory;
1229             fireContentsChanged(this, -1, -1);
1230         }
1231 
1232         public Object getSelectedItem() {
1233             return fSelectedDirectory;
1234         }
1235 
1236         public int getSize() {
1237             return fDirectories.size();
1238         }
1239 
1240         public Object getElementAt(final int index) {
1241             return fDirectories.elementAt(index);
1242         }
1243     }
1244 
1245     //
1246     // Renderer for Types ComboBox
1247     //

1248     protected ListCellRenderer createFilterComboBoxRenderer() {
1249         return new AquaComboBoxRendererInternal(filterComboBox) {
1250             public Component getListCellRendererComponent(final JList list, final Object value, final int index, final boolean isSelected, final boolean cellHasFocus) {
1251                 super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
1252                 final FileFilter filter = (FileFilter)value;
1253                 if (filter != null) setText(filter.getDescription());
1254                 return this;
1255             }
1256         };
1257     }
1258 
1259     //
1260     // DataModel for Types Comboxbox
1261     //
1262     protected FilterComboBoxModel createFilterComboBoxModel() {
1263         return new FilterComboBoxModel();
1264     }
1265 
1266     /**
1267      * Data model for a type-face selection combo-box.
1268      */

1269     protected class FilterComboBoxModel extends AbstractListModel<FileFilter> implements ComboBoxModel<FileFilter>,
1270             PropertyChangeListener {
1271         protected FileFilter[] filters;
1272         protected FilterComboBoxModel() {
1273             super();
1274             filters = getFileChooser().getChoosableFileFilters();
1275         }
1276 
1277         public void propertyChange(PropertyChangeEvent e) {
1278             String prop = e.getPropertyName();
1279             if(prop == JFileChooser.CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY) {
1280                 filters = (FileFilter[]) e.getNewValue();
1281                 fireContentsChanged(this, -1, -1);
1282             } else if (prop == JFileChooser.FILE_FILTER_CHANGED_PROPERTY) {
1283                 fireContentsChanged(this, -1, -1);
1284             }
1285         }
1286 
1287         public void setSelectedItem(Object filter) {
1288             if(filter != null) {


1319                 return 0;
1320             }
1321         }
1322 
1323         public FileFilter getElementAt(int index) {
1324             if(index > getSize() - 1) {
1325                 // This shouldn't happen. Try to recover gracefully.
1326                 return getFileChooser().getFileFilter();
1327             }
1328             if(filters != null) {
1329                 return filters[index];
1330             } else {
1331                 return null;
1332             }
1333         }
1334     }
1335 
1336     /**
1337      * Acts when FilterComboBox has changed the selected item.
1338      */

1339     protected class FilterComboBoxAction extends AbstractAction {
1340         protected FilterComboBoxAction() {
1341             super("FilterComboBoxAction");
1342         }
1343 
1344         public void actionPerformed(final ActionEvent e) {
1345             getFileChooser().setFileFilter((FileFilter)filterComboBox.getSelectedItem());
1346         }
1347     }
1348 
1349     /**
1350      * Acts when DirectoryComboBox has changed the selected item.
1351      */

1352     protected class DirectoryComboBoxAction extends AbstractAction {
1353         protected DirectoryComboBoxAction() {
1354             super("DirectoryComboBoxAction");
1355         }
1356 
1357         public void actionPerformed(final ActionEvent e) {
1358             getFileChooser().setCurrentDirectory((File)directoryComboBox.getSelectedItem());
1359         }
1360     }
1361 
1362     // Sorting Table operations

1363     class JSortingTableHeader extends JTableHeader {
1364         public JSortingTableHeader(final TableColumnModel cm) {
1365             super(cm);
1366             setReorderingAllowed(true); // This causes mousePress to call setDraggedColumn
1367         }
1368 
1369         // One sort state for each column.  Both are ascending by default
1370         final boolean fSortAscending[] = {true, true};
1371 
1372         // Instead of dragging, it selects which one to sort by
1373         public void setDraggedColumn(final TableColumn aColumn) {
1374             if (aColumn != null) {
1375                 final int colIndex = aColumn.getModelIndex();
1376                 if (colIndex != fSortColumn) {
1377                     filechooser.firePropertyChange(AquaFileSystemModel.SORT_BY_CHANGED, fSortColumn, colIndex);
1378                     fSortColumn = colIndex;
1379                 } else {
1380                     fSortAscending[colIndex] = !fSortAscending[colIndex];
1381                     filechooser.firePropertyChange(AquaFileSystemModel.SORT_ASCENDING_CHANGED, !fSortAscending[colIndex], fSortAscending[colIndex]);
1382                 }
1383                 // Need to repaint the highlighted column.
1384                 repaint();
1385             }
1386         }
1387 
1388         // This stops mouseDrags from moving the column
1389         public TableColumn getDraggedColumn() {
1390             return null;
1391         }
1392 
1393         protected TableCellRenderer createDefaultRenderer() {
1394             final DefaultTableCellRenderer label = new AquaTableCellRenderer();
1395             label.setHorizontalAlignment(SwingConstants.LEFT);
1396             return label;
1397         }
1398 

1399         class AquaTableCellRenderer extends DefaultTableCellRenderer implements UIResource {
1400             public Component getTableCellRendererComponent(final JTable localTable, final Object value, final boolean isSelected, final boolean hasFocus, final int row, final int column) {
1401                 if (localTable != null) {
1402                     final JTableHeader header = localTable.getTableHeader();
1403                     if (header != null) {
1404                         setForeground(header.getForeground());
1405                         setBackground(header.getBackground());
1406                         setFont(UIManager.getFont("TableHeader.font"));
1407                     }
1408                 }
1409 
1410                 setText((value == null) ? "" : value.toString());
1411 
1412                 // Modify the table "border" to draw smaller, and with the titles in the right position
1413                 // and sort indicators, just like an NSSave/Open panel.
1414                 final AquaTableHeaderBorder cellBorder = AquaTableHeaderBorder.getListHeaderBorder();
1415                 cellBorder.setSelected(column == fSortColumn);
1416                 final int horizontalShift = (column == 0 ? 35 : 10);
1417                 cellBorder.setHorizontalShift(horizontalShift);
1418 


1457 
1458         // text field
1459         filenameTextField = new JTextField();
1460         fTextFieldLabel.setLabelFor(filenameTextField);
1461         filenameTextField.addActionListener(getAction(kOpen));
1462         filenameTextField.addFocusListener(new SaveTextFocusListener());
1463         final Dimension minSize = filenameTextField.getMinimumSize();
1464         Dimension d = new Dimension(250, (int)minSize.getHeight());
1465         filenameTextField.setPreferredSize(d);
1466         filenameTextField.setMaximumSize(d);
1467         labelArea.add(filenameTextField);
1468         final File f = fc.getSelectedFile();
1469         if (f != null) {
1470             setFileName(fc.getName(f));
1471         } else if (fc.getDialogType() == JFileChooser.SAVE_DIALOG) {
1472             setFileName(newFileDefaultName);
1473         }
1474 
1475         tPanel.add(labelArea);
1476         // separator line

1477         final JSeparator sep = new JSeparator(){
1478             public Dimension getPreferredSize() {
1479                 return new Dimension(((JComponent)getParent()).getWidth(), 3);
1480             }
1481         };
1482         tPanel.add(Box.createRigidArea(new Dimension(1, 8)));
1483         tPanel.add(sep);
1484         tPanel.add(Box.createRigidArea(new Dimension(1, 7)));
1485         fTextfieldPanel.add(tPanel, BorderLayout.CENTER);
1486 
1487         // DirectoryComboBox, left-justified, 200x20 not including drop shadow
1488         directoryComboBox = new JComboBox();
1489         directoryComboBox.putClientProperty("JComboBox.lightweightKeyboardNavigation", "Lightweight");
1490         fDirectoryComboBoxModel = createDirectoryComboBoxModel(fc);
1491         directoryComboBox.setModel(fDirectoryComboBoxModel);
1492         directoryComboBox.addActionListener(directoryComboBoxAction);
1493         directoryComboBox.setRenderer(createDirectoryComboBoxRenderer(fc));
1494         directoryComboBox.setToolTipText(directoryComboBoxToolTipText);
1495         d = new Dimension(250, (int)directoryComboBox.getMinimumSize().getHeight());
1496         directoryComboBox.setPreferredSize(d);


1744         fFileList.setDefaultRenderer(File.class, new FileRenderer(f));
1745         fFileList.setDefaultRenderer(Date.class, new DateRenderer(f));
1746         final FontMetrics fm = fFileList.getFontMetrics(f);
1747 
1748         // Row height isn't based on the renderers.  It defaults to 16 so we have to set it
1749         fFileList.setRowHeight(Math.max(fm.getHeight(), fileIcon.getIconHeight() + 2));
1750 
1751         // Add a binding for the file list that triggers return and escape
1752         fFileList.registerKeyboardAction(new CancelSelectionAction(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_FOCUSED);
1753         // Add a binding for the file list that triggers the default button (see DefaultButtonAction)
1754         fFileList.registerKeyboardAction(new DefaultButtonAction(), KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), JComponent.WHEN_FOCUSED);
1755         fFileList.setDropTarget(dragAndDropTarget);
1756 
1757         final JScrollPane scrollpane = new JScrollPane(fFileList, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
1758         scrollpane.setComponentOrientation(ComponentOrientation.getOrientation(Locale.getDefault()));
1759         scrollpane.setCorner(ScrollPaneConstants.UPPER_TRAILING_CORNER, new ScrollPaneCornerPanel());
1760         p.add(scrollpane, BorderLayout.CENTER);
1761         return p;
1762     }
1763 

1764     protected class ScrollPaneCornerPanel extends JPanel {
1765         final Border border = UIManager.getBorder("TableHeader.cellBorder");
1766 
1767         protected void paintComponent(final Graphics g) {
1768             border.paintBorder(this, g, 0, 0, getWidth() + 1, getHeight());
1769         }
1770     }
1771 
1772     JComboBox directoryComboBox;
1773     DirectoryComboBoxModel fDirectoryComboBoxModel;
1774     private final Action directoryComboBoxAction = new DirectoryComboBoxAction();
1775 
1776     JTextField filenameTextField;
1777 
1778     JTableExtension fFileList;
1779 
1780     private FilterComboBoxModel filterComboBoxModel;
1781     JComboBox filterComboBox;
1782     private final Action filterComboBoxAction = new FilterComboBoxAction();
1783 


2208 
2209         // If there's text, make a file and select it
2210         void approveSelection(final JFileChooser fc) {
2211             final File f = makeFile(fc, getFileName());
2212             if (f != null) {
2213                 selectionInProgress = true;
2214                 getFileChooser().setSelectedFile(f);
2215                 selectionInProgress = false;
2216             }
2217             getFileChooser().approveSelection();
2218         }
2219 
2220         void updateButtonState(final JFileChooser fc, final File f) {
2221             // Button is disabled if there's nothing selected
2222             getApproveButton(fc).setEnabled(f != null || textfieldIsValid());
2223             super.updateButtonState(fc, f);
2224         }
2225     }
2226 
2227     // See FileRenderer - documents in Save dialogs draw disabled, so they shouldn't be selected

2228     class MacListSelectionModel extends DefaultListSelectionModel {
2229         AquaFileSystemModel fModel;
2230 
2231         MacListSelectionModel(final AquaFileSystemModel model) {
2232             fModel = model;
2233         }
2234 
2235         // Can the file be selected in this mode?
2236         // (files are visible even if they can't be selected)
2237         boolean isSelectableInListIndex(final int index) {
2238             final File file = (File)fModel.getValueAt(index, 0);
2239             return (file != null && isSelectableInList(file));
2240         }
2241 
2242         // Make sure everything in the selection interval is valid
2243         void verifySelectionInterval(int index0, int index1, boolean isSetSelection) {
2244             if (index0 > index1) {
2245                 final int tmp = index1;
2246                 index1 = index0;
2247                 index0 = tmp;


2298 
2299         public void addSelectionInterval(final int index0, final int index1) {
2300             if (index0 == -1 || index1 == -1) { return; }
2301 
2302             if (index0 == index1) {
2303                 if (isSelectableInListIndex(index1)) super.addSelectionInterval(index1, index1);
2304                 return;
2305             }
2306 
2307             if (getSelectionMode() != MULTIPLE_INTERVAL_SELECTION) {
2308                 setSelectionInterval(index0, index1);
2309                 return;
2310             }
2311 
2312             verifySelectionInterval(index0, index1, false);
2313         }
2314     }
2315 
2316     // Convenience, to translate from the JList directory view to the Mac-style JTable
2317     //   & minimize diffs between this and BasicFileChooserUI

2318     class JTableExtension extends JTable {
2319         public void setSelectedIndex(final int index) {
2320             getSelectionModel().setSelectionInterval(index, index);
2321         }
2322 
2323         public void removeSelectedIndex(final int index) {
2324             getSelectionModel().removeSelectionInterval(index, index);
2325         }
2326 
2327         public void ensureIndexIsVisible(final int index) {
2328             final Rectangle cellBounds = getCellRect(index, 0, false);
2329             if (cellBounds != null) {
2330                 scrollRectToVisible(cellBounds);
2331             }
2332         }
2333 
2334         public int locationToIndex(final Point location) {
2335             return rowAtPoint(location);
2336         }
2337     }
   1 /*
   2  * Copyright (c) 2011, 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


 840         File selectedFile = null;
 841         // whitespace is legal on Macs, even on beginning and end of filename
 842         if (filename != null && !filename.equals("")) {
 843             final FileSystemView fs = fc.getFileSystemView();
 844             selectedFile = fs.createFileObject(filename);
 845             if (!selectedFile.isAbsolute()) {
 846                 selectedFile = fs.createFileObject(fc.getCurrentDirectory(), filename);
 847             }
 848         }
 849         return selectedFile;
 850     }
 851 
 852     // Utility to tell if the textfield has anything in it
 853     boolean textfieldIsValid() {
 854         final String s = getFileName();
 855         return (s != null && !s.equals(""));
 856     }
 857 
 858     // Action to attach to the file list so we can override the default action
 859     // of the table for the return key, which is to select the next line.
 860     @SuppressWarnings("serial") // Superclass is not serializable across versions
 861     protected class DefaultButtonAction extends AbstractAction {
 862         public void actionPerformed(final ActionEvent e) {
 863             final JRootPane root = AquaFileChooserUI.this.getFileChooser().getRootPane();
 864             final JFileChooser fc = AquaFileChooserUI.this.getFileChooser();
 865             final JButton owner = root.getDefaultButton();
 866             if (owner != null && SwingUtilities.getRootPane(owner) == root && owner.isEnabled()) {
 867                 owner.doClick(20);
 868             } else if (!fc.getControlButtonsAreShown()) {
 869                 final JButton defaultButton = AquaFileChooserUI.this.fSubPanel.getDefaultButton(fc);
 870 
 871                 if (defaultButton != null) {
 872                     defaultButton.doClick(20);
 873                 }
 874             } else {
 875                 Toolkit.getDefaultToolkit().beep();
 876             }
 877         }
 878 
 879         public boolean isEnabled() {
 880             return true;
 881         }
 882     }
 883 
 884     /**
 885      * Creates a new folder.
 886      */
 887     @SuppressWarnings("serial") // Superclass is not serializable across versions
 888     protected class NewFolderAction extends AbstractAction {
 889         protected NewFolderAction() {
 890             super(newFolderAccessibleName);
 891         }
 892 
 893         // Muchlike showInputDialog, but we give it options instead of selectionValues
 894         private Object showNewFolderDialog(final Component parentComponent, final Object message, final String title, final int messageType, final Icon icon, final Object[] options, final Object initialSelectionValue) {
 895             final JOptionPane pane = new JOptionPane(message, messageType, JOptionPane.OK_CANCEL_OPTION, icon, options, null);
 896 
 897             pane.setWantsInput(true);
 898             pane.setInitialSelectionValue(initialSelectionValue);
 899 
 900             final JDialog dialog = pane.createDialog(parentComponent, title);
 901 
 902             pane.selectInitialValue();
 903             dialog.setVisible(true);
 904             dialog.dispose();
 905 
 906             final Object value = pane.getValue();
 907 


 929                     newFolder = fc.getFileSystemView().createFileObject(currentDirectory, filename);
 930                     if (newFolder.exists()) {
 931                         JOptionPane.showMessageDialog(fc, newFolderExistsErrorText, "", JOptionPane.ERROR_MESSAGE);
 932                         return;
 933                     }
 934 
 935                     newFolder.mkdirs();
 936                 } catch(final Exception exc) {
 937                     JOptionPane.showMessageDialog(fc, newFolderErrorText, "", JOptionPane.ERROR_MESSAGE);
 938                     return;
 939                 }
 940 
 941                 openDirectory(newFolder);
 942             }
 943         }
 944     }
 945 
 946     /**
 947      * Responds to an Open, Save, or Choose request
 948      */
 949     @SuppressWarnings("serial") // Superclass is not serializable across versions
 950     protected class ApproveSelectionAction extends AbstractAction {
 951         public void actionPerformed(final ActionEvent e) {
 952             fSubPanel.approveSelection(getFileChooser());
 953         }
 954     }
 955 
 956     /**
 957      * Responds to an OpenDirectory request
 958      */
 959     @SuppressWarnings("serial") // Superclass is not serializable across versions
 960     protected class OpenSelectionAction extends AbstractAction {
 961         public void actionPerformed(final ActionEvent e) {
 962             final int index = fFileList.getSelectedRow();
 963             if (index >= 0) {
 964                 final File selectedFile = (File)((AquaFileSystemModel)fFileList.getModel()).getElementAt(index);
 965                 if (selectedFile != null) openDirectory(selectedFile);
 966             }
 967         }
 968     }
 969 
 970     /**
 971      * Responds to a cancel request.
 972      */
 973     @SuppressWarnings("serial") // Superclass is not serializable across versions
 974     protected class CancelSelectionAction extends AbstractAction {
 975         public void actionPerformed(final ActionEvent e) {
 976             getFileChooser().cancelSelection();
 977         }
 978 
 979         public boolean isEnabled() {
 980             return getFileChooser().isEnabled();
 981         }
 982     }
 983 
 984     /**
 985      * Rescans the files in the current directory
 986      */
 987     @SuppressWarnings("serial") // Superclass is not serializable across versions
 988     protected class UpdateAction extends AbstractAction {
 989         public void actionPerformed(final ActionEvent e) {
 990             final JFileChooser fc = getFileChooser();
 991             fc.setCurrentDirectory(fc.getFileSystemView().createFileObject(getDirectoryName()));
 992             fc.rescanCurrentDirectory();
 993         }
 994     }
 995 
 996     // *****************************************
 997     // ***** default AcceptAll file filter *****
 998     // *****************************************
 999     protected class AcceptAllFileFilter extends FileFilter {
1000         public AcceptAllFileFilter() {
1001         }
1002 
1003         public boolean accept(final File f) {
1004             return true;
1005         }
1006 
1007         public String getDescription() {
1008             return UIManager.getString("FileChooser.acceptAllFileFilterText");
1009         }
1010     }
1011 
1012     // Penultimate superclass is JLabel
1013     @SuppressWarnings("serial") // Superclass is not serializable across versions
1014     protected class MacFCTableCellRenderer extends DefaultTableCellRenderer {
1015         boolean fIsSelected = false;
1016 
1017         public MacFCTableCellRenderer(final Font f) {
1018             super();
1019             setFont(f);
1020             setIconTextGap(10);
1021         }
1022 
1023         public Component getTableCellRendererComponent(final JTable list, final Object value, final boolean isSelected, final boolean cellHasFocus, final int index, final int col) {
1024             super.getTableCellRendererComponent(list, value, isSelected, false, index, col); // No focus border, thanks
1025             fIsSelected = isSelected;
1026             return this;
1027         }
1028 
1029         public boolean isSelected() {
1030             return fIsSelected && isEnabled();
1031         }
1032 
1033         protected String layoutCL(final JLabel label, final FontMetrics fontMetrics, final String text, final Icon icon, final Rectangle viewR, final Rectangle iconR, final Rectangle textR) {


1074                     g.setColor(background);
1075                     g.fillRect(textX - 1, paintTextR.y, paintTextR.width + 2, fm.getAscent() + 2);
1076 
1077                     g.setColor(getForeground());
1078                     SwingUtilities2.drawString(filechooser, g, clippedText, textX, textY);
1079                 } else {
1080                     final Color background = getBackground();
1081                     g.setColor(background);
1082                     g.fillRect(textX - 1, paintTextR.y, paintTextR.width + 2, fm.getAscent() + 2);
1083 
1084                     g.setColor(background.brighter());
1085                     SwingUtilities2.drawString(filechooser, g, clippedText, textX, textY);
1086                     g.setColor(background.darker());
1087                     SwingUtilities2.drawString(filechooser, g, clippedText, textX + 1, textY + 1);
1088                 }
1089             }
1090         }
1091 
1092     }
1093 
1094     @SuppressWarnings("serial") // Superclass is not serializable across versions
1095     protected class FileRenderer extends MacFCTableCellRenderer {
1096         public FileRenderer(final Font f) {
1097             super(f);
1098         }
1099 
1100         public Component getTableCellRendererComponent(final JTable list, final Object value, final boolean isSelected, final boolean cellHasFocus, final int index, final int col) {
1101             super.getTableCellRendererComponent(list, value, isSelected, false, index, col); // No focus border, thanks
1102             final File file = (File)value;
1103             final JFileChooser fc = getFileChooser();
1104             setText(fc.getName(file));
1105             setIcon(fc.getIcon(file));
1106             setEnabled(isSelectableInList(file));
1107             return this;
1108         }
1109     }
1110 
1111     @SuppressWarnings("serial") // Superclass is not serializable across versions
1112     protected class DateRenderer extends MacFCTableCellRenderer {
1113         public DateRenderer(final Font f) {
1114             super(f);
1115         }
1116 
1117         public Component getTableCellRendererComponent(final JTable list, final Object value, final boolean isSelected, final boolean cellHasFocus, final int index, final int col) {
1118             super.getTableCellRendererComponent(list, value, isSelected, false, index, col);
1119             final File file = (File)fFileList.getValueAt(index, 0);
1120             setEnabled(isSelectableInList(file));
1121             final DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.SHORT);
1122             final Date date = (Date)value;
1123 
1124             if (date != null) {
1125                 setText(formatter.format(date));
1126             } else {
1127                 setText("");
1128             }
1129 
1130             return this;
1131         }
1132     }
1133 
1134     public Dimension getPreferredSize(final JComponent c) {
1135         return PREF_SIZE;
1136     }
1137 
1138     public Dimension getMinimumSize(final JComponent c) {
1139         return MIN_SIZE;
1140     }
1141 
1142     public Dimension getMaximumSize(final JComponent c) {
1143         return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
1144     }
1145 
1146     @SuppressWarnings("serial") // anonymous class
1147     protected ListCellRenderer createDirectoryComboBoxRenderer(final JFileChooser fc) {
1148         return new AquaComboBoxRendererInternal(directoryComboBox) {
1149             public Component getListCellRendererComponent(final JList list, final Object value, final int index, final boolean isSelected, final boolean cellHasFocus) {
1150                 super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
1151                 final File directory = (File)value;
1152                 if (directory == null) {
1153                     setText("");
1154                     return this;
1155                 }
1156 
1157                 final JFileChooser chooser = getFileChooser();
1158                 setText(chooser.getName(directory));
1159                 setIcon(chooser.getIcon(directory));
1160                 return this;
1161             }
1162         };
1163     }
1164 
1165     //
1166     // DataModel for DirectoryComboxbox
1167     //
1168     protected DirectoryComboBoxModel createDirectoryComboBoxModel(final JFileChooser fc) {
1169         return new DirectoryComboBoxModel();
1170     }
1171 
1172     /**
1173      * Data model for a type-face selection combo-box.
1174      */
1175     @SuppressWarnings("serial") // Superclass is not serializable across versions
1176     protected class DirectoryComboBoxModel extends AbstractListModel implements ComboBoxModel {
1177         Vector<File> fDirectories = new Vector<File>();
1178         int topIndex = -1;
1179         int fPathCount = 0;
1180 
1181         File fSelectedDirectory = null;
1182 
1183         public DirectoryComboBoxModel() {
1184             super();
1185             // Add the current directory to the model, and make it the
1186             // selectedDirectory
1187             addItem(getFileChooser().getCurrentDirectory());
1188         }
1189 
1190         /**
1191          * Removes the selected directory, and clears out the
1192          * path file entries leading up to that directory.
1193          */
1194         private void removeSelectedDirectory() {
1195             fDirectories.removeAllElements();


1239             this.fSelectedDirectory = (File)selectedDirectory;
1240             fireContentsChanged(this, -1, -1);
1241         }
1242 
1243         public Object getSelectedItem() {
1244             return fSelectedDirectory;
1245         }
1246 
1247         public int getSize() {
1248             return fDirectories.size();
1249         }
1250 
1251         public Object getElementAt(final int index) {
1252             return fDirectories.elementAt(index);
1253         }
1254     }
1255 
1256     //
1257     // Renderer for Types ComboBox
1258     //
1259     @SuppressWarnings("serial") // anonymous class
1260     protected ListCellRenderer createFilterComboBoxRenderer() {
1261         return new AquaComboBoxRendererInternal(filterComboBox) {
1262             public Component getListCellRendererComponent(final JList list, final Object value, final int index, final boolean isSelected, final boolean cellHasFocus) {
1263                 super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
1264                 final FileFilter filter = (FileFilter)value;
1265                 if (filter != null) setText(filter.getDescription());
1266                 return this;
1267             }
1268         };
1269     }
1270 
1271     //
1272     // DataModel for Types Comboxbox
1273     //
1274     protected FilterComboBoxModel createFilterComboBoxModel() {
1275         return new FilterComboBoxModel();
1276     }
1277 
1278     /**
1279      * Data model for a type-face selection combo-box.
1280      */
1281     @SuppressWarnings("serial") // Superclass is not serializable across versions
1282     protected class FilterComboBoxModel extends AbstractListModel<FileFilter> implements ComboBoxModel<FileFilter>,
1283             PropertyChangeListener {
1284         protected FileFilter[] filters;
1285         protected FilterComboBoxModel() {
1286             super();
1287             filters = getFileChooser().getChoosableFileFilters();
1288         }
1289 
1290         public void propertyChange(PropertyChangeEvent e) {
1291             String prop = e.getPropertyName();
1292             if(prop == JFileChooser.CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY) {
1293                 filters = (FileFilter[]) e.getNewValue();
1294                 fireContentsChanged(this, -1, -1);
1295             } else if (prop == JFileChooser.FILE_FILTER_CHANGED_PROPERTY) {
1296                 fireContentsChanged(this, -1, -1);
1297             }
1298         }
1299 
1300         public void setSelectedItem(Object filter) {
1301             if(filter != null) {


1332                 return 0;
1333             }
1334         }
1335 
1336         public FileFilter getElementAt(int index) {
1337             if(index > getSize() - 1) {
1338                 // This shouldn't happen. Try to recover gracefully.
1339                 return getFileChooser().getFileFilter();
1340             }
1341             if(filters != null) {
1342                 return filters[index];
1343             } else {
1344                 return null;
1345             }
1346         }
1347     }
1348 
1349     /**
1350      * Acts when FilterComboBox has changed the selected item.
1351      */
1352     @SuppressWarnings("serial") // Superclass is not serializable across versions
1353     protected class FilterComboBoxAction extends AbstractAction {
1354         protected FilterComboBoxAction() {
1355             super("FilterComboBoxAction");
1356         }
1357 
1358         public void actionPerformed(final ActionEvent e) {
1359             getFileChooser().setFileFilter((FileFilter)filterComboBox.getSelectedItem());
1360         }
1361     }
1362 
1363     /**
1364      * Acts when DirectoryComboBox has changed the selected item.
1365      */
1366     @SuppressWarnings("serial") // Superclass is not serializable across versions
1367     protected class DirectoryComboBoxAction extends AbstractAction {
1368         protected DirectoryComboBoxAction() {
1369             super("DirectoryComboBoxAction");
1370         }
1371 
1372         public void actionPerformed(final ActionEvent e) {
1373             getFileChooser().setCurrentDirectory((File)directoryComboBox.getSelectedItem());
1374         }
1375     }
1376 
1377     // Sorting Table operations
1378     @SuppressWarnings("serial") // Superclass is not serializable across versions
1379     class JSortingTableHeader extends JTableHeader {
1380         public JSortingTableHeader(final TableColumnModel cm) {
1381             super(cm);
1382             setReorderingAllowed(true); // This causes mousePress to call setDraggedColumn
1383         }
1384 
1385         // One sort state for each column.  Both are ascending by default
1386         final boolean fSortAscending[] = {true, true};
1387 
1388         // Instead of dragging, it selects which one to sort by
1389         public void setDraggedColumn(final TableColumn aColumn) {
1390             if (aColumn != null) {
1391                 final int colIndex = aColumn.getModelIndex();
1392                 if (colIndex != fSortColumn) {
1393                     filechooser.firePropertyChange(AquaFileSystemModel.SORT_BY_CHANGED, fSortColumn, colIndex);
1394                     fSortColumn = colIndex;
1395                 } else {
1396                     fSortAscending[colIndex] = !fSortAscending[colIndex];
1397                     filechooser.firePropertyChange(AquaFileSystemModel.SORT_ASCENDING_CHANGED, !fSortAscending[colIndex], fSortAscending[colIndex]);
1398                 }
1399                 // Need to repaint the highlighted column.
1400                 repaint();
1401             }
1402         }
1403 
1404         // This stops mouseDrags from moving the column
1405         public TableColumn getDraggedColumn() {
1406             return null;
1407         }
1408 
1409         protected TableCellRenderer createDefaultRenderer() {
1410             final DefaultTableCellRenderer label = new AquaTableCellRenderer();
1411             label.setHorizontalAlignment(SwingConstants.LEFT);
1412             return label;
1413         }
1414 
1415         @SuppressWarnings("serial") // Superclass is not serializable across versions
1416         class AquaTableCellRenderer extends DefaultTableCellRenderer implements UIResource {
1417             public Component getTableCellRendererComponent(final JTable localTable, final Object value, final boolean isSelected, final boolean hasFocus, final int row, final int column) {
1418                 if (localTable != null) {
1419                     final JTableHeader header = localTable.getTableHeader();
1420                     if (header != null) {
1421                         setForeground(header.getForeground());
1422                         setBackground(header.getBackground());
1423                         setFont(UIManager.getFont("TableHeader.font"));
1424                     }
1425                 }
1426 
1427                 setText((value == null) ? "" : value.toString());
1428 
1429                 // Modify the table "border" to draw smaller, and with the titles in the right position
1430                 // and sort indicators, just like an NSSave/Open panel.
1431                 final AquaTableHeaderBorder cellBorder = AquaTableHeaderBorder.getListHeaderBorder();
1432                 cellBorder.setSelected(column == fSortColumn);
1433                 final int horizontalShift = (column == 0 ? 35 : 10);
1434                 cellBorder.setHorizontalShift(horizontalShift);
1435 


1474 
1475         // text field
1476         filenameTextField = new JTextField();
1477         fTextFieldLabel.setLabelFor(filenameTextField);
1478         filenameTextField.addActionListener(getAction(kOpen));
1479         filenameTextField.addFocusListener(new SaveTextFocusListener());
1480         final Dimension minSize = filenameTextField.getMinimumSize();
1481         Dimension d = new Dimension(250, (int)minSize.getHeight());
1482         filenameTextField.setPreferredSize(d);
1483         filenameTextField.setMaximumSize(d);
1484         labelArea.add(filenameTextField);
1485         final File f = fc.getSelectedFile();
1486         if (f != null) {
1487             setFileName(fc.getName(f));
1488         } else if (fc.getDialogType() == JFileChooser.SAVE_DIALOG) {
1489             setFileName(newFileDefaultName);
1490         }
1491 
1492         tPanel.add(labelArea);
1493         // separator line
1494         @SuppressWarnings("serial") // anonymous class
1495         final JSeparator sep = new JSeparator(){
1496             public Dimension getPreferredSize() {
1497                 return new Dimension(((JComponent)getParent()).getWidth(), 3);
1498             }
1499         };
1500         tPanel.add(Box.createRigidArea(new Dimension(1, 8)));
1501         tPanel.add(sep);
1502         tPanel.add(Box.createRigidArea(new Dimension(1, 7)));
1503         fTextfieldPanel.add(tPanel, BorderLayout.CENTER);
1504 
1505         // DirectoryComboBox, left-justified, 200x20 not including drop shadow
1506         directoryComboBox = new JComboBox();
1507         directoryComboBox.putClientProperty("JComboBox.lightweightKeyboardNavigation", "Lightweight");
1508         fDirectoryComboBoxModel = createDirectoryComboBoxModel(fc);
1509         directoryComboBox.setModel(fDirectoryComboBoxModel);
1510         directoryComboBox.addActionListener(directoryComboBoxAction);
1511         directoryComboBox.setRenderer(createDirectoryComboBoxRenderer(fc));
1512         directoryComboBox.setToolTipText(directoryComboBoxToolTipText);
1513         d = new Dimension(250, (int)directoryComboBox.getMinimumSize().getHeight());
1514         directoryComboBox.setPreferredSize(d);


1762         fFileList.setDefaultRenderer(File.class, new FileRenderer(f));
1763         fFileList.setDefaultRenderer(Date.class, new DateRenderer(f));
1764         final FontMetrics fm = fFileList.getFontMetrics(f);
1765 
1766         // Row height isn't based on the renderers.  It defaults to 16 so we have to set it
1767         fFileList.setRowHeight(Math.max(fm.getHeight(), fileIcon.getIconHeight() + 2));
1768 
1769         // Add a binding for the file list that triggers return and escape
1770         fFileList.registerKeyboardAction(new CancelSelectionAction(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_FOCUSED);
1771         // Add a binding for the file list that triggers the default button (see DefaultButtonAction)
1772         fFileList.registerKeyboardAction(new DefaultButtonAction(), KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), JComponent.WHEN_FOCUSED);
1773         fFileList.setDropTarget(dragAndDropTarget);
1774 
1775         final JScrollPane scrollpane = new JScrollPane(fFileList, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
1776         scrollpane.setComponentOrientation(ComponentOrientation.getOrientation(Locale.getDefault()));
1777         scrollpane.setCorner(ScrollPaneConstants.UPPER_TRAILING_CORNER, new ScrollPaneCornerPanel());
1778         p.add(scrollpane, BorderLayout.CENTER);
1779         return p;
1780     }
1781 
1782     @SuppressWarnings("serial") // Superclass is not serializable across versions
1783     protected class ScrollPaneCornerPanel extends JPanel {
1784         final Border border = UIManager.getBorder("TableHeader.cellBorder");
1785 
1786         protected void paintComponent(final Graphics g) {
1787             border.paintBorder(this, g, 0, 0, getWidth() + 1, getHeight());
1788         }
1789     }
1790 
1791     JComboBox directoryComboBox;
1792     DirectoryComboBoxModel fDirectoryComboBoxModel;
1793     private final Action directoryComboBoxAction = new DirectoryComboBoxAction();
1794 
1795     JTextField filenameTextField;
1796 
1797     JTableExtension fFileList;
1798 
1799     private FilterComboBoxModel filterComboBoxModel;
1800     JComboBox filterComboBox;
1801     private final Action filterComboBoxAction = new FilterComboBoxAction();
1802 


2227 
2228         // If there's text, make a file and select it
2229         void approveSelection(final JFileChooser fc) {
2230             final File f = makeFile(fc, getFileName());
2231             if (f != null) {
2232                 selectionInProgress = true;
2233                 getFileChooser().setSelectedFile(f);
2234                 selectionInProgress = false;
2235             }
2236             getFileChooser().approveSelection();
2237         }
2238 
2239         void updateButtonState(final JFileChooser fc, final File f) {
2240             // Button is disabled if there's nothing selected
2241             getApproveButton(fc).setEnabled(f != null || textfieldIsValid());
2242             super.updateButtonState(fc, f);
2243         }
2244     }
2245 
2246     // See FileRenderer - documents in Save dialogs draw disabled, so they shouldn't be selected
2247     @SuppressWarnings("serial") // Superclass is not serializable across versions
2248     class MacListSelectionModel extends DefaultListSelectionModel {
2249         AquaFileSystemModel fModel;
2250 
2251         MacListSelectionModel(final AquaFileSystemModel model) {
2252             fModel = model;
2253         }
2254 
2255         // Can the file be selected in this mode?
2256         // (files are visible even if they can't be selected)
2257         boolean isSelectableInListIndex(final int index) {
2258             final File file = (File)fModel.getValueAt(index, 0);
2259             return (file != null && isSelectableInList(file));
2260         }
2261 
2262         // Make sure everything in the selection interval is valid
2263         void verifySelectionInterval(int index0, int index1, boolean isSetSelection) {
2264             if (index0 > index1) {
2265                 final int tmp = index1;
2266                 index1 = index0;
2267                 index0 = tmp;


2318 
2319         public void addSelectionInterval(final int index0, final int index1) {
2320             if (index0 == -1 || index1 == -1) { return; }
2321 
2322             if (index0 == index1) {
2323                 if (isSelectableInListIndex(index1)) super.addSelectionInterval(index1, index1);
2324                 return;
2325             }
2326 
2327             if (getSelectionMode() != MULTIPLE_INTERVAL_SELECTION) {
2328                 setSelectionInterval(index0, index1);
2329                 return;
2330             }
2331 
2332             verifySelectionInterval(index0, index1, false);
2333         }
2334     }
2335 
2336     // Convenience, to translate from the JList directory view to the Mac-style JTable
2337     //   & minimize diffs between this and BasicFileChooserUI
2338     @SuppressWarnings("serial") // Superclass is not serializable across versions
2339     class JTableExtension extends JTable {
2340         public void setSelectedIndex(final int index) {
2341             getSelectionModel().setSelectionInterval(index, index);
2342         }
2343 
2344         public void removeSelectedIndex(final int index) {
2345             getSelectionModel().removeSelectionInterval(index, index);
2346         }
2347 
2348         public void ensureIndexIsVisible(final int index) {
2349             final Rectangle cellBounds = getCellRect(index, 0, false);
2350             if (cellBounds != null) {
2351                 scrollRectToVisible(cellBounds);
2352             }
2353         }
2354 
2355         public int locationToIndex(final Point location) {
2356             return rowAtPoint(location);
2357         }
2358     }