diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ac0ca56..25f254a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,8 @@ FlatLaf Change Log - `2px` at `1.25x` and `2.25x` in **IntelliJ** and **Darcula** themes - OptionPane: Do not make child components, which are derived from `JPanel`, non-opaque. (issue #349) +- OptionPane: Align wrapped lines to the right if component orientation is + right-to-left. (issue #350) - Window decorations: Window title bar width is no longer considered when calculating preferred/minimum width of window. (issue #351) diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatOptionPaneUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatOptionPaneUI.java index f7632e33..7475ce9b 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatOptionPaneUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatOptionPaneUI.java @@ -22,7 +22,10 @@ import java.awt.Dimension; import java.awt.Graphics; import java.awt.GridBagConstraints; import java.awt.Insets; +import javax.swing.Box; +import javax.swing.BoxLayout; import javax.swing.JComponent; +import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.UIManager; import javax.swing.border.Border; @@ -160,6 +163,24 @@ public class FlatOptionPaneUI if( msg instanceof String && BasicHTML.isHTMLString( (String) msg ) ) maxll = Integer.MAX_VALUE; + // fix right-to-left alignment if super.addMessageComponents() breaks longer lines + // into multiple labels and puts them into a box that aligns them to the left + if( msg instanceof Box ) { + Box box = (Box) msg; + if( "OptionPane.verticalBox".equals( box.getName() ) && + box.getLayout() instanceof BoxLayout && + ((BoxLayout)box.getLayout()).getAxis() == BoxLayout.Y_AXIS ) + { + box.addPropertyChangeListener( "componentOrientation", e -> { + float alignX = box.getComponentOrientation().isLeftToRight() ? 0 : 1; + for( Component c : box.getComponents() ) { + if( c instanceof JLabel && "OptionPane.label".equals( c.getName() ) ) + ((JLabel)c).setAlignmentX( alignX ); + } + } ); + } + } + super.addMessageComponents( container, cons, msg, maxll, internallyCreated ); } diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatOptionPaneTest.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatOptionPaneTest.java index 38b90638..3c3cda88 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatOptionPaneTest.java +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatOptionPaneTest.java @@ -89,6 +89,10 @@ public class FlatOptionPaneTest JPanel panel6 = new JPanel(); customOptionPane = new JOptionPane(); FlatOptionPaneTest.ShowDialogLinkLabel customShowDialogLabel = new FlatOptionPaneTest.ShowDialogLinkLabel(); + JLabel rightToLeftLabel = new JLabel(); + JPanel panel10 = new JPanel(); + JOptionPane rightToLeftOptionPane = new JOptionPane(); + rightToLeftShowDialogLabel = new FlatOptionPaneTest.ShowDialogLinkLabel(); //======== this ======== setBorder(BorderFactory.createEmptyBorder()); @@ -109,6 +113,7 @@ public class FlatOptionPaneTest "[top]" + "[top]" + "[top]" + + "[top]" + "[top]")); //---- plainLabel ---- @@ -283,6 +288,28 @@ public class FlatOptionPaneTest customShowDialogLabel.setOptionPane(customOptionPane); customShowDialogLabel.setTitleLabel(customLabel); panel9.add(customShowDialogLabel, "cell 2 7"); + + //---- rightToLeftLabel ---- + rightToLeftLabel.setText("Right-to-left:"); + panel9.add(rightToLeftLabel, "cell 0 8"); + + //======== panel10 ======== + { + panel10.setBorder(LineBorder.createGrayLineBorder()); + panel10.setLayout(new BorderLayout()); + + //---- rightToLeftOptionPane ---- + rightToLeftOptionPane.setMessageType(JOptionPane.INFORMATION_MESSAGE); + rightToLeftOptionPane.setMessage("\u0627\u0644\u0645\u0627\u062f\u0629 1 \u064a\u0648\u0644\u062f \u062c\u0645\u064a\u0639 \u0627\u0644\u0646\u0627\u0633 \u0623\u062d\u0631\u0627\u0631\u064b\u0627 \u0645\u062a\u0633\u0627\u0648\u064a\u0646 \u0641\u064a \u0627\u0644\u0643\u0631\u0627\u0645\u0629 \u0648\u0627\u0644\u062d\u0642\u0648\u0642. \u0648\u0642\u062f \u0648\u0647\u0628\u0648\u0627 \u0639\u0642\u0644\u0627\u064b \u0648\u0636\u0645\u064a\u0631\u064b\u0627 \u0648\u0639\u0644\u064a\u0647\u0645 \u0623\u0646 \u064a\u0639\u0627\u0645\u0644 \u0628\u0639\u0636\u0647\u0645 \u0628\u0639\u0636\u064b\u0627 \u0628\u0631\u0648\u062d \u0627\u0644\u0625\u062e\u0627\u0621.\n\u0627\u0644\u0645\u0627\u062f\u0629 1 \u064a\u0648\u0644\u062f \u062c\u0645\u064a\u0639 \u0627\u0644\u0646\u0627\u0633 \u0623\u062d\u0631\u0627\u0631\u064b\u0627 \u0645\u062a\u0633\u0627\u0648\u064a\u0646 \u0641\u064a \u0627\u0644\u0643\u0631\u0627\u0645\u0629 \u0648\u0627\u0644\u062d\u0642\u0648\u0642. \u0648\u0642\u062f \u0648\u0647\u0628\u0648\u0627 \u0639\u0642\u0644\u0627\u064b \u0648\u0636\u0645\u064a\u0631\u064b\u0627 \u0648\u0639\u0644\u064a\u0647\u0645 \u0623\u0646 \u064a\u0639\u0627\u0645\u0644 \u0628\u0639\u0636\u0647\u0645 \u0628\u0639\u0636\u064b\u0627 \u0628\u0631\u0648\u062d \u0627\u0644\u0625\u062e\u0627\u0621.\n\n\u0627\u0644\u0645\u0627\u062f\u0629 1 \u064a\u0648\u0644\u062f \u062c\u0645\u064a\u0639 \u0627\u0644\u0646\u0627\u0633 \u0623\u062d\u0631\u0627\u0631\u064b\u0627 \u0645\u062a\u0633\u0627\u0648\u064a\u0646 \u0641\u064a \u0627\u0644\u0643\u0631\u0627\u0645\u0629 \n\u0648\u0627\u0644\u062d\u0642\u0648\u0642. \u0648\u0642\u062f \u0648\u0647\u0628\u0648\u0627 \u0639\u0642\u0644\u0627\u064b \u0648\u0636\u0645\u064a\u0631\u064b\u0627 \u0648\u0639\u0644\u064a\u0647\u0645 \u0623\u0646 \u064a\u0639\u0627\u0645\u0644 \u0628\u0639\u0636\u0647\u0645 \u0628\u0639\u0636\u064b\u0627 \u0628\u0631\u0648\u062d \u0627\u0644\u0625\u062e\u0627\u0621."); + rightToLeftOptionPane.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT); + panel10.add(rightToLeftOptionPane, BorderLayout.CENTER); + } + panel9.add(panel10, "cell 1 8"); + + //---- rightToLeftShowDialogLabel ---- + rightToLeftShowDialogLabel.setOptionPane(rightToLeftOptionPane); + rightToLeftShowDialogLabel.setTitleLabel(rightToLeftLabel); + panel9.add(rightToLeftShowDialogLabel, "cell 2 8"); } setViewportView(panel9); // JFormDesigner - End of component initialization //GEN-END:initComponents @@ -293,6 +320,7 @@ public class FlatOptionPaneTest private FlatOptionPaneTest.ShowDialogLinkLabel errorShowDialogLabel; private FlatOptionPaneTest.ShowDialogLinkLabel informationShowDialogLabel; private JOptionPane customOptionPane; + private FlatOptionPaneTest.ShowDialogLinkLabel rightToLeftShowDialogLabel; // JFormDesigner - End of variables declaration //GEN-END:variables //---- class ShowDialogLinkLabel ------------------------------------------ @@ -315,9 +343,15 @@ public class FlatOptionPaneTest } private void showDialog() { + Component parent = SwingUtilities.windowForComponent( this ); + + // use optionPane as parent if component orientation is different + if( parent.getComponentOrientation().isLeftToRight() != optionPane.getComponentOrientation().isLeftToRight() ) + parent = optionPane; + if( optionPane.getWantsInput() ) { JOptionPane.showInputDialog( - getParent(), + parent, optionPane.getMessage(), titleLabel.getText() + " Title", optionPane.getMessageType(), @@ -326,7 +360,7 @@ public class FlatOptionPaneTest null ); } else { JOptionPane.showOptionDialog( - getParent(), + parent, optionPane.getMessage(), titleLabel.getText() + " Title", optionPane.getOptionType(), diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatOptionPaneTest.jfd b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatOptionPaneTest.jfd index ff83c766..78d9bf17 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatOptionPaneTest.jfd +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatOptionPaneTest.jfd @@ -1,4 +1,4 @@ -JFDML JFormDesigner: "7.0.1.0.272" Java: "13.0.2" encoding: "UTF-8" +JFDML JFormDesigner: "7.0.4.0.360" Java: "16" encoding: "UTF-8" new FormModel { contentType: "form/swing" @@ -12,7 +12,7 @@ new FormModel { add( new FormContainer( "com.formdev.flatlaf.demo.ScrollablePanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { "$layoutConstraints": "flowy,ltr,insets dialog,hidemode 3" "$columnConstraints": "[][][fill]" - "$rowConstraints": "[top][top][top][top][top][top][top][top]" + "$rowConstraints": "[top][top][top][top][top][top][top][top][top]" } ) { name: "panel9" add( new FormComponent( "javax.swing.JLabel" ) { @@ -240,10 +240,40 @@ new FormModel { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 2 7" } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "rightToLeftLabel" + "text": "Right-to-left:" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 8" + } ) + add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class java.awt.BorderLayout ) ) { + name: "panel10" + "border": #LineBorder0 + add( new FormComponent( "javax.swing.JOptionPane" ) { + name: "rightToLeftOptionPane" + "messageType": 1 + "message": "المادة 1 يولد جميع الناس أحرارًا متساوين في الكرامة والحقوق. وقد وهبوا عقلاً وضميرًا وعليهم أن يعامل بعضهم بعضًا بروح الإخاء.\nالمادة 1 يولد جميع الناس أحرارًا متساوين في الكرامة والحقوق. وقد وهبوا عقلاً وضميرًا وعليهم أن يعامل بعضهم بعضًا بروح الإخاء.\n\nالمادة 1 يولد جميع الناس أحرارًا متساوين في الكرامة \nوالحقوق. وقد وهبوا عقلاً وضميرًا وعليهم أن يعامل بعضهم بعضًا بروح الإخاء." + "componentOrientation": sfield java.awt.ComponentOrientation RIGHT_TO_LEFT + }, new FormLayoutConstraints( class java.lang.String ) { + "value": "Center" + } ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 8" + } ) + add( new FormComponent( "com.formdev.flatlaf.testing.FlatOptionPaneTest$ShowDialogLinkLabel" ) { + name: "rightToLeftShowDialogLabel" + "optionPane": new FormReference( "rightToLeftOptionPane" ) + "titleLabel": new FormReference( "rightToLeftLabel" ) + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 2 8" + } ) } ) }, new FormLayoutConstraints( null ) { "location": new java.awt.Point( 0, 0 ) - "size": new java.awt.Dimension( 840, 900 ) + "size": new java.awt.Dimension( 895, 1080 ) } ) } }