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
26 package javax.swing.filechooser;
27
28
29 import javax.swing.*;
30
31 import java.awt.Image;
32 import java.io.File;
33 import java.io.FileNotFoundException;
34 import java.io.IOException;
35 import java.text.MessageFormat;
36 import java.util.List;
37 import java.util.ArrayList;
38 import java.lang.ref.WeakReference;
39 import java.beans.PropertyChangeListener;
40 import java.beans.PropertyChangeEvent;
41 import java.security.AccessController;
42 import java.security.PrivilegedAction;
43
44 import sun.awt.shell.*;
45
46 /**
47 * FileSystemView is JFileChooser's gateway to the
48 * file system. Since the JDK1.1 File API doesn't allow
49 * access to such information as root partitions, file type
50 * information, or hidden file bits, this class is designed
51 * to intuit as much OS-specific file system information as
52 * possible.
53 *
54 * <p>
55 *
56 * Java Licensees may want to provide a different implementation of
57 * FileSystemView to better handle a given operating system.
58 *
59 * @author Jeff Dinkins
60 */
61
62 // PENDING(jeff) - need to provide a specification for
630 * @throws FileNotFoundException if the linked file does not exist
631 * @throws NullPointerException if {@code file} equals {@code null}
632 * @throws SecurityException if the caller does not have necessary
633 * permissions
634 * @since 9
635 */
636 public File getLinkLocation(File file) throws FileNotFoundException {
637 if (file == null) {
638 throw new NullPointerException("file is null");
639 }
640 ShellFolder shellFolder;
641 try {
642 shellFolder = ShellFolder.getShellFolder(file);
643 } catch (FileNotFoundException e) {
644 return null;
645 }
646 return shellFolder.isLink() ? shellFolder.getLinkLocation() : null;
647 }
648
649 /**
650 * Throws {@code FileNotFoundException} if file not found or current thread was interrupted
651 */
652 ShellFolder getShellFolder(File f) throws FileNotFoundException {
653 if (!(f instanceof ShellFolder) && !(f instanceof FileSystemRoot) && isFileSystemRoot(f)) {
654 f = createFileSystemRoot(f);
655 }
656
657 try {
658 return ShellFolder.getShellFolder(f);
659 } catch (InternalError e) {
660 System.err.println("FileSystemView.getShellFolder: f="+f);
661 e.printStackTrace();
662 return null;
663 }
664 }
665
666 /**
667 * Creates a new <code>File</code> object for <code>f</code> with correct
668 * behavior for a file system root directory.
669 *
741 public boolean isDrive(File dir) {
742 return isFloppyDrive(dir);
743 }
744
745 public boolean isFloppyDrive(File dir) {
746 // Could be looking at the path for Solaris, but wouldn't be reliable.
747 // For example:
748 // return (dir != null && dir.getAbsolutePath().toLowerCase().startsWith("/floppy"));
749 return false;
750 }
751
752 public boolean isComputerNode(File dir) {
753 if (dir != null) {
754 String parent = dir.getParent();
755 if (parent != null && parent.equals("/net")) {
756 return true;
757 }
758 }
759 return false;
760 }
761 }
762
763
764 /**
765 * FileSystemView that handles some specific windows concepts.
766 */
767 class WindowsFileSystemView extends FileSystemView {
768
769 private static final String newFolderString =
770 UIManager.getString("FileChooser.win32.newFolder");
771 private static final String newFolderNextString =
772 UIManager.getString("FileChooser.win32.newFolder.subsequent");
773
774 public Boolean isTraversable(File f) {
775 return Boolean.valueOf(isFileSystemRoot(f) || isComputerNode(f) || f.isDirectory());
776 }
777
778 public File getChild(File parent, String fileName) {
779 if (fileName.startsWith("\\")
780 && !fileName.startsWith("\\\\")
855 public String run() {
856 return dir.getAbsolutePath();
857 }
858 });
859
860 return path != null && (path.equals("A:\\") || path.equals("B:\\"));
861 }
862
863 /**
864 * Returns a File object constructed from the given path string.
865 */
866 public File createFileObject(String path) {
867 // Check for missing backslash after drive letter such as "C:" or "C:filename"
868 if (path.length() >= 2 && path.charAt(1) == ':' && Character.isLetter(path.charAt(0))) {
869 if (path.length() == 2) {
870 path += "\\";
871 } else if (path.charAt(2) != '\\') {
872 path = path.substring(0, 2) + "\\" + path.substring(2);
873 }
874 }
875 return super.createFileObject(path);
876 }
877
878 @SuppressWarnings("serial") // anonymous class
879 protected File createFileSystemRoot(File f) {
880 // Problem: Removable drives on Windows return false on f.exists()
881 // Workaround: Override exists() to always return true.
882 return new FileSystemRoot(f) {
883 public boolean exists() {
884 return true;
885 }
886 };
887 }
888
889 }
890
891 /**
892 * Fallthrough FileSystemView in case we can't determine the OS.
893 */
894 class GenericFileSystemView extends FileSystemView {
895
897 UIManager.getString("FileChooser.other.newFolder");
898
899 /**
900 * Creates a new folder with a default folder name.
901 */
902 public File createNewFolder(File containingDir) throws IOException {
903 if(containingDir == null) {
904 throw new IOException("Containing directory is null:");
905 }
906 // Using NT's default folder name
907 File newFolder = createFileObject(containingDir, newFolderString);
908
909 if(newFolder.exists()) {
910 throw new IOException("Directory already exists:" + newFolder.getAbsolutePath());
911 } else {
912 if(!newFolder.mkdirs()) {
913 throw new IOException(newFolder.getAbsolutePath());
914 }
915 }
916 return newFolder;
917 }
918
919 }
|
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
26 package javax.swing.filechooser;
27
28
29 import javax.swing.*;
30
31 import java.awt.Image;
32 import java.beans.BeanProperty;
33 import java.beans.JavaBean;
34 import java.io.File;
35 import java.io.FileNotFoundException;
36 import java.io.IOException;
37 import java.text.MessageFormat;
38 import java.util.List;
39 import java.util.ArrayList;
40 import java.lang.ref.WeakReference;
41 import java.beans.PropertyChangeListener;
42 import java.beans.PropertyChangeEvent;
43 import java.beans.PropertyChangeSupport;
44 import java.security.AccessController;
45 import java.security.PrivilegedAction;
46 import java.util.Arrays;
47 import java.util.Collections;
48 import java.util.Objects;
49 import sun.awt.OSInfo;
50
51 import sun.awt.shell.*;
52
53 /**
54 * FileSystemView is JFileChooser's gateway to the
55 * file system. Since the JDK1.1 File API doesn't allow
56 * access to such information as root partitions, file type
57 * information, or hidden file bits, this class is designed
58 * to intuit as much OS-specific file system information as
59 * possible.
60 *
61 * <p>
62 *
63 * Java Licensees may want to provide a different implementation of
64 * FileSystemView to better handle a given operating system.
65 *
66 * @author Jeff Dinkins
67 */
68
69 // PENDING(jeff) - need to provide a specification for
637 * @throws FileNotFoundException if the linked file does not exist
638 * @throws NullPointerException if {@code file} equals {@code null}
639 * @throws SecurityException if the caller does not have necessary
640 * permissions
641 * @since 9
642 */
643 public File getLinkLocation(File file) throws FileNotFoundException {
644 if (file == null) {
645 throw new NullPointerException("file is null");
646 }
647 ShellFolder shellFolder;
648 try {
649 shellFolder = ShellFolder.getShellFolder(file);
650 } catch (FileNotFoundException e) {
651 return null;
652 }
653 return shellFolder.isLink() ? shellFolder.getLinkLocation() : null;
654 }
655
656 /**
657 * A group of essential folder that are intented to appear in a left pane of
658 * a file chooser.
659 */
660 @JavaBean(description = "A group of essential folder that are intented to "
661 + "appear in a left pane of a file chooser. ")
662 public static class EssentialFolderSection {
663
664 public static final String FOLDERS_PROPERTY = "folders";
665
666 private final PropertyChangeSupport propertyChangeSupport =
667 new PropertyChangeSupport(this);
668
669 private List<File> folders = Collections.emptyList();
670
671 /**
672 * Creates a new {@code EssentialFolderSection} with no folders.
673 */
674 public EssentialFolderSection() {
675 }
676
677 /**
678 * Creates a new {@code EssentialFolderSection} with the specified
679 * folders.
680 *
681 * @param folders
682 */
683 public EssentialFolderSection(File... folders) {
684 setFolders(Arrays.asList(folders));
685 }
686
687
688 /**
689 * Gets a list of the essential folders in this section.
690 *
691 * @return the value of folders
692 */
693 @SuppressWarnings("ReturnOfCollectionOrArrayField") // already an unmodifiableList or emptyList
694 public List<File> getFolders() {
695 return folders;
696 }
697
698 /**
699 * Updates the list of the essential folders in this section to the specified list.
700 *
701 * @param folders
702 * @throws NullPointerException if the argument is null
703 */
704 @BeanProperty(description = "The folders that are in ", bound = true, visualUpdate =true)
705 public void setFolders(List<File> folders) {
706 Objects.requireNonNull(folders);
707 folders = Collections.unmodifiableList(new ArrayList<>(folders));
708
709 List<File> oldFolders = this.folders;
710 this.folders = folders;
711 propertyChangeSupport.firePropertyChange(FOLDERS_PROPERTY, oldFolders, folders);
712 }
713
714 /**
715 * Adds a PropertyChangeListener to the listener list. Currently the
716 * listener will be fired only when the
717 * {@link #setFolders(java.util.List) folders} property is changed,
718 * but in the future more properties will be added.
719 * @param listener the PropertyChangeListener to be added
720 */
721 public void addPropertyChangeListener(PropertyChangeListener listener) {
722 propertyChangeSupport.addPropertyChangeListener(listener);
723 }
724
725 /**
726 * Removes a PropertyChangeListener from the listener list. If listener is null,
727 * or was never added, no exception is thrown and no action is taken.
728 *
729 * @param listener the PropertyChangeListener to be removed (registered using
730 * {@link #addPropertyChangeListener(java.beans.PropertyChangeListener)})
731 */
732 public void removePropertyChangeListener(PropertyChangeListener listener) {
733 propertyChangeSupport.removePropertyChangeListener(listener);
734 }
735
736 }
737
738 public EssentialFolderSection[] getEssentialFolders() {
739 return FileSystemView.getFileSystemView().getEssentialFolders();
740 }
741
742 /**
743 * Throws {@code FileNotFoundException} if file not found or current thread was interrupted
744 */
745 ShellFolder getShellFolder(File f) throws FileNotFoundException {
746 if (!(f instanceof ShellFolder) && !(f instanceof FileSystemRoot) && isFileSystemRoot(f)) {
747 f = createFileSystemRoot(f);
748 }
749
750 try {
751 return ShellFolder.getShellFolder(f);
752 } catch (InternalError e) {
753 System.err.println("FileSystemView.getShellFolder: f="+f);
754 e.printStackTrace();
755 return null;
756 }
757 }
758
759 /**
760 * Creates a new <code>File</code> object for <code>f</code> with correct
761 * behavior for a file system root directory.
762 *
834 public boolean isDrive(File dir) {
835 return isFloppyDrive(dir);
836 }
837
838 public boolean isFloppyDrive(File dir) {
839 // Could be looking at the path for Solaris, but wouldn't be reliable.
840 // For example:
841 // return (dir != null && dir.getAbsolutePath().toLowerCase().startsWith("/floppy"));
842 return false;
843 }
844
845 public boolean isComputerNode(File dir) {
846 if (dir != null) {
847 String parent = dir.getParent();
848 if (parent != null && parent.equals("/net")) {
849 return true;
850 }
851 }
852 return false;
853 }
854
855 @Override
856 public EssentialFolderSection[] getEssentialFolders() {
857 return new EssentialFolderSection[]{
858 new EssentialFolderSection(getChooserComboBoxFiles())
859 };
860 }
861 }
862
863
864 /**
865 * FileSystemView that handles some specific windows concepts.
866 */
867 class WindowsFileSystemView extends FileSystemView {
868
869 private static final String newFolderString =
870 UIManager.getString("FileChooser.win32.newFolder");
871 private static final String newFolderNextString =
872 UIManager.getString("FileChooser.win32.newFolder.subsequent");
873
874 public Boolean isTraversable(File f) {
875 return Boolean.valueOf(isFileSystemRoot(f) || isComputerNode(f) || f.isDirectory());
876 }
877
878 public File getChild(File parent, String fileName) {
879 if (fileName.startsWith("\\")
880 && !fileName.startsWith("\\\\")
955 public String run() {
956 return dir.getAbsolutePath();
957 }
958 });
959
960 return path != null && (path.equals("A:\\") || path.equals("B:\\"));
961 }
962
963 /**
964 * Returns a File object constructed from the given path string.
965 */
966 public File createFileObject(String path) {
967 // Check for missing backslash after drive letter such as "C:" or "C:filename"
968 if (path.length() >= 2 && path.charAt(1) == ':' && Character.isLetter(path.charAt(0))) {
969 if (path.length() == 2) {
970 path += "\\";
971 } else if (path.charAt(2) != '\\') {
972 path = path.substring(0, 2) + "\\" + path.substring(2);
973 }
974 }
975 return (File) ShellFolder.get("parseDisplayName " + path);
976 }
977
978 private static final String CLSID_NETWORK = "{F02C1A0D-BE21-4350-88B0-7367FC96EF3C}";
979 private static final String CLSID_COMPUTER = "{20d04fe0-3aea-1069-a2d8-08002b30309d}";
980 private static final String CLSID_HOMEGROUP = "{67CA7650-96E6-4FDD-BB43-A8E774F73A57}";
981 private static final String CLSID_FAVORITES = "{323CA680-C24D-4099-B94D-446DD2D7249E}";
982 private static final String CLSID_LIBRARIES = "{031E4825-7B94-4dc3-B131-E946B44C8DD5}";
983 private static final String CLSID_QUICK_ACCESS = "{679f85cb-0220-4080-b29b-5540cc05aab6}";
984 private static final String CLSID_HOMEGROUP_WIN10 = "{B4FB3F98-C1EA-428d-A78A-D1F5659CBA93}";
985
986 private static final EssentialFolderSection[] ESSENTIAL_FOLDERS = createEssentialFolders();
987
988 private static EssentialFolderSection[] createEssentialFolders() {
989 List<File> folders = new ArrayList<>();
990 if (OSInfo.getWindowsVersion().compareTo(OSInfo.WINDOWS_7) <= 0) {
991 folders.add((File) ShellFolder.get(CLSID_FAVORITES));
992 folders.add((File) ShellFolder.get(CLSID_LIBRARIES));
993 folders.add((File) ShellFolder.get(CLSID_HOMEGROUP));
994 folders.add((File) ShellFolder.get(CLSID_COMPUTER));
995 folders.add((File) ShellFolder.get(CLSID_NETWORK));
996 } else {
997 folders.add((File) ShellFolder.get(CLSID_QUICK_ACCESS));
998 folders.add((File) ShellFolder.get(CLSID_COMPUTER));
999 folders.add((File) ShellFolder.get(CLSID_NETWORK));
1000
1001 // for some unknown reason, adding both Quick Access and Home Group
1002 // on Windows 10 results in all folders in the FilePane (!) with
1003 // default icon switched their icon to a green person icon.
1004 }
1005
1006 return new EssentialFolderSection[]{
1007 new EssentialFolderSection(folders.toArray(new File[0]))
1008 };
1009 }
1010
1011
1012 @Override
1013 public EssentialFolderSection[] getEssentialFolders() {
1014 return Arrays.copyOf(ESSENTIAL_FOLDERS, ESSENTIAL_FOLDERS.length);
1015 }
1016
1017 @SuppressWarnings("serial") // anonymous class
1018 protected File createFileSystemRoot(File f) {
1019 // Problem: Removable drives on Windows return false on f.exists()
1020 // Workaround: Override exists() to always return true.
1021 return new FileSystemRoot(f) {
1022 public boolean exists() {
1023 return true;
1024 }
1025 };
1026 }
1027
1028 }
1029
1030 /**
1031 * Fallthrough FileSystemView in case we can't determine the OS.
1032 */
1033 class GenericFileSystemView extends FileSystemView {
1034
1036 UIManager.getString("FileChooser.other.newFolder");
1037
1038 /**
1039 * Creates a new folder with a default folder name.
1040 */
1041 public File createNewFolder(File containingDir) throws IOException {
1042 if(containingDir == null) {
1043 throw new IOException("Containing directory is null:");
1044 }
1045 // Using NT's default folder name
1046 File newFolder = createFileObject(containingDir, newFolderString);
1047
1048 if(newFolder.exists()) {
1049 throw new IOException("Directory already exists:" + newFolder.getAbsolutePath());
1050 } else {
1051 if(!newFolder.mkdirs()) {
1052 throw new IOException(newFolder.getAbsolutePath());
1053 }
1054 }
1055 return newFolder;
1056 }
1057
1058 @Override
1059 public EssentialFolderSection[] getEssentialFolders() {
1060 return new EssentialFolderSection[]{
1061 new EssentialFolderSection(getChooserComboBoxFiles())
1062 };
1063 }
1064
1065 }
|