History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/javax/swing/plaf/basic/BasicFileChooserUI.java (1 of 18352 files). Show all

Unified · Split

java/pkg/javax/swing/plaf/basic/BasicFileChooserUI.java+1372−0
@@ -0,0 +1,1372 @@
1/*
2 * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package javax.swing.plaf.basic;
27
28import javax.swing.*;
29import javax.swing.filechooser.*;
30import javax.swing.filechooser.FileFilter;
31import javax.swing.event.*;
32import javax.swing.plaf.*;
33import java.awt.*;
34import java.awt.event.*;
35import java.awt.datatransfer.*;
36import java.beans.*;
37import java.io.*;
38import java.util.*;
39import java.util.List;
40import java.util.regex.*;
41import sun.awt.shell.ShellFolder;
42import sun.swing.*;
43import sun.swing.SwingUtilities2;
44
45/**
46 * Basic L&F implementation of a FileChooser.
47 *
48 * @author Jeff Dinkins
49 */
50public 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;
121 private String newFolderParentDoesntExistTitleText = null;
122 private String newFolderParentDoesntExistText = null;
123 private String fileDescriptionText = null;
124 private String directoryDescriptionText = null;
125
126 private JFileChooser filechooser = null;
127
128 private boolean directorySelected = false;
129 private File directory = null;
130
131 private PropertyChangeListener propertyChangeListener = null;
132 private AcceptAllFileFilter acceptAllFileFilter = new AcceptAllFileFilter();
133 private FileFilter actualFileFilter = null;
134 private GlobFilter globFilter = null;
135 private BasicDirectoryModel model = null;
136 private BasicFileView fileView = new BasicFileView();
137 private boolean usesSingleFilePane;
138 private boolean readOnly;
139
140 // The accessoryPanel is a container to place the JFileChooser accessory component
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 }
219 return null;
220 }
221
222 ActionMap getActionMap() {
223 return createActionMap();
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 // compatability
460 if (list != null &&
461 SwingUtilities.isLeftMouseButton(evt) &&
462 (evt.getClickCount()%2 == 0)) {
463
464 int index = SwingUtilities2.loc2IndexFileList(list, evt.getPoint());
465 if (index >= 0) {
466 File f = (File)list.getModel().getElementAt(index);
467 try {
468 // Strip trailing ".."
469 f = ShellFolder.getNormalizedFile(f);
470 } catch (IOException ex) {
471 // That's ok, we'll use f as is
472 }
473 if(getFileChooser().isTraversable(f)) {
474 list.clearSelection();
475 changeDirectory(f);
476 } else {
477 getFileChooser().approveSelection();
478 }
479 }
480 }
481 }
482
483 public void mouseEntered(MouseEvent evt) {
484 if (list != null) {
485 TransferHandler th1 = getFileChooser().getTransferHandler();
486 TransferHandler th2 = list.getTransferHandler();
487 if (th1 != th2) {
488 list.setTransferHandler(th1);
489 }
490 if (getFileChooser().getDragEnabled() != list.getDragEnabled()) {
491 list.setDragEnabled(getFileChooser().getDragEnabled());
492 }
493 }
494 }
495
496 public void mouseExited(MouseEvent evt) {
497 }
498
499 public void mousePressed(MouseEvent evt) {
500 }
501
502 public void mouseReleased(MouseEvent evt) {
503 }
504
505 public void valueChanged(ListSelectionEvent evt) {
506 if(!evt.getValueIsAdjusting()) {
507 JFileChooser chooser = getFileChooser();
508 FileSystemView fsv = chooser.getFileSystemView();
509 JList list = (JList)evt.getSource();
510
511 int fsm = chooser.getFileSelectionMode();
512 boolean useSetDirectory = usesSingleFilePane &&
513 (fsm == JFileChooser.FILES_ONLY);
514
515 if (chooser.isMultiSelectionEnabled()) {
516 File[] files = null;
517 Object[] objects = list.getSelectedValues();
518 if (objects != null) {
519 if (objects.length == 1
520 && ((File)objects[0]).isDirectory()
521 && chooser.isTraversable(((File)objects[0]))
522 && (useSetDirectory || !fsv.isFileSystem(((File)objects[0])))) {
523 setDirectorySelected(true);
524 setDirectory(((File)objects[0]));
525 } else {
526 ArrayList<File> fList = new ArrayList<File>(objects.length);
527 for (Object object : objects) {
528 File f = (File) object;
529 boolean isDir = f.isDirectory();
530 if ((chooser.isFileSelectionEnabled() && !isDir)
531 || (chooser.isDirectorySelectionEnabled()
532 && fsv.isFileSystem(f)
533 && isDir)) {
534 fList.add(f);
535 }
536 }
537 if (fList.size() > 0) {
538 files = fList.toArray(new File[fList.size()]);
539 }
540 setDirectorySelected(false);
541 }
542 }
543 chooser.setSelectedFiles(files);
544 } else {
545 File file = (File)list.getSelectedValue();
546 if (file != null
547 && file.isDirectory()
548 && chooser.isTraversable(file)
549 && (useSetDirectory || !fsv.isFileSystem(file))) {
550
551 setDirectorySelected(true);
552 setDirectory(file);
553 if (usesSingleFilePane) {
554 chooser.setSelectedFile(null);
555 }
556 } else {
557 setDirectorySelected(false);
558 if (file != null) {
559 chooser.setSelectedFile(file);
560 }
561 }
562 }
563 }
564 }
565 }
566
567 protected class DoubleClickListener extends MouseAdapter {
568 // NOTE: This class exists only for backward compatability. All
569 // its functionality has been moved into Handler. If you need to add
570 // new functionality add it to the Handler, but make sure this
571 // class calls into the Handler.
572 Handler handler;
573 public DoubleClickListener(JList list) {
574 handler = new Handler(list);
575 }
576
577 /**
578 * The JList used for representing the files is created by subclasses, but the
579 * selection is monitored in this class. The TransferHandler installed in the
580 * JFileChooser is also installed in the file list as it is used as the actual
581 * transfer source. The list is updated on a mouse enter to reflect the current
582 * data transfer state of the file chooser.
583 */
584 public void mouseEntered(MouseEvent e) {
585 handler.mouseEntered(e);
586 }
587
588 public void mouseClicked(MouseEvent e) {
589 handler.mouseClicked(e);
590 }
591 }
592
593 protected class SelectionListener implements ListSelectionListener {
594 // NOTE: This class exists only for backward compatability. All
595 // its functionality has been moved into Handler. If you need to add
596 // new functionality add it to the Handler, but make sure this
597 // class calls into the Handler.
598 public void valueChanged(ListSelectionEvent e) {
599 getHandler().valueChanged(e);
600 }
601 }
602
603 /**
604 * Property to remember whether a directory is currently selected in the UI.
605 *
606 * @return <code>true</code> iff a directory is currently selected.
607 * @since 1.4
608 */
609 protected boolean isDirectorySelected() {
610 return directorySelected;
611 }
612
613 /**
614 * Property to remember whether a directory is currently selected in the UI.
615 * This is normally called by the UI on a selection event.
616 *
617 * @param b iff a directory is currently selected.
618 * @since 1.4
619 */
620 protected void setDirectorySelected(boolean b) {
621 directorySelected = b;
622 }
623
624 /**
625 * Property to remember the directory that is currently selected in the UI.
626 *
627 * @return the value of the <code>directory</code> property
628 * @see #setDirectory
629 * @since 1.4
630 */
631 protected File getDirectory() {
632 return directory;
633 }
634
635 /**
636 * Property to remember the directory that is currently selected in the UI.
637 * This is normally called by the UI on a selection event.
638 *
639 * @param f the <code>File</code> object representing the directory that is
640 * currently selected
641 * @since 1.4
642 */
643 protected void setDirectory(File f) {
644 directory = f;
645 }
646
647 /**
648 * Returns the mnemonic for the given key.
649 */
650 private int getMnemonic(String key, Locale l) {
651 return SwingUtilities2.getUIDefaultsInt(key, l);
652 }
653
654 // *******************************************************
655 // ************ FileChooser UI PLAF methods **************
656 // *******************************************************
657
658 /**
659 * Returns the default accept all file filter
660 */
661 public FileFilter getAcceptAllFileFilter(JFileChooser fc) {
662 return acceptAllFileFilter;
663 }
664
665
666 public FileView getFileView(JFileChooser fc) {
667 return fileView;
668 }
669
670
671 /**
672 * Returns the title of this dialog
673 */
674 public String getDialogTitle(JFileChooser fc) {
675 String dialogTitle = fc.getDialogTitle();
676 if (dialogTitle != null) {
677 return dialogTitle;
678 } else if (fc.getDialogType() == JFileChooser.OPEN_DIALOG) {
679 return openDialogTitleText;
680 } else if (fc.getDialogType() == JFileChooser.SAVE_DIALOG) {
681 return saveDialogTitleText;
682 } else {
683 return getApproveButtonText(fc);
684 }
685 }
686
687
688 public int getApproveButtonMnemonic(JFileChooser fc) {
689 int mnemonic = fc.getApproveButtonMnemonic();
690 if (mnemonic > 0) {
691 return mnemonic;
692 } else if (fc.getDialogType() == JFileChooser.OPEN_DIALOG) {
693 return openButtonMnemonic;
694 } else if (fc.getDialogType() == JFileChooser.SAVE_DIALOG) {
695 return saveButtonMnemonic;
696 } else {
697 return mnemonic;
698 }
699 }
700
701 public String getApproveButtonText(JFileChooser fc) {
702 String buttonText = fc.getApproveButtonText();
703 if (buttonText != null) {
704 return buttonText;
705 } else if (fc.getDialogType() == JFileChooser.OPEN_DIALOG) {
706 return openButtonText;
707 } else if (fc.getDialogType() == JFileChooser.SAVE_DIALOG) {
708 return saveButtonText;
709 } else {
710 return null;
711 }
712 }
713
714
715 // *****************************
716 // ***** Directory Actions *****
717 // *****************************
718
719 public Action getNewFolderAction() {
720 if (newFolderAction == null) {
721 newFolderAction = new NewFolderAction();
722 // Note: Don't return null for readOnly, it might
723 // break older apps.
724 if (readOnly) {
725 newFolderAction.setEnabled(false);
726 }
727 }
728 return newFolderAction;
729 }
730
731 public Action getGoHomeAction() {
732 return goHomeAction;
733 }
734
735 public Action getChangeToParentDirectoryAction() {
736 return changeToParentDirectoryAction;
737 }
738
739 public Action getApproveSelectionAction() {
740 return approveSelectionAction;
741 }
742
743 public Action getCancelSelectionAction() {
744 return cancelSelectionAction;
745 }
746
747 public Action getUpdateAction() {
748 return updateAction;
749 }
750
751
752 /**
753 * Creates a new folder.
754 */
755 protected class NewFolderAction extends AbstractAction {
756 protected NewFolderAction() {
757 super(FilePane.ACTION_NEW_FOLDER);
758 }
759 public void actionPerformed(ActionEvent e) {
760 if (readOnly) {
761 return;
762 }
763 JFileChooser fc = getFileChooser();
764 File currentDirectory = fc.getCurrentDirectory();
765
766 if (!currentDirectory.exists()) {
767 JOptionPane.showMessageDialog(
768 fc,
769 newFolderParentDoesntExistText,
770 newFolderParentDoesntExistTitleText, JOptionPane.WARNING_MESSAGE);
771 return;
772 }
773
774 File newFolder;
775 try {
776 newFolder = fc.getFileSystemView().createNewFolder(currentDirectory);
777 if (fc.isMultiSelectionEnabled()) {
778 fc.setSelectedFiles(new File[] { newFolder });
779 } else {
780 fc.setSelectedFile(newFolder);
781 }
782 } catch (IOException exc) {
783 JOptionPane.showMessageDialog(
784 fc,
785 newFolderErrorText + newFolderErrorSeparator + exc,
786 newFolderErrorText, JOptionPane.ERROR_MESSAGE);
787 return;
788 }
789
790 fc.rescanCurrentDirectory();
791 }
792 }
793
794 /**
795 * Acts on the "home" key event or equivalent event.
796 */
797 protected class GoHomeAction extends AbstractAction {
798 protected GoHomeAction() {
799 super("Go Home");
800 }
801 public void actionPerformed(ActionEvent e) {
802 JFileChooser fc = getFileChooser();
803 changeDirectory(fc.getFileSystemView().getHomeDirectory());
804 }
805 }
806
807 protected class ChangeToParentDirectoryAction extends AbstractAction {
808 protected ChangeToParentDirectoryAction() {
809 super("Go Up");
810 putValue(Action.ACTION_COMMAND_KEY, FilePane.ACTION_CHANGE_TO_PARENT_DIRECTORY);
811 }
812 public void actionPerformed(ActionEvent e) {
813 Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
814 if (focusOwner == null || !(focusOwner instanceof javax.swing.text.JTextComponent)) {
815 getFileChooser().changeToParentDirectory();
816 }
817 }
818 }
819
820 /**
821 * Responds to an Open or Save request
822 */
823 protected class ApproveSelectionAction extends AbstractAction {
824 protected ApproveSelectionAction() {
825 super(FilePane.ACTION_APPROVE_SELECTION);
826 }
827 public void actionPerformed(ActionEvent e) {
828 if (isDirectorySelected()) {
829 File dir = getDirectory();
830 if (dir != null) {
831 try {
832 // Strip trailing ".."
833 dir = ShellFolder.getNormalizedFile(dir);
834 } catch (IOException ex) {
835 // Ok, use f as is
836 }
837 changeDirectory(dir);
838 return;
839 }
840 }
841
842 JFileChooser chooser = getFileChooser();
843
844 String filename = getFileName();
845 FileSystemView fs = chooser.getFileSystemView();
846 File dir = chooser.getCurrentDirectory();
847
848 if (filename != null) {
849 // Remove whitespaces from end of filename
850 int i = filename.length() - 1;
851
852 while (i >=0 && filename.charAt(i) <= ' ') {
853 i--;
854 }
855
856 filename = filename.substring(0, i + 1);
857 }
858
859 if (filename == null || filename.length() == 0) {
860 // no file selected, multiple selection off, therefore cancel the approve action
861 resetGlobFilter();
862 return;
863 }
864
865 File selectedFile = null;
866 File[] selectedFiles = null;
867
868 // Unix: Resolve '~' to user's home directory
869 if (File.separatorChar == '/') {
870 if (filename.startsWith("~/")) {
871 filename = System.getProperty("user.home") + filename.substring(1);
872 } else if (filename.equals("~")) {
873 filename = System.getProperty("user.home");
874 }
875 }
876
877 if (chooser.isMultiSelectionEnabled() && filename.length() > 1 &&
878 filename.charAt(0) == '"' && filename.charAt(filename.length() - 1) == '"') {
879 List<File> fList = new ArrayList<File>();
880
881 String[] files = filename.substring(1, filename.length() - 1).split("\" \"");
882 // Optimize searching files by names in "children" array
883 Arrays.sort(files);
884
885 File[] children = null;
886 int childIndex = 0;
887
888 for (String str : files) {
889 File file = fs.createFileObject(str);
890 if (!file.isAbsolute()) {
891 if (children == null) {
892 children = fs.getFiles(dir, false);
893 Arrays.sort(children);
894 }
895 for (int k = 0; k < children.length; k++) {
896 int l = (childIndex + k) % children.length;
897 if (children[l].getName().equals(str)) {
898 file = children[l];
899 childIndex = l + 1;
900 break;
901 }
902 }
903 }
904 fList.add(file);
905 }
906
907 if (!fList.isEmpty()) {
908 selectedFiles = fList.toArray(new File[fList.size()]);
909 }
910 resetGlobFilter();
911 } else {
912 selectedFile = fs.createFileObject(filename);
913 if (!selectedFile.isAbsolute()) {
914 selectedFile = fs.getChild(dir, filename);
915 }
916 // check for wildcard pattern
917 FileFilter currentFilter = chooser.getFileFilter();
918 if (!selectedFile.exists() && isGlobPattern(filename)) {
919 changeDirectory(selectedFile.getParentFile());
920 if (globFilter == null) {
921 globFilter = new GlobFilter();
922 }
923 try {
924 globFilter.setPattern(selectedFile.getName());
925 if (!(currentFilter instanceof GlobFilter)) {
926 actualFileFilter = currentFilter;
927 }
928 chooser.setFileFilter(null);
929 chooser.setFileFilter(globFilter);
930 return;
931 } catch (PatternSyntaxException pse) {
932 // Not a valid glob pattern. Abandon filter.
933 }
934 }
935
936 resetGlobFilter();
937
938 // Check for directory change action
939 boolean isDir = (selectedFile != null && selectedFile.isDirectory());
940 boolean isTrav = (selectedFile != null && chooser.isTraversable(selectedFile));
941 boolean isDirSelEnabled = chooser.isDirectorySelectionEnabled();
942 boolean isFileSelEnabled = chooser.isFileSelectionEnabled();
943 boolean isCtrl = (e != null && (e.getModifiers() &
944 Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()) != 0);
945
946 if (isDir && isTrav && (isCtrl || !isDirSelEnabled)) {
947 changeDirectory(selectedFile);
948 return;
949 } else if ((isDir || !isFileSelEnabled)
950 && (!isDir || !isDirSelEnabled)
951 && (!isDirSelEnabled || selectedFile.exists())) {
952 selectedFile = null;
953 }
954 }
955
956 if (selectedFiles != null || selectedFile != null) {
957 if (selectedFiles != null || chooser.isMultiSelectionEnabled()) {
958 if (selectedFiles == null) {
959 selectedFiles = new File[] { selectedFile };
960 }
961 chooser.setSelectedFiles(selectedFiles);
962 // Do it again. This is a fix for bug 4949273 to force the
963 // selected value in case the ListSelectionModel clears it
964 // for non-existing file names.
965 chooser.setSelectedFiles(selectedFiles);
966 } else {
967 chooser.setSelectedFile(selectedFile);
968 }
969 chooser.approveSelection();
970 } else {
971 if (chooser.isMultiSelectionEnabled()) {
972 chooser.setSelectedFiles(null);
973 } else {
974 chooser.setSelectedFile(null);
975 }
976 chooser.cancelSelection();
977 }
978 }
979 }
980
981
982 private void resetGlobFilter() {
983 if (actualFileFilter != null) {
984 JFileChooser chooser = getFileChooser();
985 FileFilter currentFilter = chooser.getFileFilter();
986 if (currentFilter != null && currentFilter.equals(globFilter)) {
987 chooser.setFileFilter(actualFileFilter);
988 chooser.removeChoosableFileFilter(globFilter);
989 }
990 actualFileFilter = null;
991 }
992 }
993
994 private static boolean isGlobPattern(String filename) {
995 return ((File.separatorChar == '\\' && (filename.indexOf('*') >= 0
996 || filename.indexOf('?') >= 0))
997 || (File.separatorChar == '/' && (filename.indexOf('*') >= 0
998 || filename.indexOf('?') >= 0
999 || filename.indexOf('[') >= 0)));
1000 }
1001
1002
1003 /* A file filter which accepts file patterns containing
1004 * the special wildcards *? on Windows and *?[] on Unix.
1005 */
1006 class GlobFilter extends FileFilter {
1007 Pattern pattern;
1008 String globPattern;
1009
1010 public void setPattern(String globPattern) {
1011 char[] gPat = globPattern.toCharArray();
1012 char[] rPat = new char[gPat.length * 2];
1013 boolean isWin32 = (File.separatorChar == '\\');
1014 boolean inBrackets = false;
1015 int j = 0;
1016
1017 this.globPattern = globPattern;
1018
1019 if (isWin32) {
1020 // On windows, a pattern ending with *.* is equal to ending with *
1021 int len = gPat.length;
1022 if (globPattern.endsWith("*.*")) {
1023 len -= 2;
1024 }
1025 for (int i = 0; i < len; i++) {
1026 switch(gPat[i]) {
1027 case '*':
1028 rPat[j++] = '.';
1029 rPat[j++] = '*';
1030 break;
1031
1032 case '?':
1033 rPat[j++] = '.';
1034 break;
1035
1036 case '\\':
1037 rPat[j++] = '\\';
1038 rPat[j++] = '\\';
1039 break;
1040
1041 default:
1042 if ("+()^$.{}[]".indexOf(gPat[i]) >= 0) {
1043 rPat[j++] = '\\';
1044 }
1045 rPat[j++] = gPat[i];
1046 break;
1047 }
1048 }
1049 } else {
1050 for (int i = 0; i < gPat.length; i++) {
1051 switch(gPat[i]) {
1052 case '*':
1053 if (!inBrackets) {
1054 rPat[j++] = '.';
1055 }
1056 rPat[j++] = '*';
1057 break;
1058
1059 case '?':
1060 rPat[j++] = inBrackets ? '?' : '.';
1061 break;
1062
1063 case '[':
1064 inBrackets = true;
1065 rPat[j++] = gPat[i];
1066
1067 if (i < gPat.length - 1) {
1068 switch (gPat[i+1]) {
1069 case '!':
1070 case '^':
1071 rPat[j++] = '^';
1072 i++;
1073 break;
1074
1075 case ']':
1076 rPat[j++] = gPat[++i];
1077 break;
1078 }
1079 }
1080 break;
1081
1082 case ']':
1083 rPat[j++] = gPat[i];
1084 inBrackets = false;
1085 break;
1086
1087 case '\\':
1088 if (i == 0 && gPat.length > 1 && gPat[1] == '~') {
1089 rPat[j++] = gPat[++i];
1090 } else {
1091 rPat[j++] = '\\';
1092 if (i < gPat.length - 1 && "*?[]".indexOf(gPat[i+1]) >= 0) {
1093 rPat[j++] = gPat[++i];
1094 } else {
1095 rPat[j++] = '\\';
1096 }
1097 }
1098 break;
1099
1100 default:
1101 //if ("+()|^$.{}<>".indexOf(gPat[i]) >= 0) {
1102 if (!Character.isLetterOrDigit(gPat[i])) {
1103 rPat[j++] = '\\';
1104 }
1105 rPat[j++] = gPat[i];
1106 break;
1107 }
1108 }
1109 }
1110 this.pattern = Pattern.compile(new String(rPat, 0, j), Pattern.CASE_INSENSITIVE);
1111 }
1112
1113 public boolean accept(File f) {
1114 if (f == null) {
1115 return false;
1116 }
1117 if (f.isDirectory()) {
1118 return true;
1119 }
1120 return pattern.matcher(f.getName()).matches();
1121 }
1122
1123 public String getDescription() {
1124 return globPattern;
1125 }
1126 }
1127
1128 /**
1129 * Responds to a cancel request.
1130 */
1131 protected class CancelSelectionAction extends AbstractAction {
1132 public void actionPerformed(ActionEvent e) {
1133 getFileChooser().cancelSelection();
1134 }
1135 }
1136
1137 /**
1138 * Rescans the files in the current directory
1139 */
1140 protected class UpdateAction extends AbstractAction {
1141 public void actionPerformed(ActionEvent e) {
1142 JFileChooser fc = getFileChooser();
1143 fc.setCurrentDirectory(fc.getFileSystemView().createFileObject(getDirectoryName()));
1144 fc.rescanCurrentDirectory();
1145 }
1146 }
1147
1148
1149 private void changeDirectory(File dir) {
1150 JFileChooser fc = getFileChooser();
1151 // Traverse shortcuts on Windows
1152 if (dir != null && FilePane.usesShellFolder(fc)) {
1153 try {
1154 ShellFolder shellFolder = ShellFolder.getShellFolder(dir);
1155
1156 if (shellFolder.isLink()) {
1157 File linkedTo = shellFolder.getLinkLocation();
1158
1159 if (linkedTo != null && fc.isTraversable(linkedTo)) {
1160 dir = linkedTo;
1161 } else {
1162 return;
1163 }
1164 }
1165 } catch (FileNotFoundException ex) {
1166 return;
1167 }
1168 }
1169 fc.setCurrentDirectory(dir);
1170 if (fc.getFileSelectionMode() == JFileChooser.FILES_AND_DIRECTORIES &&
1171 fc.getFileSystemView().isFileSystem(dir)) {
1172
1173 setFileName(dir.getAbsolutePath());
1174 }
1175 }
1176
1177
1178 // *****************************************
1179 // ***** default AcceptAll file filter *****
1180 // *****************************************
1181 protected class AcceptAllFileFilter extends FileFilter {
1182
1183 public AcceptAllFileFilter() {
1184 }
1185
1186 public boolean accept(File f) {
1187 return true;
1188 }
1189
1190 public String getDescription() {
1191 return UIManager.getString("FileChooser.acceptAllFileFilterText");
1192 }
1193 }
1194
1195
1196 // ***********************
1197 // * FileView operations *
1198 // ***********************
1199 protected class BasicFileView extends FileView {
1200 /* FileView type descriptions */
1201 // PENDING(jeff) - pass in the icon cache size
1202 protected Hashtable<File,Icon> iconCache = new Hashtable<File,Icon>();
1203
1204 public BasicFileView() {
1205 }
1206
1207 public void clearIconCache() {
1208 iconCache = new Hashtable<File,Icon>();
1209 }
1210
1211 public String getName(File f) {
1212 // Note: Returns display name rather than file name
1213 String fileName = null;
1214 if(f != null) {
1215 fileName = getFileChooser().getFileSystemView().getSystemDisplayName(f);
1216 }
1217 return fileName;
1218 }
1219
1220
1221 public String getDescription(File f) {
1222 return f.getName();
1223 }
1224
1225 public String getTypeDescription(File f) {
1226 String type = getFileChooser().getFileSystemView().getSystemTypeDescription(f);
1227 if (type == null) {
1228 if (f.isDirectory()) {
1229 type = directoryDescriptionText;
1230 } else {
1231 type = fileDescriptionText;
1232 }
1233 }
1234 return type;
1235 }
1236
1237 public Icon getCachedIcon(File f) {
1238 return iconCache.get(f);
1239 }
1240
1241 public void cacheIcon(File f, Icon i) {
1242 if(f == null || i == null) {
1243 return;
1244 }
1245 iconCache.put(f, i);
1246 }
1247
1248 public Icon getIcon(File f) {
1249 Icon icon = getCachedIcon(f);
1250 if(icon != null) {
1251 return icon;
1252 }
1253 icon = fileIcon;
1254 if (f != null) {
1255 FileSystemView fsv = getFileChooser().getFileSystemView();
1256
1257 if (fsv.isFloppyDrive(f)) {
1258 icon = floppyDriveIcon;
1259 } else if (fsv.isDrive(f)) {
1260 icon = hardDriveIcon;
1261 } else if (fsv.isComputerNode(f)) {
1262 icon = computerIcon;
1263 } else if (f.isDirectory()) {
1264 icon = directoryIcon;
1265 }
1266 }
1267 cacheIcon(f, icon);
1268 return icon;
1269 }
1270
1271 public Boolean isHidden(File f) {
1272 String name = f.getName();
1273 if(name != null && name.charAt(0) == '.') {
1274 return Boolean.TRUE;
1275 } else {
1276 return Boolean.FALSE;
1277 }
1278 }
1279 }
1280
1281 private static final TransferHandler defaultTransferHandler = new FileTransferHandler();
1282
1283 /**
1284 * Data transfer support for the file chooser. Since files are currently presented
1285 * as a list, the list support is reused with the added flavor of DataFlavor.javaFileListFlavor
1286 */
1287 static class FileTransferHandler extends TransferHandler implements UIResource {
1288
1289 /**
1290 * Create a Transferable to use as the source for a data transfer.
1291 *
1292 * @param c The component holding the data to be transfered. This
1293 * argument is provided to enable sharing of TransferHandlers by
1294 * multiple components.
1295 * @return The representation of the data to be transfered.
1296 *
1297 */
1298 protected Transferable createTransferable(JComponent c) {
1299 Object[] values = null;
1300 if (c instanceof JList) {
1301 values = ((JList)c).getSelectedValues();
1302 } else if (c instanceof JTable) {
1303 JTable table = (JTable)c;
1304 int[] rows = table.getSelectedRows();
1305 if (rows != null) {
1306 values = new Object[rows.length];
1307 for (int i=0; i<rows.length; i++) {
1308 values[i] = table.getValueAt(rows[i], 0);
1309 }
1310 }
1311 }
1312 if (values == null || values.length == 0) {
1313 return null;
1314 }
1315
1316 StringBuffer plainBuf = new StringBuffer();
1317 StringBuffer htmlBuf = new StringBuffer();
1318
1319 htmlBuf.append("<html>\n<body>\n<ul>\n");
1320
1321 for (Object obj : values) {
1322 String val = ((obj == null) ? "" : obj.toString());
1323 plainBuf.append(val + "\n");
1324 htmlBuf.append(" <li>" + val + "\n");
1325 }
1326
1327 // remove the last newline
1328 plainBuf.deleteCharAt(plainBuf.length() - 1);
1329 htmlBuf.append("</ul>\n</body>\n</html>");
1330
1331 return new FileTransferable(plainBuf.toString(), htmlBuf.toString(), values);
1332 }
1333
1334 public int getSourceActions(JComponent c) {
1335 return COPY;
1336 }
1337
1338 static class FileTransferable extends BasicTransferable {
1339
1340 Object[] fileData;
1341
1342 FileTransferable(String plainData, String htmlData, Object[] fileData) {
1343 super(plainData, htmlData);
1344 this.fileData = fileData;
1345 }
1346
1347 /**
1348 * Best format of the file chooser is DataFlavor.javaFileListFlavor.
1349 */
1350 protected DataFlavor[] getRicherFlavors() {
1351 DataFlavor[] flavors = new DataFlavor[1];
1352 flavors[0] = DataFlavor.javaFileListFlavor;
1353 return flavors;
1354 }
1355
1356 /**
1357 * The only richer format supported is the file list flavor
1358 */
1359 protected Object getRicherData(DataFlavor flavor) {
1360 if (DataFlavor.javaFileListFlavor.equals(flavor)) {
1361 ArrayList<Object> files = new ArrayList<Object>();
1362 for (Object file : this.fileData) {
1363 files.add(file);
1364 }
1365 return files;
1366 }
1367 return null;
1368 }
1369
1370 }
1371 }
1372}