Skip to content

Commit edda520

Browse files
committed
System File Chooser: update current filter before invoking approve callback and after closing dialog (issue #1065)
1 parent 7680c3a commit edda520

File tree

19 files changed

+207
-72
lines changed

19 files changed

+207
-72
lines changed

.github/workflows/natives.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ jobs:
7373
run: ./gradlew build-natives --no-daemon
7474

7575
- name: Sign Windows DLLs
76-
if: matrix.os == 'windows-latest'
76+
if: false
77+
# if: matrix.os == 'windows-latest'
7778
uses: skymatic/code-sign-action@v3
7879
with:
7980
certificate: '${{ secrets.CODE_SIGN_CERT_BASE64 }}'
@@ -82,7 +83,8 @@ jobs:
8283
folder: 'flatlaf-core/src/main/resources/com/formdev/flatlaf/natives'
8384

8485
- name: Sign macOS natives
85-
if: matrix.os == 'DISABLED--macos-latest'
86+
if: false
87+
# if: matrix.os == 'DISABLED--macos-latest'
8688
env:
8789
CERT_BASE64: ${{ secrets.CODE_SIGN_CERT_BASE64 }}
8890
CERT_PASSWORD: ${{ secrets.CODE_SIGN_CERT_PASSWORD }}

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ FlatLaf Change Log
33

44
## 3.7.1-SNAPSHOT
55

6+
- System File Chooser: Update current filter before invoking approve callback
7+
and after closing dialog. (issue #1065)
68
- ComboBox: Added UI property `ComboBox.buttonFocusedEditableBackground`. (issue
79
#1068)
810
- Popup: Fixed scrolling popup painting issue on Windows 10 when a glass pane is

flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeLinuxLibrary.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
*/
3838
public class FlatNativeLinuxLibrary
3939
{
40-
private static int API_VERSION_LINUX = 3003;
40+
private static int API_VERSION_LINUX = 3004;
4141

4242
/**
4343
* Checks whether native library is loaded/available.
@@ -186,28 +186,29 @@ public static boolean isGtk3Available() {
186186
* Use '__' for '_' character (e.g. "Choose__and__Quit").
187187
* @param currentName user-editable filename currently shown in the filename field in save dialog; or {@code null}
188188
* @param currentFolder current directory shown in the dialog; or {@code null}
189-
* @param optionsSet options to set; see {@code FOS_*} constants
190-
* @param optionsClear options to clear; see {@code FOS_*} constants
189+
* @param optionsSet options to set; see {@code FC_*} constants
190+
* @param optionsClear options to clear; see {@code FC_*} constants
191191
* @param callback approve callback; or {@code null}
192192
* @param fileTypeIndex the file type that appears as selected (zero-based)
193193
* @param fileTypes file types that the dialog can open or save.
194194
* Two or more strings and {@code null} are required for each filter.
195195
* First string is the display name of the filter shown in the combobox (e.g. "Text Files").
196196
* Subsequent strings are the filter patterns (e.g. "*.txt" or "*").
197197
* {@code null} is required to mark end of filter.
198+
* @param retFileTypeIndex returns selected file type (zero-based); array must be have one element
198199
* @return file path(s) that the user selected; an empty array if canceled;
199200
* or {@code null} on failures (no dialog shown)
200201
*
201-
* @since 3.7
202+
* @since 3.7.1
202203
*/
203204
public native static String[] showFileChooser( Window owner, int dark, boolean open,
204205
String title, String okButtonLabel, String currentName, String currentFolder,
205206
int optionsSet, int optionsClear, FileChooserCallback callback,
206-
int fileTypeIndex, String... fileTypes );
207+
int fileTypeIndex, String[] fileTypes, int[] retFileTypeIndex );
207208

208-
/** @since 3.7 */
209+
/** @since 3.7.1 */
209210
public interface FileChooserCallback {
210-
boolean approve( String[] files, long hwndFileDialog );
211+
boolean approve( String[] files, int fileTypeIndex, long hwndFileDialog );
211212
}
212213

213214
/**

flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeMacLibrary.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
*/
4646
public class FlatNativeMacLibrary
4747
{
48-
private static int API_VERSION_MACOS = 2002;
48+
private static int API_VERSION_MACOS = 2003;
4949

5050
/**
5151
* Checks whether native library is loaded/available.
@@ -117,20 +117,21 @@ public static boolean isLoaded() {
117117
* First string is the display name of the filter shown in the combobox (e.g. "Text Files").
118118
* Subsequent strings are the filter patterns (e.g. "txt" or "*").
119119
* {@code null} is required to mark end of filter.
120+
* @param retFileTypeIndex returns selected file type (zero-based); array must be have one element
120121
* @return file path(s) that the user selected; an empty array if canceled;
121122
* or {@code null} on failures (no dialog shown)
122123
*
123-
* @since 3.7
124+
* @since 3.7.1
124125
*/
125126
public native static String[] showFileChooser( Window owner, int dark, boolean open,
126127
String title, String prompt, String message, String filterFieldLabel,
127128
String nameFieldLabel, String nameFieldStringValue, String directoryURL,
128129
int optionsSet, int optionsClear, FileChooserCallback callback,
129-
int fileTypeIndex, String... fileTypes );
130+
int fileTypeIndex, String[] fileTypes, int[] retFileTypeIndex );
130131

131-
/** @since 3.7 */
132+
/** @since 3.7.1 */
132133
public interface FileChooserCallback {
133-
boolean approve( String[] files, long hwndFileDialog );
134+
boolean approve( String[] files, int fileTypeIndex, long hwndFileDialog );
134135
}
135136

136137
/**

flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeWindowsLibrary.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
*/
3232
public class FlatNativeWindowsLibrary
3333
{
34-
private static int API_VERSION_WINDOWS = 1002;
34+
private static int API_VERSION_WINDOWS = 1003;
3535

3636
private static long osBuildNumber = Long.MIN_VALUE;
3737

@@ -226,20 +226,21 @@ public static boolean dwmSetWindowAttributeCOLORREF( long hwnd, int attribute, C
226226
* Pairs of strings are required for each filter.
227227
* First string is the display name of the filter shown in the combobox (e.g. "Text Files").
228228
* Second string is the filter pattern (e.g. "*.txt", "*.exe;*.dll" or "*.*").
229+
* @param retFileTypeIndex returns selected file type (zero-based); array must be have one element
229230
* @return file path(s) that the user selected; an empty array if canceled;
230231
* or {@code null} on failures (no dialog shown)
231232
*
232-
* @since 3.7
233+
* @since 3.7.1
233234
*/
234235
public native static String[] showFileChooser( Window owner, boolean open,
235236
String title, String okButtonLabel, String fileNameLabel, String fileName,
236237
String folder, String saveAsItem, String defaultFolder, String defaultExtension,
237238
int optionsSet, int optionsClear, FileChooserCallback callback,
238-
int fileTypeIndex, String... fileTypes );
239+
int fileTypeIndex, String[] fileTypes, int[] retFileTypeIndex );
239240

240-
/** @since 3.7 */
241+
/** @since 3.7.1 */
241242
public interface FileChooserCallback {
242-
boolean approve( String[] files, long hwndFileDialog );
243+
boolean approve( String[] files, int fileTypeIndex, long hwndFileDialog );
243244
}
244245

245246
/**

flatlaf-core/src/main/java/com/formdev/flatlaf/util/SystemFileChooser.java

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import java.util.ArrayList;
2929
import java.util.Arrays;
3030
import java.util.HashMap;
31+
import java.util.IdentityHashMap;
3132
import java.util.List;
3233
import java.util.Locale;
3334
import java.util.Map;
@@ -607,6 +608,11 @@ private List<FileFilter> getFiltersForDialog() {
607608
return filters2;
608609
}
609610

611+
private void updateFileFilter( List<FileFilter> filters, int index ) {
612+
if( index >= 0 && index < filters.size() )
613+
setFileFilter( filters.get( index ) );
614+
}
615+
610616
public ApproveCallback getApproveCallback() {
611617
return approveCallback;
612618
}
@@ -890,6 +896,7 @@ String[] showSystemDialog( Window owner, SystemFileChooser fc ) {
890896
// filter
891897
int fileTypeIndex = 0;
892898
ArrayList<String> fileTypes = new ArrayList<>();
899+
ArrayList<FileFilter> fileTypeFilters = new ArrayList<>();
893900
if( !fc.isDirectorySelectionEnabled() ) {
894901
List<FileFilter> filters = fc.getFiltersForDialog();
895902
if( !filters.isEmpty() ) {
@@ -898,9 +905,11 @@ String[] showSystemDialog( Window owner, SystemFileChooser fc ) {
898905
if( filter instanceof FileNameExtensionFilter ) {
899906
fileTypes.add( filter.getDescription() );
900907
fileTypes.add( "*." + String.join( ";*.", ((FileNameExtensionFilter)filter).getExtensions() ) );
908+
fileTypeFilters.add( filter );
901909
} else if( filter instanceof AcceptAllFileFilter ) {
902910
fileTypes.add( filter.getDescription() );
903911
fileTypes.add( "*.*" );
912+
fileTypeFilters.add( filter );
904913
}
905914
}
906915
}
@@ -916,19 +925,24 @@ String[] showSystemDialog( Window owner, SystemFileChooser fc ) {
916925

917926
// callback
918927
FlatNativeWindowsLibrary.FileChooserCallback callback = (fc.getApproveCallback() != null)
919-
? (files, hwndFileDialog) -> {
928+
? (files, fileTypeIndex2, hwndFileDialog) -> {
929+
fc.updateFileFilter( fileTypeFilters, fileTypeIndex2 );
920930
return invokeApproveCallback( fc, files, new WindowsApproveContext( hwndFileDialog ) );
921931
} : null;
922932

923933
// show system file dialog
924-
return FlatNativeWindowsLibrary.showFileChooser( owner, open,
934+
int[] retFileTypeIndex = { -1 };
935+
String[] result = FlatNativeWindowsLibrary.showFileChooser( owner, open,
925936
fc.getDialogTitle(), approveButtonText,
926937
fc.getPlatformProperty( WINDOWS_FILE_NAME_LABEL ),
927938
fileName, folder, saveAsItem,
928939
fc.getPlatformProperty( WINDOWS_DEFAULT_FOLDER ),
929940
fc.getPlatformProperty( WINDOWS_DEFAULT_EXTENSION ),
930941
optionsSet, optionsClear, callback,
931-
fileTypeIndex, fileTypes.toArray( new String[fileTypes.size()] ) );
942+
fileTypeIndex, fileTypes.toArray( new String[fileTypes.size()] ), retFileTypeIndex );
943+
if( result != null )
944+
fc.updateFileFilter( fileTypeFilters, retFileTypeIndex[0] );
945+
return result;
932946
}
933947

934948
//---- class WindowsApproveContext ----
@@ -1013,6 +1027,7 @@ String[] showSystemDialog( Window owner, SystemFileChooser fc ) {
10131027
// filter
10141028
int fileTypeIndex = 0;
10151029
ArrayList<String> fileTypes = new ArrayList<>();
1030+
ArrayList<FileFilter> fileTypeFilters = new ArrayList<>();
10161031
if( !fc.isDirectorySelectionEnabled() ) {
10171032
List<FileFilter> filters = fc.getFiltersForDialog();
10181033
if( !filters.isEmpty() ) {
@@ -1023,29 +1038,36 @@ String[] showSystemDialog( Window owner, SystemFileChooser fc ) {
10231038
for( String ext : ((FileNameExtensionFilter)filter).getExtensions() )
10241039
fileTypes.add( ext );
10251040
fileTypes.add( null );
1041+
fileTypeFilters.add( filter );
10261042
} else if( filter instanceof AcceptAllFileFilter ) {
10271043
fileTypes.add( filter.getDescription() );
10281044
fileTypes.add( "*" );
10291045
fileTypes.add( null );
1046+
fileTypeFilters.add( filter );
10301047
}
10311048
}
10321049
}
10331050
}
10341051

10351052
// callback
10361053
FlatNativeMacLibrary.FileChooserCallback callback = (fc.getApproveCallback() != null)
1037-
? (files, hwndFileDialog) -> {
1054+
? (files, fileTypeIndex2, hwndFileDialog) -> {
1055+
fc.updateFileFilter( fileTypeFilters, fileTypeIndex2 );
10381056
return invokeApproveCallback( fc, files, new MacApproveContext( hwndFileDialog ) );
10391057
} : null;
10401058

10411059
// show system file dialog
1042-
return FlatNativeMacLibrary.showFileChooser( owner, dark, open,
1060+
int[] retFileTypeIndex = { -1 };
1061+
String[] result = FlatNativeMacLibrary.showFileChooser( owner, dark, open,
10431062
fc.getDialogTitle(), fc.getApproveButtonText(),
10441063
fc.getPlatformProperty( MAC_MESSAGE ),
10451064
fc.getPlatformProperty( MAC_FILTER_FIELD_LABEL ),
10461065
fc.getPlatformProperty( MAC_NAME_FIELD_LABEL ),
10471066
nameFieldStringValue, directoryURL, optionsSet, optionsClear, callback,
1048-
fileTypeIndex, fileTypes.toArray( new String[fileTypes.size()] ) );
1067+
fileTypeIndex, fileTypes.toArray( new String[fileTypes.size()] ), retFileTypeIndex );
1068+
if( result != null )
1069+
fc.updateFileFilter( fileTypeFilters, retFileTypeIndex[0] );
1070+
return result;
10491071
}
10501072

10511073
//---- class MacApproveContext ----
@@ -1141,6 +1163,7 @@ String[] showSystemDialog( Window owner, SystemFileChooser fc ) {
11411163
// filter
11421164
int fileTypeIndex = 0;
11431165
ArrayList<String> fileTypes = new ArrayList<>();
1166+
ArrayList<FileFilter> fileTypeFilters = new ArrayList<>();
11441167
if( !fc.isDirectorySelectionEnabled() ) {
11451168
List<FileFilter> filters = fc.getFiltersForDialog();
11461169
if( !filters.isEmpty() ) {
@@ -1151,26 +1174,33 @@ String[] showSystemDialog( Window owner, SystemFileChooser fc ) {
11511174
for( String ext : ((FileNameExtensionFilter)filter).getExtensions() )
11521175
fileTypes.add( caseInsensitiveGlobPattern( ext ) );
11531176
fileTypes.add( null );
1177+
fileTypeFilters.add( filter );
11541178
} else if( filter instanceof AcceptAllFileFilter ) {
11551179
fileTypes.add( filter.getDescription() );
11561180
fileTypes.add( "*" );
11571181
fileTypes.add( null );
1182+
fileTypeFilters.add( filter );
11581183
}
11591184
}
11601185
}
11611186
}
11621187

11631188
// callback
11641189
FlatNativeLinuxLibrary.FileChooserCallback callback = (fc.getApproveCallback() != null)
1165-
? (files, hwndFileDialog) -> {
1190+
? (files, fileTypeIndex2, hwndFileDialog) -> {
1191+
fc.updateFileFilter( fileTypeFilters, fileTypeIndex2 );
11661192
return invokeApproveCallback( fc, files, new LinuxApproveContext( hwndFileDialog ) );
11671193
} : null;
11681194

11691195
// show system file dialog
1170-
return FlatNativeLinuxLibrary.showFileChooser( owner, dark, open,
1196+
int[] retFileTypeIndex = { -1 };
1197+
String[] result = FlatNativeLinuxLibrary.showFileChooser( owner, dark, open,
11711198
fc.getDialogTitle(), approveButtonText, currentName, currentFolder,
11721199
optionsSet, optionsClear, callback,
1173-
fileTypeIndex, fileTypes.toArray( new String[fileTypes.size()] ) );
1200+
fileTypeIndex, fileTypes.toArray( new String[fileTypes.size()] ), retFileTypeIndex );
1201+
if( result != null )
1202+
fc.updateFileFilter( fileTypeFilters, retFileTypeIndex[0] );
1203+
return result;
11741204
}
11751205

11761206
private String caseInsensitiveGlobPattern( String ext ) {
@@ -1253,6 +1283,8 @@ private static class SwingFileChooserProvider
12531283
{
12541284
@Override
12551285
public File[] showDialog( Window owner, SystemFileChooser fc ) {
1286+
IdentityHashMap<javax.swing.filechooser.FileFilter, FileFilter> filterMap = new IdentityHashMap<>();
1287+
12561288
JFileChooser chooser = new JFileChooser() {
12571289
@Override
12581290
public void approveSelection() {
@@ -1273,6 +1305,7 @@ public void approveSelection() {
12731305
// callback
12741306
ApproveCallback approveCallback = fc.getApproveCallback();
12751307
if( approveCallback != null ) {
1308+
updateFileFilter( fc, this, filterMap );
12761309
int result = approveCallback.approve( files, new SwingApproveContext( this ) );
12771310
if( result == CANCEL_OPTION )
12781311
return;
@@ -1313,6 +1346,7 @@ public void approveSelection() {
13131346
chooser.addChoosableFileFilter( jfilter );
13141347
if( filter == currentFilter )
13151348
chooser.setFileFilter( jfilter );
1349+
filterMap.put( jfilter, filter );
13161350
}
13171351
}
13181352
}
@@ -1340,6 +1374,7 @@ public void approveSelection() {
13401374

13411375
// show dialog
13421376
int result = chooser.showDialog( owner, null );
1377+
updateFileFilter( fc, chooser, filterMap );
13431378

13441379
// save window size
13451380
Dimension windowSize = chooser.getSize();
@@ -1367,6 +1402,14 @@ private javax.swing.filechooser.FileFilter convertFilter( FileFilter filter, JFi
13671402
return null;
13681403
}
13691404

1405+
private void updateFileFilter( SystemFileChooser fc, JFileChooser chooser,
1406+
IdentityHashMap<javax.swing.filechooser.FileFilter, FileFilter> filterMap )
1407+
{
1408+
FileFilter fileFilter = filterMap.get( chooser.getFileFilter() );
1409+
if( fileFilter != null )
1410+
fc.setFileFilter( fileFilter );
1411+
}
1412+
13701413
private static boolean checkMustExist( JFileChooser chooser, File[] files ) {
13711414
for( File file : files ) {
13721415
if( !file.exists() ) {

flatlaf-natives/flatlaf-natives-linux/src/main/cpp/ApiVersion.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
// increase this version if changing API or functionality of native library
2626
// also update version in Java class com.formdev.flatlaf.ui.FlatNativeLinuxLibrary
27-
#define API_VERSION_LINUX 3003
27+
#define API_VERSION_LINUX 3004
2828

2929

3030
//---- JNI methods ------------------------------------------------------------

0 commit comments

Comments
 (0)