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 5ea7d178..1cbefc97 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
@@ -146,7 +146,8 @@ public class FlatNativeLinuxLibrary
* @param owner the owner of the file dialog; or {@code null}
* @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}. Use '_' for mnemonics (e.g. "_Choose")
+ * @param okButtonLabel text displayed in default button; or {@code null}.
+ * Use '_' for mnemonics (e.g. "_Choose")
* Use '__' for '_' character (e.g. "Choose__and__Quit").
* @param currentName user-editable filename currently shown in the filename field in save dialog; or {@code null}
* @param currentFolder current directory shown in the dialog; or {@code null}
@@ -189,7 +190,9 @@ public class FlatNativeLinuxLibrary
* 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
+ * @param buttons texts of the buttons; if no buttons given the a default "OK" button is shown.
+ * Use '_' for mnemonics (e.g. "_Choose")
+ * Use '__' for '_' character (e.g. "Choose__and__Quit").
* @return index of pressed button; or -1 for ESC key
*
* @since 3.6
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 ec2bed8f..65326049 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
@@ -18,6 +18,7 @@ package com.formdev.flatlaf.ui;
import java.awt.Color;
import java.awt.Window;
+import javax.swing.JOptionPane;
import com.formdev.flatlaf.util.SystemInfo;
/**
@@ -204,7 +205,8 @@ public class FlatNativeWindowsLibrary
* @param owner the owner of the file dialog; or {@code null}
* @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}. Use '&' for mnemonics (e.g. "&Choose").
+ * @param okButtonLabel text displayed in default button; or {@code null}.
+ * Use '&' for mnemonics (e.g. "&Choose").
* Use '&&' for '&' character (e.g. "Choose && Quit").
* @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}
@@ -240,6 +242,29 @@ public class FlatNativeWindowsLibrary
boolean approve( String[] files, long hwndFileDialog );
}
+ /**
+ * Shows a modal Windows message dialog.
+ *
+ * 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 title dialog box title; or {@code null} to use title from parent window
+ * @param text message to be displayed
+ * @param defaultButton index of the default button, which can be pressed using ENTER key
+ * @param buttons texts of the buttons.
+ * Use '&' for mnemonics (e.g. "&Choose").
+ * Use '&&' for '&' character (e.g. "Choose && Quit").
+ * @return index of pressed button; or -1 for ESC key
+ *
+ * @since 3.6
+ */
+ public native static int showMessageDialog( long hwndParent, int messageType,
+ String title, String text, int defaultButton, String... buttons );
+
/**
* Shows a Windows message box
* MessageBox.
@@ -251,10 +276,8 @@ public class FlatNativeWindowsLibrary
* @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 );
+ public native static int showMessageBox( long hwndParent, String text, String caption, int type );
}
diff --git a/flatlaf-natives/flatlaf-natives-windows/src/main/cpp/Runtime.cpp b/flatlaf-natives/flatlaf-natives-windows/src/main/cpp/Runtime.cpp
index cbd5163d..cea43d13 100644
--- a/flatlaf-natives/flatlaf-natives-windows/src/main/cpp/Runtime.cpp
+++ b/flatlaf-natives/flatlaf-natives-windows/src/main/cpp/Runtime.cpp
@@ -36,8 +36,11 @@
* @author Karl Tauber
*/
+HINSTANCE _instance;
+
extern "C"
BOOL WINAPI _DllMainCRTStartup( HINSTANCE instance, DWORD reason, LPVOID reserved ) {
+ _instance = instance;
return TRUE;
}
diff --git a/flatlaf-natives/flatlaf-natives-windows/src/main/cpp/WinMessageDialog.cpp b/flatlaf-natives/flatlaf-natives-windows/src/main/cpp/WinMessageDialog.cpp
index 38b9dd3a..7a087fc8 100644
--- a/flatlaf-natives/flatlaf-natives-windows/src/main/cpp/WinMessageDialog.cpp
+++ b/flatlaf-natives/flatlaf-natives-windows/src/main/cpp/WinMessageDialog.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2024 FormDev Software GmbH
+ * Copyright 2025 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.
@@ -18,6 +18,7 @@
#define _NO_CRT_STDIO_INLINE
#include
+#include
#include "JNIUtils.h"
#include "com_formdev_flatlaf_ui_FlatNativeWindowsLibrary.h"
@@ -26,8 +27,24 @@
* @since 3.6
*/
+#define ID_BUTTON1 101
+
+// declare external fields
+extern HINSTANCE _instance;
+
+// declare internal methods
+static byte* createInMemoryTemplate( HWND owner, int messageType, LPCWSTR title, LPCWSTR text,
+ int defaultButton, int buttonCount, LPCWSTR* buttons );
+static INT_PTR CALLBACK messageDialogProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
+static int textLengthAsDLUs( HDC hdc, LPCWSTR str, int strLen );
+static LONG pixel2dluX( LONG px );
+static LONG pixel2dluY( LONG px );
+static LONG dluX2pixel( LONG dluX );
+static LPWORD lpwAlign( LPWORD lpIn );
+
+
extern "C"
-JNIEXPORT jint JNICALL Java_com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_showMessageDialog
+JNIEXPORT jint JNICALL Java_com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_showMessageBox
( JNIEnv* env, jclass cls, jlong hwndParent, jstring text, jstring caption, jint type )
{
// convert Java strings to C strings
@@ -36,3 +53,326 @@ JNIEXPORT jint JNICALL Java_com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_show
return ::MessageBox( reinterpret_cast( hwndParent ), ctext, ccaption, type );
}
+
+extern "C"
+JNIEXPORT jint JNICALL Java_com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_showMessageDialog
+ ( JNIEnv* env, jclass cls, jlong hwndParent, jint messageType, jstring title,
+ jstring text, jint defaultButton, jobjectArray buttons )
+{
+ HWND owner = reinterpret_cast( hwndParent );
+
+ // convert Java strings to C strings
+ AutoReleaseString ctitle( env, title );
+ AutoReleaseString ctext( env, text );
+ AutoReleaseStringArray cbuttons( env, buttons );
+
+ // get title from parent window if necessary
+ WCHAR parentTitle[100];
+ if( ctitle == NULL )
+ ::GetWindowText( owner, parentTitle, 100 );
+
+ byte* templ = createInMemoryTemplate( owner, messageType, (ctitle != NULL) ? ctitle : parentTitle,
+ ctext, defaultButton, cbuttons.count, cbuttons );
+ if( templ == NULL )
+ return -1;
+
+ LRESULT ret = ::DialogBoxIndirect( _instance, (LPDLGTEMPLATE) templ, owner, messageDialogProc );
+ delete templ;
+ return (ret >= ID_BUTTON1) ? ret - ID_BUTTON1 : -1;
+}
+
+
+// all values in DLUs
+
+#define INSETS_TOP 16
+#define INSETS_LEFT 12
+#define INSETS_RIGHT 12
+#define INSETS_BOTTOM 8
+
+#define ICON_TEXT_GAP 8
+
+#define LABEL_MIN_WIDTH 100
+#define LABEL_MAX_WIDTH 250
+#define LABEL_HEIGHT 8
+
+#define BUTTON_WIDTH 50
+#define BUTTON_HEIGHT 14
+#define BUTTON_GAP 5
+#define BUTTON_TOP_GAP 16
+#define BUTTON_LEFT_RIGHT_GAP 8
+
+// based on https://learn.microsoft.com/en-us/windows/win32/dlgbox/using-dialog-boxes#creating-a-template-in-memory
+static byte* createInMemoryTemplate( HWND owner, int messageType, LPCWSTR title, LPCWSTR text,
+ int defaultButton, int buttonCount, LPCWSTR* buttons )
+{
+ //---- calculate layout (in DLUs) ----
+
+ HDC hdc = GetDC( owner );
+
+ // layout icon
+ LPWSTR icon;
+ switch( messageType ) {
+ case /* JOptionPane.ERROR_MESSAGE */ 0: icon = IDI_ERROR; break;
+ case /* JOptionPane.INFORMATION_MESSAGE */ 1: icon = IDI_INFORMATION; break;
+ case /* JOptionPane.WARNING_MESSAGE */ 2: icon = IDI_WARNING; break;
+ case /* JOptionPane.QUESTION_MESSAGE */ 3: icon = IDI_QUESTION; break;
+ default:
+ case /* JOptionPane.PLAIN_MESSAGE */ -1: icon = NULL; break;
+ }
+ int ix = INSETS_LEFT;
+ int iy = INSETS_TOP;
+ int iw = pixel2dluX( ::GetSystemMetrics( SM_CXICON ) );
+ int ih = pixel2dluY( ::GetSystemMetrics( SM_CYICON ) );
+
+ // layout text
+ int tx = ix + (icon != NULL ? iw + ICON_TEXT_GAP : 0);
+ int ty = iy;
+ int tw = 0;
+ int th = 0;
+ if( text == NULL )
+ text = L"";
+ LPWSTR wrappedText = new WCHAR[wcslen( text ) + 1];
+ wcscpy( wrappedText, text );
+ LPWSTR lineStart = wrappedText;
+ for( LPWSTR t = wrappedText; ; t++ ) {
+ if( *t != '\n' && *t != 0 )
+ continue;
+
+ // calculate line width (in pixels) and number of charaters that fit into LABEL_MAX_WIDTH
+ int lineLen = t - lineStart;
+ int fit = 0;
+ SIZE size{ 0 };
+ if( !::GetTextExtentExPoint( hdc, lineStart, lineLen, dluX2pixel( LABEL_MAX_WIDTH ), &fit, NULL, &size ) )
+ break;
+
+ if( fit < lineLen ) {
+ // wrap too long line --> try to wrap at space character
+ bool wrapped = false;
+ for( LPWSTR t2 = lineStart + fit - 1; t2 > lineStart; t2-- ) {
+ if( *t2 == ' ' || *t2 == '\t' ) {
+ *t2 = '\n';
+ int w = textLengthAsDLUs( hdc, lineStart, t2 - lineStart );
+ tw = max( tw, w );
+ th += LABEL_HEIGHT;
+
+ // continue wrapping after inserted line break
+ t = t2;
+ lineStart = t + 1;
+ wrapped = true;
+ break;
+ }
+ }
+ if( !wrapped ) {
+ // not able to wrap at word --> break long word
+ int breakIndex = (lineStart + fit) - wrappedText;
+ int w = textLengthAsDLUs( hdc, lineStart, breakIndex );
+ tw = max( tw, w );
+ th += LABEL_HEIGHT;
+
+ // duplicate string
+ LPWSTR wrappedText2 = new WCHAR[wcslen( wrappedText ) + 1 + 1];
+ // use wcscpy(), instead of wcsncpy(), because this method is inlined and does not require linking to runtime lib
+ wcscpy( wrappedText2, wrappedText );
+ wrappedText2[breakIndex] = '\n';
+ wcscpy( wrappedText2 + breakIndex + 1, wrappedText + breakIndex );
+
+ // delete old text
+ delete[] wrappedText;
+ wrappedText = wrappedText2;
+
+ // continue wrapping after inserted line break
+ t = wrappedText + breakIndex;
+ lineStart = t + 1;
+ }
+ } else {
+ // line fits into LABEL_MAX_WIDTH
+ int w = pixel2dluX( size.cx );
+ tw = max( tw, w );
+ th += LABEL_HEIGHT;
+ lineStart = t + 1;
+ }
+
+ if( *t == 0 )
+ break;
+ }
+ tw = min( max( tw, LABEL_MIN_WIDTH ), LABEL_MAX_WIDTH );
+ th = max( th, LABEL_HEIGHT );
+ if( icon != NULL && th < ih )
+ ty += (ih - th) / 2; // vertically center text
+
+ // layout buttons
+ int* bw = new int[buttonCount];
+ int buttonTotalWidth = BUTTON_GAP * (buttonCount - 1);
+ for( int i = 0; i < buttonCount; i++ ) {
+ int w = textLengthAsDLUs( hdc, buttons[i], -1 ) + 16;
+ bw[i] = max( BUTTON_WIDTH, w );
+ buttonTotalWidth += bw[i];
+ }
+
+ // layout dialog
+ int dx = 0;
+ int dy = 0;
+ int dw = max( tx + tw + INSETS_RIGHT, BUTTON_LEFT_RIGHT_GAP + buttonTotalWidth + BUTTON_LEFT_RIGHT_GAP );
+ int dh = max( iy + ih, ty + th ) + BUTTON_TOP_GAP + BUTTON_HEIGHT + INSETS_BOTTOM;
+
+ // center dialog in owner
+ RECT ownerRect{ 0 };
+ if( ::GetClientRect( owner, &ownerRect ) ) {
+ dx = (pixel2dluX( ownerRect.right - ownerRect.left ) - dw) / 2;
+ dy = (pixel2dluY( ownerRect.bottom - ownerRect.top ) - dh) / 2;
+ }
+
+ // layout button area
+ int bx = dw - buttonTotalWidth - BUTTON_LEFT_RIGHT_GAP;
+ int by = dh - BUTTON_HEIGHT - INSETS_BOTTOM;
+
+ // (approximately) calculate memory size needed for in-memory template
+ int templSize = (sizeof(DLGTEMPLATE) + /*menu*/ 2 + /*class*/ 2 + /*title*/ 2)
+ + ((sizeof(DLGITEMTEMPLATE) + /*class*/ 4 + /*title/icon*/ 4 + /*creation data*/ 2) * (/*icon+text*/2 + buttonCount))
+ + (title != NULL ? wcslen( title ) * sizeof(wchar_t) : 0)
+ + (wcslen( wrappedText ) * sizeof(wchar_t));
+ for( int i = 0; i < buttonCount; i++ )
+ templSize += (wcslen( buttons[i] ) * sizeof(wchar_t));
+
+ templSize += (2 * (1 + 1 + buttonCount)); // necessary for DWORD alignment
+ templSize += 100; // some reserve
+
+ // allocate memory for in-memory template
+ byte* templ = new byte[templSize];
+ if( templ == NULL )
+ return NULL;
+
+
+ //---- define dialog box ----
+
+ LPDLGTEMPLATE lpdt = (LPDLGTEMPLATE) templ;
+ lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU | DS_MODALFRAME | WS_CAPTION;
+ lpdt->cdit = /*text*/ 1 + buttonCount; // number of controls
+ lpdt->x = dx;
+ lpdt->y = dy;
+ lpdt->cx = dw;
+ lpdt->cy = dh;
+
+ LPWORD lpw = (LPWORD) (lpdt + 1);
+ *lpw++ = 0; // no menu
+ *lpw++ = 0; // predefined dialog box class (by default)
+ if( title != NULL ) {
+ wcscpy( (LPWSTR) lpw, title );
+ lpw += wcslen( title ) + 1;
+ } else
+ *lpw++ = 0; // no title
+
+
+ //---- define icon ----
+
+ if( icon != NULL ) {
+ lpdt->cdit++;
+
+ lpw = lpwAlign( lpw );
+ LPDLGITEMTEMPLATE lpdit = (LPDLGITEMTEMPLATE) lpw;
+ lpdit->x = ix;
+ lpdit->y = iy;
+ lpdit->cx = iw;
+ lpdit->cy = ih;
+ lpdit->id = ID_BUTTON1 - 1;
+ lpdit->style = WS_CHILD | WS_VISIBLE | SS_ICON;
+
+ lpw = (LPWORD) (lpdit + 1);
+ *lpw++ = 0xffff; *lpw++ = 0x0082; // Static class
+ *lpw++ = 0xffff; *lpw++ = (WORD) icon; // icon
+ *lpw++ = 0; // creation data
+ }
+
+
+ //---- define text ----
+
+ lpw = lpwAlign( lpw );
+ LPDLGITEMTEMPLATE lpdit = (LPDLGITEMTEMPLATE) lpw;
+ lpdit->x = tx;
+ lpdit->y = ty;
+ lpdit->cx = tw;
+ lpdit->cy = th;
+ lpdit->id = ID_BUTTON1 - 2;
+ lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT | SS_NOPREFIX | SS_EDITCONTROL;
+
+ lpw = (LPWORD) (lpdit + 1);
+ *lpw++ = 0xffff; *lpw++ = 0x0082; // Static class
+ wcscpy( (LPWSTR) lpw, wrappedText ); lpw += wcslen( wrappedText ) + 1; // text
+ *lpw++ = 0; // creation data
+
+
+ //---- define buttons ----
+
+ defaultButton = min( max( defaultButton, 0 ), buttonCount - 1 );
+ int buttonId = ID_BUTTON1;
+ for( int i = 0; i < buttonCount; i++ ) {
+ lpw = lpwAlign( lpw );
+ LPDLGITEMTEMPLATE lpdit = (LPDLGITEMTEMPLATE) lpw;
+ lpdit->x = bx;
+ lpdit->y = by;
+ lpdit->cx = bw[i];
+ lpdit->cy = BUTTON_HEIGHT;
+ lpdit->id = buttonId++;
+ lpdit->style = WS_CHILD | WS_VISIBLE | WS_TABSTOP | (i == 0 ? WS_GROUP : 0)
+ | BS_TEXT | (i == defaultButton ? BS_DEFPUSHBUTTON : BS_PUSHBUTTON);
+
+ lpw = (LPWORD) (lpdit + 1);
+ *lpw++ = 0xffff; *lpw++ = 0x0080; // Button class
+ wcscpy( (LPWSTR) lpw, buttons[i] ); lpw += wcslen( buttons[i] ) + 1; // text
+ *lpw++ = 0; // creation data
+
+ bx += bw[i] + BUTTON_GAP;
+ }
+
+ delete[] wrappedText;
+ delete[] bw;
+
+ return templ;
+}
+
+static BOOL CALLBACK focusDefaultButtonProc( HWND hwnd, LPARAM lParam ) {
+ if( ::GetWindowLong( hwnd, GWL_ID ) >= ID_BUTTON1 ) {
+ LONG style = ::GetWindowLong( hwnd, GWL_STYLE );
+ if( (style & BS_DEFPUSHBUTTON) != 0 ) {
+ ::SetFocus( hwnd );
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+static INT_PTR CALLBACK messageDialogProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) {
+ if( uMsg == WM_INITDIALOG )
+ ::EnumChildWindows( hwnd, focusDefaultButtonProc, 0 );
+ else if( uMsg == WM_COMMAND ) {
+ ::EndDialog( hwnd, wParam );
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static int textLengthAsDLUs( HDC hdc, LPCWSTR str, int strLen ) {
+ SIZE size{ 0 };
+ ::GetTextExtentPoint32( hdc, str, (strLen >= 0) ? strLen : wcslen( str ), &size );
+ return pixel2dluX( size.cx );
+}
+
+static LONG pixel2dluX( LONG px ) {
+ return MulDiv( px, 4, LOWORD( ::GetDialogBaseUnits() ) );
+}
+
+static LONG pixel2dluY( LONG py ) {
+ return MulDiv( py, 8, HIWORD( ::GetDialogBaseUnits() ) );
+}
+
+static LONG dluX2pixel( LONG dluX ) {
+ return MulDiv( dluX, LOWORD( ::GetDialogBaseUnits() ), 4 );
+}
+
+static LPWORD lpwAlign( LPWORD lpIn ) {
+ ULONG_PTR ul = (ULONG_PTR) lpIn;
+ ul += 3;
+ ul >>= 2;
+ ul <<= 2;
+ return (LPWORD) ul;
+}
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 18b9f377..b5b33245 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
@@ -124,9 +124,17 @@ JNIEXPORT jobjectArray JNICALL Java_com_formdev_flatlaf_ui_FlatNativeWindowsLibr
/*
* Class: com_formdev_flatlaf_ui_FlatNativeWindowsLibrary
* Method: showMessageDialog
- * Signature: (JLjava/lang/String;Ljava/lang/String;I)I
+ * Signature: (JILjava/lang/String;Ljava/lang/String;I[Ljava/lang/String;)I
*/
JNIEXPORT jint JNICALL Java_com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_showMessageDialog
+ (JNIEnv *, jclass, jlong, jint, jstring, jstring, jint, jobjectArray);
+
+/*
+ * Class: com_formdev_flatlaf_ui_FlatNativeWindowsLibrary
+ * Method: showMessageBox
+ * Signature: (JLjava/lang/String;Ljava/lang/String;I)I
+ */
+JNIEXPORT jint JNICALL Java_com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_showMessageBox
(JNIEnv *, jclass, jlong, jstring, jstring, jint);
#ifdef __cplusplus
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 621d00d8..cc36e77b 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
@@ -30,7 +30,10 @@ import java.awt.event.WindowListener;
import java.awt.event.WindowStateListener;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.prefs.Preferences;
import javax.swing.*;
+import javax.swing.border.TitledBorder;
+import com.formdev.flatlaf.demo.DemoPrefs;
import com.formdev.flatlaf.extras.components.*;
import com.formdev.flatlaf.extras.components.FlatTriStateCheckBox.State;
import com.formdev.flatlaf.ui.FlatNativeWindowsLibrary;
@@ -50,7 +53,7 @@ public class FlatSystemFileChooserWindowsTest
}
FlatTestFrame frame = FlatTestFrame.create( args, "FlatSystemFileChooserWindowsTest" );
- addListeners( frame );
+// addListeners( frame );
frame.showFrame( FlatSystemFileChooserWindowsTest::new );
} );
}
@@ -59,6 +62,10 @@ public class FlatSystemFileChooserWindowsTest
initComponents();
fileTypesField.setSelectedItem( null );
+
+ Preferences state = DemoPrefs.getState();
+ messageField.setText( state.get( "systemfilechooser.windows.message", "some message" ) );
+ buttonsField.setText( state.get( "systemfilechooser.windows.buttons", "OK" ) );
}
private void open() {
@@ -143,8 +150,8 @@ public class FlatSystemFileChooserWindowsTest
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 ) );
+ JOptionPane.INFORMATION_MESSAGE,
+ null, "some text", 1, "Yes", "No" ) );
}
return true;
};
@@ -189,6 +196,28 @@ public class FlatSystemFileChooserWindowsTest
optionsClear.set( optionsClear.get() | option );
}
+ private void messageDialog() {
+ long hwnd = getHWND( SwingUtilities.windowForComponent( this ) );
+ String message = messageField.getText();
+ String[] buttons = buttonsField.getText().trim().split( "[,]+" );
+
+ Preferences state = DemoPrefs.getState();
+ state.put( "systemfilechooser.windows.message", message );
+ state.put( "systemfilechooser.windows.buttons", buttonsField.getText() );
+
+ System.out.println( FlatNativeWindowsLibrary.showMessageDialog( hwnd,
+ JOptionPane.WARNING_MESSAGE, null, message, 1, buttons ) );
+ }
+
+ private void messageBox() {
+ long hwnd = getHWND( SwingUtilities.windowForComponent( this ) );
+ String message = messageField.getText();
+
+ System.out.println( FlatNativeWindowsLibrary.showMessageBox( hwnd, message, null,
+ /* MB_ICONINFORMATION */ 0x00000040 | /* MB_YESNO */ 0x00000004 ) );
+ }
+
+ @SuppressWarnings( "unused" )
private static void addListeners( Window w ) {
w.addWindowListener( new WindowListener() {
@Override
@@ -278,6 +307,12 @@ public class FlatSystemFileChooserWindowsTest
supportStreamableItemsCheckBox = new FlatTriStateCheckBox();
allowMultiSelectCheckBox = new FlatTriStateCheckBox();
hidePinnedPlacesCheckBox = new FlatTriStateCheckBox();
+ messageDialogPanel = new JPanel();
+ messageLabel = new JLabel();
+ messageScrollPane = new JScrollPane();
+ messageField = new JTextArea();
+ buttonsLabel = new JLabel();
+ buttonsField = new JTextField();
okButtonLabelLabel = new JLabel();
okButtonLabelField = new JTextField();
fileNameLabelLabel = new JLabel();
@@ -301,6 +336,9 @@ public class FlatSystemFileChooserWindowsTest
openDirectButton = new JButton();
saveDirectButton = new JButton();
showMessageDialogOnOKCheckBox = new JCheckBox();
+ hSpacer1 = new JPanel(null);
+ messageDialogButton = new JButton();
+ messageBoxButton = new JButton();
filesScrollPane = new JScrollPane();
filesField = new JTextArea();
@@ -365,7 +403,8 @@ public class FlatSystemFileChooserWindowsTest
"[]0" +
"[]0" +
"[]0" +
- "[]0"));
+ "[]0" +
+ "[grow]"));
//---- overwritePromptCheckBox ----
overwritePromptCheckBox.setText("overwritePrompt");
@@ -461,8 +500,41 @@ public class FlatSystemFileChooserWindowsTest
//---- hidePinnedPlacesCheckBox ----
hidePinnedPlacesCheckBox.setText("hidePinnedPlaces");
panel1.add(hidePinnedPlacesCheckBox, "cell 1 7");
+
+ //======== messageDialogPanel ========
+ {
+ messageDialogPanel.setBorder(new TitledBorder("MessageDialog"));
+ messageDialogPanel.setLayout(new MigLayout(
+ "hidemode 3",
+ // columns
+ "[fill]" +
+ "[grow,fill]",
+ // rows
+ "[grow,fill]" +
+ "[]"));
+
+ //---- messageLabel ----
+ messageLabel.setText("Message");
+ messageDialogPanel.add(messageLabel, "cell 0 0,aligny top,growy 0");
+
+ //======== messageScrollPane ========
+ {
+
+ //---- messageField ----
+ messageField.setColumns(40);
+ messageField.setRows(4);
+ messageScrollPane.setViewportView(messageField);
+ }
+ messageDialogPanel.add(messageScrollPane, "cell 1 0");
+
+ //---- buttonsLabel ----
+ buttonsLabel.setText("Buttons:");
+ messageDialogPanel.add(buttonsLabel, "cell 0 1");
+ messageDialogPanel.add(buttonsField, "cell 1 1");
+ }
+ panel1.add(messageDialogPanel, "cell 0 8 3 1,grow");
}
- add(panel1, "cell 2 1 1 10,aligny top,growy 0");
+ add(panel1, "cell 2 1 1 10,growy");
//---- okButtonLabelLabel ----
okButtonLabelLabel.setText("okButtonLabel");
@@ -548,6 +620,17 @@ public class FlatSystemFileChooserWindowsTest
//---- showMessageDialogOnOKCheckBox ----
showMessageDialogOnOKCheckBox.setText("show message dialog on OK");
add(showMessageDialogOnOKCheckBox, "cell 0 11 3 1");
+ add(hSpacer1, "cell 0 11 3 1,growx");
+
+ //---- messageDialogButton ----
+ messageDialogButton.setText("MessageDialog...");
+ messageDialogButton.addActionListener(e -> messageDialog());
+ add(messageDialogButton, "cell 0 11 3 1,alignx right,growx 0");
+
+ //---- messageBoxButton ----
+ messageBoxButton.setText("MessageBox...");
+ messageBoxButton.addActionListener(e -> messageBox());
+ add(messageBoxButton, "cell 0 11 3 1");
//======== filesScrollPane ========
{
@@ -598,6 +681,12 @@ public class FlatSystemFileChooserWindowsTest
private FlatTriStateCheckBox supportStreamableItemsCheckBox;
private FlatTriStateCheckBox allowMultiSelectCheckBox;
private FlatTriStateCheckBox hidePinnedPlacesCheckBox;
+ private JPanel messageDialogPanel;
+ private JLabel messageLabel;
+ private JScrollPane messageScrollPane;
+ private JTextArea messageField;
+ private JLabel buttonsLabel;
+ private JTextField buttonsField;
private JLabel okButtonLabelLabel;
private JTextField okButtonLabelField;
private JLabel fileNameLabelLabel;
@@ -621,6 +710,9 @@ public class FlatSystemFileChooserWindowsTest
private JButton openDirectButton;
private JButton saveDirectButton;
private JCheckBox showMessageDialogOnOKCheckBox;
+ private JPanel hSpacer1;
+ private JButton messageDialogButton;
+ private JButton messageBoxButton;
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 74e22930..040c5c82 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
@@ -56,7 +56,7 @@ new FormModel {
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"
+ "$rowConstraints": "[]0[]0[]0[][]0[]0[]0[]0[grow]"
} ) {
name: "panel1"
add( new FormComponent( "com.formdev.flatlaf.extras.components.FlatTriStateCheckBox" ) {
@@ -200,8 +200,45 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 7"
} )
+ add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
+ "$layoutConstraints": "hidemode 3"
+ "$columnConstraints": "[fill][grow,fill]"
+ "$rowConstraints": "[grow,fill][]"
+ } ) {
+ name: "messageDialogPanel"
+ "border": new javax.swing.border.TitledBorder( "MessageDialog" )
+ add( new FormComponent( "javax.swing.JLabel" ) {
+ name: "messageLabel"
+ "text": "Message"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 0 0,aligny top,growy 0"
+ } )
+ add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) {
+ name: "messageScrollPane"
+ add( new FormComponent( "javax.swing.JTextArea" ) {
+ name: "messageField"
+ "columns": 40
+ "rows": 4
+ } )
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 1 0"
+ } )
+ add( new FormComponent( "javax.swing.JLabel" ) {
+ name: "buttonsLabel"
+ "text": "Buttons:"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 0 1"
+ } )
+ add( new FormComponent( "javax.swing.JTextField" ) {
+ name: "buttonsField"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 1 1"
+ } )
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 0 8 3 1,grow"
+ } )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
- "value": "cell 2 1 1 10,aligny top,growy 0"
+ "value": "cell 2 1 1 10,growy"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "okButtonLabelLabel"
@@ -344,11 +381,30 @@ new FormModel {
"value": "cell 0 11 3 1"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
- name: "showMessageDialogsOnOKCheckBox"
+ name: "showMessageDialogOnOKCheckBox"
"text": "show message dialog on OK"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 11 3 1"
} )
+ add( new FormComponent( "com.jformdesigner.designer.wrapper.HSpacer" ) {
+ name: "hSpacer1"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 0 11 3 1,growx"
+ } )
+ add( new FormComponent( "javax.swing.JButton" ) {
+ name: "messageDialogButton"
+ "text": "MessageDialog..."
+ addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "messageDialog", false ) )
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 0 11 3 1,alignx right,growx 0"
+ } )
+ add( new FormComponent( "javax.swing.JButton" ) {
+ name: "messageBoxButton"
+ "text": "MessageBox..."
+ addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "messageBox", false ) )
+ }, 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" ) {
@@ -360,7 +416,7 @@ new FormModel {
} )
}, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 0, 0 )
- "size": new java.awt.Dimension( 845, 630 )
+ "size": new java.awt.Dimension( 890, 630 )
} )
add( new FormNonVisual( "javax.swing.ButtonGroup" ) {
name: "ownerButtonGroup"