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 }
|