diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeMacLibrary.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeMacLibrary.java index 73bef9b7..3615ef20 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeMacLibrary.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeMacLibrary.java @@ -77,6 +77,7 @@ public class FlatNativeMacLibrary FC_canChooseDirectories = 1 << 1, FC_resolvesAliases = 1 << 2, // default FC_allowsMultipleSelection = 1 << 3, + FC_accessoryViewDisclosed = 1 << 4, // NSSavePanel FC_showsTagField = 1 << 8, // default for Save FC_canCreateDirectories = 1 << 9, // default for Save @@ -84,7 +85,9 @@ public class FlatNativeMacLibrary FC_showsHiddenFiles = 1 << 11, FC_extensionHidden = 1 << 12, FC_allowsOtherFileTypes = 1 << 13, - FC_treatsFilePackagesAsDirectories = 1 << 14; + FC_treatsFilePackagesAsDirectories = 1 << 14, + // custom + FC_showSingleFilterField = 1 << 24; /** * Shows the macOS system file dialogs @@ -99,19 +102,25 @@ public class FlatNativeMacLibrary * @param title text displayed at top of save dialog (not used in open dialog); or {@code null} * @param prompt text displayed in default button; or {@code null} * @param message text displayed at top of open/save dialogs; or {@code null} + * @param filterFieldLabel text displayed in front of the filter combobox; or {@code null} * @param nameFieldLabel text displayed in front of the filename text field in save dialog (not used in open dialog); or {@code null} * @param nameFieldStringValue user-editable filename currently shown in the name field in save dialog (not used in open dialog); or {@code null} * @param directoryURL current directory shown in the dialog; or {@code null} * @param optionsSet options to set; see {@code FC_*} constants * @param optionsClear options to clear; see {@code FC_*} constants - * @param allowedFileTypes allowed filename extensions (e.g. "txt") + * @param fileTypeIndex the file type that appears as selected (zero-based) + * @param fileTypes file types that the dialog can open or save. + * Two or more strings and {@code null} are required for each filter. + * First string is the display name of the filter shown in the combobox (e.g. "Text Files"). + * Subsequent strings are the filter patterns (e.g. "*.txt" or "*"). + * {@code null} is required to mark end of filter. * @return file path(s) that the user selected; an empty array if canceled; * or {@code null} on failures (no dialog shown) * * @since 3.6 */ public native static String[] showFileChooser( boolean open, - String title, String prompt, String message, String nameFieldLabel, - String nameFieldStringValue, String directoryURL, - int optionsSet, int optionsClear, String... allowedFileTypes ); + String title, String prompt, String message, String filterFieldLabel, + String nameFieldLabel, String nameFieldStringValue, String directoryURL, + int optionsSet, int optionsClear, int fileTypeIndex, String... fileTypes ); } 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 23f6a2d6..dea48265 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 @@ -445,7 +445,7 @@ public class SystemFileChooser directoryURL = currentDirectory.getAbsolutePath(); // options - int optionsSet = 0; + int optionsSet = FlatNativeMacLibrary.FC_accessoryViewDisclosed; int optionsClear = 0; if( fc.isDirectorySelectionEnabled() ) { optionsSet |= FlatNativeMacLibrary.FC_canChooseDirectories; @@ -459,9 +459,9 @@ public class SystemFileChooser // show system file dialog return FlatNativeMacLibrary.showFileChooser( open, - fc.getDialogTitle(), fc.getApproveButtonText(), null, null, + fc.getDialogTitle(), fc.getApproveButtonText(), null, null, null, nameFieldStringValue, directoryURL, - optionsSet, optionsClear ); + optionsSet, optionsClear, 0 ); } } diff --git a/flatlaf-natives/flatlaf-natives-macos/src/main/headers/com_formdev_flatlaf_ui_FlatNativeMacLibrary.h b/flatlaf-natives/flatlaf-natives-macos/src/main/headers/com_formdev_flatlaf_ui_FlatNativeMacLibrary.h index 7d163d7f..1e581622 100644 --- a/flatlaf-natives/flatlaf-natives-macos/src/main/headers/com_formdev_flatlaf_ui_FlatNativeMacLibrary.h +++ b/flatlaf-natives/flatlaf-natives-macos/src/main/headers/com_formdev_flatlaf_ui_FlatNativeMacLibrary.h @@ -21,6 +21,8 @@ extern "C" { #define com_formdev_flatlaf_ui_FlatNativeMacLibrary_FC_resolvesAliases 4L #undef com_formdev_flatlaf_ui_FlatNativeMacLibrary_FC_allowsMultipleSelection #define com_formdev_flatlaf_ui_FlatNativeMacLibrary_FC_allowsMultipleSelection 8L +#undef com_formdev_flatlaf_ui_FlatNativeMacLibrary_FC_accessoryViewDisclosed +#define com_formdev_flatlaf_ui_FlatNativeMacLibrary_FC_accessoryViewDisclosed 16L #undef com_formdev_flatlaf_ui_FlatNativeMacLibrary_FC_showsTagField #define com_formdev_flatlaf_ui_FlatNativeMacLibrary_FC_showsTagField 256L #undef com_formdev_flatlaf_ui_FlatNativeMacLibrary_FC_canCreateDirectories @@ -35,6 +37,8 @@ extern "C" { #define com_formdev_flatlaf_ui_FlatNativeMacLibrary_FC_allowsOtherFileTypes 8192L #undef com_formdev_flatlaf_ui_FlatNativeMacLibrary_FC_treatsFilePackagesAsDirectories #define com_formdev_flatlaf_ui_FlatNativeMacLibrary_FC_treatsFilePackagesAsDirectories 16384L +#undef com_formdev_flatlaf_ui_FlatNativeMacLibrary_FC_showSingleFilterField +#define com_formdev_flatlaf_ui_FlatNativeMacLibrary_FC_showSingleFilterField 16777216L /* * Class: com_formdev_flatlaf_ui_FlatNativeMacLibrary * Method: setWindowRoundedBorder @@ -78,10 +82,10 @@ JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_togg /* * Class: com_formdev_flatlaf_ui_FlatNativeMacLibrary * Method: showFileChooser - * Signature: (ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;II[Ljava/lang/String;)[Ljava/lang/String; + * Signature: (ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;III[Ljava/lang/String;)[Ljava/lang/String; */ JNIEXPORT jobjectArray JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_showFileChooser - (JNIEnv *, jclass, jboolean, jstring, jstring, jstring, jstring, jstring, jstring, jint, jint, jobjectArray); + (JNIEnv *, jclass, jboolean, jstring, jstring, jstring, jstring, jstring, jstring, jstring, jint, jint, jint, jobjectArray); #ifdef __cplusplus } diff --git a/flatlaf-natives/flatlaf-natives-macos/src/main/objcpp/MacFileChooser.mm b/flatlaf-natives/flatlaf-natives-macos/src/main/objcpp/MacFileChooser.mm index 9755c5ab..8a6615ec 100644 --- a/flatlaf-natives/flatlaf-natives-macos/src/main/objcpp/MacFileChooser.mm +++ b/flatlaf-natives/flatlaf-natives-macos/src/main/objcpp/MacFileChooser.mm @@ -26,6 +26,80 @@ * @since 3.6 */ +//---- class FileChooserDelegate ---------------------------------------------- + +@interface FileChooserDelegate : NSObject { + NSArray* _filters; + } + + @property (nonatomic, assign) NSSavePanel* dialog; + + - (void)initFilterAccessoryView: (NSMutableArray*)filters :(int)filterIndex + :(NSString*)filterFieldLabel :(bool)showSingleFilterField; + - (void)selectFormat: (id)sender; + - (void)selectFormatAtIndex: (int)index; +@end + +@implementation FileChooserDelegate + + - (void)initFilterAccessoryView: (NSMutableArray*)filters :(int)filterIndex + :(NSString*)filterFieldLabel :(bool)showSingleFilterField + { + _filters = filters; + + // get filter names + NSArray* filterNames = filters.lastObject; + [filters removeLastObject]; + + // do not add filter/format combobox if there is only one filter + if( filters.count <= 1 && !showSingleFilterField ) { + [self selectFormatAtIndex:0]; + return; + } + + // create label + NSTextField* label = [[NSTextField alloc] initWithFrame:NSMakeRect( 0, 0, 60, 22 )]; + label.stringValue = (filterFieldLabel != NULL) ? filterFieldLabel : @"Format:"; + label.editable = NO; + label.bordered = NO; + label.bezeled = NO; + label.drawsBackground = NO; + + // create combobox + NSPopUpButton* popupButton = [[NSPopUpButton alloc] initWithFrame:NSMakeRect( 50, 2, 140, 22 ) pullsDown:NO]; + [popupButton addItemsWithTitles:filterNames]; + [popupButton selectItemAtIndex:MIN( MAX( filterIndex, 0 ), filterNames.count - 1 )]; + [popupButton setTarget:self]; + [popupButton setAction:@selector(selectFormat:)]; + + // create view + NSView* accessoryView = [[NSView alloc] initWithFrame:NSMakeRect( 0, 0, 200, 32 )]; + [accessoryView addSubview:label]; + [accessoryView addSubview:popupButton]; + + [_dialog setAccessoryView:accessoryView]; + + // initial filter + [self selectFormatAtIndex:filterIndex]; + } + + - (void)selectFormat:(id)sender { + NSPopUpButton* popupButton = (NSPopUpButton*) sender; + [self selectFormatAtIndex:popupButton.indexOfSelectedItem]; + } + + - (void)selectFormatAtIndex: (int)index { + index = MIN( MAX( index, 0 ), _filters.count - 1 ); + NSArray* fileTypes = [_filters objectAtIndex:index]; + + // use deprecated allowedFileTypes instead of newer allowedContentTypes (since macOS 11+) + // to support older macOS versions 10.14+ and because of some problems with allowedContentTypes: + // https://github.com/chromium/chromium/blob/d8e0032963b7ca4728ff4117933c0feb3e479b7a/components/remote_cocoa/app_shim/select_file_dialog_bridge.mm#L209-232 + _dialog.allowedFileTypes = [fileTypes containsObject:@"*"] ? nil : fileTypes; + } + +@end + //---- helper ----------------------------------------------------------------- #define isOptionSet( option ) ((optionsSet & com_formdev_flatlaf_ui_FlatNativeMacLibrary_ ## option) != 0) @@ -40,14 +114,55 @@ jobjectArray newJavaStringArray( JNIEnv* env, jsize count ) { return env->NewObjectArray( count, stringClass, NULL ); } +static NSMutableArray* initFilters( JNIEnv* env, jobjectArray fileTypes ) { + jint length = env->GetArrayLength( fileTypes ); + if( length <= 0 ) + return NULL; + + NSMutableArray* filterNames = [NSMutableArray array]; + NSMutableArray* filters = [NSMutableArray array]; + NSString* filterName = NULL; + NSMutableArray* filter = NULL; + for( int i = 0; i < length; i++ ) { + jstring jstr = (jstring) env->GetObjectArrayElement( fileTypes, i ); + if( jstr == NULL ) { + if( filter != NULL ) { + if( filter.count > 0 ) { + [filterNames addObject:filterName]; + [filters addObject:filter]; + } + filterName = NULL; + filter = NULL; + } + continue; + } + + NSString* str = JavaToNSString( env, jstr ); + env->DeleteLocalRef( jstr ); + if( filter == NULL ) { + filterName = str; + filter = [NSMutableArray array]; + } else + [filter addObject:str]; + } + + if( filters.count == 0 ) + return NULL; + + // add filter names to array (removed again after creating combobox) + [filters addObject:filterNames]; + + return filters; +} + //---- JNI methods ------------------------------------------------------------ extern "C" JNIEXPORT jobjectArray JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_showFileChooser ( JNIEnv* env, jclass cls, jboolean open, - jstring title, jstring prompt, jstring message, jstring nameFieldLabel, - jstring nameFieldStringValue, jstring directoryURL, - jint optionsSet, jint optionsClear, jobjectArray allowedFileTypes ) + jstring title, jstring prompt, jstring message, jstring filterFieldLabel, + jstring nameFieldLabel, jstring nameFieldStringValue, jstring directoryURL, + jint optionsSet, jint optionsClear, jint fileTypeIndex, jobjectArray fileTypes ) { JNI_COCOA_ENTER() @@ -55,21 +170,11 @@ JNIEXPORT jobjectArray JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_ NSString* nsTitle = JavaToNSString( env, title ); NSString* nsPrompt = JavaToNSString( env, prompt ); NSString* nsMessage = JavaToNSString( env, message ); + NSString* nsFilterFieldLabel = JavaToNSString( env, filterFieldLabel ); NSString* nsNameFieldLabel = JavaToNSString( env, nameFieldLabel ); NSString* nsNameFieldStringValue = JavaToNSString( env, nameFieldStringValue ); NSString* nsDirectoryURL = JavaToNSString( env, directoryURL ); - - NSArray* nsAllowedFileTypes = NULL; - jsize len = env->GetArrayLength( allowedFileTypes ); - if( len > 0 ) { - NSMutableArray* nsArray = [NSMutableArray arrayWithCapacity:len]; - for( int i = 0; i < len; i++ ) { - jstring str = (jstring) env->GetObjectArrayElement( allowedFileTypes, i ); - nsArray[i] = JavaToNSString( env, str ); - env->DeleteLocalRef( str ); - } - nsAllowedFileTypes = nsArray; - } + NSMutableArray* filters = initFilters( env, fileTypes ); NSArray* urls = NULL; NSArray** purls = &urls; @@ -93,6 +198,7 @@ JNIEXPORT jobjectArray JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_ if( nsDirectoryURL != NULL ) dialog.directoryURL = [NSURL fileURLWithPath:nsDirectoryURL isDirectory:YES]; + // set open options if( open ) { NSOpenPanel* openDialog = (NSOpenPanel*) dialog; @@ -109,6 +215,7 @@ JNIEXPORT jobjectArray JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_ openDialog.allowsMultipleSelection = isOptionSet( FC_allowsMultipleSelection ); } + // set options if( isOptionSetOrClear( FC_showsTagField ) ) dialog.showsTagField = isOptionSet( FC_showsTagField ); if( isOptionSetOrClear( FC_canCreateDirectories ) ) @@ -124,13 +231,21 @@ JNIEXPORT jobjectArray JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_ if( isOptionSetOrClear( FC_treatsFilePackagesAsDirectories ) ) dialog.treatsFilePackagesAsDirectories = isOptionSet( FC_treatsFilePackagesAsDirectories ); - // use deprecated allowedFileTypes instead of newer allowedContentTypes (since macOS 11+) - // to support older macOS versions 10.14+ and because of some problems with allowedContentTypes: - // https://github.com/chromium/chromium/blob/d8e0032963b7ca4728ff4117933c0feb3e479b7a/components/remote_cocoa/app_shim/select_file_dialog_bridge.mm#L209-232 - if( nsAllowedFileTypes != NULL ) - dialog.allowedFileTypes = nsAllowedFileTypes; + FileChooserDelegate* delegate = [FileChooserDelegate new]; + delegate.dialog = dialog; - if( [dialog runModal] != NSModalResponseOK ) + // initialize filter accessory view + if( filters != NULL ) { + [delegate initFilterAccessoryView:filters :fileTypeIndex :nsFilterFieldLabel :isOptionSet( FC_showSingleFilterField )]; + + if( open && isOptionSetOrClear( FC_accessoryViewDisclosed ) ) + ((NSOpenPanel*)dialog).accessoryViewDisclosed = isOptionSet( FC_accessoryViewDisclosed ); + } + + // show dialog + NSModalResponse response = [dialog runModal]; + [delegate release]; + if( response != NSModalResponseOK ) return; if( open ) diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatSystemFileChooserMacTest.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatSystemFileChooserMacTest.java index ae52327d..99d2297b 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatSystemFileChooserMacTest.java +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatSystemFileChooserMacTest.java @@ -66,6 +66,8 @@ public class FlatSystemFileChooserMacTest FlatSystemFileChooserMacTest() { initComponents(); + + fileTypesField.setSelectedItem( null ); } private void open() { @@ -88,6 +90,7 @@ public class FlatSystemFileChooserMacTest String title = n( titleField.getText() ); String prompt = n( promptField.getText() ); String message = n( messageField.getText() ); + String filterFieldLabel = n( filterFieldLabelField.getText() ); String nameFieldLabel = n( nameFieldLabelField.getText() ); String nameFieldStringValue = n( nameFieldStringValueField.getText() ); String directoryURL = n( directoryURLField.getText() ); @@ -101,6 +104,8 @@ public class FlatSystemFileChooserMacTest optionsSet.set( optionsSet.get() | FC_canChooseDirectories ); o( FC_resolvesAliases, resolvesAliasesCheckBox, optionsSet, optionsClear ); o( FC_allowsMultipleSelection, allowsMultipleSelectionCheckBox, optionsSet, optionsClear ); + if( accessoryViewDisclosedCheckBox.isSelected() ) + optionsSet.set( optionsSet.get() | FC_accessoryViewDisclosed ); // NSSavePanel o( FC_showsTagField, showsTagFieldCheckBox, optionsSet, optionsClear ); @@ -111,25 +116,39 @@ public class FlatSystemFileChooserMacTest o( FC_allowsOtherFileTypes, allowsOtherFileTypesCheckBox, optionsSet, optionsClear ); o( FC_treatsFilePackagesAsDirectories, treatsFilePackagesAsDirectoriesCheckBox, optionsSet, optionsClear ); - String allowedFileTypesStr = n( allowedFileTypesField.getText() ); - String[] allowedFileTypes = {}; - if( allowedFileTypesStr != null ) - allowedFileTypes = allowedFileTypesStr.trim().split( "[ ,]+" ); + // custom + if( showSingleFilterFieldCheckBox.isSelected() ) + optionsSet.set( optionsSet.get() | FC_showSingleFilterField ); + + String fileTypesStr = n( (String) fileTypesField.getSelectedItem() ); + String[] fileTypes = {}; + if( fileTypesStr != null ) { + if( !fileTypesStr.endsWith( ",null" ) ) + fileTypesStr += ",null"; + fileTypes = fileTypesStr.trim().split( "[,]+" ); + for( int i = 0; i < fileTypes.length; i++ ) { + if( "null".equals( fileTypes[i] ) ) + fileTypes[i] = null; + } + } + int fileTypeIndex = fileTypeIndexSlider.getValue(); if( direct ) { - String[] files = FlatNativeMacLibrary.showFileChooser( open, title, prompt, message, + String[] files = FlatNativeMacLibrary.showFileChooser( open, + title, prompt, message, filterFieldLabel, nameFieldLabel, nameFieldStringValue, directoryURL, - optionsSet.get(), optionsClear.get(), allowedFileTypes ); + optionsSet.get(), optionsClear.get(), fileTypeIndex, fileTypes ); filesField.setText( (files != null) ? Arrays.toString( files ).replace( ',', '\n' ) : "null" ); } else { SecondaryLoop secondaryLoop = Toolkit.getDefaultToolkit().getSystemEventQueue().createSecondaryLoop(); - String[] allowedFileTypes2 = allowedFileTypes; + String[] fileTypes2 = fileTypes; new Thread( () -> { - String[] files = FlatNativeMacLibrary.showFileChooser( open, title, prompt, message, + String[] files = FlatNativeMacLibrary.showFileChooser( open, + title, prompt, message, filterFieldLabel, nameFieldLabel, nameFieldStringValue, directoryURL, - optionsSet.get(), optionsClear.get(), allowedFileTypes2 ); + optionsSet.get(), optionsClear.get(), fileTypeIndex, fileTypes2 ); System.out.println( " secondaryLoop.exit() returned " + secondaryLoop.exit() ); @@ -144,7 +163,7 @@ public class FlatSystemFileChooserMacTest } private static String n( String s ) { - return !s.isEmpty() ? s : null; + return s != null && !s.isEmpty() ? s : null; } private static void o( int option, FlatTriStateCheckBox checkBox, AtomicInteger optionsSet, AtomicInteger optionsClear ) { @@ -220,6 +239,7 @@ public class FlatSystemFileChooserMacTest canChooseDirectoriesCheckBox = new JCheckBox(); resolvesAliasesCheckBox = new FlatTriStateCheckBox(); allowsMultipleSelectionCheckBox = new FlatTriStateCheckBox(); + accessoryViewDisclosedCheckBox = new JCheckBox(); options2Label = new JLabel(); showsTagFieldCheckBox = new FlatTriStateCheckBox(); canCreateDirectoriesCheckBox = new FlatTriStateCheckBox(); @@ -228,18 +248,24 @@ public class FlatSystemFileChooserMacTest extensionHiddenCheckBox = new FlatTriStateCheckBox(); allowsOtherFileTypesCheckBox = new FlatTriStateCheckBox(); treatsFilePackagesAsDirectoriesCheckBox = new FlatTriStateCheckBox(); + options3Label = new JLabel(); + showSingleFilterFieldCheckBox = new JCheckBox(); promptLabel = new JLabel(); promptField = new JTextField(); messageLabel = new JLabel(); messageField = new JTextField(); + filterFieldLabelLabel = new JLabel(); + filterFieldLabelField = new JTextField(); nameFieldLabelLabel = new JLabel(); nameFieldLabelField = new JTextField(); nameFieldStringValueLabel = new JLabel(); nameFieldStringValueField = new JTextField(); directoryURLLabel = new JLabel(); directoryURLField = new JTextField(); - allowedFileTypesLabel = new JLabel(); - allowedFileTypesField = new JTextField(); + fileTypesLabel = new JLabel(); + fileTypesField = new JComboBox<>(); + fileTypeIndexLabel = new JLabel(); + fileTypeIndexSlider = new JSlider(); openButton = new JButton(); saveButton = new JButton(); openDirectButton = new JButton(); @@ -264,6 +290,8 @@ public class FlatSystemFileChooserMacTest "[]" + "[]" + "[]" + + "[]" + + "[]" + "[grow,fill]")); //---- titleLabel ---- @@ -282,6 +310,7 @@ public class FlatSystemFileChooserMacTest "[]0" + "[]0" + "[]0" + + "[]0" + "[]para" + "[]" + "[]0" + @@ -290,6 +319,8 @@ public class FlatSystemFileChooserMacTest "[]0" + "[]0" + "[]0" + + "[]para" + + "[]" + "[]")); //---- options1Label ---- @@ -314,39 +345,51 @@ public class FlatSystemFileChooserMacTest allowsMultipleSelectionCheckBox.setText("allowsMultipleSelection"); panel1.add(allowsMultipleSelectionCheckBox, "cell 0 4"); + //---- accessoryViewDisclosedCheckBox ---- + accessoryViewDisclosedCheckBox.setText("accessoryViewDisclosed"); + panel1.add(accessoryViewDisclosedCheckBox, "cell 0 5"); + //---- options2Label ---- options2Label.setText("NSOpenPanel and NSSavePanel options:"); - panel1.add(options2Label, "cell 0 5"); + panel1.add(options2Label, "cell 0 6"); //---- showsTagFieldCheckBox ---- showsTagFieldCheckBox.setText("showsTagField"); - panel1.add(showsTagFieldCheckBox, "cell 0 6"); + panel1.add(showsTagFieldCheckBox, "cell 0 7"); //---- canCreateDirectoriesCheckBox ---- canCreateDirectoriesCheckBox.setText("canCreateDirectories"); - panel1.add(canCreateDirectoriesCheckBox, "cell 0 7"); + panel1.add(canCreateDirectoriesCheckBox, "cell 0 8"); //---- canSelectHiddenExtensionCheckBox ---- canSelectHiddenExtensionCheckBox.setText("canSelectHiddenExtension"); - panel1.add(canSelectHiddenExtensionCheckBox, "cell 0 8"); + panel1.add(canSelectHiddenExtensionCheckBox, "cell 0 9"); //---- showsHiddenFilesCheckBox ---- showsHiddenFilesCheckBox.setText("showsHiddenFiles"); - panel1.add(showsHiddenFilesCheckBox, "cell 0 9"); + panel1.add(showsHiddenFilesCheckBox, "cell 0 10"); //---- extensionHiddenCheckBox ---- extensionHiddenCheckBox.setText("extensionHidden"); - panel1.add(extensionHiddenCheckBox, "cell 0 10"); + panel1.add(extensionHiddenCheckBox, "cell 0 11"); //---- allowsOtherFileTypesCheckBox ---- allowsOtherFileTypesCheckBox.setText("allowsOtherFileTypes"); - panel1.add(allowsOtherFileTypesCheckBox, "cell 0 11"); + panel1.add(allowsOtherFileTypesCheckBox, "cell 0 12"); //---- treatsFilePackagesAsDirectoriesCheckBox ---- treatsFilePackagesAsDirectoriesCheckBox.setText("treatsFilePackagesAsDirectories"); - panel1.add(treatsFilePackagesAsDirectoriesCheckBox, "cell 0 12"); + panel1.add(treatsFilePackagesAsDirectoriesCheckBox, "cell 0 13"); + + //---- options3Label ---- + options3Label.setText("Custom options:"); + panel1.add(options3Label, "cell 0 14"); + + //---- showSingleFilterFieldCheckBox ---- + showSingleFilterFieldCheckBox.setText("showSingleFilterField"); + panel1.add(showSingleFilterFieldCheckBox, "cell 0 15"); } - add(panel1, "cell 2 0 1 8,aligny top,growy 0"); + add(panel1, "cell 2 0 1 10,aligny top,growy 0"); //---- promptLabel ---- promptLabel.setText("prompt"); @@ -358,45 +401,72 @@ public class FlatSystemFileChooserMacTest add(messageLabel, "cell 0 2"); add(messageField, "cell 1 2"); + //---- filterFieldLabelLabel ---- + filterFieldLabelLabel.setText("filterFieldLabel"); + add(filterFieldLabelLabel, "cell 0 3"); + add(filterFieldLabelField, "cell 1 3"); + //---- nameFieldLabelLabel ---- nameFieldLabelLabel.setText("nameFieldLabel"); - add(nameFieldLabelLabel, "cell 0 3"); - add(nameFieldLabelField, "cell 1 3"); + add(nameFieldLabelLabel, "cell 0 4"); + add(nameFieldLabelField, "cell 1 4"); //---- nameFieldStringValueLabel ---- nameFieldStringValueLabel.setText("nameFieldStringValue"); - add(nameFieldStringValueLabel, "cell 0 4"); - add(nameFieldStringValueField, "cell 1 4"); + add(nameFieldStringValueLabel, "cell 0 5"); + add(nameFieldStringValueField, "cell 1 5"); //---- directoryURLLabel ---- directoryURLLabel.setText("directoryURL"); - add(directoryURLLabel, "cell 0 5"); - add(directoryURLField, "cell 1 5"); + add(directoryURLLabel, "cell 0 6"); + add(directoryURLField, "cell 1 6"); - //---- allowedFileTypesLabel ---- - allowedFileTypesLabel.setText("allowedFileTypes"); - add(allowedFileTypesLabel, "cell 0 6"); - add(allowedFileTypesField, "cell 1 6"); + //---- fileTypesLabel ---- + fileTypesLabel.setText("fileTypes"); + add(fileTypesLabel, "cell 0 7"); + + //---- fileTypesField ---- + fileTypesField.setEditable(true); + fileTypesField.setModel(new DefaultComboBoxModel<>(new String[] { + "Text Files,txt,null", + "All Files,*,null", + "Text Files,txt,null,PDF Files,pdf,null,All Files,*,null", + "Text and PDF Files,txt,pdf,null", + "Compressed,zip,gz,null,Disk Images,dmg,null" + })); + add(fileTypesField, "cell 1 7"); + + //---- fileTypeIndexLabel ---- + fileTypeIndexLabel.setText("fileTypeIndex"); + add(fileTypeIndexLabel, "cell 0 8"); + + //---- fileTypeIndexSlider ---- + fileTypeIndexSlider.setMaximum(10); + fileTypeIndexSlider.setMajorTickSpacing(1); + fileTypeIndexSlider.setValue(0); + fileTypeIndexSlider.setPaintLabels(true); + fileTypeIndexSlider.setSnapToTicks(true); + add(fileTypeIndexSlider, "cell 1 8"); //---- openButton ---- openButton.setText("Open..."); openButton.addActionListener(e -> open()); - add(openButton, "cell 0 8 3 1"); + add(openButton, "cell 0 10 3 1"); //---- saveButton ---- saveButton.setText("Save..."); saveButton.addActionListener(e -> save()); - add(saveButton, "cell 0 8 3 1"); + add(saveButton, "cell 0 10 3 1"); //---- openDirectButton ---- openDirectButton.setText("Open (no-thread)..."); openDirectButton.addActionListener(e -> openDirect()); - add(openDirectButton, "cell 0 8 3 1"); + add(openDirectButton, "cell 0 10 3 1"); //---- saveDirectButton ---- saveDirectButton.setText("Save (no-thread)..."); saveDirectButton.addActionListener(e -> saveDirect()); - add(saveDirectButton, "cell 0 8 3 1"); + add(saveDirectButton, "cell 0 10 3 1"); //======== filesScrollPane ======== { @@ -405,7 +475,7 @@ public class FlatSystemFileChooserMacTest filesField.setRows(8); filesScrollPane.setViewportView(filesField); } - add(filesScrollPane, "cell 0 9 3 1,growx"); + add(filesScrollPane, "cell 0 11 3 1,growx"); // JFormDesigner - End of component initialization //GEN-END:initComponents } @@ -418,6 +488,7 @@ public class FlatSystemFileChooserMacTest private JCheckBox canChooseDirectoriesCheckBox; private FlatTriStateCheckBox resolvesAliasesCheckBox; private FlatTriStateCheckBox allowsMultipleSelectionCheckBox; + private JCheckBox accessoryViewDisclosedCheckBox; private JLabel options2Label; private FlatTriStateCheckBox showsTagFieldCheckBox; private FlatTriStateCheckBox canCreateDirectoriesCheckBox; @@ -426,18 +497,24 @@ public class FlatSystemFileChooserMacTest private FlatTriStateCheckBox extensionHiddenCheckBox; private FlatTriStateCheckBox allowsOtherFileTypesCheckBox; private FlatTriStateCheckBox treatsFilePackagesAsDirectoriesCheckBox; + private JLabel options3Label; + private JCheckBox showSingleFilterFieldCheckBox; private JLabel promptLabel; private JTextField promptField; private JLabel messageLabel; private JTextField messageField; + private JLabel filterFieldLabelLabel; + private JTextField filterFieldLabelField; private JLabel nameFieldLabelLabel; private JTextField nameFieldLabelField; private JLabel nameFieldStringValueLabel; private JTextField nameFieldStringValueField; private JLabel directoryURLLabel; private JTextField directoryURLField; - private JLabel allowedFileTypesLabel; - private JTextField allowedFileTypesField; + private JLabel fileTypesLabel; + private JComboBox fileTypesField; + private JLabel fileTypeIndexLabel; + private JSlider fileTypeIndexSlider; private JButton openButton; private JButton saveButton; private JButton openDirectButton; diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatSystemFileChooserMacTest.jfd b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatSystemFileChooserMacTest.jfd index 65c30bc1..02b47359 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatSystemFileChooserMacTest.jfd +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatSystemFileChooserMacTest.jfd @@ -6,7 +6,7 @@ new FormModel { add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { "$layoutConstraints": "ltr,insets dialog,hidemode 3" "$columnConstraints": "[left][grow,fill][fill]" - "$rowConstraints": "[][][][][][][][][][grow,fill]" + "$rowConstraints": "[][][][][][][][][][][][grow,fill]" } ) { name: "this" add( new FormComponent( "javax.swing.JLabel" ) { @@ -23,7 +23,7 @@ new FormModel { add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { "$layoutConstraints": "insets 2,hidemode 3" "$columnConstraints": "[left]" - "$rowConstraints": "[][]0[]0[]0[]para[][]0[]0[]0[]0[]0[]0[]" + "$rowConstraints": "[][]0[]0[]0[]0[]para[][]0[]0[]0[]0[]0[]0[]para[][]" } ) { name: "panel1" add( new FormComponent( "javax.swing.JLabel" ) { @@ -58,56 +58,74 @@ new FormModel { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 0 4" } ) + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "accessoryViewDisclosedCheckBox" + "text": "accessoryViewDisclosed" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 5" + } ) add( new FormComponent( "javax.swing.JLabel" ) { name: "options2Label" "text": "NSOpenPanel and NSSavePanel options:" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 5" + "value": "cell 0 6" } ) add( new FormComponent( "com.formdev.flatlaf.extras.components.FlatTriStateCheckBox" ) { name: "showsTagFieldCheckBox" "text": "showsTagField" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 6" + "value": "cell 0 7" } ) add( new FormComponent( "com.formdev.flatlaf.extras.components.FlatTriStateCheckBox" ) { name: "canCreateDirectoriesCheckBox" "text": "canCreateDirectories" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 7" + "value": "cell 0 8" } ) add( new FormComponent( "com.formdev.flatlaf.extras.components.FlatTriStateCheckBox" ) { name: "canSelectHiddenExtensionCheckBox" "text": "canSelectHiddenExtension" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 8" + "value": "cell 0 9" } ) add( new FormComponent( "com.formdev.flatlaf.extras.components.FlatTriStateCheckBox" ) { name: "showsHiddenFilesCheckBox" "text": "showsHiddenFiles" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 9" + "value": "cell 0 10" } ) add( new FormComponent( "com.formdev.flatlaf.extras.components.FlatTriStateCheckBox" ) { name: "extensionHiddenCheckBox" "text": "extensionHidden" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 10" + "value": "cell 0 11" } ) add( new FormComponent( "com.formdev.flatlaf.extras.components.FlatTriStateCheckBox" ) { name: "allowsOtherFileTypesCheckBox" "text": "allowsOtherFileTypes" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 11" + "value": "cell 0 12" } ) add( new FormComponent( "com.formdev.flatlaf.extras.components.FlatTriStateCheckBox" ) { name: "treatsFilePackagesAsDirectoriesCheckBox" "text": "treatsFilePackagesAsDirectories" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 12" + "value": "cell 0 13" + } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "options3Label" + "text": "Custom options:" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 14" + } ) + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "showSingleFilterFieldCheckBox" + "text": "showSingleFilterField" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 15" } ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 2 0 1 8,aligny top,growy 0" + "value": "cell 2 0 1 10,aligny top,growy 0" } ) add( new FormComponent( "javax.swing.JLabel" ) { name: "promptLabel" @@ -132,76 +150,112 @@ new FormModel { "value": "cell 1 2" } ) add( new FormComponent( "javax.swing.JLabel" ) { - name: "nameFieldLabelLabel" - "text": "nameFieldLabel" + name: "filterFieldLabelLabel" + "text": "filterFieldLabel" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 0 3" } ) add( new FormComponent( "javax.swing.JTextField" ) { - name: "nameFieldLabelField" + name: "filterFieldLabelField" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 1 3" } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "nameFieldLabelLabel" + "text": "nameFieldLabel" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 4" + } ) + add( new FormComponent( "javax.swing.JTextField" ) { + name: "nameFieldLabelField" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 4" + } ) add( new FormComponent( "javax.swing.JLabel" ) { name: "nameFieldStringValueLabel" "text": "nameFieldStringValue" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 4" + "value": "cell 0 5" } ) add( new FormComponent( "javax.swing.JTextField" ) { name: "nameFieldStringValueField" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 4" + "value": "cell 1 5" } ) add( new FormComponent( "javax.swing.JLabel" ) { name: "directoryURLLabel" "text": "directoryURL" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 5" + "value": "cell 0 6" } ) add( new FormComponent( "javax.swing.JTextField" ) { name: "directoryURLField" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 5" + "value": "cell 1 6" } ) add( new FormComponent( "javax.swing.JLabel" ) { - name: "allowedFileTypesLabel" - "text": "allowedFileTypes" + name: "fileTypesLabel" + "text": "fileTypes" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 6" + "value": "cell 0 7" } ) - add( new FormComponent( "javax.swing.JTextField" ) { - name: "allowedFileTypesField" + add( new FormComponent( "javax.swing.JComboBox" ) { + name: "fileTypesField" + "editable": true + "model": new javax.swing.DefaultComboBoxModel { + selectedItem: "Text Files,txt,null" + addElement( "Text Files,txt,null" ) + addElement( "All Files,*,null" ) + addElement( "Text Files,txt,null,PDF Files,pdf,null,All Files,*,null" ) + addElement( "Text and PDF Files,txt,pdf,null" ) + addElement( "Compressed,zip,gz,null,Disk Images,dmg,null" ) + } }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 6" + "value": "cell 1 7" + } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "fileTypeIndexLabel" + "text": "fileTypeIndex" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 8" + } ) + add( new FormComponent( "javax.swing.JSlider" ) { + name: "fileTypeIndexSlider" + "maximum": 10 + "majorTickSpacing": 1 + "value": 0 + "paintLabels": true + "snapToTicks": true + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 8" } ) add( new FormComponent( "javax.swing.JButton" ) { name: "openButton" "text": "Open..." addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "open", false ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 8 3 1" + "value": "cell 0 10 3 1" } ) add( new FormComponent( "javax.swing.JButton" ) { name: "saveButton" "text": "Save..." addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "save", false ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 8 3 1" + "value": "cell 0 10 3 1" } ) add( new FormComponent( "javax.swing.JButton" ) { name: "openDirectButton" "text": "Open (no-thread)..." addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "openDirect", false ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 8 3 1" + "value": "cell 0 10 3 1" } ) add( new FormComponent( "javax.swing.JButton" ) { name: "saveDirectButton" "text": "Save (no-thread)..." addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "saveDirect", false ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 8 3 1" + "value": "cell 0 10 3 1" } ) add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) { name: "filesScrollPane" @@ -210,11 +264,11 @@ new FormModel { "rows": 8 } ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 9 3 1,growx" + "value": "cell 0 11 3 1,growx" } ) }, new FormLayoutConstraints( null ) { "location": new java.awt.Point( 0, 0 ) - "size": new java.awt.Dimension( 535, 465 ) + "size": new java.awt.Dimension( 750, 475 ) } ) } }