System File Chooser: support "approve" callback and system message dialog on Windows and Linux (not yet used in SystemFileChooser

This commit is contained in:
Karl Tauber
2025-01-11 17:50:46 +01:00
parent c73fd51704
commit d49282dfe8
12 changed files with 335 additions and 25 deletions

View File

@@ -24,6 +24,7 @@ import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import com.formdev.flatlaf.util.SystemInfo;
/**
@@ -131,7 +132,7 @@ public class FlatNativeLinuxLibrary
FC_create_folders = 1 << 5; // default for Save
/**
* Shows the Linux system file dialog
* Shows the Linux/GTK system file dialog
* <a href="https://docs.gtk.org/gtk3/class.FileChooserDialog.html">GtkFileChooserDialog</a>.
* <p>
* Uses {@code GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER} if {@link #FC_select_folder} is set in parameter {@code optionsSet}.
@@ -151,6 +152,7 @@ public class FlatNativeLinuxLibrary
* @param currentFolder current directory shown in the dialog; or {@code null}
* @param optionsSet options to set; see {@code FOS_*} constants
* @param optionsClear options to clear; see {@code FOS_*} constants
* @param callback approve callback; or {@code null}
* @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.
@@ -164,5 +166,34 @@ public class FlatNativeLinuxLibrary
*/
public native static String[] showFileChooser( Window owner, boolean open,
String title, String okButtonLabel, String currentName, String currentFolder,
int optionsSet, int optionsClear, int fileTypeIndex, String... fileTypes );
int optionsSet, int optionsClear, FileChooserCallback callback,
int fileTypeIndex, String... fileTypes );
/** @since 3.6 */
public interface FileChooserCallback {
boolean approve( String[] files, long hwndFileDialog );
}
/**
* Shows a GTK message box
* <a href="https://docs.gtk.org/gtk3/class.MessageDialog.html">GtkMessageDialog</a>.
* <p>
* For use in {@link FileChooserCallback} only.
*
* @param hwndParent the parent of the message box
* @param messageType type of message being displayed:
* {@link JOptionPane#ERROR_MESSAGE}, {@link JOptionPane#INFORMATION_MESSAGE},
* {@link JOptionPane#WARNING_MESSAGE}, {@link JOptionPane#QUESTION_MESSAGE} or
* {@link JOptionPane#PLAIN_MESSAGE}
* @param primaryText primary text; if the dialog has a secondary text,
* this will appear as title in a larger bold font
* @param secondaryText secondary text; shown below of primary text; or {@code null}
* @param defaultButton index of the default button, which can be pressed using ENTER key
* @param buttons texts of the buttons; if no buttons given the a default "OK" button is shown
* @return index of pressed button; or -1 for ESC key
*
* @since 3.6
*/
public native static int showMessageDialog( long hwndParent, int messageType,
String primaryText, String secondaryText, int defaultButton, String... buttons );
}

View File

@@ -218,6 +218,7 @@ public class FlatNativeWindowsLibrary
* @param defaultExtension default extension to be added to file name in save dialog; or {@code null}
* @param optionsSet options to set; see {@code FOS_*} constants
* @param optionsClear options to clear; see {@code FOS_*} constants
* @param callback approve callback; or {@code null}
* @param fileTypeIndex the file type that appears as selected (zero-based)
* @param fileTypes file types that the dialog can open or save.
* Pairs of strings are required for each filter.
@@ -231,5 +232,29 @@ public class FlatNativeWindowsLibrary
public native static String[] showFileChooser( Window owner, boolean open,
String title, String okButtonLabel, String fileNameLabel, String fileName,
String folder, String saveAsItem, String defaultFolder, String defaultExtension,
int optionsSet, int optionsClear, int fileTypeIndex, String... fileTypes );
int optionsSet, int optionsClear, FileChooserCallback callback,
int fileTypeIndex, String... fileTypes );
/** @since 3.6 */
public interface FileChooserCallback {
boolean approve( String[] files, long hwndFileDialog );
}
/**
* Shows a Windows message box
* <a href="https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messagebox">MessageBox</a>.
* <p>
* For use in {@link FileChooserCallback} only.
*
* @param hwndParent the parent of the message box
* @param text message to be displayed
* @param caption dialog box title
* @param type see <a href="https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messagebox#parameters">MessageBox parameter uType</a>
* @return see <a href="https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messagebox#return-value">MessageBox Return value</a>
* @return index of pressed button; or -1 for ESC key
*
* @since 3.6
*/
public native static int showMessageDialog( long hwndParent,
String text, String caption, int type );
}

View File

@@ -450,7 +450,7 @@ public class SystemFileChooser
new Thread( () -> {
filenamesRef.set( showSystemDialog( owner, fc ) );
secondaryLoop.exit();
} ).start();
}, "FlatLaf SystemFileChooser" ).start();
secondaryLoop.enter();
String[] filenames = filenamesRef.get();
@@ -552,7 +552,7 @@ public class SystemFileChooser
// show system file dialog
return FlatNativeWindowsLibrary.showFileChooser( owner, open,
fc.getDialogTitle(), approveButtonText, null, fileName,
folder, saveAsItem, null, null, optionsSet, optionsClear,
folder, saveAsItem, null, null, optionsSet, optionsClear, null,
fileTypeIndex, fileTypes.toArray( new String[fileTypes.size()] ) );
}
}
@@ -693,7 +693,7 @@ public class SystemFileChooser
// show system file dialog
return FlatNativeLinuxLibrary.showFileChooser( owner, open,
fc.getDialogTitle(), approveButtonText, currentName, currentFolder,
optionsSet, optionsClear, fileTypeIndex, fileTypes.toArray( new String[fileTypes.size()] ) );
optionsSet, optionsClear, null, fileTypeIndex, fileTypes.toArray( new String[fileTypes.size()] ) );
}
private String caseInsensitiveGlobPattern( String ext ) {

View File

@@ -29,6 +29,9 @@
// declare external methods
extern Window getWindowHandle( JNIEnv* env, JAWT* awt, jobject window, Display** display_return );
// declare internal methods
static jobjectArray fileListToStringArray( JNIEnv* env, GSList* fileList );
//---- class AutoReleaseStringUTF8 --------------------------------------------
class AutoReleaseStringUTF8 {
@@ -142,10 +145,37 @@ static void handle_realize( GtkWidget* dialog, gpointer data ) {
g_object_unref( gdkOwner );
}
struct ResponseData {
JNIEnv* env;
jobject callback;
GSList* fileList;
ResponseData( JNIEnv* _env, jobject _callback ) {
env = _env;
callback = _callback;
fileList = NULL;
}
};
static void handle_response( GtkWidget* dialog, gint responseId, gpointer data ) {
// get filenames if user pressed OK
if( responseId == GTK_RESPONSE_ACCEPT )
*((GSList**)data) = gtk_file_chooser_get_filenames( GTK_FILE_CHOOSER( dialog ) );
if( responseId == GTK_RESPONSE_ACCEPT ) {
ResponseData *response = static_cast<ResponseData*>( data );
if( response->callback != NULL ) {
GSList* fileList = gtk_file_chooser_get_filenames( GTK_FILE_CHOOSER( dialog ) );
jobjectArray files = fileListToStringArray( response->env, fileList );
GtkWindow* window = GTK_WINDOW( dialog );
// invoke callback: boolean approve( String[] files, long hwnd );
jclass cls = response->env->GetObjectClass( response->callback );
jmethodID approveID = response->env->GetMethodID( cls, "approve", "([Ljava/lang/String;J)Z" );
if( approveID != NULL && !response->env->CallBooleanMethod( response->callback, approveID, files, window ) )
return; // keep dialog open
}
response->fileList = gtk_file_chooser_get_filenames( GTK_FILE_CHOOSER( dialog ) );
}
// hide/destroy file dialog and quit loop
gtk_widget_hide( dialog );
@@ -159,7 +189,7 @@ extern "C"
JNIEXPORT jobjectArray JNICALL Java_com_formdev_flatlaf_ui_FlatNativeLinuxLibrary_showFileChooser
( JNIEnv* env, jclass cls, jobject owner, jboolean open,
jstring title, jstring okButtonLabel, jstring currentName, jstring currentFolder,
jint optionsSet, jint optionsClear, jint fileTypeIndex, jobjectArray fileTypes )
jint optionsSet, jint optionsClear, jobject callback, jint fileTypeIndex, jobjectArray fileTypes )
{
// initialize GTK
if( !gtk_init_check( NULL, NULL ) )
@@ -222,8 +252,8 @@ JNIEXPORT jobjectArray JNICALL Java_com_formdev_flatlaf_ui_FlatNativeLinuxLibrar
// show dialog
// (similar to what's done in sun_awt_X11_GtkFileDialogPeer.c)
GSList* fileList = NULL;
g_signal_connect( dialog, "response", G_CALLBACK( handle_response ), &fileList );
ResponseData responseData( env, callback );
g_signal_connect( dialog, "response", G_CALLBACK( handle_response ), &responseData );
gtk_widget_show( dialog );
// necessary to bring file dialog to the front (and make it active)
@@ -241,10 +271,14 @@ JNIEXPORT jobjectArray JNICALL Java_com_formdev_flatlaf_ui_FlatNativeLinuxLibrar
gtk_main();
// canceled?
if( fileList == NULL )
if( responseData.fileList == NULL )
return newJavaStringArray( env, 0 );
// convert GSList to Java string array
return fileListToStringArray( env, responseData.fileList );
}
static jobjectArray fileListToStringArray( JNIEnv* env, GSList* fileList ) {
guint count = g_slist_length( fileList );
jobjectArray array = newJavaStringArray( env, count );
GSList* it = fileList;
@@ -259,3 +293,52 @@ JNIEXPORT jobjectArray JNICALL Java_com_formdev_flatlaf_ui_FlatNativeLinuxLibrar
g_slist_free( fileList );
return array;
}
extern "C"
JNIEXPORT jint JNICALL Java_com_formdev_flatlaf_ui_FlatNativeLinuxLibrary_showMessageDialog
( JNIEnv* env, jclass cls, jlong hwndParent, jint messageType, jstring primaryText, jstring secondaryText,
jint defaultButton, jobjectArray buttons )
{
GtkWindow* window = (GtkWindow*) hwndParent;
// convert message type
GtkMessageType gmessageType;
switch( messageType ) {
case /* JOptionPane.ERROR_MESSAGE */ 0: gmessageType = GTK_MESSAGE_ERROR; break;
case /* JOptionPane.INFORMATION_MESSAGE */ 1: gmessageType = GTK_MESSAGE_INFO; break;
case /* JOptionPane.WARNING_MESSAGE */ 2: gmessageType = GTK_MESSAGE_WARNING; break;
case /* JOptionPane.QUESTION_MESSAGE */ 3: gmessageType = GTK_MESSAGE_QUESTION; break;
default:
case /* JOptionPane.PLAIN_MESSAGE */ -1: gmessageType = GTK_MESSAGE_OTHER; break;
}
// convert Java strings to C strings
AutoReleaseStringUTF8 cprimaryText( env, primaryText );
AutoReleaseStringUTF8 csecondaryText( env, secondaryText );
// create GTK file chooser dialog
// https://docs.gtk.org/gtk3/class.MessageDialog.html
jint buttonCount = env->GetArrayLength( buttons );
GtkWidget* dialog = gtk_message_dialog_new( window, GTK_DIALOG_MODAL, gmessageType,
(buttonCount > 0) ? GTK_BUTTONS_NONE : GTK_BUTTONS_OK,
"%s", (const gchar*) cprimaryText );
if( csecondaryText != NULL )
gtk_message_dialog_format_secondary_text( GTK_MESSAGE_DIALOG( dialog ), "%s", (const gchar*) csecondaryText );
// add buttons
for( int i = 0; i < buttonCount; i++ ) {
AutoReleaseStringUTF8 str( env, (jstring) env->GetObjectArrayElement( buttons, i ) );
gtk_dialog_add_button( GTK_DIALOG( dialog ), str, i );
}
// set default button
gtk_dialog_set_default_response( GTK_DIALOG( dialog ), MIN( MAX( defaultButton, 0 ), buttonCount - 1 ) );
// show message dialog
gint responseID = gtk_dialog_run( GTK_DIALOG( dialog ) );
gtk_widget_destroy( dialog );
// return -1 if closed with ESC key
return (responseID >= 0) ? responseID : -1;
}

View File

@@ -40,10 +40,18 @@ JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeLinuxLibrary_xS
/*
* Class: com_formdev_flatlaf_ui_FlatNativeLinuxLibrary
* Method: showFileChooser
* Signature: (Ljava/awt/Window;ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;III[Ljava/lang/String;)[Ljava/lang/String;
* Signature: (Ljava/awt/Window;ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IILcom/formdev/flatlaf/ui/FlatNativeLinuxLibrary/FileChooserCallback;I[Ljava/lang/String;)[Ljava/lang/String;
*/
JNIEXPORT jobjectArray JNICALL Java_com_formdev_flatlaf_ui_FlatNativeLinuxLibrary_showFileChooser
(JNIEnv *, jclass, jobject, jboolean, jstring, jstring, jstring, jstring, jint, jint, jint, jobjectArray);
(JNIEnv *, jclass, jobject, jboolean, jstring, jstring, jstring, jstring, jint, jint, jobject, jint, jobjectArray);
/*
* Class: com_formdev_flatlaf_ui_FlatNativeLinuxLibrary
* Method: showMessageDialog
* Signature: (JILjava/lang/String;Ljava/lang/String;I[Ljava/lang/String;)I
*/
JNIEXPORT jint JNICALL Java_com_formdev_flatlaf_ui_FlatNativeLinuxLibrary_showMessageDialog
(JNIEnv *, jclass, jlong, jint, jstring, jstring, jint, jobjectArray);
#ifdef __cplusplus
}

View File

@@ -64,7 +64,7 @@ tasks {
compilerArgs.addAll( toolChain.map {
when( it ) {
is Gcc, is Clang -> listOf( "-O2", "-DUNICODE" )
is VisualCpp -> listOf( "/O2", "/Zl", "/GS-", "/DUNICODE" )
is VisualCpp -> listOf( "/O2", "/GS-", "/DUNICODE" )
else -> emptyList()
}
} )
@@ -81,7 +81,7 @@ tasks {
linkerArgs.addAll( toolChain.map {
when( it ) {
is Gcc, is Clang -> listOf( "-lUser32", "-lGdi32", "-lshell32", "-lAdvAPI32", "-lKernel32", "-lDwmapi", "-lOle32", "-luuid" )
is VisualCpp -> listOf( "User32.lib", "Gdi32.lib", "shell32.lib", "AdvAPI32.lib", "Kernel32.lib", "Dwmapi.lib", "Ole32.lib", "uuid.lib", "/NODEFAULTLIB" )
is VisualCpp -> listOf( "User32.lib", "Gdi32.lib", "shell32.lib", "AdvAPI32.lib", "Kernel32.lib", "Dwmapi.lib", "Ole32.lib", "uuid.lib" )
else -> emptyList()
}
} )

View File

@@ -29,6 +29,9 @@
// declare external methods
extern HWND getWindowHandle( JNIEnv* env, jobject window );
// declare internal methods
static jobjectArray getFiles( JNIEnv* env, jboolean open, IFileDialog* dialog );
//---- class AutoReleasePtr ---------------------------------------------------
template<class T> class AutoReleasePtr {
@@ -38,6 +41,10 @@ public:
AutoReleasePtr() {
ptr = NULL;
}
AutoReleasePtr( T* p ) {
ptr = p;
ptr->AddRef();
}
~AutoReleasePtr() {
if( ptr != NULL )
ptr->Release();
@@ -126,6 +133,86 @@ public:
}
};
//---- class DialogEventHandler -----------------------------------------------
// see https://github.com/microsoft/Windows-classic-samples/blob/main/Samples/Win7Samples/winui/shell/appplatform/commonfiledialog/CommonFileDialogApp.cpp
class DialogEventHandler : public IFileDialogEvents {
JNIEnv* env;
jboolean open;
jobject callback;
LONG refCount = 1;
public:
DialogEventHandler( JNIEnv* _env, jboolean _open, jobject _callback ) {
env = _env;
open = _open;
callback = _callback;
}
//---- IFileDialogEvents methods ----
IFACEMETHODIMP OnFileOk( IFileDialog* dialog ) {
if( callback == NULL )
return S_OK;
// get files
jobjectArray files;
if( open ) {
AutoReleasePtr<IFileOpenDialog> openDialog;
HRESULT hr = dialog->QueryInterface( &openDialog );
files = SUCCEEDED( hr ) ? getFiles( env, true, openDialog ) : getFiles( env, false, dialog );
} else
files = getFiles( env, false, dialog );
// get hwnd of file dialog
HWND hwndFileDialog = 0;
AutoReleasePtr<IOleWindow> window;
if( SUCCEEDED( dialog->QueryInterface( &window ) ) )
window->GetWindow( &hwndFileDialog );
// invoke callback: boolean approve( String[] files, long hwnd );
jclass cls = env->GetObjectClass( callback );
jmethodID approveID = env->GetMethodID( cls, "approve", "([Ljava/lang/String;J)Z" );
if( approveID == NULL )
return S_OK;
return env->CallBooleanMethod( callback, approveID, files, hwndFileDialog ) ? S_OK : S_FALSE;
}
IFACEMETHODIMP OnFolderChange( IFileDialog* ) { return S_OK; }
IFACEMETHODIMP OnFolderChanging( IFileDialog*, IShellItem* ) { return S_OK; }
IFACEMETHODIMP OnHelp( IFileDialog* ) { return S_OK; }
IFACEMETHODIMP OnSelectionChange( IFileDialog* ) { return S_OK; }
IFACEMETHODIMP OnShareViolation( IFileDialog*, IShellItem*, FDE_SHAREVIOLATION_RESPONSE* ) { return S_OK; }
IFACEMETHODIMP OnTypeChange( IFileDialog*pfd ) { return S_OK; }
IFACEMETHODIMP OnOverwrite( IFileDialog*, IShellItem*, FDE_OVERWRITE_RESPONSE* ) { return S_OK; }
//---- IUnknown methods ----
IFACEMETHODIMP QueryInterface( REFIID riid, void** ppv ) {
if( riid != IID_IFileDialogEvents && riid != IID_IUnknown )
return E_NOINTERFACE;
*ppv = static_cast<IFileDialogEvents*>( this );
AddRef();
return S_OK;
}
IFACEMETHODIMP_(ULONG) AddRef() {
return InterlockedIncrement( &refCount );
}
IFACEMETHODIMP_(ULONG) Release() {
LONG newRefCount = InterlockedDecrement( &refCount );
if( newRefCount == 0 )
delete this;
return newRefCount;
}
private:
~DialogEventHandler() {}
};
//---- class CoInitializer ----------------------------------------------------
class CoInitializer {
@@ -163,7 +250,7 @@ JNIEXPORT jobjectArray JNICALL Java_com_formdev_flatlaf_ui_FlatNativeWindowsLibr
( JNIEnv* env, jclass cls, jobject owner, jboolean open,
jstring title, jstring okButtonLabel, jstring fileNameLabel, jstring fileName,
jstring folder, jstring saveAsItem, jstring defaultFolder, jstring defaultExtension,
jint optionsSet, jint optionsClear, jint fileTypeIndex, jobjectArray fileTypes )
jint optionsSet, jint optionsClear, jobject callback, jint fileTypeIndex, jobjectArray fileTypes )
{
// initialize COM library
CoInitializer coInitializer;
@@ -226,20 +313,31 @@ JNIEXPORT jobjectArray JNICALL Java_com_formdev_flatlaf_ui_FlatNativeWindowsLibr
CHECK_HRESULT( dialog->SetFileTypeIndex( min( fileTypeIndex + 1, specs.count ) ) );
}
// add event handler
AutoReleasePtr<DialogEventHandler> handler( new DialogEventHandler( env, open, callback ) );
DWORD dwCookie = 0;
CHECK_HRESULT( dialog->Advise( handler, &dwCookie ) );
// show dialog
HWND hwndOwner = (owner != NULL) ? getWindowHandle( env, owner ) : NULL;
HRESULT hr = dialog->Show( hwndOwner );
dialog->Unadvise( dwCookie );
if( hr == HRESULT_FROM_WIN32(ERROR_CANCELLED) )
return newJavaStringArray( env, 0 );
CHECK_HRESULT( hr );
// convert shell items to Java string array
// get selected files as Java string array
return getFiles( env, open, dialog );
}
static jobjectArray getFiles( JNIEnv* env, jboolean open, IFileDialog* dialog ) {
if( open ) {
AutoReleasePtr<IShellItemArray> shellItems;
DWORD count;
CHECK_HRESULT( ((IFileOpenDialog*)(IFileDialog*)dialog)->GetResults( &shellItems ) );
CHECK_HRESULT( shellItems->GetCount( &count ) );
// convert shell items to Java string array
jobjectArray array = newJavaStringArray( env, count );
for( int i = 0; i < count; i++ ) {
AutoReleasePtr<IShellItem> shellItem;
@@ -260,6 +358,7 @@ JNIEXPORT jobjectArray JNICALL Java_com_formdev_flatlaf_ui_FlatNativeWindowsLibr
CHECK_HRESULT( dialog->GetResult( &shellItem ) );
CHECK_HRESULT( shellItem->GetDisplayName( SIGDN_FILESYSPATH, &path ) );
// convert shell item to Java string array
jstring jpath = newJavaString( env, path );
CoTaskMemFree( path );
@@ -270,3 +369,15 @@ JNIEXPORT jobjectArray JNICALL Java_com_formdev_flatlaf_ui_FlatNativeWindowsLibr
return array;
}
}
extern "C"
JNIEXPORT jint JNICALL Java_com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_showMessageDialog
( JNIEnv* env, jclass cls, jlong hwndParent, jstring text, jstring caption, jint type )
{
// convert Java strings to C strings
AutoReleaseString ctext( env, text );
AutoReleaseString ccaption( env, caption );
return ::MessageBox( reinterpret_cast<HWND>( hwndParent ), ctext, ccaption, type );
}

View File

@@ -116,10 +116,18 @@ JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_
/*
* Class: com_formdev_flatlaf_ui_FlatNativeWindowsLibrary
* Method: showFileChooser
* Signature: (Ljava/awt/Window;ZLjava/lang/String;Ljava/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;
* Signature: (Ljava/awt/Window;ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IILcom/formdev/flatlaf/ui/FlatNativeWindowsLibrary/FileChooserCallback;I[Ljava/lang/String;)[Ljava/lang/String;
*/
JNIEXPORT jobjectArray JNICALL Java_com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_showFileChooser
(JNIEnv *, jclass, jobject, jboolean, jstring, jstring, jstring, jstring, jstring, jstring, jstring, jstring, jint, jint, jint, jobjectArray);
(JNIEnv *, jclass, jobject, jboolean, jstring, jstring, jstring, jstring, jstring, jstring, jstring, jstring, jint, jint, jobject, jint, jobjectArray);
/*
* Class: com_formdev_flatlaf_ui_FlatNativeWindowsLibrary
* Method: showMessageDialog
* Signature: (JLjava/lang/String;Ljava/lang/String;I)I
*/
JNIEXPORT jint JNICALL Java_com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_showMessageDialog
(JNIEnv *, jclass, jlong, jstring, jstring, jint);
#ifdef __cplusplus
}

View File

@@ -124,10 +124,20 @@ public class FlatSystemFileChooserLinuxTest
}
int fileTypeIndex = fileTypeIndexSlider.getValue();
FlatNativeLinuxLibrary.FileChooserCallback callback = (files, hwndFileDialog) -> {
System.out.println( " -- callback " + hwndFileDialog + " " + Arrays.toString( files ) );
if( showMessageDialogOnOKCheckBox.isSelected() ) {
System.out.println( FlatNativeLinuxLibrary.showMessageDialog( hwndFileDialog,
JOptionPane.INFORMATION_MESSAGE,
"primary text", "secondary text", 1, "Yes", "No" ) );
}
return true;
};
if( direct ) {
String[] files = FlatNativeLinuxLibrary.showFileChooser( owner, open,
title, okButtonLabel, currentName, currentFolder,
optionsSet.get(), optionsClear.get(), fileTypeIndex, fileTypes );
optionsSet.get(), optionsClear.get(), callback, fileTypeIndex, fileTypes );
filesField.setText( (files != null) ? Arrays.toString( files ).replace( ',', '\n' ) : "null" );
} else {
@@ -137,7 +147,7 @@ public class FlatSystemFileChooserLinuxTest
new Thread( () -> {
String[] files = FlatNativeLinuxLibrary.showFileChooser( owner, open,
title, okButtonLabel, currentName, currentFolder,
optionsSet.get(), optionsClear.get(), fileTypeIndex, fileTypes2 );
optionsSet.get(), optionsClear.get(), callback, fileTypeIndex, fileTypes2 );
System.out.println( " secondaryLoop.exit() returned " + secondaryLoop.exit() );
@@ -248,6 +258,7 @@ public class FlatSystemFileChooserLinuxTest
saveButton = new JButton();
openDirectButton = new JButton();
saveDirectButton = new JButton();
showMessageDialogOnOKCheckBox = new JCheckBox();
filesScrollPane = new JScrollPane();
filesField = new JTextArea();
@@ -397,6 +408,10 @@ public class FlatSystemFileChooserLinuxTest
saveDirectButton.addActionListener(e -> saveDirect());
add(saveDirectButton, "cell 0 7 3 1");
//---- showMessageDialogOnOKCheckBox ----
showMessageDialogOnOKCheckBox.setText("show message dialog on OK");
add(showMessageDialogOnOKCheckBox, "cell 0 7 3 1");
//======== filesScrollPane ========
{
@@ -443,6 +458,7 @@ public class FlatSystemFileChooserLinuxTest
private JButton saveButton;
private JButton openDirectButton;
private JButton saveDirectButton;
private JCheckBox showMessageDialogOnOKCheckBox;
private JScrollPane filesScrollPane;
private JTextArea filesField;
// JFormDesigner - End of variables declaration //GEN-END:variables

View File

@@ -1,4 +1,4 @@
JFDML JFormDesigner: "8.3" encoding: "UTF-8"
JFDML JFormDesigner: "8.2.2.0.9999" Java: "21.0.1" encoding: "UTF-8"
new FormModel {
contentType: "form/swing"
@@ -198,6 +198,12 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 7 3 1"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "showMessageDialogOnOKCheckBox"
"text": "show message dialog on OK"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 7 3 1"
} )
add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) {
name: "filesScrollPane"
add( new FormComponent( "javax.swing.JTextArea" ) {

View File

@@ -139,11 +139,21 @@ public class FlatSystemFileChooserWindowsTest
fileTypes = fileTypesStr.trim().split( "[,]+" );
int fileTypeIndex = fileTypeIndexSlider.getValue();
FlatNativeWindowsLibrary.FileChooserCallback callback = (files, hwndFileDialog) -> {
System.out.println( " -- callback " + hwndFileDialog + " " + Arrays.toString( files ) );
if( showMessageDialogOnOKCheckBox.isSelected() ) {
System.out.println( FlatNativeWindowsLibrary.showMessageDialog( hwndFileDialog,
"some text", "title",
/* MB_ICONINFORMATION */ 0x00000040 | /* MB_YESNO */ 0x00000004 ) );
}
return true;
};
if( direct ) {
String[] files = FlatNativeWindowsLibrary.showFileChooser( owner, open,
title, okButtonLabel, fileNameLabel, fileName,
folder, saveAsItem, defaultFolder, defaultExtension,
optionsSet.get(), optionsClear.get(), fileTypeIndex, fileTypes );
optionsSet.get(), optionsClear.get(), callback, fileTypeIndex, fileTypes );
filesField.setText( (files != null) ? Arrays.toString( files ).replace( ',', '\n' ) : "null" );
} else {
@@ -154,7 +164,7 @@ public class FlatSystemFileChooserWindowsTest
String[] files = FlatNativeWindowsLibrary.showFileChooser( owner, open,
title, okButtonLabel, fileNameLabel, fileName,
folder, saveAsItem, defaultFolder, defaultExtension,
optionsSet.get(), optionsClear.get(), fileTypeIndex, fileTypes2 );
optionsSet.get(), optionsClear.get(), callback, fileTypeIndex, fileTypes2 );
System.out.println( " secondaryLoop.exit() returned " + secondaryLoop.exit() );
@@ -290,6 +300,7 @@ public class FlatSystemFileChooserWindowsTest
saveButton = new JButton();
openDirectButton = new JButton();
saveDirectButton = new JButton();
showMessageDialogOnOKCheckBox = new JCheckBox();
filesScrollPane = new JScrollPane();
filesField = new JTextArea();
@@ -534,6 +545,10 @@ public class FlatSystemFileChooserWindowsTest
saveDirectButton.addActionListener(e -> saveDirect());
add(saveDirectButton, "cell 0 11 3 1");
//---- showMessageDialogOnOKCheckBox ----
showMessageDialogOnOKCheckBox.setText("show message dialog on OK");
add(showMessageDialogOnOKCheckBox, "cell 0 11 3 1");
//======== filesScrollPane ========
{
@@ -605,6 +620,7 @@ public class FlatSystemFileChooserWindowsTest
private JButton saveButton;
private JButton openDirectButton;
private JButton saveDirectButton;
private JCheckBox showMessageDialogOnOKCheckBox;
private JScrollPane filesScrollPane;
private JTextArea filesField;
// JFormDesigner - End of variables declaration //GEN-END:variables

View File

@@ -343,6 +343,12 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 11 3 1"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "showMessageDialogsOnOKCheckBox"
"text": "show message dialog on OK"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 11 3 1"
} )
add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) {
name: "filesScrollPane"
add( new FormComponent( "javax.swing.JTextArea" ) {