1 /*
2 * Copyright (c) 1998, 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
33 import java.awt.*;
34 import java.awt.event.*;
35 import java.awt.datatransfer.*;
36 import java.beans.*;
37 import java.io.*;
38 import java.util.*;
39 import java.util.List;
40 import java.util.regex.*;
41 import sun.awt.shell.ShellFolder;
42 import sun.swing.*;
43 import sun.swing.SwingUtilities2;
44
45 /**
46 * Basic L&F implementation of a FileChooser.
47 *
48 * @author Jeff Dinkins
49 */
50 public class BasicFileChooserUI extends FileChooserUI {
51
52 /* FileView icons */
53 protected Icon directoryIcon = null;
54 protected Icon fileIcon = null;
55 protected Icon computerIcon = null;
56 protected Icon hardDriveIcon = null;
57 protected Icon floppyDriveIcon = null;
58
59 protected Icon newFolderIcon = null;
60 protected Icon upFolderIcon = null;
61 protected Icon homeFolderIcon = null;
62 protected Icon listViewIcon = null;
63 protected Icon detailsViewIcon = null;
64 protected Icon viewMenuIcon = null;
65
66 protected int saveButtonMnemonic = 0;
67 protected int openButtonMnemonic = 0;
68 protected int cancelButtonMnemonic = 0;
69 protected int updateButtonMnemonic = 0;
70 protected int helpButtonMnemonic = 0;
71
72 /**
73 * The mnemonic keycode used for the approve button when a directory
74 * is selected and the current selection mode is FILES_ONLY.
75 *
76 * @since 1.4
77 */
78 protected int directoryOpenButtonMnemonic = 0;
79
80 protected String saveButtonText = null;
81 protected String openButtonText = null;
82 protected String cancelButtonText = null;
83 protected String updateButtonText = null;
84 protected String helpButtonText = null;
85
86 /**
87 * The label text displayed on the approve button when a directory
88 * is selected and the current selection mode is FILES_ONLY.
89 *
90 * @since 1.4
91 */
92 protected String directoryOpenButtonText = null;
93
94 private String openDialogTitleText = null;
95 private String saveDialogTitleText = null;
96
97 protected String saveButtonToolTipText = null;
98 protected String openButtonToolTipText = null;
99 protected String cancelButtonToolTipText = null;
100 protected String updateButtonToolTipText = null;
101 protected String helpButtonToolTipText = null;
102
103 /**
104 * The tooltip text displayed on the approve button when a directory
105 * is selected and the current selection mode is FILES_ONLY.
106 *
107 * @since 1.4
108 */
109 protected String directoryOpenButtonToolTipText = null;
110
111 // Some generic FileChooser functions
112 private Action approveSelectionAction = new ApproveSelectionAction();
113 private Action cancelSelectionAction = new CancelSelectionAction();
114 private Action updateAction = new UpdateAction();
115 private Action newFolderAction;
116 private Action goHomeAction = new GoHomeAction();
117 private Action changeToParentDirectoryAction = new ChangeToParentDirectoryAction();
118
119 private String newFolderErrorSeparator = null;
120 private String newFolderErrorText = null;
141 private JPanel accessoryPanel = null;
142 private Handler handler;
143
144 /**
145 * Creates a {@code BasicFileChooserUI} implementation
146 * for the specified component. By default
147 * the {@code BasicLookAndFeel} class uses
148 * {@code createUI} methods of all basic UIs classes
149 * to instantiate UIs.
150 *
151 * @param c the {@code JFileChooser} which needs a UI
152 * @return the {@code BasicFileChooserUI} object
153 *
154 * @see UIDefaults#getUI(JComponent)
155 * @since 1.7
156 */
157 public static ComponentUI createUI(JComponent c) {
158 return new BasicFileChooserUI((JFileChooser) c);
159 }
160
161 public BasicFileChooserUI(JFileChooser b) {
162 }
163
164 public void installUI(JComponent c) {
165 accessoryPanel = new JPanel(new BorderLayout());
166 filechooser = (JFileChooser) c;
167
168 createModel();
169
170 clearIconCache();
171
172 installDefaults(filechooser);
173 installComponents(filechooser);
174 installListeners(filechooser);
175 filechooser.applyComponentOrientation(filechooser.getComponentOrientation());
176 }
177
178 public void uninstallUI(JComponent c) {
179 uninstallListeners(filechooser);
180 uninstallComponents(filechooser);
181 uninstallDefaults(filechooser);
182
183 if(accessoryPanel != null) {
184 accessoryPanel.removeAll();
185 }
186
187 accessoryPanel = null;
188 getFileChooser().removeAll();
189
190 handler = null;
191 }
192
193 public void installComponents(JFileChooser fc) {
194 }
195
196 public void uninstallComponents(JFileChooser fc) {
197 }
198
199 protected void installListeners(JFileChooser fc) {
200 propertyChangeListener = createPropertyChangeListener(fc);
201 if(propertyChangeListener != null) {
202 fc.addPropertyChangeListener(propertyChangeListener);
203 }
204 fc.addPropertyChangeListener(getModel());
205
206 InputMap inputMap = getInputMap(JComponent.
207 WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
208 SwingUtilities.replaceUIInputMap(fc, JComponent.
209 WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, inputMap);
210 ActionMap actionMap = getActionMap();
211 SwingUtilities.replaceUIActionMap(fc, actionMap);
212 }
213
214 InputMap getInputMap(int condition) {
215 if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) {
216 return (InputMap)DefaultLookup.get(getFileChooser(), this,
217 "FileChooser.ancestorInputMap");
218 }
224 }
225
226 ActionMap createActionMap() {
227 ActionMap map = new ActionMapUIResource();
228
229 Action refreshAction = new UIAction(FilePane.ACTION_REFRESH) {
230 public void actionPerformed(ActionEvent evt) {
231 getFileChooser().rescanCurrentDirectory();
232 }
233 };
234
235 map.put(FilePane.ACTION_APPROVE_SELECTION, getApproveSelectionAction());
236 map.put(FilePane.ACTION_CANCEL, getCancelSelectionAction());
237 map.put(FilePane.ACTION_REFRESH, refreshAction);
238 map.put(FilePane.ACTION_CHANGE_TO_PARENT_DIRECTORY,
239 getChangeToParentDirectoryAction());
240 return map;
241 }
242
243
244 protected void uninstallListeners(JFileChooser fc) {
245 if(propertyChangeListener != null) {
246 fc.removePropertyChangeListener(propertyChangeListener);
247 }
248 fc.removePropertyChangeListener(getModel());
249 SwingUtilities.replaceUIInputMap(fc, JComponent.
250 WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null);
251 SwingUtilities.replaceUIActionMap(fc, null);
252 }
253
254
255 protected void installDefaults(JFileChooser fc) {
256 installIcons(fc);
257 installStrings(fc);
258 usesSingleFilePane = UIManager.getBoolean("FileChooser.usesSingleFilePane");
259 readOnly = UIManager.getBoolean("FileChooser.readOnly");
260 TransferHandler th = fc.getTransferHandler();
261 if (th == null || th instanceof UIResource) {
262 fc.setTransferHandler(defaultTransferHandler);
263 }
264 LookAndFeel.installProperty(fc, "opaque", Boolean.FALSE);
265 }
266
267 protected void installIcons(JFileChooser fc) {
268 directoryIcon = UIManager.getIcon("FileView.directoryIcon");
269 fileIcon = UIManager.getIcon("FileView.fileIcon");
270 computerIcon = UIManager.getIcon("FileView.computerIcon");
271 hardDriveIcon = UIManager.getIcon("FileView.hardDriveIcon");
272 floppyDriveIcon = UIManager.getIcon("FileView.floppyDriveIcon");
273
274 newFolderIcon = UIManager.getIcon("FileChooser.newFolderIcon");
275 upFolderIcon = UIManager.getIcon("FileChooser.upFolderIcon");
276 homeFolderIcon = UIManager.getIcon("FileChooser.homeFolderIcon");
277 detailsViewIcon = UIManager.getIcon("FileChooser.detailsViewIcon");
278 listViewIcon = UIManager.getIcon("FileChooser.listViewIcon");
279 viewMenuIcon = UIManager.getIcon("FileChooser.viewMenuIcon");
280 }
281
282 protected void installStrings(JFileChooser fc) {
283
284 Locale l = fc.getLocale();
285 newFolderErrorText = UIManager.getString("FileChooser.newFolderErrorText",l);
286 newFolderErrorSeparator = UIManager.getString("FileChooser.newFolderErrorSeparator",l);
287
288 newFolderParentDoesntExistTitleText = UIManager.getString("FileChooser.newFolderParentDoesntExistTitleText", l);
289 newFolderParentDoesntExistText = UIManager.getString("FileChooser.newFolderParentDoesntExistText", l);
290
291 fileDescriptionText = UIManager.getString("FileChooser.fileDescriptionText",l);
292 directoryDescriptionText = UIManager.getString("FileChooser.directoryDescriptionText",l);
293
294 saveButtonText = UIManager.getString("FileChooser.saveButtonText",l);
295 openButtonText = UIManager.getString("FileChooser.openButtonText",l);
296 saveDialogTitleText = UIManager.getString("FileChooser.saveDialogTitleText",l);
297 openDialogTitleText = UIManager.getString("FileChooser.openDialogTitleText",l);
298 cancelButtonText = UIManager.getString("FileChooser.cancelButtonText",l);
299 updateButtonText = UIManager.getString("FileChooser.updateButtonText",l);
300 helpButtonText = UIManager.getString("FileChooser.helpButtonText",l);
301 directoryOpenButtonText = UIManager.getString("FileChooser.directoryOpenButtonText",l);
302
303 saveButtonMnemonic = getMnemonic("FileChooser.saveButtonMnemonic", l);
304 openButtonMnemonic = getMnemonic("FileChooser.openButtonMnemonic", l);
305 cancelButtonMnemonic = getMnemonic("FileChooser.cancelButtonMnemonic", l);
306 updateButtonMnemonic = getMnemonic("FileChooser.updateButtonMnemonic", l);
307 helpButtonMnemonic = getMnemonic("FileChooser.helpButtonMnemonic", l);
308 directoryOpenButtonMnemonic = getMnemonic("FileChooser.directoryOpenButtonMnemonic", l);
309
310 saveButtonToolTipText = UIManager.getString("FileChooser.saveButtonToolTipText",l);
311 openButtonToolTipText = UIManager.getString("FileChooser.openButtonToolTipText",l);
312 cancelButtonToolTipText = UIManager.getString("FileChooser.cancelButtonToolTipText",l);
313 updateButtonToolTipText = UIManager.getString("FileChooser.updateButtonToolTipText",l);
314 helpButtonToolTipText = UIManager.getString("FileChooser.helpButtonToolTipText",l);
315 directoryOpenButtonToolTipText = UIManager.getString("FileChooser.directoryOpenButtonToolTipText",l);
316 }
317
318 protected void uninstallDefaults(JFileChooser fc) {
319 uninstallIcons(fc);
320 uninstallStrings(fc);
321 if (fc.getTransferHandler() instanceof UIResource) {
322 fc.setTransferHandler(null);
323 }
324 }
325
326 protected void uninstallIcons(JFileChooser fc) {
327 directoryIcon = null;
328 fileIcon = null;
329 computerIcon = null;
330 hardDriveIcon = null;
331 floppyDriveIcon = null;
332
333 newFolderIcon = null;
334 upFolderIcon = null;
335 homeFolderIcon = null;
336 detailsViewIcon = null;
337 listViewIcon = null;
338 viewMenuIcon = null;
339 }
340
341 protected void uninstallStrings(JFileChooser fc) {
342 saveButtonText = null;
343 openButtonText = null;
344 cancelButtonText = null;
345 updateButtonText = null;
346 helpButtonText = null;
347 directoryOpenButtonText = null;
348
349 saveButtonToolTipText = null;
350 openButtonToolTipText = null;
351 cancelButtonToolTipText = null;
352 updateButtonToolTipText = null;
353 helpButtonToolTipText = null;
354 directoryOpenButtonToolTipText = null;
355 }
356
357 protected void createModel() {
358 if (model != null) {
359 model.invalidateFileCache();
360 }
361 model = new BasicDirectoryModel(getFileChooser());
362 }
363
364 public BasicDirectoryModel getModel() {
365 return model;
366 }
367
368 public PropertyChangeListener createPropertyChangeListener(JFileChooser fc) {
369 return null;
370 }
371
372 public String getFileName() {
373 return null;
374 }
375
376 public String getDirectoryName() {
377 return null;
378 }
379
380 public void setFileName(String filename) {
381 }
382
383 public void setDirectoryName(String dirname) {
384 }
385
386 public void rescanCurrentDirectory(JFileChooser fc) {
387 }
388
389 public void ensureFileIsVisible(JFileChooser fc, File f) {
390 }
391
392 public JFileChooser getFileChooser() {
393 return filechooser;
394 }
395
396 public JPanel getAccessoryPanel() {
397 return accessoryPanel;
398 }
399
400 protected JButton getApproveButton(JFileChooser fc) {
401 return null;
402 }
403
404 public JButton getDefaultButton(JFileChooser fc) {
405 return getApproveButton(fc);
406 }
407
408 public String getApproveButtonToolTipText(JFileChooser fc) {
409 String tooltipText = fc.getApproveButtonToolTipText();
410 if(tooltipText != null) {
411 return tooltipText;
412 }
413
414 if(fc.getDialogType() == JFileChooser.OPEN_DIALOG) {
415 return openButtonToolTipText;
416 } else if(fc.getDialogType() == JFileChooser.SAVE_DIALOG) {
417 return saveButtonToolTipText;
418 }
419 return null;
420 }
421
422 public void clearIconCache() {
423 fileView.clearIconCache();
424 }
425
426
427 // ********************************************
428 // ************ Create Listeners **************
429 // ********************************************
430
431 private Handler getHandler() {
432 if (handler == null) {
433 handler = new Handler();
434 }
435 return handler;
436 }
437
438 protected MouseListener createDoubleClickListener(JFileChooser fc,
439 JList<?> list) {
440 return new Handler(list);
441 }
442
443 public ListSelectionListener createListSelectionListener(JFileChooser fc) {
444 return getHandler();
445 }
446
447 private class Handler implements MouseListener, ListSelectionListener {
448 JList<?> list;
449
450 Handler() {
451 }
452
453 Handler(JList<?> list) {
454 this.list = list;
455 }
456
457 public void mouseClicked(MouseEvent evt) {
458 // Note: we can't depend on evt.getSource() because of backward
459 // compatibility
460 if (list != null &&
461 SwingUtilities.isLeftMouseButton(evt) &&
462 (evt.getClickCount()%2 == 0)) {
549 && file.isDirectory()
550 && chooser.isTraversable(file)
551 && (useSetDirectory || !fsv.isFileSystem(file))) {
552
553 setDirectorySelected(true);
554 setDirectory(file);
555 if (usesSingleFilePane) {
556 chooser.setSelectedFile(null);
557 }
558 } else {
559 setDirectorySelected(false);
560 if (file != null) {
561 chooser.setSelectedFile(file);
562 }
563 }
564 }
565 }
566 }
567 }
568
569 protected class DoubleClickListener extends MouseAdapter {
570 // NOTE: This class exists only for backward compatibility. All
571 // its functionality has been moved into Handler. If you need to add
572 // new functionality add it to the Handler, but make sure this
573 // class calls into the Handler.
574 Handler handler;
575 public DoubleClickListener(JList<?> list) {
576 handler = new Handler(list);
577 }
578
579 /**
580 * The JList used for representing the files is created by subclasses, but the
581 * selection is monitored in this class. The TransferHandler installed in the
582 * JFileChooser is also installed in the file list as it is used as the actual
583 * transfer source. The list is updated on a mouse enter to reflect the current
584 * data transfer state of the file chooser.
585 */
586 public void mouseEntered(MouseEvent e) {
587 handler.mouseEntered(e);
588 }
589
590 public void mouseClicked(MouseEvent e) {
591 handler.mouseClicked(e);
592 }
593 }
594
595 protected class SelectionListener implements ListSelectionListener {
596 // NOTE: This class exists only for backward compatibility. All
597 // its functionality has been moved into Handler. If you need to add
598 // new functionality add it to the Handler, but make sure this
599 // class calls into the Handler.
600 public void valueChanged(ListSelectionEvent e) {
601 getHandler().valueChanged(e);
602 }
603 }
604
605 /**
606 * Property to remember whether a directory is currently selected in the UI.
607 *
608 * @return <code>true</code> iff a directory is currently selected.
609 * @since 1.4
610 */
611 protected boolean isDirectorySelected() {
612 return directorySelected;
613 }
614
615 /**
616 * Property to remember whether a directory is currently selected in the UI.
617 * This is normally called by the UI on a selection event.
618 *
619 * @param b iff a directory is currently selected.
655
656 // *******************************************************
657 // ************ FileChooser UI PLAF methods **************
658 // *******************************************************
659
660 /**
661 * Returns the default accept all file filter
662 */
663 public FileFilter getAcceptAllFileFilter(JFileChooser fc) {
664 return acceptAllFileFilter;
665 }
666
667
668 public FileView getFileView(JFileChooser fc) {
669 return fileView;
670 }
671
672
673 /**
674 * Returns the title of this dialog
675 */
676 public String getDialogTitle(JFileChooser fc) {
677 String dialogTitle = fc.getDialogTitle();
678 if (dialogTitle != null) {
679 return dialogTitle;
680 } else if (fc.getDialogType() == JFileChooser.OPEN_DIALOG) {
681 return openDialogTitleText;
682 } else if (fc.getDialogType() == JFileChooser.SAVE_DIALOG) {
683 return saveDialogTitleText;
684 } else {
685 return getApproveButtonText(fc);
686 }
687 }
688
689
690 public int getApproveButtonMnemonic(JFileChooser fc) {
691 int mnemonic = fc.getApproveButtonMnemonic();
692 if (mnemonic > 0) {
693 return mnemonic;
694 } else if (fc.getDialogType() == JFileChooser.OPEN_DIALOG) {
695 return openButtonMnemonic;
696 } else if (fc.getDialogType() == JFileChooser.SAVE_DIALOG) {
697 return saveButtonMnemonic;
698 } else {
699 return mnemonic;
700 }
701 }
702
703 public String getApproveButtonText(JFileChooser fc) {
704 String buttonText = fc.getApproveButtonText();
705 if (buttonText != null) {
706 return buttonText;
707 } else if (fc.getDialogType() == JFileChooser.OPEN_DIALOG) {
708 return openButtonText;
709 } else if (fc.getDialogType() == JFileChooser.SAVE_DIALOG) {
710 return saveButtonText;
711 } else {
712 return null;
713 }
714 }
715
716
717 // *****************************
718 // ***** Directory Actions *****
719 // *****************************
720
721 public Action getNewFolderAction() {
722 if (newFolderAction == null) {
723 newFolderAction = new NewFolderAction();
724 // Note: Don't return null for readOnly, it might
725 // break older apps.
726 if (readOnly) {
727 newFolderAction.setEnabled(false);
728 }
729 }
730 return newFolderAction;
731 }
732
733 public Action getGoHomeAction() {
734 return goHomeAction;
735 }
736
737 public Action getChangeToParentDirectoryAction() {
738 return changeToParentDirectoryAction;
739 }
740
741 public Action getApproveSelectionAction() {
742 return approveSelectionAction;
743 }
744
745 public Action getCancelSelectionAction() {
746 return cancelSelectionAction;
747 }
748
749 public Action getUpdateAction() {
750 return updateAction;
751 }
752
753
754 /**
755 * Creates a new folder.
756 */
757 @SuppressWarnings("serial") // Superclass is not serializable across versions
758 protected class NewFolderAction extends AbstractAction {
759 protected NewFolderAction() {
760 super(FilePane.ACTION_NEW_FOLDER);
761 }
762 public void actionPerformed(ActionEvent e) {
763 if (readOnly) {
764 return;
765 }
766 JFileChooser fc = getFileChooser();
767 File currentDirectory = fc.getCurrentDirectory();
768
769 if (!currentDirectory.exists()) {
770 JOptionPane.showMessageDialog(
771 fc,
772 newFolderParentDoesntExistText,
773 newFolderParentDoesntExistTitleText, JOptionPane.WARNING_MESSAGE);
774 return;
775 }
776
777 File newFolder;
778 try {
779 newFolder = fc.getFileSystemView().createNewFolder(currentDirectory);
780 if (fc.isMultiSelectionEnabled()) {
781 fc.setSelectedFiles(new File[] { newFolder });
782 } else {
783 fc.setSelectedFile(newFolder);
784 }
785 } catch (IOException exc) {
786 JOptionPane.showMessageDialog(
787 fc,
788 newFolderErrorText + newFolderErrorSeparator + exc,
789 newFolderErrorText, JOptionPane.ERROR_MESSAGE);
790 return;
791 }
792
793 fc.rescanCurrentDirectory();
794 }
795 }
796
797 /**
798 * Acts on the "home" key event or equivalent event.
799 */
800 @SuppressWarnings("serial") // Superclass is not serializable across versions
801 protected class GoHomeAction extends AbstractAction {
802 protected GoHomeAction() {
803 super("Go Home");
804 }
805 public void actionPerformed(ActionEvent e) {
806 JFileChooser fc = getFileChooser();
807 changeDirectory(fc.getFileSystemView().getHomeDirectory());
808 }
809 }
810
811 @SuppressWarnings("serial") // Superclass is not serializable across versions
812 protected class ChangeToParentDirectoryAction extends AbstractAction {
813 protected ChangeToParentDirectoryAction() {
814 super("Go Up");
815 putValue(Action.ACTION_COMMAND_KEY, FilePane.ACTION_CHANGE_TO_PARENT_DIRECTORY);
816 }
817 public void actionPerformed(ActionEvent e) {
818 getFileChooser().changeToParentDirectory();
819 }
820 }
821
822 /**
823 * Responds to an Open or Save request
824 */
825 @SuppressWarnings("serial") // Superclass is not serializable across versions
826 protected class ApproveSelectionAction extends AbstractAction {
827 protected ApproveSelectionAction() {
828 super(FilePane.ACTION_APPROVE_SELECTION);
829 }
830 public void actionPerformed(ActionEvent e) {
831 if (isDirectorySelected()) {
832 File dir = getDirectory();
833 if (dir != null) {
834 try {
835 // Strip trailing ".."
836 dir = ShellFolder.getNormalizedFile(dir);
837 } catch (IOException ex) {
838 // Ok, use f as is
839 }
840 changeDirectory(dir);
841 return;
842 }
843 }
844
845 JFileChooser chooser = getFileChooser();
846
847 String filename = getFileName();
848 FileSystemView fs = chooser.getFileSystemView();
849 File dir = chooser.getCurrentDirectory();
1116 public boolean accept(File f) {
1117 if (f == null) {
1118 return false;
1119 }
1120 if (f.isDirectory()) {
1121 return true;
1122 }
1123 return pattern.matcher(f.getName()).matches();
1124 }
1125
1126 public String getDescription() {
1127 return globPattern;
1128 }
1129 }
1130
1131 /**
1132 * Responds to a cancel request.
1133 */
1134 @SuppressWarnings("serial") // Superclass is not serializable across versions
1135 protected class CancelSelectionAction extends AbstractAction {
1136 public void actionPerformed(ActionEvent e) {
1137 getFileChooser().cancelSelection();
1138 }
1139 }
1140
1141 /**
1142 * Rescans the files in the current directory
1143 */
1144 @SuppressWarnings("serial") // Superclass is not serializable across versions
1145 protected class UpdateAction extends AbstractAction {
1146 public void actionPerformed(ActionEvent e) {
1147 JFileChooser fc = getFileChooser();
1148 fc.setCurrentDirectory(fc.getFileSystemView().createFileObject(getDirectoryName()));
1149 fc.rescanCurrentDirectory();
1150 }
1151 }
1152
1153
1154 private void changeDirectory(File dir) {
1155 JFileChooser fc = getFileChooser();
1156 // Traverse shortcuts on Windows
1157 if (dir != null && FilePane.usesShellFolder(fc)) {
1158 try {
1159 ShellFolder shellFolder = ShellFolder.getShellFolder(dir);
1160
1161 if (shellFolder.isLink()) {
1162 File linkedTo = shellFolder.getLinkLocation();
1163
1164 // If linkedTo is null we try to use dir
1165 if (linkedTo != null) {
1171 } else {
1172 dir = shellFolder;
1173 }
1174 }
1175 } catch (FileNotFoundException ex) {
1176 return;
1177 }
1178 }
1179 fc.setCurrentDirectory(dir);
1180 if (fc.getFileSelectionMode() == JFileChooser.FILES_AND_DIRECTORIES &&
1181 fc.getFileSystemView().isFileSystem(dir)) {
1182
1183 setFileName(dir.getAbsolutePath());
1184 }
1185 }
1186
1187
1188 // *****************************************
1189 // ***** default AcceptAll file filter *****
1190 // *****************************************
1191 protected class AcceptAllFileFilter extends FileFilter {
1192
1193 public AcceptAllFileFilter() {
1194 }
1195
1196 public boolean accept(File f) {
1197 return true;
1198 }
1199
1200 public String getDescription() {
1201 return UIManager.getString("FileChooser.acceptAllFileFilterText");
1202 }
1203 }
1204
1205
1206 // ***********************
1207 // * FileView operations *
1208 // ***********************
1209 protected class BasicFileView extends FileView {
1210 /* FileView type descriptions */
1211 // PENDING(jeff) - pass in the icon cache size
1212 protected Hashtable<File,Icon> iconCache = new Hashtable<File,Icon>();
1213
1214 public BasicFileView() {
1215 }
1216
1217 public void clearIconCache() {
1218 iconCache = new Hashtable<File,Icon>();
1219 }
1220
1221 public String getName(File f) {
1222 // Note: Returns display name rather than file name
1223 String fileName = null;
1224 if(f != null) {
1225 fileName = getFileChooser().getFileSystemView().getSystemDisplayName(f);
1226 }
1227 return fileName;
1228 }
1229
1230
1231 public String getDescription(File f) {
1232 return f.getName();
1233 }
1234
1235 public String getTypeDescription(File f) {
1236 String type = getFileChooser().getFileSystemView().getSystemTypeDescription(f);
1237 if (type == null) {
1238 if (f.isDirectory()) {
1239 type = directoryDescriptionText;
1240 } else {
1241 type = fileDescriptionText;
1242 }
1243 }
1244 return type;
1245 }
1246
1247 public Icon getCachedIcon(File f) {
1248 return iconCache.get(f);
1249 }
1250
1251 public void cacheIcon(File f, Icon i) {
1252 if(f == null || i == null) {
1253 return;
1254 }
1255 iconCache.put(f, i);
1256 }
1257
1258 public Icon getIcon(File f) {
1259 Icon icon = getCachedIcon(f);
1260 if(icon != null) {
1261 return icon;
1262 }
1263 icon = fileIcon;
1264 if (f != null) {
1265 FileSystemView fsv = getFileChooser().getFileSystemView();
1266
1267 if (fsv.isFloppyDrive(f)) {
1268 icon = floppyDriveIcon;
1269 } else if (fsv.isDrive(f)) {
1270 icon = hardDriveIcon;
1271 } else if (fsv.isComputerNode(f)) {
1272 icon = computerIcon;
1273 } else if (f.isDirectory()) {
1274 icon = directoryIcon;
1275 }
1276 }
1277 cacheIcon(f, icon);
1278 return icon;
1279 }
1280
1281 public Boolean isHidden(File f) {
1282 String name = f.getName();
1283 if(name != null && name.charAt(0) == '.') {
1284 return Boolean.TRUE;
1285 } else {
1286 return Boolean.FALSE;
1287 }
1288 }
1289 }
1290
1291 private static final TransferHandler defaultTransferHandler = new FileTransferHandler();
1292
1293 /**
1294 * Data transfer support for the file chooser. Since files are currently presented
1295 * as a list, the list support is reused with the added flavor of DataFlavor.javaFileListFlavor
1296 */
1297 @SuppressWarnings("serial") // JDK-implementation class
1298 static class FileTransferHandler extends TransferHandler implements UIResource {
1299
1300 /**
|
1 /*
2 * Copyright (c) 1998, 2015, 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
33 import java.awt.*;
34 import java.awt.event.*;
35 import java.awt.datatransfer.*;
36 import java.beans.*;
37 import java.io.*;
38 import java.util.*;
39 import java.util.List;
40 import java.util.regex.*;
41 import sun.awt.shell.ShellFolder;
42 import sun.swing.*;
43 import sun.swing.SwingUtilities2;
44
45 /**
46 * Basic L&F implementation of a FileChooser.
47 *
48 * @author Jeff Dinkins
49 */
50 public class BasicFileChooserUI extends FileChooserUI {
51
52 /* FileView icons */
53 /** Directory icon */
54 protected Icon directoryIcon = null;
55 /** File icon */
56 protected Icon fileIcon = null;
57 /** Computer icon */
58 protected Icon computerIcon = null;
59 /** Hard drive icon */
60 protected Icon hardDriveIcon = null;
61 /** Floppy drive icon */
62 protected Icon floppyDriveIcon = null;
63
64 /** New folder icon */
65 protected Icon newFolderIcon = null;
66 /** Up folder icon */
67 protected Icon upFolderIcon = null;
68 /** Home folder icon */
69 protected Icon homeFolderIcon = null;
70 /** List view icon */
71 protected Icon listViewIcon = null;
72 /** Details view icon */
73 protected Icon detailsViewIcon = null;
74 /** View menu icon */
75 protected Icon viewMenuIcon = null;
76
77 /** Save button mnemonic */
78 protected int saveButtonMnemonic = 0;
79 /** Open button mnemonic */
80 protected int openButtonMnemonic = 0;
81 /** Cancel button mnemonic */
82 protected int cancelButtonMnemonic = 0;
83 /** Update button mnemonic */
84 protected int updateButtonMnemonic = 0;
85 /** Help button mnemonic */
86 protected int helpButtonMnemonic = 0;
87
88 /**
89 * The mnemonic keycode used for the approve button when a directory
90 * is selected and the current selection mode is FILES_ONLY.
91 *
92 * @since 1.4
93 */
94 protected int directoryOpenButtonMnemonic = 0;
95
96 /** Save button text */
97 protected String saveButtonText = null;
98 /** Open button text */
99 protected String openButtonText = null;
100 /** Cancel button text */
101 protected String cancelButtonText = null;
102 /** Update button text */
103 protected String updateButtonText = null;
104 /** Help button text */
105 protected String helpButtonText = null;
106
107 /**
108 * The label text displayed on the approve button when a directory
109 * is selected and the current selection mode is FILES_ONLY.
110 *
111 * @since 1.4
112 */
113 protected String directoryOpenButtonText = null;
114
115 /** Open dialog title text */
116 private String openDialogTitleText = null;
117 /** Save dialog title text */
118 private String saveDialogTitleText = null;
119
120 /** Save button tool tip text */
121 protected String saveButtonToolTipText = null;
122 /** Open button tool tip text */
123 protected String openButtonToolTipText = null;
124 /** Cancel button tool tip text */
125 protected String cancelButtonToolTipText = null;
126 /** Update button tool tip text */
127 protected String updateButtonToolTipText = null;
128 /** Help button tool tip text */
129 protected String helpButtonToolTipText = null;
130
131 /**
132 * The tooltip text displayed on the approve button when a directory
133 * is selected and the current selection mode is FILES_ONLY.
134 *
135 * @since 1.4
136 */
137 protected String directoryOpenButtonToolTipText = null;
138
139 // Some generic FileChooser functions
140 private Action approveSelectionAction = new ApproveSelectionAction();
141 private Action cancelSelectionAction = new CancelSelectionAction();
142 private Action updateAction = new UpdateAction();
143 private Action newFolderAction;
144 private Action goHomeAction = new GoHomeAction();
145 private Action changeToParentDirectoryAction = new ChangeToParentDirectoryAction();
146
147 private String newFolderErrorSeparator = null;
148 private String newFolderErrorText = null;
169 private JPanel accessoryPanel = null;
170 private Handler handler;
171
172 /**
173 * Creates a {@code BasicFileChooserUI} implementation
174 * for the specified component. By default
175 * the {@code BasicLookAndFeel} class uses
176 * {@code createUI} methods of all basic UIs classes
177 * to instantiate UIs.
178 *
179 * @param c the {@code JFileChooser} which needs a UI
180 * @return the {@code BasicFileChooserUI} object
181 *
182 * @see UIDefaults#getUI(JComponent)
183 * @since 1.7
184 */
185 public static ComponentUI createUI(JComponent c) {
186 return new BasicFileChooserUI((JFileChooser) c);
187 }
188
189 /**
190 * Constructs a {@code BasicFileChooserUI}.
191 * @param b file chooser
192 */
193 public BasicFileChooserUI(JFileChooser b) {
194 }
195
196 /**
197 * Installs the UI.
198 * @param c the component
199 */
200 public void installUI(JComponent c) {
201 accessoryPanel = new JPanel(new BorderLayout());
202 filechooser = (JFileChooser) c;
203
204 createModel();
205
206 clearIconCache();
207
208 installDefaults(filechooser);
209 installComponents(filechooser);
210 installListeners(filechooser);
211 filechooser.applyComponentOrientation(filechooser.getComponentOrientation());
212 }
213
214 /**
215 * Uninstalls the UI.
216 * @param c the component
217 */
218 public void uninstallUI(JComponent c) {
219 uninstallListeners(filechooser);
220 uninstallComponents(filechooser);
221 uninstallDefaults(filechooser);
222
223 if(accessoryPanel != null) {
224 accessoryPanel.removeAll();
225 }
226
227 accessoryPanel = null;
228 getFileChooser().removeAll();
229
230 handler = null;
231 }
232
233 /**
234 * Installs the components.
235 * @param fc the file chooser
236 */
237 public void installComponents(JFileChooser fc) {
238 }
239
240 /**
241 * Uninstalls the components.
242 * @param fc the file chooser
243 */
244 public void uninstallComponents(JFileChooser fc) {
245 }
246
247 /**
248 * Installs the listeners.
249 * @param fc the file chooser
250 */
251 protected void installListeners(JFileChooser fc) {
252 propertyChangeListener = createPropertyChangeListener(fc);
253 if(propertyChangeListener != null) {
254 fc.addPropertyChangeListener(propertyChangeListener);
255 }
256 fc.addPropertyChangeListener(getModel());
257
258 InputMap inputMap = getInputMap(JComponent.
259 WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
260 SwingUtilities.replaceUIInputMap(fc, JComponent.
261 WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, inputMap);
262 ActionMap actionMap = getActionMap();
263 SwingUtilities.replaceUIActionMap(fc, actionMap);
264 }
265
266 InputMap getInputMap(int condition) {
267 if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) {
268 return (InputMap)DefaultLookup.get(getFileChooser(), this,
269 "FileChooser.ancestorInputMap");
270 }
276 }
277
278 ActionMap createActionMap() {
279 ActionMap map = new ActionMapUIResource();
280
281 Action refreshAction = new UIAction(FilePane.ACTION_REFRESH) {
282 public void actionPerformed(ActionEvent evt) {
283 getFileChooser().rescanCurrentDirectory();
284 }
285 };
286
287 map.put(FilePane.ACTION_APPROVE_SELECTION, getApproveSelectionAction());
288 map.put(FilePane.ACTION_CANCEL, getCancelSelectionAction());
289 map.put(FilePane.ACTION_REFRESH, refreshAction);
290 map.put(FilePane.ACTION_CHANGE_TO_PARENT_DIRECTORY,
291 getChangeToParentDirectoryAction());
292 return map;
293 }
294
295
296 /**
297 * Uninstalls the listeners.
298 * @param fc the file chooser
299 */
300 protected void uninstallListeners(JFileChooser fc) {
301 if(propertyChangeListener != null) {
302 fc.removePropertyChangeListener(propertyChangeListener);
303 }
304 fc.removePropertyChangeListener(getModel());
305 SwingUtilities.replaceUIInputMap(fc, JComponent.
306 WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null);
307 SwingUtilities.replaceUIActionMap(fc, null);
308 }
309
310
311 /**
312 * Installs the defaults.
313 * @param fc the file chooser
314 */
315 protected void installDefaults(JFileChooser fc) {
316 installIcons(fc);
317 installStrings(fc);
318 usesSingleFilePane = UIManager.getBoolean("FileChooser.usesSingleFilePane");
319 readOnly = UIManager.getBoolean("FileChooser.readOnly");
320 TransferHandler th = fc.getTransferHandler();
321 if (th == null || th instanceof UIResource) {
322 fc.setTransferHandler(defaultTransferHandler);
323 }
324 LookAndFeel.installProperty(fc, "opaque", Boolean.FALSE);
325 }
326
327 /**
328 * Installs the icons.
329 * @param fc the file chooser
330 */
331 protected void installIcons(JFileChooser fc) {
332 directoryIcon = UIManager.getIcon("FileView.directoryIcon");
333 fileIcon = UIManager.getIcon("FileView.fileIcon");
334 computerIcon = UIManager.getIcon("FileView.computerIcon");
335 hardDriveIcon = UIManager.getIcon("FileView.hardDriveIcon");
336 floppyDriveIcon = UIManager.getIcon("FileView.floppyDriveIcon");
337
338 newFolderIcon = UIManager.getIcon("FileChooser.newFolderIcon");
339 upFolderIcon = UIManager.getIcon("FileChooser.upFolderIcon");
340 homeFolderIcon = UIManager.getIcon("FileChooser.homeFolderIcon");
341 detailsViewIcon = UIManager.getIcon("FileChooser.detailsViewIcon");
342 listViewIcon = UIManager.getIcon("FileChooser.listViewIcon");
343 viewMenuIcon = UIManager.getIcon("FileChooser.viewMenuIcon");
344 }
345
346 /**
347 * Installs the strings.
348 * @param fc the file chooser
349 */
350 protected void installStrings(JFileChooser fc) {
351
352 Locale l = fc.getLocale();
353 newFolderErrorText = UIManager.getString("FileChooser.newFolderErrorText",l);
354 newFolderErrorSeparator = UIManager.getString("FileChooser.newFolderErrorSeparator",l);
355
356 newFolderParentDoesntExistTitleText = UIManager.getString("FileChooser.newFolderParentDoesntExistTitleText", l);
357 newFolderParentDoesntExistText = UIManager.getString("FileChooser.newFolderParentDoesntExistText", l);
358
359 fileDescriptionText = UIManager.getString("FileChooser.fileDescriptionText",l);
360 directoryDescriptionText = UIManager.getString("FileChooser.directoryDescriptionText",l);
361
362 saveButtonText = UIManager.getString("FileChooser.saveButtonText",l);
363 openButtonText = UIManager.getString("FileChooser.openButtonText",l);
364 saveDialogTitleText = UIManager.getString("FileChooser.saveDialogTitleText",l);
365 openDialogTitleText = UIManager.getString("FileChooser.openDialogTitleText",l);
366 cancelButtonText = UIManager.getString("FileChooser.cancelButtonText",l);
367 updateButtonText = UIManager.getString("FileChooser.updateButtonText",l);
368 helpButtonText = UIManager.getString("FileChooser.helpButtonText",l);
369 directoryOpenButtonText = UIManager.getString("FileChooser.directoryOpenButtonText",l);
370
371 saveButtonMnemonic = getMnemonic("FileChooser.saveButtonMnemonic", l);
372 openButtonMnemonic = getMnemonic("FileChooser.openButtonMnemonic", l);
373 cancelButtonMnemonic = getMnemonic("FileChooser.cancelButtonMnemonic", l);
374 updateButtonMnemonic = getMnemonic("FileChooser.updateButtonMnemonic", l);
375 helpButtonMnemonic = getMnemonic("FileChooser.helpButtonMnemonic", l);
376 directoryOpenButtonMnemonic = getMnemonic("FileChooser.directoryOpenButtonMnemonic", l);
377
378 saveButtonToolTipText = UIManager.getString("FileChooser.saveButtonToolTipText",l);
379 openButtonToolTipText = UIManager.getString("FileChooser.openButtonToolTipText",l);
380 cancelButtonToolTipText = UIManager.getString("FileChooser.cancelButtonToolTipText",l);
381 updateButtonToolTipText = UIManager.getString("FileChooser.updateButtonToolTipText",l);
382 helpButtonToolTipText = UIManager.getString("FileChooser.helpButtonToolTipText",l);
383 directoryOpenButtonToolTipText = UIManager.getString("FileChooser.directoryOpenButtonToolTipText",l);
384 }
385
386 /**
387 * Uninstalls the defaults.
388 * @param fc the file chooser
389 */
390 protected void uninstallDefaults(JFileChooser fc) {
391 uninstallIcons(fc);
392 uninstallStrings(fc);
393 if (fc.getTransferHandler() instanceof UIResource) {
394 fc.setTransferHandler(null);
395 }
396 }
397
398 /**
399 * Uninstalls the icons.
400 * @param fc the file chooser
401 */
402 protected void uninstallIcons(JFileChooser fc) {
403 directoryIcon = null;
404 fileIcon = null;
405 computerIcon = null;
406 hardDriveIcon = null;
407 floppyDriveIcon = null;
408
409 newFolderIcon = null;
410 upFolderIcon = null;
411 homeFolderIcon = null;
412 detailsViewIcon = null;
413 listViewIcon = null;
414 viewMenuIcon = null;
415 }
416
417 /**
418 * Uninstalls the strings.
419 * @param fc the file chooser
420 */
421 protected void uninstallStrings(JFileChooser fc) {
422 saveButtonText = null;
423 openButtonText = null;
424 cancelButtonText = null;
425 updateButtonText = null;
426 helpButtonText = null;
427 directoryOpenButtonText = null;
428
429 saveButtonToolTipText = null;
430 openButtonToolTipText = null;
431 cancelButtonToolTipText = null;
432 updateButtonToolTipText = null;
433 helpButtonToolTipText = null;
434 directoryOpenButtonToolTipText = null;
435 }
436
437 /**
438 * Creates the model.
439 */
440 protected void createModel() {
441 if (model != null) {
442 model.invalidateFileCache();
443 }
444 model = new BasicDirectoryModel(getFileChooser());
445 }
446
447 /**
448 * Returns the model.
449 * @return the model
450 */
451 public BasicDirectoryModel getModel() {
452 return model;
453 }
454
455 /**
456 * Creates the property change listener.
457 * @param fc the file chooser
458 * @return the property change listener
459 */
460 public PropertyChangeListener createPropertyChangeListener(JFileChooser fc) {
461 return null;
462 }
463
464 /**
465 * Returns the file name.
466 * @return the file name
467 */
468 public String getFileName() {
469 return null;
470 }
471
472 /**
473 * Returns the directory name.
474 * @return the directory name
475 */
476 public String getDirectoryName() {
477 return null;
478 }
479
480 /**
481 * Sets the file name.
482 * @param filename the file name
483 */
484 public void setFileName(String filename) {
485 }
486
487 /**
488 * Sets the directory name.
489 * @param dirname the file name
490 */
491 public void setDirectoryName(String dirname) {
492 }
493
494 /**
495 * {@inheritDoc}
496 */
497 public void rescanCurrentDirectory(JFileChooser fc) {
498 }
499
500 /**
501 * {@inheritDoc}
502 */
503 public void ensureFileIsVisible(JFileChooser fc, File f) {
504 }
505
506 /**
507 * Returns the file chooser.
508 * @return the file chooser
509 */
510 public JFileChooser getFileChooser() {
511 return filechooser;
512 }
513
514 /**
515 * Returns the accessory panel.
516 * @return the accessory panel
517 */
518 public JPanel getAccessoryPanel() {
519 return accessoryPanel;
520 }
521
522 /**
523 * Returns the approve button.
524 * @param fc the file chooser
525 * @return the approve button
526 */
527 protected JButton getApproveButton(JFileChooser fc) {
528 return null;
529 }
530
531 /**
532 * {@inheritDoc}
533 */
534 public JButton getDefaultButton(JFileChooser fc) {
535 return getApproveButton(fc);
536 }
537
538 /**
539 * Returns the approve button tool tip.
540 * @param fc the file chooser
541 * @return the approve button tool tip
542 */
543 public String getApproveButtonToolTipText(JFileChooser fc) {
544 String tooltipText = fc.getApproveButtonToolTipText();
545 if(tooltipText != null) {
546 return tooltipText;
547 }
548
549 if(fc.getDialogType() == JFileChooser.OPEN_DIALOG) {
550 return openButtonToolTipText;
551 } else if(fc.getDialogType() == JFileChooser.SAVE_DIALOG) {
552 return saveButtonToolTipText;
553 }
554 return null;
555 }
556
557 /**
558 * Clears the icon cache.
559 */
560 public void clearIconCache() {
561 fileView.clearIconCache();
562 }
563
564
565 // ********************************************
566 // ************ Create Listeners **************
567 // ********************************************
568
569 private Handler getHandler() {
570 if (handler == null) {
571 handler = new Handler();
572 }
573 return handler;
574 }
575
576 /**
577 * Creates a double click listener.
578 * @param fc the file chooser
579 * @param list the list
580 * @return a double click listener
581 */
582 protected MouseListener createDoubleClickListener(JFileChooser fc,
583 JList<?> list) {
584 return new Handler(list);
585 }
586
587 /**
588 * Creates a list selection listener.
589 * @param fc the file chooser
590 * @return a list selection listener
591 */
592 public ListSelectionListener createListSelectionListener(JFileChooser fc) {
593 return getHandler();
594 }
595
596 private class Handler implements MouseListener, ListSelectionListener {
597 JList<?> list;
598
599 Handler() {
600 }
601
602 Handler(JList<?> list) {
603 this.list = list;
604 }
605
606 public void mouseClicked(MouseEvent evt) {
607 // Note: we can't depend on evt.getSource() because of backward
608 // compatibility
609 if (list != null &&
610 SwingUtilities.isLeftMouseButton(evt) &&
611 (evt.getClickCount()%2 == 0)) {
698 && file.isDirectory()
699 && chooser.isTraversable(file)
700 && (useSetDirectory || !fsv.isFileSystem(file))) {
701
702 setDirectorySelected(true);
703 setDirectory(file);
704 if (usesSingleFilePane) {
705 chooser.setSelectedFile(null);
706 }
707 } else {
708 setDirectorySelected(false);
709 if (file != null) {
710 chooser.setSelectedFile(file);
711 }
712 }
713 }
714 }
715 }
716 }
717
718 /**
719 * A double click listener.
720 */
721 protected class DoubleClickListener extends MouseAdapter {
722 // NOTE: This class exists only for backward compatibility. All
723 // its functionality has been moved into Handler. If you need to add
724 // new functionality add it to the Handler, but make sure this
725 // class calls into the Handler.
726 Handler handler;
727 /**
728 * Constucts a {@code DoubleClickListener}.
729 * @param list the lsit
730 */
731 public DoubleClickListener(JList<?> list) {
732 handler = new Handler(list);
733 }
734
735 /**
736 * The JList used for representing the files is created by subclasses, but the
737 * selection is monitored in this class. The TransferHandler installed in the
738 * JFileChooser is also installed in the file list as it is used as the actual
739 * transfer source. The list is updated on a mouse enter to reflect the current
740 * data transfer state of the file chooser.
741 */
742 public void mouseEntered(MouseEvent e) {
743 handler.mouseEntered(e);
744 }
745
746 /** {@inheritDoc} */
747 public void mouseClicked(MouseEvent e) {
748 handler.mouseClicked(e);
749 }
750 }
751
752 /**
753 * A selection listener.
754 */
755 protected class SelectionListener implements ListSelectionListener {
756 // NOTE: This class exists only for backward compatibility. All
757 // its functionality has been moved into Handler. If you need to add
758 // new functionality add it to the Handler, but make sure this
759 // class calls into the Handler.
760 /** {@inheritDoc} */
761 public void valueChanged(ListSelectionEvent e) {
762 getHandler().valueChanged(e);
763 }
764 }
765
766 /**
767 * Property to remember whether a directory is currently selected in the UI.
768 *
769 * @return <code>true</code> iff a directory is currently selected.
770 * @since 1.4
771 */
772 protected boolean isDirectorySelected() {
773 return directorySelected;
774 }
775
776 /**
777 * Property to remember whether a directory is currently selected in the UI.
778 * This is normally called by the UI on a selection event.
779 *
780 * @param b iff a directory is currently selected.
816
817 // *******************************************************
818 // ************ FileChooser UI PLAF methods **************
819 // *******************************************************
820
821 /**
822 * Returns the default accept all file filter
823 */
824 public FileFilter getAcceptAllFileFilter(JFileChooser fc) {
825 return acceptAllFileFilter;
826 }
827
828
829 public FileView getFileView(JFileChooser fc) {
830 return fileView;
831 }
832
833
834 /**
835 * Returns the title of this dialog
836 * @param fc the file chooser
837 * @return the title of this dialog
838 */
839 public String getDialogTitle(JFileChooser fc) {
840 String dialogTitle = fc.getDialogTitle();
841 if (dialogTitle != null) {
842 return dialogTitle;
843 } else if (fc.getDialogType() == JFileChooser.OPEN_DIALOG) {
844 return openDialogTitleText;
845 } else if (fc.getDialogType() == JFileChooser.SAVE_DIALOG) {
846 return saveDialogTitleText;
847 } else {
848 return getApproveButtonText(fc);
849 }
850 }
851
852 /**
853 * Returns the approve button mnemonic.
854 * @param fc the file chooser
855 * @return the approve button mnemonic
856 */
857 public int getApproveButtonMnemonic(JFileChooser fc) {
858 int mnemonic = fc.getApproveButtonMnemonic();
859 if (mnemonic > 0) {
860 return mnemonic;
861 } else if (fc.getDialogType() == JFileChooser.OPEN_DIALOG) {
862 return openButtonMnemonic;
863 } else if (fc.getDialogType() == JFileChooser.SAVE_DIALOG) {
864 return saveButtonMnemonic;
865 } else {
866 return mnemonic;
867 }
868 }
869
870 /** {@inheritDoc} */
871 public String getApproveButtonText(JFileChooser fc) {
872 String buttonText = fc.getApproveButtonText();
873 if (buttonText != null) {
874 return buttonText;
875 } else if (fc.getDialogType() == JFileChooser.OPEN_DIALOG) {
876 return openButtonText;
877 } else if (fc.getDialogType() == JFileChooser.SAVE_DIALOG) {
878 return saveButtonText;
879 } else {
880 return null;
881 }
882 }
883
884
885 // *****************************
886 // ***** Directory Actions *****
887 // *****************************
888
889 /**
890 * Returns a new folder action.
891 * @return a new folder action
892 */
893 public Action getNewFolderAction() {
894 if (newFolderAction == null) {
895 newFolderAction = new NewFolderAction();
896 // Note: Don't return null for readOnly, it might
897 // break older apps.
898 if (readOnly) {
899 newFolderAction.setEnabled(false);
900 }
901 }
902 return newFolderAction;
903 }
904
905 /**
906 * Returns a go home action.
907 * @return a go home action
908 */
909 public Action getGoHomeAction() {
910 return goHomeAction;
911 }
912
913 /**
914 * Returns a change to parent directory action.
915 * @return a change to parent directory action
916 */
917 public Action getChangeToParentDirectoryAction() {
918 return changeToParentDirectoryAction;
919 }
920
921 /**
922 * Returns an approve selection action.
923 * @return an approve selection action
924 */
925 public Action getApproveSelectionAction() {
926 return approveSelectionAction;
927 }
928
929 /**
930 * Returns a cancel selection action.
931 * @return a cancel selection action
932 */
933 public Action getCancelSelectionAction() {
934 return cancelSelectionAction;
935 }
936
937 /**
938 * Returns an update action.
939 * @return an update action
940 */
941 public Action getUpdateAction() {
942 return updateAction;
943 }
944
945
946 /**
947 * Creates a new folder.
948 */
949 @SuppressWarnings("serial") // Superclass is not serializable across versions
950 protected class NewFolderAction extends AbstractAction {
951 /** Constructs a {@code NewFolderAction}. */
952 protected NewFolderAction() {
953 super(FilePane.ACTION_NEW_FOLDER);
954 }
955 /** {@inheritDoc} */
956 public void actionPerformed(ActionEvent e) {
957 if (readOnly) {
958 return;
959 }
960 JFileChooser fc = getFileChooser();
961 File currentDirectory = fc.getCurrentDirectory();
962
963 if (!currentDirectory.exists()) {
964 JOptionPane.showMessageDialog(
965 fc,
966 newFolderParentDoesntExistText,
967 newFolderParentDoesntExistTitleText, JOptionPane.WARNING_MESSAGE);
968 return;
969 }
970
971 File newFolder;
972 try {
973 newFolder = fc.getFileSystemView().createNewFolder(currentDirectory);
974 if (fc.isMultiSelectionEnabled()) {
975 fc.setSelectedFiles(new File[] { newFolder });
976 } else {
977 fc.setSelectedFile(newFolder);
978 }
979 } catch (IOException exc) {
980 JOptionPane.showMessageDialog(
981 fc,
982 newFolderErrorText + newFolderErrorSeparator + exc,
983 newFolderErrorText, JOptionPane.ERROR_MESSAGE);
984 return;
985 }
986
987 fc.rescanCurrentDirectory();
988 }
989 }
990
991 /**
992 * Acts on the "home" key event or equivalent event.
993 */
994 @SuppressWarnings("serial") // Superclass is not serializable across versions
995 protected class GoHomeAction extends AbstractAction {
996 /** Constructs a {@code GoHomeAction}. */
997 protected GoHomeAction() {
998 super("Go Home");
999 }
1000 public void actionPerformed(ActionEvent e) {
1001 JFileChooser fc = getFileChooser();
1002 changeDirectory(fc.getFileSystemView().getHomeDirectory());
1003 }
1004 }
1005
1006 /**
1007 * Change to parent directory action.
1008 */
1009 @SuppressWarnings("serial") // Superclass is not serializable across versions
1010 protected class ChangeToParentDirectoryAction extends AbstractAction {
1011 /** Constructs a {@code ChangeToParentDirectoryAction}. */
1012 protected ChangeToParentDirectoryAction() {
1013 super("Go Up");
1014 putValue(Action.ACTION_COMMAND_KEY, FilePane.ACTION_CHANGE_TO_PARENT_DIRECTORY);
1015 }
1016 /** {@inheritDoc} */
1017 public void actionPerformed(ActionEvent e) {
1018 getFileChooser().changeToParentDirectory();
1019 }
1020 }
1021
1022 /**
1023 * Responds to an Open or Save request
1024 */
1025 @SuppressWarnings("serial") // Superclass is not serializable across versions
1026 protected class ApproveSelectionAction extends AbstractAction {
1027 /** Constructs an {@code ApproveSelectionAction}. */
1028 protected ApproveSelectionAction() {
1029 super(FilePane.ACTION_APPROVE_SELECTION);
1030 }
1031 /** {@inheritDoc} */
1032 public void actionPerformed(ActionEvent e) {
1033 if (isDirectorySelected()) {
1034 File dir = getDirectory();
1035 if (dir != null) {
1036 try {
1037 // Strip trailing ".."
1038 dir = ShellFolder.getNormalizedFile(dir);
1039 } catch (IOException ex) {
1040 // Ok, use f as is
1041 }
1042 changeDirectory(dir);
1043 return;
1044 }
1045 }
1046
1047 JFileChooser chooser = getFileChooser();
1048
1049 String filename = getFileName();
1050 FileSystemView fs = chooser.getFileSystemView();
1051 File dir = chooser.getCurrentDirectory();
1318 public boolean accept(File f) {
1319 if (f == null) {
1320 return false;
1321 }
1322 if (f.isDirectory()) {
1323 return true;
1324 }
1325 return pattern.matcher(f.getName()).matches();
1326 }
1327
1328 public String getDescription() {
1329 return globPattern;
1330 }
1331 }
1332
1333 /**
1334 * Responds to a cancel request.
1335 */
1336 @SuppressWarnings("serial") // Superclass is not serializable across versions
1337 protected class CancelSelectionAction extends AbstractAction {
1338 /** {@inheritDoc} */
1339 public void actionPerformed(ActionEvent e) {
1340 getFileChooser().cancelSelection();
1341 }
1342 }
1343
1344 /**
1345 * Rescans the files in the current directory
1346 */
1347 @SuppressWarnings("serial") // Superclass is not serializable across versions
1348 protected class UpdateAction extends AbstractAction {
1349 /** {@inheritDoc} */
1350 public void actionPerformed(ActionEvent e) {
1351 JFileChooser fc = getFileChooser();
1352 fc.setCurrentDirectory(fc.getFileSystemView().createFileObject(getDirectoryName()));
1353 fc.rescanCurrentDirectory();
1354 }
1355 }
1356
1357
1358 private void changeDirectory(File dir) {
1359 JFileChooser fc = getFileChooser();
1360 // Traverse shortcuts on Windows
1361 if (dir != null && FilePane.usesShellFolder(fc)) {
1362 try {
1363 ShellFolder shellFolder = ShellFolder.getShellFolder(dir);
1364
1365 if (shellFolder.isLink()) {
1366 File linkedTo = shellFolder.getLinkLocation();
1367
1368 // If linkedTo is null we try to use dir
1369 if (linkedTo != null) {
1375 } else {
1376 dir = shellFolder;
1377 }
1378 }
1379 } catch (FileNotFoundException ex) {
1380 return;
1381 }
1382 }
1383 fc.setCurrentDirectory(dir);
1384 if (fc.getFileSelectionMode() == JFileChooser.FILES_AND_DIRECTORIES &&
1385 fc.getFileSystemView().isFileSystem(dir)) {
1386
1387 setFileName(dir.getAbsolutePath());
1388 }
1389 }
1390
1391
1392 // *****************************************
1393 // ***** default AcceptAll file filter *****
1394 // *****************************************
1395 /**
1396 * Accept all file filter.
1397 */
1398 protected class AcceptAllFileFilter extends FileFilter {
1399
1400 /** Constructs an {@code AcceptAllFileFilter}. */
1401 public AcceptAllFileFilter() {
1402 }
1403
1404 /**
1405 * Returns true.
1406 * @param f the file
1407 * @return true
1408 */
1409 public boolean accept(File f) {
1410 return true;
1411 }
1412
1413 /**
1414 * {@inheritDoc}
1415 */
1416 public String getDescription() {
1417 return UIManager.getString("FileChooser.acceptAllFileFilterText");
1418 }
1419 }
1420
1421
1422 // ***********************
1423 // * FileView operations *
1424 // ***********************
1425 /**
1426 * A basic file view.
1427 */
1428 protected class BasicFileView extends FileView {
1429 /* FileView type descriptions */
1430 /** The icon cache */
1431 protected Hashtable<File,Icon> iconCache = new Hashtable<File,Icon>();
1432
1433 /** Constructs a {@code BasicFileView}. */
1434 public BasicFileView() {
1435 }
1436
1437 /**
1438 * Clears the icon cache.
1439 */
1440 public void clearIconCache() {
1441 iconCache = new Hashtable<File,Icon>();
1442 }
1443
1444 /** {@inheritDoc} */
1445 public String getName(File f) {
1446 // Note: Returns display name rather than file name
1447 String fileName = null;
1448 if(f != null) {
1449 fileName = getFileChooser().getFileSystemView().getSystemDisplayName(f);
1450 }
1451 return fileName;
1452 }
1453
1454 /** {@inheritDoc} */
1455 public String getDescription(File f) {
1456 return f.getName();
1457 }
1458
1459 /** {@inheritDoc} */
1460 public String getTypeDescription(File f) {
1461 String type = getFileChooser().getFileSystemView().getSystemTypeDescription(f);
1462 if (type == null) {
1463 if (f.isDirectory()) {
1464 type = directoryDescriptionText;
1465 } else {
1466 type = fileDescriptionText;
1467 }
1468 }
1469 return type;
1470 }
1471
1472 /**
1473 * Returns the cached icon for the file.
1474 * @param f the file
1475 * @return the cached icon for the file
1476 */
1477 public Icon getCachedIcon(File f) {
1478 return iconCache.get(f);
1479 }
1480
1481 /**
1482 * Caches an icon for a file.
1483 * @param f the file
1484 * @param i the icon
1485 */
1486 public void cacheIcon(File f, Icon i) {
1487 if(f == null || i == null) {
1488 return;
1489 }
1490 iconCache.put(f, i);
1491 }
1492
1493 /** {@inheritDoc} */
1494 public Icon getIcon(File f) {
1495 Icon icon = getCachedIcon(f);
1496 if(icon != null) {
1497 return icon;
1498 }
1499 icon = fileIcon;
1500 if (f != null) {
1501 FileSystemView fsv = getFileChooser().getFileSystemView();
1502
1503 if (fsv.isFloppyDrive(f)) {
1504 icon = floppyDriveIcon;
1505 } else if (fsv.isDrive(f)) {
1506 icon = hardDriveIcon;
1507 } else if (fsv.isComputerNode(f)) {
1508 icon = computerIcon;
1509 } else if (f.isDirectory()) {
1510 icon = directoryIcon;
1511 }
1512 }
1513 cacheIcon(f, icon);
1514 return icon;
1515 }
1516
1517 /**
1518 * Returns whether or not a file is hidden.
1519 * @param f the file
1520 * @return whether or not a file is hidden
1521 */
1522 public Boolean isHidden(File f) {
1523 String name = f.getName();
1524 if(name != null && name.charAt(0) == '.') {
1525 return Boolean.TRUE;
1526 } else {
1527 return Boolean.FALSE;
1528 }
1529 }
1530 }
1531
1532 private static final TransferHandler defaultTransferHandler = new FileTransferHandler();
1533
1534 /**
1535 * Data transfer support for the file chooser. Since files are currently presented
1536 * as a list, the list support is reused with the added flavor of DataFlavor.javaFileListFlavor
1537 */
1538 @SuppressWarnings("serial") // JDK-implementation class
1539 static class FileTransferHandler extends TransferHandler implements UIResource {
1540
1541 /**
|