diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeLinuxLibrary.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeLinuxLibrary.java
index f1bed502..5ea7d178 100644
--- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeLinuxLibrary.java
+++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeLinuxLibrary.java
@@ -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
* GtkFileChooserDialog.
*
* 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
+ * GtkMessageDialog.
+ *
+ * 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 );
}
diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeWindowsLibrary.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeWindowsLibrary.java
index 8dfa52a4..ec2bed8f 100644
--- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeWindowsLibrary.java
+++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeWindowsLibrary.java
@@ -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
+ * MessageBox.
+ *
+ * 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 MessageBox parameter uType
+ * @return see MessageBox Return value
+ * @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 );
}
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 6801014e..b4528f62 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
@@ -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 ) {
diff --git a/flatlaf-natives/flatlaf-natives-linux/src/main/cpp/GtkFileChooser.cpp b/flatlaf-natives/flatlaf-natives-linux/src/main/cpp/GtkFileChooser.cpp
index 567c485c..7e427a85 100644
--- a/flatlaf-natives/flatlaf-natives-linux/src/main/cpp/GtkFileChooser.cpp
+++ b/flatlaf-natives/flatlaf-natives-linux/src/main/cpp/GtkFileChooser.cpp
@@ -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( 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;
+}
diff --git a/flatlaf-natives/flatlaf-natives-linux/src/main/headers/com_formdev_flatlaf_ui_FlatNativeLinuxLibrary.h b/flatlaf-natives/flatlaf-natives-linux/src/main/headers/com_formdev_flatlaf_ui_FlatNativeLinuxLibrary.h
index 4ca717bb..5e9573b4 100644
--- a/flatlaf-natives/flatlaf-natives-linux/src/main/headers/com_formdev_flatlaf_ui_FlatNativeLinuxLibrary.h
+++ b/flatlaf-natives/flatlaf-natives-linux/src/main/headers/com_formdev_flatlaf_ui_FlatNativeLinuxLibrary.h
@@ -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
}
diff --git a/flatlaf-natives/flatlaf-natives-windows/build.gradle.kts b/flatlaf-natives/flatlaf-natives-windows/build.gradle.kts
index 3dc0a1dc..a0893c8c 100644
--- a/flatlaf-natives/flatlaf-natives-windows/build.gradle.kts
+++ b/flatlaf-natives/flatlaf-natives-windows/build.gradle.kts
@@ -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()
}
} )
diff --git a/flatlaf-natives/flatlaf-natives-windows/src/main/cpp/WinFileChooser.cpp b/flatlaf-natives/flatlaf-natives-windows/src/main/cpp/WinFileChooser.cpp
index 8b300d34..2a643643 100644
--- a/flatlaf-natives/flatlaf-natives-windows/src/main/cpp/WinFileChooser.cpp
+++ b/flatlaf-natives/flatlaf-natives-windows/src/main/cpp/WinFileChooser.cpp
@@ -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 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 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 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( 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 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 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 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( hwndParent ), ctext, ccaption, type );
+}
diff --git a/flatlaf-natives/flatlaf-natives-windows/src/main/headers/com_formdev_flatlaf_ui_FlatNativeWindowsLibrary.h b/flatlaf-natives/flatlaf-natives-windows/src/main/headers/com_formdev_flatlaf_ui_FlatNativeWindowsLibrary.h
index 895b7267..18b9f377 100644
--- a/flatlaf-natives/flatlaf-natives-windows/src/main/headers/com_formdev_flatlaf_ui_FlatNativeWindowsLibrary.h
+++ b/flatlaf-natives/flatlaf-natives-windows/src/main/headers/com_formdev_flatlaf_ui_FlatNativeWindowsLibrary.h
@@ -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
}
diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatSystemFileChooserLinuxTest.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatSystemFileChooserLinuxTest.java
index 05289d16..0c4f59f6 100644
--- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatSystemFileChooserLinuxTest.java
+++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatSystemFileChooserLinuxTest.java
@@ -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
diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatSystemFileChooserLinuxTest.jfd b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatSystemFileChooserLinuxTest.jfd
index d172fc00..3506768d 100644
--- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatSystemFileChooserLinuxTest.jfd
+++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatSystemFileChooserLinuxTest.jfd
@@ -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" ) {
diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatSystemFileChooserWindowsTest.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatSystemFileChooserWindowsTest.java
index 2aa9af1e..621d00d8 100644
--- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatSystemFileChooserWindowsTest.java
+++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatSystemFileChooserWindowsTest.java
@@ -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
diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatSystemFileChooserWindowsTest.jfd b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatSystemFileChooserWindowsTest.jfd
index 82828444..74e22930 100644
--- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatSystemFileChooserWindowsTest.jfd
+++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatSystemFileChooserWindowsTest.jfd
@@ -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" ) {