System File Chooser: implemented native bindings for NSOpenPanel and NSSavePanel on macOS

This commit is contained in:
Karl Tauber
2024-12-30 12:46:28 +01:00
parent 80ba75fdeb
commit 516bd80702
8 changed files with 941 additions and 4 deletions

View File

@@ -44,7 +44,7 @@ import com.formdev.flatlaf.util.SystemInfo;
*/
public class FlatNativeMacLibrary
{
private static int API_VERSION_MACOS = 2001;
private static int API_VERSION_MACOS = 2002;
/**
* Checks whether native library is loaded/available.
@@ -68,4 +68,50 @@ public class FlatNativeMacLibrary
/** @since 3.4 */ public native static Rectangle getWindowButtonsBounds( Window window );
/** @since 3.4 */ public native static boolean isWindowFullScreen( Window window );
/** @since 3.4 */ public native static boolean toggleWindowFullScreen( Window window );
/** @since 3.6 */
public static final int
// NSOpenPanel
FC_canChooseFiles = 1 << 0, // default
FC_canChooseDirectories = 1 << 1,
FC_resolvesAliases_NO = 1 << 2, // default
FC_allowsMultipleSelection = 1 << 3,
// NSSavePanel
FC_showsTagField_YES = 1 << 8, // default for Save
FC_showsTagField_NO = 1 << 9, // default for Open
FC_canCreateDirectories_YES = 1 << 10, // default for Save
FC_canCreateDirectories_NO = 1 << 11, // default for Open
FC_canSelectHiddenExtension = 1 << 12,
FC_showsHiddenFiles = 1 << 14,
FC_extensionHidden = 1 << 16,
FC_allowsOtherFileTypes = 1 << 18,
FC_treatsFilePackagesAsDirectories = 1 << 20;
/**
* Shows the macOS system file dialogs
* <a href="https://developer.apple.com/documentation/appkit/nsopenpanel?language=objc">NSOpenPanel</a> or
* <a href="https://developer.apple.com/documentation/appkit/nssavepanel?language=objc">NSSavePanel</a>.
* <p>
* <b>Note:</b> This method blocks the current thread until the user closes
* the file dialog. It is highly recommended to invoke it from a new thread
* to avoid blocking the AWT event dispatching thread.
*
* @param open if {@code true}, shows the open dialog; if {@code false}, shows the save dialog
* @param title text displayed at top of save dialog (not used in open dialog)
* @param prompt text displayed in default button
* @param message text displayed at top of open/save dialogs
* @param nameFieldLabel text displayed in front of the filename text field in save dialog (not used in open dialog)
* @param nameFieldStringValue user-editable filename currently shown in the name field in save dialog (not used in open dialog)
* @param directoryURL current directory shown in the dialog
* @param options see {@code FC_*} constants
* @param allowedFileTypes allowed filename extensions (e.g. "txt")
* @return file path(s) that the user selected, or {@code null} if canceled
*
* @since 3.6
*/
public native static String[] showFileChooser( boolean open,
String title, String prompt, String message, String nameFieldLabel,
String nameFieldStringValue, String directoryURL, int options,
String... allowedFileTypes );
}

View File

@@ -44,3 +44,7 @@
jclass findClass( JNIEnv *env, const char* className, bool globalRef );
jfieldID getFieldID( JNIEnv *env, jclass cls, const char* fieldName, const char* fieldSignature, bool staticField );
jmethodID getMethodID( JNIEnv *env, jclass cls, const char* methodName, const char* methodSignature, bool staticMethod );
NSString* JavaToNSString( JNIEnv *env, jstring javaString );
jstring NSToJavaString( JNIEnv *env, NSString *nsString );
jstring NormalizedPathJavaFromNSString( JNIEnv* env, NSString *nsString );

View File

@@ -13,6 +13,32 @@ extern "C" {
#define com_formdev_flatlaf_ui_FlatNativeMacLibrary_BUTTONS_SPACING_MEDIUM 1L
#undef com_formdev_flatlaf_ui_FlatNativeMacLibrary_BUTTONS_SPACING_LARGE
#define com_formdev_flatlaf_ui_FlatNativeMacLibrary_BUTTONS_SPACING_LARGE 2L
#undef com_formdev_flatlaf_ui_FlatNativeMacLibrary_FC_canChooseFiles
#define com_formdev_flatlaf_ui_FlatNativeMacLibrary_FC_canChooseFiles 1L
#undef com_formdev_flatlaf_ui_FlatNativeMacLibrary_FC_canChooseDirectories
#define com_formdev_flatlaf_ui_FlatNativeMacLibrary_FC_canChooseDirectories 2L
#undef com_formdev_flatlaf_ui_FlatNativeMacLibrary_FC_resolvesAliases_NO
#define com_formdev_flatlaf_ui_FlatNativeMacLibrary_FC_resolvesAliases_NO 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_showsTagField_YES
#define com_formdev_flatlaf_ui_FlatNativeMacLibrary_FC_showsTagField_YES 256L
#undef com_formdev_flatlaf_ui_FlatNativeMacLibrary_FC_showsTagField_NO
#define com_formdev_flatlaf_ui_FlatNativeMacLibrary_FC_showsTagField_NO 512L
#undef com_formdev_flatlaf_ui_FlatNativeMacLibrary_FC_canCreateDirectories_YES
#define com_formdev_flatlaf_ui_FlatNativeMacLibrary_FC_canCreateDirectories_YES 1024L
#undef com_formdev_flatlaf_ui_FlatNativeMacLibrary_FC_canCreateDirectories_NO
#define com_formdev_flatlaf_ui_FlatNativeMacLibrary_FC_canCreateDirectories_NO 2048L
#undef com_formdev_flatlaf_ui_FlatNativeMacLibrary_FC_canSelectHiddenExtension
#define com_formdev_flatlaf_ui_FlatNativeMacLibrary_FC_canSelectHiddenExtension 4096L
#undef com_formdev_flatlaf_ui_FlatNativeMacLibrary_FC_showsHiddenFiles
#define com_formdev_flatlaf_ui_FlatNativeMacLibrary_FC_showsHiddenFiles 16384L
#undef com_formdev_flatlaf_ui_FlatNativeMacLibrary_FC_extensionHidden
#define com_formdev_flatlaf_ui_FlatNativeMacLibrary_FC_extensionHidden 65536L
#undef com_formdev_flatlaf_ui_FlatNativeMacLibrary_FC_allowsOtherFileTypes
#define com_formdev_flatlaf_ui_FlatNativeMacLibrary_FC_allowsOtherFileTypes 262144L
#undef com_formdev_flatlaf_ui_FlatNativeMacLibrary_FC_treatsFilePackagesAsDirectories
#define com_formdev_flatlaf_ui_FlatNativeMacLibrary_FC_treatsFilePackagesAsDirectories 1048576L
/*
* Class: com_formdev_flatlaf_ui_FlatNativeMacLibrary
* Method: setWindowRoundedBorder
@@ -53,6 +79,14 @@ JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_isWi
JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_toggleWindowFullScreen
(JNIEnv *, jclass, jobject);
/*
* 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;I[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, jobjectArray);
#ifdef __cplusplus
}
#endif

View File

@@ -14,8 +14,8 @@
* limitations under the License.
*/
#include <jni.h>
#include "com_formdev_flatlaf_ui_FlatNativeLibrary.h"
#import <jni.h>
#import "com_formdev_flatlaf_ui_FlatNativeLibrary.h"
/**
* @author Karl Tauber
@@ -24,7 +24,7 @@
// increase this version if changing API or functionality of native library
// also update version in Java class com.formdev.flatlaf.ui.FlatNativeMacLibrary
#define API_VERSION_MACOS 2001
#define API_VERSION_MACOS 2002
//---- JNI methods ------------------------------------------------------------

View File

@@ -75,3 +75,38 @@ jmethodID getMethodID( JNIEnv *env, jclass cls, const char* methodName, const ch
return methodID;
}
NSString* JavaToNSString( JNIEnv *env, jstring javaString ) {
if( javaString == NULL )
return NULL;
int len = env->GetStringLength( javaString );
const jchar* chars = env->GetStringChars( javaString, NULL );
if( chars == NULL )
return NULL;
NSString* nsString = [NSString stringWithCharacters:(unichar*)chars length:len];
env->ReleaseStringChars( javaString, chars );
return nsString;
}
jstring NSToJavaString( JNIEnv *env, NSString *nsString ) {
if( nsString == NULL )
return NULL;
jsize len = [nsString length];
unichar* buffer = (unichar*) calloc( len, sizeof( unichar ) );
if( buffer == NULL )
return NULL;
[nsString getCharacters:buffer];
jstring javaString = env->NewString( buffer, len );
free( buffer );
return javaString;
}
jstring NormalizedPathJavaFromNSString( JNIEnv* env, NSString *nsString ) {
return (nsString != NULL)
? NSToJavaString( env, [nsString precomposedStringWithCanonicalMapping] )
: NULL;
}

View File

@@ -0,0 +1,152 @@
/*
* Copyright 2024 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import <Cocoa/Cocoa.h>
#import <objc/runtime.h>
#import <jni.h>
#import "JNIUtils.h"
#import "JNFRunLoop.h"
#import "com_formdev_flatlaf_ui_FlatNativeMacLibrary.h"
/**
* @author Karl Tauber
*/
#define isOptionSet( option ) ((options & com_formdev_flatlaf_ui_FlatNativeMacLibrary_ ## option) != 0)
#define isYesOrNoOptionSet( option ) isOptionSet( option ## _YES ) || isOptionSet( option ## _NO )
// declare internal methods
NSWindow* getNSWindow( JNIEnv* env, jclass cls, jobject window );
//---- 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 options, jobjectArray allowedFileTypes )
{
JNI_COCOA_ENTER()
// convert Java strings to NSString (on Java thread)
NSString* nsTitle = JavaToNSString( env, title );
NSString* nsPrompt = JavaToNSString( env, prompt );
NSString* nsMessage = JavaToNSString( env, message );
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 );
NSString* nsStr = JavaToNSString( env, str );
nsArray[i] = nsStr;
}
nsAllowedFileTypes = nsArray;
}
NSArray* urls = NULL;
NSArray** purls = &urls;
NSURL* url = NULL;
NSURL** purl = &url;
// show file dialog on macOS thread
[FlatJNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){
NSSavePanel* dialog = open ? [NSOpenPanel openPanel] : [NSSavePanel savePanel];
if( nsTitle != NULL )
dialog.title = nsTitle;
if( nsPrompt != NULL )
dialog.prompt = nsPrompt;
if( nsMessage != NULL )
dialog.message = nsMessage;
if( nsNameFieldLabel != NULL )
dialog.nameFieldLabel = nsNameFieldLabel;
if( nsNameFieldStringValue != NULL )
dialog.nameFieldStringValue = nsNameFieldStringValue;
if( nsDirectoryURL != NULL )
dialog.directoryURL = [NSURL fileURLWithPath:nsDirectoryURL isDirectory:YES];
if( open ) {
NSOpenPanel* openDialog = (NSOpenPanel*) dialog;
bool canChooseFiles = isOptionSet( FC_canChooseFiles );
bool canChooseDirectories = isOptionSet( FC_canChooseDirectories );
if( !canChooseFiles && !canChooseDirectories )
canChooseFiles = true;
openDialog.canChooseFiles = canChooseFiles;
openDialog.canChooseDirectories = canChooseDirectories;
if( isOptionSet( FC_resolvesAliases_NO ) )
openDialog.resolvesAliases = NO;
if( isOptionSet( FC_allowsMultipleSelection ) )
openDialog.allowsMultipleSelection = YES;
}
if( isYesOrNoOptionSet( FC_showsTagField ) )
dialog.showsTagField = isOptionSet( FC_showsTagField_YES );
if( isYesOrNoOptionSet( FC_canCreateDirectories ) )
dialog.canCreateDirectories = isOptionSet( FC_canCreateDirectories_YES );
if( isOptionSet( FC_canSelectHiddenExtension ) )
dialog.canSelectHiddenExtension = YES;
if( isOptionSet( FC_showsHiddenFiles) )
dialog.showsHiddenFiles = YES;
if( isOptionSet( FC_extensionHidden ) )
dialog.extensionHidden = YES;
if( isOptionSet( FC_allowsOtherFileTypes ) )
dialog.allowsOtherFileTypes = YES;
if( isOptionSet( FC_treatsFilePackagesAsDirectories ) )
dialog.treatsFilePackagesAsDirectories = YES;
// 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;
if( [dialog runModal] != NSModalResponseOK )
return;
if( open )
*purls = ((NSOpenPanel*)dialog).URLs;
else
*purl = dialog.URL;
}];
if( url != NULL )
urls = @[url];
if( urls == NULL )
return NULL;
// convert URLs to Java string array
jsize count = urls.count;
jclass stringClass = env->FindClass( "java/lang/String" );
jobjectArray result = env->NewObjectArray( count, stringClass, NULL );
for( int i = 0; i < count; i++ ) {
jstring filename = NormalizedPathJavaFromNSString( env, [urls[i] path] );
env->SetObjectArrayElement( result, i, filename );
env->DeleteLocalRef( filename );
}
return result;
JNI_COCOA_EXIT()
}

View File

@@ -0,0 +1,446 @@
/*
* Copyright 2024 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.formdev.flatlaf.testing;
import static com.formdev.flatlaf.ui.FlatNativeMacLibrary.*;
import java.awt.EventQueue;
import java.awt.SecondaryLoop;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.WindowEvent;
import java.awt.event.WindowFocusListener;
import java.awt.event.WindowListener;
import java.awt.event.WindowStateListener;
import java.util.Arrays;
import javax.swing.*;
import com.formdev.flatlaf.extras.components.*;
import com.formdev.flatlaf.extras.components.FlatTriStateCheckBox.State;
import com.formdev.flatlaf.ui.FlatNativeMacLibrary;
import com.formdev.flatlaf.util.SystemInfo;
import net.miginfocom.swing.*;
/**
* @author Karl Tauber
*/
public class FlatMacOSFileChooserTest
extends FlatTestPanel
{
public static void main( String[] args ) {
// macOS (see https://www.formdev.com/flatlaf/macos/)
if( SystemInfo.isMacOS ) {
// appearance of window title bars
// possible values:
// - "system": use current macOS appearance (light or dark)
// - "NSAppearanceNameAqua": use light appearance
// - "NSAppearanceNameDarkAqua": use dark appearance
// (needs to be set on main thread; setting it on AWT thread does not work)
System.setProperty( "apple.awt.application.appearance", "system" );
}
SwingUtilities.invokeLater( () -> {
FlatTestFrame frame = FlatTestFrame.create( args, "FlatMacOSFileChooserTest" );
addListeners( frame );
frame.showFrame( FlatMacOSFileChooserTest::new );
} );
}
FlatMacOSFileChooserTest() {
initComponents();
}
private void open() {
openOrSave( true, false );
}
private void save() {
openOrSave( false, false );
}
private void openDirect() {
openOrSave( true, true );
}
private void saveDirect() {
openOrSave( false, true );
}
private void openOrSave( boolean open, boolean direct ) {
String title = n( titleField.getText() );
String prompt = n( promptField.getText() );
String message = n( messageField.getText() );
String nameFieldLabel = n( nameFieldLabelField.getText() );
String nameFieldStringValue = n( nameFieldStringValueField.getText() );
String directoryURL = n( directoryURLField.getText() );
int options = 0;
// NSOpenPanel
if( canChooseFilesCheckBox.isSelected() )
options |= FC_canChooseFiles;
if( canChooseDirectoriesCheckBox.isSelected() )
options |= FC_canChooseDirectories;
if( !resolvesAliasesCheckBox.isSelected() )
options |= FC_resolvesAliases_NO;
if( allowsMultipleSelectionCheckBox.isSelected() )
options |= FC_allowsMultipleSelection;
// NSSavePanel
if( showsTagFieldCheckBox.getState() == State.SELECTED )
options |= FC_showsTagField_YES;
else if( showsTagFieldCheckBox.getState() == State.UNSELECTED )
options |= FC_showsTagField_NO;
if( canCreateDirectoriesCheckBox.getState() == State.SELECTED )
options |= FC_canCreateDirectories_YES;
else if( canCreateDirectoriesCheckBox.getState() == State.UNSELECTED )
options |= FC_canCreateDirectories_NO;
if( canSelectHiddenExtensionCheckBox.isSelected() )
options |= FC_canSelectHiddenExtension;
if( showsHiddenFilesCheckBox.isSelected() )
options |= FC_showsHiddenFiles;
if( extensionHiddenCheckBox.isSelected() )
options |= FC_extensionHidden;
if( allowsOtherFileTypesCheckBox.isSelected() )
options |= FC_allowsOtherFileTypes;
if( treatsFilePackagesAsDirectoriesCheckBox.isSelected() )
options |= FC_treatsFilePackagesAsDirectories;
String allowedFileTypesStr = n( allowedFileTypesField.getText() );
String[] allowedFileTypes = {};
if( allowedFileTypesStr != null )
allowedFileTypes = allowedFileTypesStr.trim().split( "[ ,]+" );
if( direct ) {
String[] files = FlatNativeMacLibrary.showFileChooser( open, title, prompt, message,
nameFieldLabel, nameFieldStringValue, directoryURL, options, allowedFileTypes );
filesField.setText( (files != null) ? Arrays.toString( files ).replace( ',', '\n' ) : "null" );
} else {
SecondaryLoop secondaryLoop = Toolkit.getDefaultToolkit().getSystemEventQueue().createSecondaryLoop();
int options2 = options;
String[] allowedFileTypes2 = allowedFileTypes;
new Thread( () -> {
String[] files = FlatNativeMacLibrary.showFileChooser( open, title, prompt, message,
nameFieldLabel, nameFieldStringValue, directoryURL, options2, allowedFileTypes2 );
System.out.println( " secondaryLoop.exit() returned " + secondaryLoop.exit() );
EventQueue.invokeLater( () -> {
filesField.setText( (files != null) ? Arrays.toString( files ).replace( ',', '\n' ) : "null" );
} );
} ).start();
System.out.println( "---- enter secondary loop ----" );
System.out.println( "---- secondary loop exited (secondaryLoop.enter() returned " + secondaryLoop.enter() + ") ----" );
}
}
private static String n( String s ) {
return !s.isEmpty() ? s : null;
}
private static void addListeners( Window w ) {
w.addWindowListener( new WindowListener() {
@Override
public void windowOpened( WindowEvent e ) {
System.out.println( e );
}
@Override
public void windowIconified( WindowEvent e ) {
System.out.println( e );
}
@Override
public void windowDeiconified( WindowEvent e ) {
System.out.println( e );
}
@Override
public void windowDeactivated( WindowEvent e ) {
System.out.println( e );
}
@Override
public void windowClosing( WindowEvent e ) {
System.out.println( e );
}
@Override
public void windowClosed( WindowEvent e ) {
System.out.println( e );
}
@Override
public void windowActivated( WindowEvent e ) {
System.out.println( e );
}
} );
w.addWindowStateListener( new WindowStateListener() {
@Override
public void windowStateChanged( WindowEvent e ) {
System.out.println( e );
}
} );
w.addWindowFocusListener( new WindowFocusListener() {
@Override
public void windowLostFocus( WindowEvent e ) {
System.out.println( e );
}
@Override
public void windowGainedFocus( WindowEvent e ) {
System.out.println( e );
}
} );
}
private void initComponents() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
titleLabel = new JLabel();
titleField = new JTextField();
panel1 = new JPanel();
options1Label = new JLabel();
canChooseFilesCheckBox = new JCheckBox();
canChooseDirectoriesCheckBox = new JCheckBox();
resolvesAliasesCheckBox = new JCheckBox();
allowsMultipleSelectionCheckBox = new JCheckBox();
options2Label = new JLabel();
showsTagFieldCheckBox = new FlatTriStateCheckBox();
canCreateDirectoriesCheckBox = new FlatTriStateCheckBox();
canSelectHiddenExtensionCheckBox = new JCheckBox();
showsHiddenFilesCheckBox = new JCheckBox();
extensionHiddenCheckBox = new JCheckBox();
allowsOtherFileTypesCheckBox = new JCheckBox();
treatsFilePackagesAsDirectoriesCheckBox = new JCheckBox();
promptLabel = new JLabel();
promptField = new JTextField();
messageLabel = new JLabel();
messageField = 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();
openButton = new JButton();
saveButton = new JButton();
openDirectButton = new JButton();
saveDirectButton = new JButton();
filesScrollPane = new JScrollPane();
filesField = new JTextArea();
//======== this ========
setLayout(new MigLayout(
"ltr,insets dialog,hidemode 3",
// columns
"[left]" +
"[grow,fill]" +
"[fill]",
// rows
"[]" +
"[]" +
"[]" +
"[]" +
"[]" +
"[]" +
"[]" +
"[]" +
"[]" +
"[grow,fill]"));
//---- titleLabel ----
titleLabel.setText("title");
add(titleLabel, "cell 0 0");
add(titleField, "cell 1 0");
//======== panel1 ========
{
panel1.setLayout(new MigLayout(
"insets 2,hidemode 3",
// columns
"[left]",
// rows
"[]" +
"[]0" +
"[]0" +
"[]0" +
"[]para" +
"[]" +
"[]0" +
"[]0" +
"[]0" +
"[]0" +
"[]0" +
"[]0" +
"[]"));
//---- options1Label ----
options1Label.setText("NSOpenPanel options:");
panel1.add(options1Label, "cell 0 0");
//---- canChooseFilesCheckBox ----
canChooseFilesCheckBox.setText("canChooseFiles");
canChooseFilesCheckBox.setSelected(true);
panel1.add(canChooseFilesCheckBox, "cell 0 1");
//---- canChooseDirectoriesCheckBox ----
canChooseDirectoriesCheckBox.setText("canChooseDirectories");
panel1.add(canChooseDirectoriesCheckBox, "cell 0 2");
//---- resolvesAliasesCheckBox ----
resolvesAliasesCheckBox.setText("resolvesAliases");
resolvesAliasesCheckBox.setSelected(true);
panel1.add(resolvesAliasesCheckBox, "cell 0 3");
//---- allowsMultipleSelectionCheckBox ----
allowsMultipleSelectionCheckBox.setText("allowsMultipleSelection");
panel1.add(allowsMultipleSelectionCheckBox, "cell 0 4");
//---- options2Label ----
options2Label.setText("NSOpenPanel and NSSavePanel options:");
panel1.add(options2Label, "cell 0 5");
//---- showsTagFieldCheckBox ----
showsTagFieldCheckBox.setText("showsTagField");
panel1.add(showsTagFieldCheckBox, "cell 0 6");
//---- canCreateDirectoriesCheckBox ----
canCreateDirectoriesCheckBox.setText("canCreateDirectories");
panel1.add(canCreateDirectoriesCheckBox, "cell 0 7");
//---- canSelectHiddenExtensionCheckBox ----
canSelectHiddenExtensionCheckBox.setText("canSelectHiddenExtension");
panel1.add(canSelectHiddenExtensionCheckBox, "cell 0 8");
//---- showsHiddenFilesCheckBox ----
showsHiddenFilesCheckBox.setText("showsHiddenFiles");
panel1.add(showsHiddenFilesCheckBox, "cell 0 9");
//---- extensionHiddenCheckBox ----
extensionHiddenCheckBox.setText("extensionHidden");
panel1.add(extensionHiddenCheckBox, "cell 0 10");
//---- allowsOtherFileTypesCheckBox ----
allowsOtherFileTypesCheckBox.setText("allowsOtherFileTypes");
panel1.add(allowsOtherFileTypesCheckBox, "cell 0 11");
//---- treatsFilePackagesAsDirectoriesCheckBox ----
treatsFilePackagesAsDirectoriesCheckBox.setText("treatsFilePackagesAsDirectories");
panel1.add(treatsFilePackagesAsDirectoriesCheckBox, "cell 0 12");
}
add(panel1, "cell 2 0 1 8,aligny top,growy 0");
//---- promptLabel ----
promptLabel.setText("prompt");
add(promptLabel, "cell 0 1");
add(promptField, "cell 1 1");
//---- messageLabel ----
messageLabel.setText("message");
add(messageLabel, "cell 0 2");
add(messageField, "cell 1 2");
//---- nameFieldLabelLabel ----
nameFieldLabelLabel.setText("nameFieldLabel");
add(nameFieldLabelLabel, "cell 0 3");
add(nameFieldLabelField, "cell 1 3");
//---- nameFieldStringValueLabel ----
nameFieldStringValueLabel.setText("nameFieldStringValue");
add(nameFieldStringValueLabel, "cell 0 4");
add(nameFieldStringValueField, "cell 1 4");
//---- directoryURLLabel ----
directoryURLLabel.setText("directoryURL");
add(directoryURLLabel, "cell 0 5");
add(directoryURLField, "cell 1 5");
//---- allowedFileTypesLabel ----
allowedFileTypesLabel.setText("allowedFileTypes");
add(allowedFileTypesLabel, "cell 0 6");
add(allowedFileTypesField, "cell 1 6");
//---- openButton ----
openButton.setText("Open...");
openButton.addActionListener(e -> open());
add(openButton, "cell 0 8 3 1");
//---- saveButton ----
saveButton.setText("Save...");
saveButton.addActionListener(e -> save());
add(saveButton, "cell 0 8 3 1");
//---- openDirectButton ----
openDirectButton.setText("Open (no-thread)...");
openDirectButton.addActionListener(e -> openDirect());
add(openDirectButton, "cell 0 8 3 1");
//---- saveDirectButton ----
saveDirectButton.setText("Save (no-thread)...");
saveDirectButton.addActionListener(e -> saveDirect());
add(saveDirectButton, "cell 0 8 3 1");
//======== filesScrollPane ========
{
//---- filesField ----
filesField.setRows(8);
filesScrollPane.setViewportView(filesField);
}
add(filesScrollPane, "cell 0 9 3 1,growx");
// JFormDesigner - End of component initialization //GEN-END:initComponents
}
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
private JLabel titleLabel;
private JTextField titleField;
private JPanel panel1;
private JLabel options1Label;
private JCheckBox canChooseFilesCheckBox;
private JCheckBox canChooseDirectoriesCheckBox;
private JCheckBox resolvesAliasesCheckBox;
private JCheckBox allowsMultipleSelectionCheckBox;
private JLabel options2Label;
private FlatTriStateCheckBox showsTagFieldCheckBox;
private FlatTriStateCheckBox canCreateDirectoriesCheckBox;
private JCheckBox canSelectHiddenExtensionCheckBox;
private JCheckBox showsHiddenFilesCheckBox;
private JCheckBox extensionHiddenCheckBox;
private JCheckBox allowsOtherFileTypesCheckBox;
private JCheckBox treatsFilePackagesAsDirectoriesCheckBox;
private JLabel promptLabel;
private JTextField promptField;
private JLabel messageLabel;
private JTextField messageField;
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 JButton openButton;
private JButton saveButton;
private JButton openDirectButton;
private JButton saveDirectButton;
private JScrollPane filesScrollPane;
private JTextArea filesField;
// JFormDesigner - End of variables declaration //GEN-END:variables
}

View File

@@ -0,0 +1,220 @@
JFDML JFormDesigner: "8.2.2.0.9999" Java: "21.0.1" encoding: "UTF-8"
new FormModel {
contentType: "form/swing"
root: new FormRoot {
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]"
} ) {
name: "this"
add( new FormComponent( "javax.swing.JLabel" ) {
name: "titleLabel"
"text": "title"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 0"
} )
add( new FormComponent( "javax.swing.JTextField" ) {
name: "titleField"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 0"
} )
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[]"
} ) {
name: "panel1"
add( new FormComponent( "javax.swing.JLabel" ) {
name: "options1Label"
"text": "NSOpenPanel options:"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 0"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "canChooseFilesCheckBox"
"text": "canChooseFiles"
"selected": true
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 1"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "canChooseDirectoriesCheckBox"
"text": "canChooseDirectories"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 2"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "resolvesAliasesCheckBox"
"text": "resolvesAliases"
"selected": true
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 3"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "allowsMultipleSelectionCheckBox"
"text": "allowsMultipleSelection"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 4"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "options2Label"
"text": "NSOpenPanel and NSSavePanel options:"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 5"
} )
add( new FormComponent( "com.formdev.flatlaf.extras.components.FlatTriStateCheckBox" ) {
name: "showsTagFieldCheckBox"
"text": "showsTagField"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 6"
} )
add( new FormComponent( "com.formdev.flatlaf.extras.components.FlatTriStateCheckBox" ) {
name: "canCreateDirectoriesCheckBox"
"text": "canCreateDirectories"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 7"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "canSelectHiddenExtensionCheckBox"
"text": "canSelectHiddenExtension"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 8"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "showsHiddenFilesCheckBox"
"text": "showsHiddenFiles"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 9"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "extensionHiddenCheckBox"
"text": "extensionHidden"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 10"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "allowsOtherFileTypesCheckBox"
"text": "allowsOtherFileTypes"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 11"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "treatsFilePackagesAsDirectoriesCheckBox"
"text": "treatsFilePackagesAsDirectories"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 12"
} )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 2 0 1 8,aligny top,growy 0"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "promptLabel"
"text": "prompt"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 1"
} )
add( new FormComponent( "javax.swing.JTextField" ) {
name: "promptField"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 1"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "messageLabel"
"text": "message"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 2"
} )
add( new FormComponent( "javax.swing.JTextField" ) {
name: "messageField"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 2"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "nameFieldLabelLabel"
"text": "nameFieldLabel"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 3"
} )
add( new FormComponent( "javax.swing.JTextField" ) {
name: "nameFieldLabelField"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 3"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "nameFieldStringValueLabel"
"text": "nameFieldStringValue"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 4"
} )
add( new FormComponent( "javax.swing.JTextField" ) {
name: "nameFieldStringValueField"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 4"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "directoryURLLabel"
"text": "directoryURL"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 5"
} )
add( new FormComponent( "javax.swing.JTextField" ) {
name: "directoryURLField"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 5"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "allowedFileTypesLabel"
"text": "allowedFileTypes"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 6"
} )
add( new FormComponent( "javax.swing.JTextField" ) {
name: "allowedFileTypesField"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 6"
} )
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"
} )
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"
} )
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"
} )
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"
} )
add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) {
name: "filesScrollPane"
add( new FormComponent( "javax.swing.JTextArea" ) {
name: "filesField"
"rows": 8
} )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 9 3 1,growx"
} )
}, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 0, 0 )
"size": new java.awt.Dimension( 535, 465 )
} )
}
}