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 353b10b0..9ebdda20 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 @@ -138,9 +138,10 @@ public class FlatNativeLinuxLibrary * 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; 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} + * @param okButtonLabel text displayed in default button; or {@code null}. Use '_' for mnemonics (e.g. "_Choose") * @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} * @param optionsSet options to set; see {@code FOS_*} constants @@ -156,7 +157,7 @@ public class FlatNativeLinuxLibrary * * @since 3.6 */ - public native static String[] showFileChooser( boolean open, + 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 ); } 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 ca048af5..01017446 100644 --- a/flatlaf-natives/flatlaf-natives-linux/src/main/cpp/GtkFileChooser.cpp +++ b/flatlaf-natives/flatlaf-natives-linux/src/main/cpp/GtkFileChooser.cpp @@ -26,6 +26,9 @@ * @since 3.6 */ +// see X11WmUtils.cpp +Window getWindowHandle( JNIEnv* env, JAWT* awt, jobject window, Display** display_return ); + //---- class AutoReleaseStringUTF8 -------------------------------------------- class AutoReleaseStringUTF8 { @@ -86,10 +89,65 @@ void initFilters( GtkFileChooser* chooser, JNIEnv* env, jint fileTypeIndex, jobj } } +GdkWindow* getGdkWindow( JNIEnv* env, jobject window ) { + // get the AWT + JAWT awt; + awt.version = JAWT_VERSION_1_4; + if( !JAWT_GetAWT( env, &awt ) ) + return NULL; + + // get Xlib window and display from AWT window + Display* display; + Window w = getWindowHandle( env, &awt, window, &display ); + if( w == 0 ) + return NULL; + + // based on GetAllocNativeWindowHandle() from https://github.com/btzy/nativefiledialog-extended + // https://github.com/btzy/nativefiledialog-extended/blob/29e3bcb578345b9fa345d1d7683f00c150565ca3/src/nfd_gtk.cpp#L384-L437 + GdkDisplay* gdkDisplay = gdk_x11_lookup_xdisplay( display ); + if( gdkDisplay == NULL ) { + // search for existing X11 display (there should only be one, even if multiple screens are connected) + GdkDisplayManager* displayManager = gdk_display_manager_get(); + GSList* displays = gdk_display_manager_list_displays( displayManager ); + for( GSList* l = displays; l; l = l->next ) { + if( GDK_IS_X11_DISPLAY( l->data ) ) { + gdkDisplay = GDK_DISPLAY( l->data ); + break; + } + } + g_slist_free( displays ); + + // create our own X11 display + if( gdkDisplay == NULL ) { + gdk_set_allowed_backends( "x11" ); + gdkDisplay = gdk_display_manager_open_display( displayManager, NULL ); + gdk_set_allowed_backends( NULL ); + + if( gdkDisplay == NULL ) + return NULL; + } + } + + return gdk_x11_window_foreign_new_for_display( gdkDisplay, w ); +} + +static void handle_realize( GtkWidget* dialog, gpointer data ) { + GdkWindow* gdkOwner = static_cast( data ); + + // make file dialog a transient of owner window, + // which centers file dialog on owner and keeps file dialog above owner + gdk_window_set_transient_for( gtk_widget_get_window( dialog ), gdkOwner ); + + // necessary because gdk_x11_window_foreign_new_for_display() increases the reference counter + g_object_unref( gdkOwner ); +} + 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 ) ); + // hide/destroy file dialog and quit loop gtk_widget_hide( dialog ); gtk_widget_destroy( dialog ); gtk_main_quit(); @@ -99,7 +157,7 @@ static void handle_response( GtkWidget* dialog, gint responseId, gpointer data ) extern "C" JNIEXPORT jobjectArray JNICALL Java_com_formdev_flatlaf_ui_FlatNativeLinuxLibrary_showFileChooser - ( JNIEnv* env, jclass cls, jboolean open, + ( JNIEnv* env, jclass cls, jobject owner, jboolean open, jstring title, jstring okButtonLabel, jstring currentName, jstring currentFolder, jint optionsSet, jint optionsClear, jint fileTypeIndex, jobjectArray fileTypes ) { @@ -129,11 +187,13 @@ JNIEXPORT jobjectArray JNICALL Java_com_formdev_flatlaf_ui_FlatNativeLinuxLibrar NULL ); // marks end of buttons GtkFileChooser* chooser = GTK_FILE_CHOOSER( dialog ); + // set current name and folder if( !open && ccurrentName != NULL ) gtk_file_chooser_set_current_name( chooser, ccurrentName ); if( ccurrentFolder != NULL ) gtk_file_chooser_set_current_folder( chooser, ccurrentFolder ); + // set options if( isOptionSetOrClear( FC_select_multiple ) ) gtk_file_chooser_set_select_multiple( chooser, isOptionSet( FC_select_multiple ) ); if( isOptionSetOrClear( FC_show_hidden ) ) @@ -145,15 +205,39 @@ JNIEXPORT jobjectArray JNICALL Java_com_formdev_flatlaf_ui_FlatNativeLinuxLibrar if( isOptionSetOrClear( FC_create_folders ) ) gtk_file_chooser_set_create_folders( chooser, isOptionSet( FC_create_folders ) ); + // initialize filter initFilters( chooser, env, fileTypeIndex, fileTypes ); - gtk_window_set_modal( GTK_WINDOW( dialog ), true ); + // setup modality + GdkWindow* gdkOwner = (owner != NULL) ? getGdkWindow( env, owner ) : NULL; + if( gdkOwner != NULL ) { + gtk_window_set_modal( GTK_WINDOW( dialog ), true ); + + // file dialog should use same screen as owner + gtk_window_set_screen( GTK_WINDOW( dialog ), gdk_window_get_screen( gdkOwner ) ); + + // set the transient when the file dialog is realized + g_signal_connect( dialog, "realize", G_CALLBACK( handle_realize ), gdkOwner ); + } // 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 ); + g_signal_connect( dialog, "response", G_CALLBACK( handle_response ), &fileList ); gtk_widget_show( dialog ); + + // necessary to bring file dialog to the front (and make it active) + // see issues: + // https://github.com/btzy/nativefiledialog-extended/issues/31 + // https://github.com/mlabbe/nativefiledialog/pull/92 + // https://github.com/guillaumechereau/noc/pull/11 + if( GDK_IS_X11_DISPLAY( gtk_widget_get_display( GTK_WIDGET( dialog ) ) ) ) { + GdkWindow* gdkWindow = gtk_widget_get_window( GTK_WIDGET( dialog ) ); + gdk_window_set_events( gdkWindow, static_cast( gdk_window_get_events( gdkWindow ) | GDK_PROPERTY_CHANGE_MASK ) ); + gtk_window_present_with_time( GTK_WINDOW( dialog ), gdk_x11_get_server_time( gdkWindow ) ); + } + + // start event loop (will be quit in respone handler) gtk_main(); // canceled? 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 dd0436a0..4ca717bb 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,10 @@ JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeLinuxLibrary_xS /* * Class: com_formdev_flatlaf_ui_FlatNativeLinuxLibrary * Method: showFileChooser - * Signature: (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;III[Ljava/lang/String;)[Ljava/lang/String; */ JNIEXPORT jobjectArray JNICALL Java_com_formdev_flatlaf_ui_FlatNativeLinuxLibrary_showFileChooser - (JNIEnv *, jclass, jboolean, jstring, jstring, jstring, jstring, jint, jint, jint, jobjectArray); + (JNIEnv *, jclass, jobject, jboolean, jstring, jstring, jstring, jstring, jint, jint, jint, jobjectArray); #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 ecb0e439..05289d16 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 @@ -17,10 +17,12 @@ package com.formdev.flatlaf.testing; import static com.formdev.flatlaf.ui.FlatNativeLinuxLibrary.*; +import java.awt.Dialog; import java.awt.EventQueue; import java.awt.SecondaryLoop; import java.awt.Toolkit; import java.awt.Window; +import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.event.WindowFocusListener; import java.awt.event.WindowListener; @@ -75,6 +77,26 @@ public class FlatSystemFileChooserLinuxTest } private void openOrSave( boolean open, boolean direct ) { + Window frame = SwingUtilities.windowForComponent( this ); + if( ownerFrameRadioButton.isSelected() ) + openOrSave( open, direct, frame ); + else if( ownerDialogRadioButton.isSelected() ) { + JDialog dialog = new JDialog( frame, "Dummy Modal Dialog", Dialog.DEFAULT_MODALITY_TYPE ); + dialog.setDefaultCloseOperation( JDialog.DISPOSE_ON_CLOSE ); + dialog.addWindowListener( new WindowAdapter() { + @Override + public void windowOpened( WindowEvent e ) { + openOrSave( open, direct, dialog ); + } + } ); + dialog.setSize( 1200, 1000 ); + dialog.setLocationRelativeTo( this ); + dialog.setVisible( true ); + } else + openOrSave( open, direct, null ); + } + + private void openOrSave( boolean open, boolean direct, Window owner ) { String title = n( titleField.getText() ); String okButtonLabel = n( okButtonLabelField.getText() ); String currentName = n( currentNameField.getText() ); @@ -103,7 +125,7 @@ public class FlatSystemFileChooserLinuxTest int fileTypeIndex = fileTypeIndexSlider.getValue(); if( direct ) { - String[] files = FlatNativeLinuxLibrary.showFileChooser( open, + String[] files = FlatNativeLinuxLibrary.showFileChooser( owner, open, title, okButtonLabel, currentName, currentFolder, optionsSet.get(), optionsClear.get(), fileTypeIndex, fileTypes ); @@ -113,7 +135,7 @@ public class FlatSystemFileChooserLinuxTest String[] fileTypes2 = fileTypes; new Thread( () -> { - String[] files = FlatNativeLinuxLibrary.showFileChooser( open, + String[] files = FlatNativeLinuxLibrary.showFileChooser( owner, open, title, okButtonLabel, currentName, currentFolder, optionsSet.get(), optionsClear.get(), fileTypeIndex, fileTypes2 ); @@ -198,6 +220,11 @@ public class FlatSystemFileChooserLinuxTest private void initComponents() { // JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents + ownerLabel = new JLabel(); + ownerFrameRadioButton = new JRadioButton(); + ownerDialogRadioButton = new JRadioButton(); + ownerNullRadioButton = new JRadioButton(); + ownerSpacer = new JPanel(null); titleLabel = new JLabel(); titleField = new JTextField(); panel1 = new JPanel(); @@ -239,12 +266,31 @@ public class FlatSystemFileChooserLinuxTest "[]" + "[]" + "[]" + + "[]" + "[grow,fill]")); + //---- ownerLabel ---- + ownerLabel.setText("owner"); + add(ownerLabel, "cell 0 0"); + + //---- ownerFrameRadioButton ---- + ownerFrameRadioButton.setText("JFrame"); + ownerFrameRadioButton.setSelected(true); + add(ownerFrameRadioButton, "cell 1 0"); + + //---- ownerDialogRadioButton ---- + ownerDialogRadioButton.setText("JDialog"); + add(ownerDialogRadioButton, "cell 1 0"); + + //---- ownerNullRadioButton ---- + ownerNullRadioButton.setText("null"); + add(ownerNullRadioButton, "cell 1 0"); + add(ownerSpacer, "cell 1 0,growx"); + //---- titleLabel ---- titleLabel.setText("title"); - add(titleLabel, "cell 0 0"); - add(titleField, "cell 1 0"); + add(titleLabel, "cell 0 1"); + add(titleField, "cell 1 1"); //======== panel1 ======== { @@ -288,26 +334,26 @@ public class FlatSystemFileChooserLinuxTest local_onlyCheckBox.setText("local_only"); panel1.add(local_onlyCheckBox, "cell 0 5"); } - add(panel1, "cell 2 0 1 6,aligny top,growy 0"); + add(panel1, "cell 2 1 1 6,aligny top,growy 0"); //---- okButtonLabelLabel ---- okButtonLabelLabel.setText("okButtonLabel"); - add(okButtonLabelLabel, "cell 0 1"); - add(okButtonLabelField, "cell 1 1"); + add(okButtonLabelLabel, "cell 0 2"); + add(okButtonLabelField, "cell 1 2"); //---- currentNameLabel ---- currentNameLabel.setText("currentName"); - add(currentNameLabel, "cell 0 2"); - add(currentNameField, "cell 1 2"); + add(currentNameLabel, "cell 0 3"); + add(currentNameField, "cell 1 3"); //---- currentFolderLabel ---- currentFolderLabel.setText("currentFolder"); - add(currentFolderLabel, "cell 0 3"); - add(currentFolderField, "cell 1 3"); + add(currentFolderLabel, "cell 0 4"); + add(currentFolderField, "cell 1 4"); //---- fileTypesLabel ---- fileTypesLabel.setText("fileTypes"); - add(fileTypesLabel, "cell 0 4"); + add(fileTypesLabel, "cell 0 5"); //---- fileTypesField ---- fileTypesField.setEditable(true); @@ -317,11 +363,11 @@ public class FlatSystemFileChooserLinuxTest "Text Files,*.txt,null,PDF Files,*.pdf,null,All Files,*,null", "Text and PDF Files,*.txt,*.pdf,null" })); - add(fileTypesField, "cell 1 4"); + add(fileTypesField, "cell 1 5"); //---- fileTypeIndexLabel ---- fileTypeIndexLabel.setText("fileTypeIndex"); - add(fileTypeIndexLabel, "cell 0 5"); + add(fileTypeIndexLabel, "cell 0 6"); //---- fileTypeIndexSlider ---- fileTypeIndexSlider.setMaximum(10); @@ -329,27 +375,27 @@ public class FlatSystemFileChooserLinuxTest fileTypeIndexSlider.setValue(0); fileTypeIndexSlider.setPaintLabels(true); fileTypeIndexSlider.setSnapToTicks(true); - add(fileTypeIndexSlider, "cell 1 5"); + add(fileTypeIndexSlider, "cell 1 6"); //---- openButton ---- openButton.setText("Open..."); openButton.addActionListener(e -> open()); - add(openButton, "cell 0 6 3 1"); + add(openButton, "cell 0 7 3 1"); //---- saveButton ---- saveButton.setText("Save..."); saveButton.addActionListener(e -> save()); - add(saveButton, "cell 0 6 3 1"); + add(saveButton, "cell 0 7 3 1"); //---- openDirectButton ---- openDirectButton.setText("Open (no-thread)..."); openDirectButton.addActionListener(e -> openDirect()); - add(openDirectButton, "cell 0 6 3 1"); + add(openDirectButton, "cell 0 7 3 1"); //---- saveDirectButton ---- saveDirectButton.setText("Save (no-thread)..."); saveDirectButton.addActionListener(e -> saveDirect()); - add(saveDirectButton, "cell 0 6 3 1"); + add(saveDirectButton, "cell 0 7 3 1"); //======== filesScrollPane ======== { @@ -358,11 +404,22 @@ public class FlatSystemFileChooserLinuxTest filesField.setRows(8); filesScrollPane.setViewportView(filesField); } - add(filesScrollPane, "cell 0 7 3 1,growx"); + add(filesScrollPane, "cell 0 8 3 1,growx"); + + //---- ownerButtonGroup ---- + ButtonGroup ownerButtonGroup = new ButtonGroup(); + ownerButtonGroup.add(ownerFrameRadioButton); + ownerButtonGroup.add(ownerDialogRadioButton); + ownerButtonGroup.add(ownerNullRadioButton); // JFormDesigner - End of component initialization //GEN-END:initComponents } // JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables + private JLabel ownerLabel; + private JRadioButton ownerFrameRadioButton; + private JRadioButton ownerDialogRadioButton; + private JRadioButton ownerNullRadioButton; + private JPanel ownerSpacer; private JLabel titleLabel; private JTextField titleField; private JPanel panel1; 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 2c463484..d172fc00 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 @@ -6,19 +6,52 @@ new FormModel { 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]" + "$rowConstraints": "[][][][][][][][][grow,fill]" } ) { name: "this" + add( new FormComponent( "javax.swing.JLabel" ) { + name: "ownerLabel" + "text": "owner" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 0" + } ) + add( new FormComponent( "javax.swing.JRadioButton" ) { + name: "ownerFrameRadioButton" + "text": "JFrame" + "$buttonGroup": new FormReference( "ownerButtonGroup" ) + "selected": true + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 0" + } ) + add( new FormComponent( "javax.swing.JRadioButton" ) { + name: "ownerDialogRadioButton" + "text": "JDialog" + "$buttonGroup": new FormReference( "ownerButtonGroup" ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 0" + } ) + add( new FormComponent( "javax.swing.JRadioButton" ) { + name: "ownerNullRadioButton" + "text": "null" + "$buttonGroup": new FormReference( "ownerButtonGroup" ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 0" + } ) + add( new FormComponent( "com.jformdesigner.designer.wrapper.HSpacer" ) { + name: "ownerSpacer" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 0,growx" + } ) add( new FormComponent( "javax.swing.JLabel" ) { name: "titleLabel" "text": "title" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 0" + "value": "cell 0 1" } ) add( new FormComponent( "javax.swing.JTextField" ) { name: "titleField" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 0" + "value": "cell 1 1" } ) add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { "$layoutConstraints": "insets 2,hidemode 3" @@ -67,46 +100,46 @@ new FormModel { "value": "cell 0 5" } ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 2 0 1 6,aligny top,growy 0" + "value": "cell 2 1 1 6,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" + "value": "cell 0 2" } ) add( new FormComponent( "javax.swing.JTextField" ) { name: "okButtonLabelField" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 1" + "value": "cell 1 2" } ) add( new FormComponent( "javax.swing.JLabel" ) { name: "currentNameLabel" "text": "currentName" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 2" + "value": "cell 0 3" } ) add( new FormComponent( "javax.swing.JTextField" ) { name: "currentNameField" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 2" + "value": "cell 1 3" } ) add( new FormComponent( "javax.swing.JLabel" ) { name: "currentFolderLabel" "text": "currentFolder" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 3" + "value": "cell 0 4" } ) add( new FormComponent( "javax.swing.JTextField" ) { name: "currentFolderField" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 3" + "value": "cell 1 4" } ) add( new FormComponent( "javax.swing.JLabel" ) { name: "fileTypesLabel" "text": "fileTypes" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 4" + "value": "cell 0 5" } ) add( new FormComponent( "javax.swing.JComboBox" ) { name: "fileTypesField" @@ -119,13 +152,13 @@ new FormModel { addElement( "Text and PDF Files,*.txt,*.pdf,null" ) } }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 4" + "value": "cell 1 5" } ) add( new FormComponent( "javax.swing.JLabel" ) { name: "fileTypeIndexLabel" "text": "fileTypeIndex" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 5" + "value": "cell 0 6" } ) add( new FormComponent( "javax.swing.JSlider" ) { name: "fileTypeIndexSlider" @@ -135,35 +168,35 @@ new FormModel { "paintLabels": true "snapToTicks": true }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 5" + "value": "cell 1 6" } ) add( new FormComponent( "javax.swing.JButton" ) { name: "openButton" "text": "Open..." addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "open", false ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 6 3 1" + "value": "cell 0 7 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 6 3 1" + "value": "cell 0 7 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 6 3 1" + "value": "cell 0 7 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 6 3 1" + "value": "cell 0 7 3 1" } ) add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) { name: "filesScrollPane" @@ -172,11 +205,16 @@ new FormModel { "rows": 8 } ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 7 3 1,growx" + "value": "cell 0 8 3 1,growx" } ) }, new FormLayoutConstraints( null ) { "location": new java.awt.Point( 0, 0 ) "size": new java.awt.Dimension( 690, 630 ) } ) + add( new FormNonVisual( "javax.swing.ButtonGroup" ) { + name: "ownerButtonGroup" + }, new FormLayoutConstraints( null ) { + "location": new java.awt.Point( 0, 640 ) + } ) } }