From 1c6e8774cf1b78654ed6eb0f07179c3bf62149bf Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Sun, 30 Nov 2025 15:39:41 +0100 Subject: [PATCH] System File Chooser: (PR #988) - fixed missing filter in combobox if only `setFileFilter(myFilter)` is used, but not `addChoosableFileFilter(myFilter)` - fallback Swing file chooser did ignore `isAcceptAllFileFilterUsed()` - check for supported filter types in `setFileFilter()` --- .../flatlaf/util/SystemFileChooser.java | 141 +++++++++++------- 1 file changed, 89 insertions(+), 52 deletions(-) diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/util/SystemFileChooser.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/util/SystemFileChooser.java index 56af434e..cf2dc857 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/util/SystemFileChooser.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/util/SystemFileChooser.java @@ -24,7 +24,9 @@ import java.awt.Window; import java.io.File; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Locale; import java.util.Map; import java.util.concurrent.atomic.AtomicReference; @@ -282,14 +284,14 @@ public class SystemFileChooser this( (File) null ); } - /** @see JFileChooser#JFileChooser(String) */ + /** @see JFileChooser#JFileChooser(String) */ public SystemFileChooser( String currentDirectoryPath ) { this( (currentDirectoryPath != null) ? FileSystemView.getFileSystemView().createFileObject( currentDirectoryPath ) : null ); } - /** @see JFileChooser#JFileChooser(File) */ + /** @see JFileChooser#JFileChooser(File) */ public SystemFileChooser( File currentDirectory ) { setCurrentDirectory( currentDirectory ); @@ -367,12 +369,23 @@ public class SystemFileChooser setApproveButtonMnemonic( vk ); } - /** @see JFileChooser#getFileSelectionMode() */ + /** + * Returns file-selection mode. + * Possible values are {@link #FILES_ONLY} and {@link #DIRECTORIES_ONLY}. + * Default is {@link #FILES_ONLY}. + * + * @see JFileChooser#getFileSelectionMode() + */ public int getFileSelectionMode() { return fileSelectionMode; } - /** @see JFileChooser#setFileSelectionMode(int) */ + /** + * Sets file-selection mode. + * Possible values are {@link #FILES_ONLY} and {@link #DIRECTORIES_ONLY}. + * + * @see JFileChooser#setFileSelectionMode(int) + */ public void setFileSelectionMode( int fileSelectionMode ) { if( fileSelectionMode != FILES_ONLY && fileSelectionMode != DIRECTORIES_ONLY ) throw new IllegalArgumentException( "Invalid file selection mode " + fileSelectionMode ); @@ -488,8 +501,7 @@ public class SystemFileChooser if( filter == null || filters.contains( filter ) ) return; - if( !(filter instanceof FileNameExtensionFilter) && !(filter instanceof AcceptAllFileFilter) ) - throw new IllegalArgumentException( "Filter class not supported: " + filter.getClass().getName() ); + checkSupportedFileFilter( filter ); // either insert filter before "All Files" filter, or append to the end int size = filters.size(); @@ -559,15 +571,35 @@ public class SystemFileChooser /** @see JFileChooser#setFileFilter(javax.swing.filechooser.FileFilter) */ public void setFileFilter( FileFilter filter ) { + checkSupportedFileFilter( filter ); + this.fileFilter = filter; } - private int indexOfCurrentFilter() { - return filters.indexOf( fileFilter ); + private void checkSupportedFileFilter( FileFilter filter ) throws IllegalArgumentException { + if( filter == null || + filter instanceof FileNameExtensionFilter || + filter instanceof AcceptAllFileFilter ) + return; + + throw new IllegalArgumentException( "Filter class not supported: " + filter.getClass().getName() ); } - private boolean hasOnlyAcceptAll() { - return filters.size() == 1 && filters.get( 0 ) == getAcceptAllFileFilter(); + private List getFiltersForDialog() { + // has only accept-all filter + if( filters.size() == 1 && + filters.get( 0 ) == getAcceptAllFileFilter() && + (fileFilter == getAcceptAllFileFilter() || fileFilter == null) ) + return Collections.emptyList(); + + // check whether current filter is already in list + if( (fileFilter != null && filters.contains( fileFilter )) || fileFilter == null ) + return filters; + + // add current file filter to list + List filters2 = new ArrayList<>( filters ); + filters2.add( 0, fileFilter ); + return filters2; } public ApproveCallback getApproveCallback() { @@ -854,9 +886,10 @@ public class SystemFileChooser int fileTypeIndex = 0; ArrayList fileTypes = new ArrayList<>(); if( !fc.isDirectorySelectionEnabled() ) { - if( !fc.hasOnlyAcceptAll() ) { - fileTypeIndex = fc.indexOfCurrentFilter(); - for( FileFilter filter : fc.getChoosableFileFilters() ) { + List filters = fc.getFiltersForDialog(); + if( !filters.isEmpty() ) { + fileTypeIndex = filters.indexOf( fc.getFileFilter() ); + for( FileFilter filter : filters ) { if( filter instanceof FileNameExtensionFilter ) { fileTypes.add( filter.getDescription() ); fileTypes.add( "*." + String.join( ";*.", ((FileNameExtensionFilter)filter).getExtensions() ) ); @@ -975,18 +1008,21 @@ public class SystemFileChooser // filter int fileTypeIndex = 0; ArrayList fileTypes = new ArrayList<>(); - if( !fc.isDirectorySelectionEnabled() && !fc.hasOnlyAcceptAll() ) { - fileTypeIndex = fc.indexOfCurrentFilter(); - for( FileFilter filter : fc.getChoosableFileFilters() ) { - if( filter instanceof FileNameExtensionFilter ) { - fileTypes.add( filter.getDescription() ); - for( String ext : ((FileNameExtensionFilter)filter).getExtensions() ) - fileTypes.add( ext ); - fileTypes.add( null ); - } else if( filter instanceof AcceptAllFileFilter ) { - fileTypes.add( filter.getDescription() ); - fileTypes.add( "*" ); - fileTypes.add( null ); + if( !fc.isDirectorySelectionEnabled() ) { + List filters = fc.getFiltersForDialog(); + if( !filters.isEmpty() ) { + fileTypeIndex = filters.indexOf( fc.getFileFilter() ); + for( FileFilter filter : filters ) { + if( filter instanceof FileNameExtensionFilter ) { + fileTypes.add( filter.getDescription() ); + for( String ext : ((FileNameExtensionFilter)filter).getExtensions() ) + fileTypes.add( ext ); + fileTypes.add( null ); + } else if( filter instanceof AcceptAllFileFilter ) { + fileTypes.add( filter.getDescription() ); + fileTypes.add( "*" ); + fileTypes.add( null ); + } } } } @@ -1090,18 +1126,21 @@ public class SystemFileChooser // filter int fileTypeIndex = 0; ArrayList fileTypes = new ArrayList<>(); - if( !fc.isDirectorySelectionEnabled() && !fc.hasOnlyAcceptAll() ) { - fileTypeIndex = fc.indexOfCurrentFilter(); - for( FileFilter filter : fc.getChoosableFileFilters() ) { - if( filter instanceof FileNameExtensionFilter ) { - fileTypes.add( filter.getDescription() ); - for( String ext : ((FileNameExtensionFilter)filter).getExtensions() ) - fileTypes.add( caseInsensitiveGlobPattern( ext ) ); - fileTypes.add( null ); - } else if( filter instanceof AcceptAllFileFilter ) { - fileTypes.add( filter.getDescription() ); - fileTypes.add( "*" ); - fileTypes.add( null ); + if( !fc.isDirectorySelectionEnabled() ) { + List filters = fc.getFiltersForDialog(); + if( !filters.isEmpty() ) { + fileTypeIndex = filters.indexOf( fc.getFileFilter() ); + for( FileFilter filter : filters ) { + if( filter instanceof FileNameExtensionFilter ) { + fileTypes.add( filter.getDescription() ); + for( String ext : ((FileNameExtensionFilter)filter).getExtensions() ) + fileTypes.add( caseInsensitiveGlobPattern( ext ) ); + fileTypes.add( null ); + } else if( filter instanceof AcceptAllFileFilter ) { + fileTypes.add( filter.getDescription() ); + fileTypes.add( "*" ); + fileTypes.add( null ); + } } } } @@ -1202,6 +1241,7 @@ public class SystemFileChooser chooser.setFileSelectionMode( fc.getFileSelectionMode() ); chooser.setMultiSelectionEnabled( fc.isMultiSelectionEnabled() ); chooser.setFileHidingEnabled( fc.isFileHidingEnabled() ); + chooser.setAcceptAllFileFilterUsed( fc.isAcceptAllFileFilterUsed() ); // system file dialogs do not support multi-selection for Save File dialogs if( chooser.isMultiSelectionEnabled() && @@ -1210,24 +1250,21 @@ public class SystemFileChooser chooser.setMultiSelectionEnabled( false ); // filter - if( !fc.isDirectorySelectionEnabled() && !fc.hasOnlyAcceptAll() ) { - FileFilter currentFilter = fc.getFileFilter(); - for( FileFilter filter : fc.getChoosableFileFilters() ) { - javax.swing.filechooser.FileFilter jfilter = convertFilter( filter, chooser ); - if( jfilter == null ) - continue; + if( !fc.isDirectorySelectionEnabled() ) { + List filters = fc.getFiltersForDialog(); + if( !filters.isEmpty() ) { + FileFilter currentFilter = fc.getFileFilter(); + chooser.removeChoosableFileFilter( chooser.getAcceptAllFileFilter() ); + for( FileFilter filter : filters ) { + javax.swing.filechooser.FileFilter jfilter = convertFilter( filter, chooser ); + if( jfilter == null ) + continue; - chooser.addChoosableFileFilter( jfilter ); - if( filter == currentFilter ) { - chooser.setFileFilter( jfilter ); - currentFilter = null; + chooser.addChoosableFileFilter( jfilter ); + if( filter == currentFilter ) + chooser.setFileFilter( jfilter ); } } - if( currentFilter != null ) { - javax.swing.filechooser.FileFilter jfilter = convertFilter( currentFilter, chooser ); - if( jfilter != null ) - chooser.setFileFilter( jfilter ); - } } // paths