diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index d1f0e1e9..57acad88 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -42,7 +42,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- - uses: gradle/actions/wrapper-validation@v3
+ - uses: gradle/actions/wrapper-validation@v4
if: matrix.java == '8'
- name: Setup Java ${{ matrix.java }}
diff --git a/.github/workflows/natives.yml b/.github/workflows/natives.yml
index bae5cb2a..cf314dcc 100644
--- a/.github/workflows/natives.yml
+++ b/.github/workflows/natives.yml
@@ -30,7 +30,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- - uses: gradle/actions/wrapper-validation@v3
+ - uses: gradle/actions/wrapper-validation@v4
- name: Setup Java 11
uses: actions/setup-java@v4
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 8a4ce3cf..991a9878 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
@@ -30,7 +30,7 @@ import com.formdev.flatlaf.util.SystemInfo;
*/
public class FlatNativeWindowsLibrary
{
- private static int API_VERSION_WINDOWS = 1001;
+ private static int API_VERSION_WINDOWS = 1002;
private static long osBuildNumber = Long.MIN_VALUE;
@@ -158,4 +158,77 @@ public class FlatNativeWindowsLibrary
// DwmSetWindowAttribute() expects COLORREF as attribute value, which is defined as DWORD
return dwmSetWindowAttributeDWORD( hwnd, attribute, rgb );
}
+
+
+ /**
+ * FILEOPENDIALOGOPTIONS
+ * see https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/ne-shobjidl_core-_fileopendialogoptions
+ *
+ * @since 3.6
+ */
+ public static final int
+ FOS_OVERWRITEPROMPT = 0x2, // default for Save
+ FOS_STRICTFILETYPES = 0x4,
+ FOS_NOCHANGEDIR = 0x8, // default
+ FOS_PICKFOLDERS = 0x20,
+ FOS_FORCEFILESYSTEM = 0x40,
+ FOS_ALLNONSTORAGEITEMS = 0x80,
+ FOS_NOVALIDATE = 0x100,
+ FOS_ALLOWMULTISELECT = 0x200,
+ FOS_PATHMUSTEXIST = 0x800, // default
+ FOS_FILEMUSTEXIST = 0x1000, // default for Open
+ FOS_CREATEPROMPT = 0x2000,
+ FOS_SHAREAWARE = 0x4000,
+ FOS_NOREADONLYRETURN = 0x8000, // default for Save
+ FOS_NOTESTFILECREATE = 0x10000,
+ FOS_HIDEMRUPLACES = 0x20000,
+ FOS_HIDEPINNEDPLACES = 0x40000,
+ FOS_NODEREFERENCELINKS = 0x100000,
+ FOS_OKBUTTONNEEDSINTERACTION = 0x200000,
+ FOS_DONTADDTORECENT = 0x2000000,
+ FOS_FORCESHOWHIDDEN = 0x10000000,
+ FOS_DEFAULTNOMINIMODE = 0x20000000,
+ FOS_FORCEPREVIEWPANEON = 0x40000000,
+ FOS_SUPPORTSTREAMABLEITEMS = 0x80000000;
+
+ /**
+ * Shows the Windows system
+ * file dialogs
+ * IFileOpenDialog or
+ * IFileSaveDialog.
+ *
+ * Note: 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 owner the owner of the file dialog
+ * @param open if {@code true}, shows the open dialog; if {@code false}, shows the save dialog
+ * @param title text displayed in dialog title; or {@code null}
+ * @param okButtonLabel text displayed in default button; or {@code null}
+ * @param fileNameLabel text displayed in front of the filename text field; or {@code null}
+ * @param fileName user-editable filename currently shown in the filename field; or {@code null}
+ * @param folder current directory shown in the dialog; or {@code null}
+ * @param saveAsItem file to be used as the initial entry in a Save As dialog; or {@code null}.
+ * File name is shown in filename text field, folder is selected in view.
+ * To be used for saving files that already exist. For new files use {@code fileName}.
+ * @param defaultFolder folder used as a default if there is not a recently used folder value available; or {@code null}.
+ * Windows somewhere stores default folder on a per-app basis.
+ * So this is probably used only once when the app opens a file dialog for first time.
+ * @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 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.
+ * First string is the display name of the filter shown in the combobox (e.g. "Text Files").
+ * Second string is the filter pattern (e.g. "*.txt", "*.exe;*.dll" or "*.*").
+ * @return file path(s) that the user selected; an empty array if canceled;
+ * or {@code null} on failures (no dialog shown)
+ *
+ * @since 3.6
+ */
+ public native static String[] showFileChooser( 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 );
}
diff --git a/flatlaf-natives/flatlaf-natives-windows/build.gradle.kts b/flatlaf-natives/flatlaf-natives-windows/build.gradle.kts
index e297703e..550179d1 100644
--- a/flatlaf-natives/flatlaf-natives-windows/build.gradle.kts
+++ b/flatlaf-natives/flatlaf-natives-windows/build.gradle.kts
@@ -80,8 +80,8 @@ tasks {
linkerArgs.addAll( toolChain.map {
when( it ) {
- is Gcc, is Clang -> listOf( "-lUser32", "-lGdi32", "-lshell32", "-lAdvAPI32", "-lKernel32", "-lDwmapi" )
- is VisualCpp -> listOf( "User32.lib", "Gdi32.lib", "shell32.lib", "AdvAPI32.lib", "Kernel32.lib", "Dwmapi.lib", "/NODEFAULTLIB" )
+ 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" )
else -> emptyList()
}
} )
diff --git a/flatlaf-natives/flatlaf-natives-windows/src/main/cpp/ApiVersion.cpp b/flatlaf-natives/flatlaf-natives-windows/src/main/cpp/ApiVersion.cpp
index a32f0d6d..0f2e7a97 100644
--- a/flatlaf-natives/flatlaf-natives-windows/src/main/cpp/ApiVersion.cpp
+++ b/flatlaf-natives/flatlaf-natives-windows/src/main/cpp/ApiVersion.cpp
@@ -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.FlatNativeWindowsLibrary
-#define API_VERSION_WINDOWS 1001
+#define API_VERSION_WINDOWS 1002
//---- JNI methods ------------------------------------------------------------
diff --git a/flatlaf-natives/flatlaf-natives-windows/src/main/cpp/WinFileChooser.cpp b/flatlaf-natives/flatlaf-natives-windows/src/main/cpp/WinFileChooser.cpp
new file mode 100644
index 00000000..b51b0d7f
--- /dev/null
+++ b/flatlaf-natives/flatlaf-natives-windows/src/main/cpp/WinFileChooser.cpp
@@ -0,0 +1,257 @@
+/*
+ * 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.
+ */
+
+// avoid inlining of printf()
+#define _NO_CRT_STDIO_INLINE
+
+#include
+#include
+#include "com_formdev_flatlaf_ui_FlatNativeWindowsLibrary.h"
+
+/**
+ * @author Karl Tauber
+ */
+
+// see FlatWndProc.cpp
+HWND getWindowHandle( JNIEnv* env, jobject window );
+
+//---- class AutoReleasePtr ---------------------------------------------------
+
+template class AutoReleasePtr {
+ T* ptr;
+
+public:
+ AutoReleasePtr() {
+ ptr = NULL;
+ }
+ ~AutoReleasePtr() {
+ if( ptr != NULL )
+ ptr->Release();
+ }
+ T** operator&() { return &ptr; }
+ T* operator->() { return ptr; }
+ operator T*() { return ptr; }
+};
+
+//---- class AutoReleaseString ------------------------------------------------
+
+class AutoReleaseString {
+ JNIEnv* env;
+ jstring javaString;
+ const jchar* chars;
+
+public:
+ AutoReleaseString( JNIEnv* _env, jstring _javaString ) {
+ env = _env;
+ javaString = _javaString;
+ chars = (javaString != NULL) ? env->GetStringChars( javaString, NULL ) : NULL;
+ }
+ ~AutoReleaseString() {
+ if( chars != NULL )
+ env->ReleaseStringChars( javaString, chars );
+ }
+ operator LPCWSTR() { return (LPCWSTR) chars; }
+};
+
+//---- class AutoReleaseIShellItem --------------------------------------------
+
+class AutoReleaseIShellItem : public AutoReleasePtr {
+public:
+ AutoReleaseIShellItem( JNIEnv* env, jstring path ) {
+ AutoReleaseString cpath( env, path );
+ ::SHCreateItemFromParsingName( cpath, NULL, IID_IShellItem, reinterpret_cast( &*this ) );
+ }
+};
+
+//---- class FilterSpec -------------------------------------------------------
+
+class FilterSpec {
+ JNIEnv* env;
+ jstring* jnames = NULL;
+ jstring* jspecs = NULL;
+
+public:
+ UINT count = 0;
+ COMDLG_FILTERSPEC* specs = NULL;
+
+public:
+ FilterSpec( JNIEnv* _env, jobjectArray fileTypes ) {
+ env = _env;
+ count = env->GetArrayLength( fileTypes ) / 2;
+ if( count <= 0 )
+ return;
+
+ specs = new COMDLG_FILTERSPEC[count];
+ jnames = new jstring[count];
+ jspecs = new jstring[count];
+
+ for( int i = 0; i < count; i++ ) {
+ jnames[i] = (jstring) env->GetObjectArrayElement( fileTypes, i * 2 );
+ jspecs[i] = (jstring) env->GetObjectArrayElement( fileTypes, (i * 2) + 1 );
+ specs[i].pszName = (LPCWSTR) env->GetStringChars( jnames[i] , NULL );
+ specs[i].pszSpec = (LPCWSTR) env->GetStringChars( jspecs[i], NULL );
+ }
+ }
+ ~FilterSpec() {
+ if( specs == NULL )
+ return;
+
+ for( int i = 0; i < count; i++ ) {
+ env->ReleaseStringChars( jnames[i], (jchar *) specs[i].pszName );
+ env->ReleaseStringChars( jspecs[i], (jchar *) specs[i].pszSpec );
+ env->DeleteLocalRef( jnames[i] );
+ env->DeleteLocalRef( jspecs[i] );
+ }
+
+ delete[] jnames;
+ delete[] jspecs;
+ delete[] specs;
+ }
+};
+
+//---- class CoInitializer ----------------------------------------------------
+
+class CoInitializer {
+public:
+ bool initialized;
+
+ CoInitializer() {
+ HRESULT result = ::CoInitializeEx( NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE );
+ initialized = SUCCEEDED( result );
+ }
+ ~CoInitializer() {
+ if( initialized )
+ ::CoUninitialize();
+ }
+};
+
+//---- helper -----------------------------------------------------------------
+
+#define CHECK_HRESULT( code ) { if( (code) != S_OK ) return NULL; }
+
+jobjectArray newJavaStringArray( JNIEnv* env, jsize count ) {
+ jclass stringClass = env->FindClass( "java/lang/String" );
+ return env->NewObjectArray( count, stringClass, NULL );
+}
+
+jstring newJavaString( JNIEnv* env, LPWSTR str ) {
+ return env->NewString( reinterpret_cast( str ), static_cast( wcslen( str ) ) );
+}
+
+//---- JNI methods ------------------------------------------------------------
+
+extern "C"
+JNIEXPORT jobjectArray JNICALL Java_com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_showFileChooser
+ ( 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 )
+{
+ // initialize COM library
+ CoInitializer coInitializer;
+ if( !coInitializer.initialized )
+ return NULL;
+
+ HWND hwndOwner = getWindowHandle( env, owner );
+
+ // convert Java strings to C strings
+ AutoReleaseString ctitle( env, title );
+ AutoReleaseString cokButtonLabel( env, okButtonLabel );
+ AutoReleaseString cfileNameLabel( env, fileNameLabel );
+ AutoReleaseString cfileName( env, fileName );
+ AutoReleaseIShellItem cfolder( env, folder );
+ AutoReleaseIShellItem csaveAsItem( env, saveAsItem );
+ AutoReleaseIShellItem cdefaultFolder( env, defaultFolder );
+ AutoReleaseString cdefaultExtension( env, defaultExtension );
+ FilterSpec specs( env, fileTypes );
+
+ // create IFileOpenDialog or IFileSaveDialog
+ // https://learn.microsoft.com/en-us/windows/win32/shell/common-file-dialog
+ AutoReleasePtr dialog;
+ CHECK_HRESULT( ::CoCreateInstance( open ? CLSID_FileOpenDialog : CLSID_FileSaveDialog,
+ NULL, CLSCTX_INPROC_SERVER, open ? IID_IFileOpenDialog : IID_IFileSaveDialog,
+ reinterpret_cast( &dialog ) ) );
+
+ if( ctitle != NULL )
+ CHECK_HRESULT( dialog->SetTitle( ctitle ) );
+ if( cokButtonLabel != NULL )
+ CHECK_HRESULT( dialog->SetOkButtonLabel( cokButtonLabel ) );
+ if( cfileNameLabel != NULL )
+ CHECK_HRESULT( dialog->SetFileNameLabel( cfileNameLabel ) );
+ if( cfileName != NULL )
+ CHECK_HRESULT( dialog->SetFileName( cfileName ) );
+ if( cfolder != NULL )
+ CHECK_HRESULT( dialog->SetFolder( cfolder ) );
+ if( !open && csaveAsItem != NULL )
+ CHECK_HRESULT( ((IFileSaveDialog*)(IFileDialog*)dialog)->SetSaveAsItem( csaveAsItem ) );
+ if( cdefaultFolder != NULL )
+ CHECK_HRESULT( dialog->SetDefaultFolder( cdefaultFolder ) );
+ if( cdefaultExtension != NULL )
+ CHECK_HRESULT( dialog->SetDefaultExtension( cdefaultExtension ) );
+
+ FILEOPENDIALOGOPTIONS existingOptions;
+ CHECK_HRESULT( dialog->GetOptions( &existingOptions ) );
+ CHECK_HRESULT( dialog->SetOptions ( (existingOptions & ~optionsClear) | optionsSet ) );
+
+ if( specs.count > 0 ) {
+ CHECK_HRESULT( dialog->SetFileTypes( specs.count, specs.specs ) );
+ if( fileTypeIndex > 0 )
+ CHECK_HRESULT( dialog->SetFileTypeIndex( min( fileTypeIndex + 1, specs.count ) ) );
+ }
+
+ // show dialog
+ HRESULT hr = dialog->Show( hwndOwner );
+ if( hr == HRESULT_FROM_WIN32(ERROR_CANCELLED) )
+ return newJavaStringArray( env, 0 );
+ CHECK_HRESULT( hr );
+
+ // convert URLs to Java string array
+ if( open ) {
+ AutoReleasePtr shellItems;
+ DWORD count;
+ CHECK_HRESULT( ((IFileOpenDialog*)(IFileDialog*)dialog)->GetResults( &shellItems ) );
+ CHECK_HRESULT( shellItems->GetCount( &count ) );
+
+ jobjectArray array = newJavaStringArray( env, count );
+ for( int i = 0; i < count; i++ ) {
+ AutoReleasePtr shellItem;
+ LPWSTR path;
+ CHECK_HRESULT( shellItems->GetItemAt( i, &shellItem ) );
+ CHECK_HRESULT( shellItem->GetDisplayName( SIGDN_FILESYSPATH, &path ) );
+
+ jstring jpath = newJavaString( env, path );
+ CoTaskMemFree( path );
+
+ env->SetObjectArrayElement( array, 0, jpath );
+ env->DeleteLocalRef( jpath );
+ }
+ return array;
+ } else {
+ AutoReleasePtr shellItem;
+ LPWSTR path;
+ CHECK_HRESULT( dialog->GetResult( &shellItem ) );
+ CHECK_HRESULT( shellItem->GetDisplayName( SIGDN_FILESYSPATH, &path ) );
+
+ jstring jpath = newJavaString( env, path );
+ CoTaskMemFree( path );
+
+ jobjectArray array = newJavaStringArray( env, 1 );
+ env->SetObjectArrayElement( array, 0, jpath );
+ env->DeleteLocalRef( jpath );
+
+ return array;
+ }
+}
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 1701cb3b..895b7267 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
@@ -27,6 +27,52 @@ extern "C" {
#define com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_DWMWA_COLOR_DEFAULT -1L
#undef com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_DWMWA_COLOR_NONE
#define com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_DWMWA_COLOR_NONE -2L
+#undef com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_OVERWRITEPROMPT
+#define com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_OVERWRITEPROMPT 2L
+#undef com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_STRICTFILETYPES
+#define com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_STRICTFILETYPES 4L
+#undef com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_NOCHANGEDIR
+#define com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_NOCHANGEDIR 8L
+#undef com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_PICKFOLDERS
+#define com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_PICKFOLDERS 32L
+#undef com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_FORCEFILESYSTEM
+#define com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_FORCEFILESYSTEM 64L
+#undef com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_ALLNONSTORAGEITEMS
+#define com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_ALLNONSTORAGEITEMS 128L
+#undef com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_NOVALIDATE
+#define com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_NOVALIDATE 256L
+#undef com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_ALLOWMULTISELECT
+#define com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_ALLOWMULTISELECT 512L
+#undef com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_PATHMUSTEXIST
+#define com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_PATHMUSTEXIST 2048L
+#undef com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_FILEMUSTEXIST
+#define com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_FILEMUSTEXIST 4096L
+#undef com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_CREATEPROMPT
+#define com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_CREATEPROMPT 8192L
+#undef com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_SHAREAWARE
+#define com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_SHAREAWARE 16384L
+#undef com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_NOREADONLYRETURN
+#define com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_NOREADONLYRETURN 32768L
+#undef com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_NOTESTFILECREATE
+#define com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_NOTESTFILECREATE 65536L
+#undef com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_HIDEMRUPLACES
+#define com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_HIDEMRUPLACES 131072L
+#undef com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_HIDEPINNEDPLACES
+#define com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_HIDEPINNEDPLACES 262144L
+#undef com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_NODEREFERENCELINKS
+#define com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_NODEREFERENCELINKS 1048576L
+#undef com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_OKBUTTONNEEDSINTERACTION
+#define com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_OKBUTTONNEEDSINTERACTION 2097152L
+#undef com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_DONTADDTORECENT
+#define com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_DONTADDTORECENT 33554432L
+#undef com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_FORCESHOWHIDDEN
+#define com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_FORCESHOWHIDDEN 268435456L
+#undef com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_DEFAULTNOMINIMODE
+#define com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_DEFAULTNOMINIMODE 536870912L
+#undef com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_FORCEPREVIEWPANEON
+#define com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_FORCEPREVIEWPANEON 1073741824L
+#undef com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_SUPPORTSTREAMABLEITEMS
+#define com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_FOS_SUPPORTSTREAMABLEITEMS -2147483648L
/*
* Class: com_formdev_flatlaf_ui_FlatNativeWindowsLibrary
* Method: getOSBuildNumberImpl
@@ -67,6 +113,14 @@ JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_
JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_dwmSetWindowAttributeDWORD
(JNIEnv *, jclass, jlong, jint, jint);
+/*
+ * 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;
+ */
+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);
+
#ifdef __cplusplus
}
#endif
diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatWindowsFileChooserTest.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatWindowsFileChooserTest.java
new file mode 100644
index 00000000..c15f1e63
--- /dev/null
+++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatWindowsFileChooserTest.java
@@ -0,0 +1,551 @@
+/*
+ * 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.FlatNativeWindowsLibrary.*;
+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 java.util.concurrent.atomic.AtomicInteger;
+import javax.swing.*;
+import com.formdev.flatlaf.extras.components.*;
+import com.formdev.flatlaf.extras.components.FlatTriStateCheckBox.State;
+import com.formdev.flatlaf.ui.FlatNativeWindowsLibrary;
+import net.miginfocom.swing.*;
+
+/**
+ * @author Karl Tauber
+ */
+public class FlatWindowsFileChooserTest
+ extends FlatTestPanel
+{
+ public static void main( String[] args ) {
+ SwingUtilities.invokeLater( () -> {
+ if( !FlatNativeWindowsLibrary.isLoaded() ) {
+ JOptionPane.showMessageDialog( null, "FlatLaf native library not loaded" );
+ return;
+ }
+
+ FlatTestFrame frame = FlatTestFrame.create( args, "FlatWindowsFileChooserTest" );
+ addListeners( frame );
+ frame.showFrame( FlatWindowsFileChooserTest::new );
+ } );
+ }
+
+ FlatWindowsFileChooserTest() {
+ initComponents();
+
+ fileTypesField.setSelectedItem( null );
+ }
+
+ 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 ) {
+ Window owner = SwingUtilities.windowForComponent( this );
+ String title = n( titleField.getText() );
+ String okButtonLabel = n( okButtonLabelField.getText() );
+ String fileNameLabel = n( fileNameLabelField.getText() );
+ String fileName = n( fileNameField.getText() );
+ String folder = n( folderField.getText() );
+ String saveAsItem = n( saveAsItemField.getText() );
+ String defaultFolder = n( defaultFolderField.getText() );
+ String defaultExtension = n( defaultExtensionField.getText() );
+ AtomicInteger optionsSet = new AtomicInteger();
+ AtomicInteger optionsClear = new AtomicInteger();
+
+ o( FOS_OVERWRITEPROMPT, overwritePromptCheckBox, optionsSet, optionsClear );
+ o( FOS_STRICTFILETYPES, strictFileTypesCheckBox, optionsSet, optionsClear );
+ o( FOS_NOCHANGEDIR, noChangeDirCheckBox, optionsSet, optionsClear );
+ o( FOS_PICKFOLDERS, pickFoldersCheckBox, optionsSet, optionsClear );
+ o( FOS_FORCEFILESYSTEM, forceFileSystemCheckBox, optionsSet, optionsClear );
+ o( FOS_ALLNONSTORAGEITEMS, allNonStorageItemsCheckBox, optionsSet, optionsClear );
+ o( FOS_NOVALIDATE, noValidateCheckBox, optionsSet, optionsClear );
+ o( FOS_ALLOWMULTISELECT, allowMultiSelectCheckBox, optionsSet, optionsClear );
+ o( FOS_PATHMUSTEXIST, pathMustExistCheckBox, optionsSet, optionsClear );
+ o( FOS_FILEMUSTEXIST, fileMustExistCheckBox, optionsSet, optionsClear );
+ o( FOS_CREATEPROMPT, createPromptCheckBox, optionsSet, optionsClear );
+ o( FOS_SHAREAWARE, shareAwareCheckBox, optionsSet, optionsClear );
+ o( FOS_NOREADONLYRETURN, noReadOnlyReturnCheckBox, optionsSet, optionsClear );
+ o( FOS_NOTESTFILECREATE, noTestFileCreateCheckBox, optionsSet, optionsClear );
+ o( FOS_HIDEMRUPLACES, hideMruPlacesCheckBox, optionsSet, optionsClear );
+ o( FOS_HIDEPINNEDPLACES, hidePinnedPlacesCheckBox, optionsSet, optionsClear );
+ o( FOS_NODEREFERENCELINKS, noDereferenceLinksCheckBox, optionsSet, optionsClear );
+ o( FOS_OKBUTTONNEEDSINTERACTION, okButtonNeedsInteractionCheckBox, optionsSet, optionsClear );
+ o( FOS_DONTADDTORECENT, dontAddToRecentCheckBox, optionsSet, optionsClear );
+ o( FOS_FORCESHOWHIDDEN, forceShowHiddenCheckBox, optionsSet, optionsClear );
+ o( FOS_DEFAULTNOMINIMODE, defaultNoMiniModeCheckBox, optionsSet, optionsClear );
+ o( FOS_FORCEPREVIEWPANEON, forcePreviewPaneonCheckBox, optionsSet, optionsClear );
+ o( FOS_SUPPORTSTREAMABLEITEMS, supportStreamableItemsCheckBox, optionsSet, optionsClear );
+
+ String fileTypesStr = n( (String) fileTypesField.getSelectedItem() );
+ String[] fileTypes = {};
+ if( fileTypesStr != null )
+ fileTypes = fileTypesStr.trim().split( "[,]+" );
+ int fileTypeIndex = fileTypeIndexSlider.getValue();
+
+ if( direct ) {
+ String[] files = FlatNativeWindowsLibrary.showFileChooser( owner, open,
+ title, okButtonLabel, fileNameLabel, fileName,
+ folder, saveAsItem, defaultFolder, defaultExtension,
+ optionsSet.get(), optionsClear.get(), fileTypeIndex, fileTypes );
+
+ filesField.setText( (files != null) ? Arrays.toString( files ).replace( ',', '\n' ) : "null" );
+ } else {
+ SecondaryLoop secondaryLoop = Toolkit.getDefaultToolkit().getSystemEventQueue().createSecondaryLoop();
+
+ String[] fileTypes2 = fileTypes;
+ new Thread( () -> {
+ String[] files = FlatNativeWindowsLibrary.showFileChooser( owner, open,
+ title, okButtonLabel, fileNameLabel, fileName,
+ folder, saveAsItem, defaultFolder, defaultExtension,
+ optionsSet.get(), optionsClear.get(), fileTypeIndex, fileTypes2 );
+
+ 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 != null && !s.isEmpty() ? s : null;
+ }
+
+ private static void o( int option, FlatTriStateCheckBox checkBox, AtomicInteger optionsSet, AtomicInteger optionsClear ) {
+ if( checkBox.getState() == State.SELECTED )
+ optionsSet.set( optionsSet.get() | option );
+ else if( checkBox.getState() == State.UNSELECTED )
+ optionsClear.set( optionsClear.get() | option );
+ }
+
+ 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();
+ overwritePromptCheckBox = new FlatTriStateCheckBox();
+ pathMustExistCheckBox = new FlatTriStateCheckBox();
+ noDereferenceLinksCheckBox = new FlatTriStateCheckBox();
+ strictFileTypesCheckBox = new FlatTriStateCheckBox();
+ fileMustExistCheckBox = new FlatTriStateCheckBox();
+ okButtonNeedsInteractionCheckBox = new FlatTriStateCheckBox();
+ noChangeDirCheckBox = new FlatTriStateCheckBox();
+ createPromptCheckBox = new FlatTriStateCheckBox();
+ dontAddToRecentCheckBox = new FlatTriStateCheckBox();
+ pickFoldersCheckBox = new FlatTriStateCheckBox();
+ shareAwareCheckBox = new FlatTriStateCheckBox();
+ forceShowHiddenCheckBox = new FlatTriStateCheckBox();
+ forceFileSystemCheckBox = new FlatTriStateCheckBox();
+ noReadOnlyReturnCheckBox = new FlatTriStateCheckBox();
+ defaultNoMiniModeCheckBox = new FlatTriStateCheckBox();
+ allNonStorageItemsCheckBox = new FlatTriStateCheckBox();
+ noTestFileCreateCheckBox = new FlatTriStateCheckBox();
+ forcePreviewPaneonCheckBox = new FlatTriStateCheckBox();
+ noValidateCheckBox = new FlatTriStateCheckBox();
+ hideMruPlacesCheckBox = new FlatTriStateCheckBox();
+ supportStreamableItemsCheckBox = new FlatTriStateCheckBox();
+ allowMultiSelectCheckBox = new FlatTriStateCheckBox();
+ hidePinnedPlacesCheckBox = new FlatTriStateCheckBox();
+ okButtonLabelLabel = new JLabel();
+ okButtonLabelField = new JTextField();
+ fileNameLabelLabel = new JLabel();
+ fileNameLabelField = new JTextField();
+ fileNameLabel = new JLabel();
+ fileNameField = new JTextField();
+ folderLabel = new JLabel();
+ folderField = new JTextField();
+ saveAsItemLabel = new JLabel();
+ saveAsItemField = new JTextField();
+ defaultFolderLabel = new JLabel();
+ defaultFolderField = new JTextField();
+ defaultExtensionLabel = new JLabel();
+ defaultExtensionField = new JTextField();
+ fileTypesLabel = new JLabel();
+ fileTypesField = new JComboBox<>();
+ fileTypeIndexLabel = new JLabel();
+ fileTypeIndexSlider = new JSlider();
+ 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]para" +
+ "[left]para" +
+ "[left]",
+ // rows
+ "[]0" +
+ "[]0" +
+ "[]0" +
+ "[]" +
+ "[]0" +
+ "[]0" +
+ "[]0" +
+ "[]0"));
+
+ //---- overwritePromptCheckBox ----
+ overwritePromptCheckBox.setText("overwritePrompt");
+ panel1.add(overwritePromptCheckBox, "cell 0 0");
+
+ //---- pathMustExistCheckBox ----
+ pathMustExistCheckBox.setText("pathMustExist");
+ panel1.add(pathMustExistCheckBox, "cell 1 0");
+
+ //---- noDereferenceLinksCheckBox ----
+ noDereferenceLinksCheckBox.setText("noDereferenceLinks");
+ panel1.add(noDereferenceLinksCheckBox, "cell 2 0");
+
+ //---- strictFileTypesCheckBox ----
+ strictFileTypesCheckBox.setText("strictFileTypes");
+ panel1.add(strictFileTypesCheckBox, "cell 0 1");
+
+ //---- fileMustExistCheckBox ----
+ fileMustExistCheckBox.setText("fileMustExist");
+ panel1.add(fileMustExistCheckBox, "cell 1 1");
+
+ //---- okButtonNeedsInteractionCheckBox ----
+ okButtonNeedsInteractionCheckBox.setText("okButtonNeedsInteraction");
+ panel1.add(okButtonNeedsInteractionCheckBox, "cell 2 1");
+
+ //---- noChangeDirCheckBox ----
+ noChangeDirCheckBox.setText("noChangeDir");
+ panel1.add(noChangeDirCheckBox, "cell 0 2");
+
+ //---- createPromptCheckBox ----
+ createPromptCheckBox.setText("createPrompt");
+ panel1.add(createPromptCheckBox, "cell 1 2");
+
+ //---- dontAddToRecentCheckBox ----
+ dontAddToRecentCheckBox.setText("dontAddToRecent");
+ panel1.add(dontAddToRecentCheckBox, "cell 2 2");
+
+ //---- pickFoldersCheckBox ----
+ pickFoldersCheckBox.setText("pickFolders");
+ panel1.add(pickFoldersCheckBox, "cell 0 3");
+
+ //---- shareAwareCheckBox ----
+ shareAwareCheckBox.setText("shareAware");
+ panel1.add(shareAwareCheckBox, "cell 1 3");
+
+ //---- forceShowHiddenCheckBox ----
+ forceShowHiddenCheckBox.setText("forceShowHidden");
+ panel1.add(forceShowHiddenCheckBox, "cell 2 3");
+
+ //---- forceFileSystemCheckBox ----
+ forceFileSystemCheckBox.setText("forceFileSystem");
+ panel1.add(forceFileSystemCheckBox, "cell 0 4");
+
+ //---- noReadOnlyReturnCheckBox ----
+ noReadOnlyReturnCheckBox.setText("noReadOnlyReturn");
+ panel1.add(noReadOnlyReturnCheckBox, "cell 1 4");
+
+ //---- defaultNoMiniModeCheckBox ----
+ defaultNoMiniModeCheckBox.setText("defaultNoMiniMode");
+ panel1.add(defaultNoMiniModeCheckBox, "cell 2 4");
+
+ //---- allNonStorageItemsCheckBox ----
+ allNonStorageItemsCheckBox.setText("allNonStorageItems");
+ panel1.add(allNonStorageItemsCheckBox, "cell 0 5");
+
+ //---- noTestFileCreateCheckBox ----
+ noTestFileCreateCheckBox.setText("noTestFileCreate");
+ panel1.add(noTestFileCreateCheckBox, "cell 1 5");
+
+ //---- forcePreviewPaneonCheckBox ----
+ forcePreviewPaneonCheckBox.setText("forcePreviewPaneon");
+ panel1.add(forcePreviewPaneonCheckBox, "cell 2 5");
+
+ //---- noValidateCheckBox ----
+ noValidateCheckBox.setText("noValidate");
+ panel1.add(noValidateCheckBox, "cell 0 6");
+
+ //---- hideMruPlacesCheckBox ----
+ hideMruPlacesCheckBox.setText("hideMruPlaces");
+ panel1.add(hideMruPlacesCheckBox, "cell 1 6");
+
+ //---- supportStreamableItemsCheckBox ----
+ supportStreamableItemsCheckBox.setText("supportStreamableItems");
+ panel1.add(supportStreamableItemsCheckBox, "cell 2 6");
+
+ //---- allowMultiSelectCheckBox ----
+ allowMultiSelectCheckBox.setText("allowMultiSelect");
+ panel1.add(allowMultiSelectCheckBox, "cell 0 7");
+
+ //---- hidePinnedPlacesCheckBox ----
+ hidePinnedPlacesCheckBox.setText("hidePinnedPlaces");
+ panel1.add(hidePinnedPlacesCheckBox, "cell 1 7");
+ }
+ add(panel1, "cell 2 0 1 10,aligny top,growy 0");
+
+ //---- okButtonLabelLabel ----
+ okButtonLabelLabel.setText("okButtonLabel");
+ add(okButtonLabelLabel, "cell 0 1");
+ add(okButtonLabelField, "cell 1 1");
+
+ //---- fileNameLabelLabel ----
+ fileNameLabelLabel.setText("fileNameLabel");
+ add(fileNameLabelLabel, "cell 0 2");
+ add(fileNameLabelField, "cell 1 2");
+
+ //---- fileNameLabel ----
+ fileNameLabel.setText("fileName");
+ add(fileNameLabel, "cell 0 3");
+ add(fileNameField, "cell 1 3");
+
+ //---- folderLabel ----
+ folderLabel.setText("folder");
+ add(folderLabel, "cell 0 4");
+ add(folderField, "cell 1 4");
+
+ //---- saveAsItemLabel ----
+ saveAsItemLabel.setText("saveAsItem");
+ add(saveAsItemLabel, "cell 0 5");
+ add(saveAsItemField, "cell 1 5");
+
+ //---- defaultFolderLabel ----
+ defaultFolderLabel.setText("defaultFolder");
+ add(defaultFolderLabel, "cell 0 6");
+ add(defaultFolderField, "cell 1 6");
+
+ //---- defaultExtensionLabel ----
+ defaultExtensionLabel.setText("defaultExtension");
+ add(defaultExtensionLabel, "cell 0 7");
+ add(defaultExtensionField, "cell 1 7");
+
+ //---- fileTypesLabel ----
+ fileTypesLabel.setText("fileTypes");
+ add(fileTypesLabel, "cell 0 8");
+
+ //---- fileTypesField ----
+ fileTypesField.setEditable(true);
+ fileTypesField.setModel(new DefaultComboBoxModel<>(new String[] {
+ "Text Files,*.txt",
+ "All Files,*.*",
+ "Text Files,*.txt,PDF Files,*.pdf,All Files,*.*",
+ "Text and PDF Files,*.txt;*.pdf"
+ }));
+ add(fileTypesField, "cell 1 8");
+
+ //---- fileTypeIndexLabel ----
+ fileTypeIndexLabel.setText("fileTypeIndex");
+ add(fileTypeIndexLabel, "cell 0 9");
+
+ //---- fileTypeIndexSlider ----
+ fileTypeIndexSlider.setMaximum(10);
+ fileTypeIndexSlider.setMajorTickSpacing(1);
+ fileTypeIndexSlider.setValue(0);
+ fileTypeIndexSlider.setPaintLabels(true);
+ fileTypeIndexSlider.setSnapToTicks(true);
+ add(fileTypeIndexSlider, "cell 1 9");
+
+ //---- openButton ----
+ openButton.setText("Open...");
+ openButton.addActionListener(e -> open());
+ add(openButton, "cell 0 10 3 1");
+
+ //---- saveButton ----
+ saveButton.setText("Save...");
+ saveButton.addActionListener(e -> save());
+ add(saveButton, "cell 0 10 3 1");
+
+ //---- openDirectButton ----
+ openDirectButton.setText("Open (no-thread)...");
+ openDirectButton.addActionListener(e -> openDirect());
+ add(openDirectButton, "cell 0 10 3 1");
+
+ //---- saveDirectButton ----
+ saveDirectButton.setText("Save (no-thread)...");
+ saveDirectButton.addActionListener(e -> saveDirect());
+ add(saveDirectButton, "cell 0 10 3 1");
+
+ //======== filesScrollPane ========
+ {
+
+ //---- filesField ----
+ filesField.setRows(8);
+ filesScrollPane.setViewportView(filesField);
+ }
+ add(filesScrollPane, "cell 0 11 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 FlatTriStateCheckBox overwritePromptCheckBox;
+ private FlatTriStateCheckBox pathMustExistCheckBox;
+ private FlatTriStateCheckBox noDereferenceLinksCheckBox;
+ private FlatTriStateCheckBox strictFileTypesCheckBox;
+ private FlatTriStateCheckBox fileMustExistCheckBox;
+ private FlatTriStateCheckBox okButtonNeedsInteractionCheckBox;
+ private FlatTriStateCheckBox noChangeDirCheckBox;
+ private FlatTriStateCheckBox createPromptCheckBox;
+ private FlatTriStateCheckBox dontAddToRecentCheckBox;
+ private FlatTriStateCheckBox pickFoldersCheckBox;
+ private FlatTriStateCheckBox shareAwareCheckBox;
+ private FlatTriStateCheckBox forceShowHiddenCheckBox;
+ private FlatTriStateCheckBox forceFileSystemCheckBox;
+ private FlatTriStateCheckBox noReadOnlyReturnCheckBox;
+ private FlatTriStateCheckBox defaultNoMiniModeCheckBox;
+ private FlatTriStateCheckBox allNonStorageItemsCheckBox;
+ private FlatTriStateCheckBox noTestFileCreateCheckBox;
+ private FlatTriStateCheckBox forcePreviewPaneonCheckBox;
+ private FlatTriStateCheckBox noValidateCheckBox;
+ private FlatTriStateCheckBox hideMruPlacesCheckBox;
+ private FlatTriStateCheckBox supportStreamableItemsCheckBox;
+ private FlatTriStateCheckBox allowMultiSelectCheckBox;
+ private FlatTriStateCheckBox hidePinnedPlacesCheckBox;
+ private JLabel okButtonLabelLabel;
+ private JTextField okButtonLabelField;
+ private JLabel fileNameLabelLabel;
+ private JTextField fileNameLabelField;
+ private JLabel fileNameLabel;
+ private JTextField fileNameField;
+ private JLabel folderLabel;
+ private JTextField folderField;
+ private JLabel saveAsItemLabel;
+ private JTextField saveAsItemField;
+ private JLabel defaultFolderLabel;
+ private JTextField defaultFolderField;
+ private JLabel defaultExtensionLabel;
+ private JTextField defaultExtensionField;
+ private JLabel fileTypesLabel;
+ private JComboBox fileTypesField;
+ private JLabel fileTypeIndexLabel;
+ private JSlider fileTypeIndexSlider;
+ 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
+}
diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatWindowsFileChooserTest.jfd b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatWindowsFileChooserTest.jfd
new file mode 100644
index 00000000..f26815de
--- /dev/null
+++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatWindowsFileChooserTest.jfd
@@ -0,0 +1,324 @@
+JFDML JFormDesigner: "8.3" 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]para[left]para[left]"
+ "$rowConstraints": "[]0[]0[]0[][]0[]0[]0[]0"
+ } ) {
+ name: "panel1"
+ add( new FormComponent( "com.formdev.flatlaf.extras.components.FlatTriStateCheckBox" ) {
+ name: "overwritePromptCheckBox"
+ "text": "overwritePrompt"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 0 0"
+ } )
+ add( new FormComponent( "com.formdev.flatlaf.extras.components.FlatTriStateCheckBox" ) {
+ name: "pathMustExistCheckBox"
+ "text": "pathMustExist"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 1 0"
+ } )
+ add( new FormComponent( "com.formdev.flatlaf.extras.components.FlatTriStateCheckBox" ) {
+ name: "noDereferenceLinksCheckBox"
+ "text": "noDereferenceLinks"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 2 0"
+ } )
+ add( new FormComponent( "com.formdev.flatlaf.extras.components.FlatTriStateCheckBox" ) {
+ name: "strictFileTypesCheckBox"
+ "text": "strictFileTypes"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 0 1"
+ } )
+ add( new FormComponent( "com.formdev.flatlaf.extras.components.FlatTriStateCheckBox" ) {
+ name: "fileMustExistCheckBox"
+ "text": "fileMustExist"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 1 1"
+ } )
+ add( new FormComponent( "com.formdev.flatlaf.extras.components.FlatTriStateCheckBox" ) {
+ name: "okButtonNeedsInteractionCheckBox"
+ "text": "okButtonNeedsInteraction"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 2 1"
+ } )
+ add( new FormComponent( "com.formdev.flatlaf.extras.components.FlatTriStateCheckBox" ) {
+ name: "noChangeDirCheckBox"
+ "text": "noChangeDir"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 0 2"
+ } )
+ add( new FormComponent( "com.formdev.flatlaf.extras.components.FlatTriStateCheckBox" ) {
+ name: "createPromptCheckBox"
+ "text": "createPrompt"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 1 2"
+ } )
+ add( new FormComponent( "com.formdev.flatlaf.extras.components.FlatTriStateCheckBox" ) {
+ name: "dontAddToRecentCheckBox"
+ "text": "dontAddToRecent"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 2 2"
+ } )
+ add( new FormComponent( "com.formdev.flatlaf.extras.components.FlatTriStateCheckBox" ) {
+ name: "pickFoldersCheckBox"
+ "text": "pickFolders"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 0 3"
+ } )
+ add( new FormComponent( "com.formdev.flatlaf.extras.components.FlatTriStateCheckBox" ) {
+ name: "shareAwareCheckBox"
+ "text": "shareAware"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 1 3"
+ } )
+ add( new FormComponent( "com.formdev.flatlaf.extras.components.FlatTriStateCheckBox" ) {
+ name: "forceShowHiddenCheckBox"
+ "text": "forceShowHidden"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 2 3"
+ } )
+ add( new FormComponent( "com.formdev.flatlaf.extras.components.FlatTriStateCheckBox" ) {
+ name: "forceFileSystemCheckBox"
+ "text": "forceFileSystem"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 0 4"
+ } )
+ add( new FormComponent( "com.formdev.flatlaf.extras.components.FlatTriStateCheckBox" ) {
+ name: "noReadOnlyReturnCheckBox"
+ "text": "noReadOnlyReturn"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 1 4"
+ } )
+ add( new FormComponent( "com.formdev.flatlaf.extras.components.FlatTriStateCheckBox" ) {
+ name: "defaultNoMiniModeCheckBox"
+ "text": "defaultNoMiniMode"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 2 4"
+ } )
+ add( new FormComponent( "com.formdev.flatlaf.extras.components.FlatTriStateCheckBox" ) {
+ name: "allNonStorageItemsCheckBox"
+ "text": "allNonStorageItems"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 0 5"
+ } )
+ add( new FormComponent( "com.formdev.flatlaf.extras.components.FlatTriStateCheckBox" ) {
+ name: "noTestFileCreateCheckBox"
+ "text": "noTestFileCreate"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 1 5"
+ } )
+ add( new FormComponent( "com.formdev.flatlaf.extras.components.FlatTriStateCheckBox" ) {
+ name: "forcePreviewPaneonCheckBox"
+ "text": "forcePreviewPaneon"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 2 5"
+ } )
+ add( new FormComponent( "com.formdev.flatlaf.extras.components.FlatTriStateCheckBox" ) {
+ name: "noValidateCheckBox"
+ "text": "noValidate"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 0 6"
+ } )
+ add( new FormComponent( "com.formdev.flatlaf.extras.components.FlatTriStateCheckBox" ) {
+ name: "hideMruPlacesCheckBox"
+ "text": "hideMruPlaces"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 1 6"
+ } )
+ add( new FormComponent( "com.formdev.flatlaf.extras.components.FlatTriStateCheckBox" ) {
+ name: "supportStreamableItemsCheckBox"
+ "text": "supportStreamableItems"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 2 6"
+ } )
+ add( new FormComponent( "com.formdev.flatlaf.extras.components.FlatTriStateCheckBox" ) {
+ name: "allowMultiSelectCheckBox"
+ "text": "allowMultiSelect"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 0 7"
+ } )
+ add( new FormComponent( "com.formdev.flatlaf.extras.components.FlatTriStateCheckBox" ) {
+ name: "hidePinnedPlacesCheckBox"
+ "text": "hidePinnedPlaces"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 1 7"
+ } )
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 2 0 1 10,aligny top,growy 0"
+ } )
+ add( new FormComponent( "javax.swing.JLabel" ) {
+ name: "okButtonLabelLabel"
+ "text": "okButtonLabel"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 0 1"
+ } )
+ add( new FormComponent( "javax.swing.JTextField" ) {
+ name: "okButtonLabelField"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 1 1"
+ } )
+ add( new FormComponent( "javax.swing.JLabel" ) {
+ name: "fileNameLabelLabel"
+ "text": "fileNameLabel"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 0 2"
+ } )
+ add( new FormComponent( "javax.swing.JTextField" ) {
+ name: "fileNameLabelField"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 1 2"
+ } )
+ add( new FormComponent( "javax.swing.JLabel" ) {
+ name: "fileNameLabel"
+ "text": "fileName"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 0 3"
+ } )
+ add( new FormComponent( "javax.swing.JTextField" ) {
+ name: "fileNameField"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 1 3"
+ } )
+ add( new FormComponent( "javax.swing.JLabel" ) {
+ name: "folderLabel"
+ "text": "folder"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 0 4"
+ } )
+ add( new FormComponent( "javax.swing.JTextField" ) {
+ name: "folderField"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 1 4"
+ } )
+ add( new FormComponent( "javax.swing.JLabel" ) {
+ name: "saveAsItemLabel"
+ "text": "saveAsItem"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 0 5"
+ } )
+ add( new FormComponent( "javax.swing.JTextField" ) {
+ name: "saveAsItemField"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 1 5"
+ } )
+ add( new FormComponent( "javax.swing.JLabel" ) {
+ name: "defaultFolderLabel"
+ "text": "defaultFolder"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 0 6"
+ } )
+ add( new FormComponent( "javax.swing.JTextField" ) {
+ name: "defaultFolderField"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 1 6"
+ } )
+ add( new FormComponent( "javax.swing.JLabel" ) {
+ name: "defaultExtensionLabel"
+ "text": "defaultExtension"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 0 7"
+ } )
+ add( new FormComponent( "javax.swing.JTextField" ) {
+ name: "defaultExtensionField"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 1 7"
+ } )
+ add( new FormComponent( "javax.swing.JLabel" ) {
+ name: "fileTypesLabel"
+ "text": "fileTypes"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 0 8"
+ } )
+ add( new FormComponent( "javax.swing.JComboBox" ) {
+ name: "fileTypesField"
+ "editable": true
+ "model": new javax.swing.DefaultComboBoxModel {
+ selectedItem: "Text Files,*.txt"
+ addElement( "Text Files,*.txt" )
+ addElement( "All Files,*.*" )
+ addElement( "Text Files,*.txt,PDF Files,*.pdf,All Files,*.*" )
+ addElement( "Text and PDF Files,*.txt;*.pdf" )
+ }
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 1 8"
+ } )
+ add( new FormComponent( "javax.swing.JLabel" ) {
+ name: "fileTypeIndexLabel"
+ "text": "fileTypeIndex"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 0 9"
+ } )
+ add( new FormComponent( "javax.swing.JSlider" ) {
+ name: "fileTypeIndexSlider"
+ "maximum": 10
+ "majorTickSpacing": 1
+ "value": 0
+ "paintLabels": true
+ "snapToTicks": true
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 1 9"
+ } )
+ 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 10 3 1"
+ } )
+ add( new FormComponent( "javax.swing.JButton" ) {
+ name: "saveButton"
+ "text": "Save..."
+ addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "save", false ) )
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 0 10 3 1"
+ } )
+ add( new FormComponent( "javax.swing.JButton" ) {
+ name: "openDirectButton"
+ "text": "Open (no-thread)..."
+ addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "openDirect", false ) )
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 0 10 3 1"
+ } )
+ add( new FormComponent( "javax.swing.JButton" ) {
+ name: "saveDirectButton"
+ "text": "Save (no-thread)..."
+ addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "saveDirect", false ) )
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 0 10 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 11 3 1,growx"
+ } )
+ }, new FormLayoutConstraints( null ) {
+ "location": new java.awt.Point( 0, 0 )
+ "size": new java.awt.Dimension( 690, 630 )
+ } )
+ }
+}