Merge main into system-file-chooser

This commit is contained in:
Karl Tauber
2025-03-09 19:20:54 +01:00
170 changed files with 18264 additions and 5666 deletions

View File

@@ -0,0 +1,228 @@
/*
* 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.
* 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 java.awt.Dimension;
import java.awt.FlowLayout;
import java.net.URL;
import java.net.URLClassLoader;
import javax.swing.*;
/**
* java -classpath "<FlatLaf-root>/flatlaf-testing/bin/main" com.formdev.flatlaf.testing.FlatClassLoaderTest
*
* @author Karl Tauber
*/
public class FlatClassLoaderTest
extends JPanel
{
public static void main( String[] args ) {
try {
Class.forName( "com.formdev.flatlaf.FlatDarkLaf" );
System.err.println( "Run without FlatLaf on classpath" );
return;
} catch( ClassNotFoundException ex ) {
// continue
} catch( Exception ex ) {
ex.printStackTrace();
return;
}
if( FlatClassLoaderTest.class.getResource( "/META-INF/services/com.formdev.flatlaf.FlatDefaultsAddon" ) != null ) {
System.err.println( "Remove file 'META-INF/services/com.formdev.flatlaf.FlatDefaultsAddon'" );
return;
}
try {
@SuppressWarnings( "resource" )
URLClassLoader cl = new URLClassLoader( new URL[] {
new URL( "file", null, "../flatlaf-core/bin/main/" )
}, FlatClassLoaderTest.class.getClassLoader() );
Class<?> lafClass = cl.loadClass( "com.formdev.flatlaf.FlatDarkLaf" );
LookAndFeel laf = (LookAndFeel) lafClass.getDeclaredConstructor().newInstance();
UIManager.setLookAndFeel( laf );
JFrame frame = new JFrame( "FlatClassloaderTest" );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.add( new FlatClassLoaderTest() );
frame.setBounds( 100, 100, 600, 400 );
frame.setVisible( true );
} catch( Exception ex ) {
ex.printStackTrace();
}
}
private FlatClassLoaderTest() {
initComponents();
}
private void initComponents() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
JLabel label1 = new JLabel();
JTextField textField1 = new JTextField();
JComboBox<String> comboBox1 = new JComboBox<>();
JButton button1 = new JButton();
JCheckBox checkBox1 = new JCheckBox();
JRadioButton radioButton1 = new JRadioButton();
JToggleButton toggleButton1 = new JToggleButton();
JScrollPane scrollPane1 = new JScrollPane();
JTextArea textArea1 = new JTextArea();
JFormattedTextField formattedTextField1 = new JFormattedTextField();
JPasswordField passwordField1 = new JPasswordField();
JScrollPane scrollPane2 = new JScrollPane();
JTextPane textPane1 = new JTextPane();
JScrollPane scrollPane3 = new JScrollPane();
JEditorPane editorPane1 = new JEditorPane();
JSpinner spinner1 = new JSpinner();
JScrollPane scrollPane4 = new JScrollPane();
JList<String> list1 = new JList<>();
JScrollPane scrollPane5 = new JScrollPane();
JTable table1 = new JTable();
JScrollPane scrollPane6 = new JScrollPane();
JTree tree1 = new JTree();
JProgressBar progressBar1 = new JProgressBar();
JScrollBar scrollBar1 = new JScrollBar();
JSeparator separator1 = new JSeparator();
JSlider slider1 = new JSlider();
JPanel panel1 = new JPanel();
JTabbedPane tabbedPane1 = new JTabbedPane();
JSplitPane splitPane1 = new JSplitPane();
JToolBar toolBar1 = new JToolBar();
JMenuBar menuBar1 = new JMenuBar();
JMenu menu1 = new JMenu();
JMenuItem menuItem1 = new JMenuItem();
JCheckBoxMenuItem checkBoxMenuItem1 = new JCheckBoxMenuItem();
JRadioButtonMenuItem radioButtonMenuItem1 = new JRadioButtonMenuItem();
//======== this ========
setLayout(new FlowLayout());
//---- label1 ----
label1.setText("text");
add(label1);
add(textField1);
add(comboBox1);
//---- button1 ----
button1.setText("text");
add(button1);
//---- checkBox1 ----
checkBox1.setText("text");
add(checkBox1);
//---- radioButton1 ----
radioButton1.setText("text");
add(radioButton1);
//---- toggleButton1 ----
toggleButton1.setText("text");
add(toggleButton1);
//======== scrollPane1 ========
{
scrollPane1.setViewportView(textArea1);
}
add(scrollPane1);
add(formattedTextField1);
add(passwordField1);
//======== scrollPane2 ========
{
scrollPane2.setViewportView(textPane1);
}
add(scrollPane2);
//======== scrollPane3 ========
{
scrollPane3.setViewportView(editorPane1);
}
add(scrollPane3);
add(spinner1);
//======== scrollPane4 ========
{
scrollPane4.setViewportView(list1);
}
add(scrollPane4);
//======== scrollPane5 ========
{
//---- table1 ----
table1.setPreferredScrollableViewportSize(new Dimension(100, 80));
scrollPane5.setViewportView(table1);
}
add(scrollPane5);
//======== scrollPane6 ========
{
//---- tree1 ----
tree1.setVisibleRowCount(6);
scrollPane6.setViewportView(tree1);
}
add(scrollPane6);
add(progressBar1);
add(scrollBar1);
add(separator1);
add(slider1);
//======== panel1 ========
{
panel1.setLayout(new BoxLayout(panel1, BoxLayout.X_AXIS));
}
add(panel1);
add(tabbedPane1);
add(splitPane1);
//======== toolBar1 ========
{
toolBar1.addSeparator();
}
add(toolBar1);
//======== menuBar1 ========
{
//======== menu1 ========
{
menu1.setText("text");
//---- menuItem1 ----
menuItem1.setText("text");
menu1.add(menuItem1);
//---- checkBoxMenuItem1 ----
checkBoxMenuItem1.setText("text");
menu1.add(checkBoxMenuItem1);
//---- radioButtonMenuItem1 ----
radioButtonMenuItem1.setText("text");
menu1.add(radioButtonMenuItem1);
menu1.addSeparator();
}
menuBar1.add(menu1);
}
add(menuBar1);
// JFormDesigner - End of component initialization //GEN-END:initComponents
}
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
// JFormDesigner - End of variables declaration //GEN-END:variables
}

View File

@@ -0,0 +1,146 @@
JFDML JFormDesigner: "8.3" encoding: "UTF-8"
new FormModel {
contentType: "form/swing"
root: new FormRoot {
auxiliary() {
"JavaCodeGenerator.defaultVariableLocal": true
}
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class java.awt.FlowLayout ) ) {
name: "this"
add( new FormComponent( "javax.swing.JLabel" ) {
name: "label1"
"text": "text"
} )
add( new FormComponent( "javax.swing.JTextField" ) {
name: "textField1"
} )
add( new FormComponent( "javax.swing.JComboBox" ) {
name: "comboBox1"
auxiliary() {
"JavaCodeGenerator.typeParameters": "String"
}
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "button1"
"text": "text"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "checkBox1"
"text": "text"
} )
add( new FormComponent( "javax.swing.JRadioButton" ) {
name: "radioButton1"
"text": "text"
} )
add( new FormComponent( "javax.swing.JToggleButton" ) {
name: "toggleButton1"
"text": "text"
} )
add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) {
name: "scrollPane1"
add( new FormComponent( "javax.swing.JTextArea" ) {
name: "textArea1"
} )
} )
add( new FormComponent( "javax.swing.JFormattedTextField" ) {
name: "formattedTextField1"
} )
add( new FormComponent( "javax.swing.JPasswordField" ) {
name: "passwordField1"
} )
add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) {
name: "scrollPane2"
add( new FormComponent( "javax.swing.JTextPane" ) {
name: "textPane1"
} )
} )
add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) {
name: "scrollPane3"
add( new FormComponent( "javax.swing.JEditorPane" ) {
name: "editorPane1"
} )
} )
add( new FormComponent( "javax.swing.JSpinner" ) {
name: "spinner1"
} )
add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) {
name: "scrollPane4"
add( new FormComponent( "javax.swing.JList" ) {
name: "list1"
auxiliary() {
"JavaCodeGenerator.typeParameters": "String"
}
} )
} )
add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) {
name: "scrollPane5"
add( new FormComponent( "javax.swing.JTable" ) {
name: "table1"
"preferredScrollableViewportSize": new java.awt.Dimension( 100, 80 )
} )
} )
add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) {
name: "scrollPane6"
add( new FormComponent( "javax.swing.JTree" ) {
name: "tree1"
"visibleRowCount": 6
} )
} )
add( new FormComponent( "javax.swing.JProgressBar" ) {
name: "progressBar1"
} )
add( new FormComponent( "javax.swing.JScrollBar" ) {
name: "scrollBar1"
} )
add( new FormComponent( "javax.swing.JSeparator" ) {
name: "separator1"
} )
add( new FormComponent( "javax.swing.JSlider" ) {
name: "slider1"
} )
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class javax.swing.BoxLayout ) {
"axis": 0
} ) {
name: "panel1"
} )
add( new FormContainer( "javax.swing.JTabbedPane", new FormLayoutManager( class javax.swing.JTabbedPane ) ) {
name: "tabbedPane1"
} )
add( new FormContainer( "javax.swing.JSplitPane", new FormLayoutManager( class javax.swing.JSplitPane ) ) {
name: "splitPane1"
} )
add( new FormContainer( "javax.swing.JToolBar", new FormLayoutManager( class javax.swing.JToolBar ) ) {
name: "toolBar1"
add( new FormComponent( "javax.swing.JToolBar$Separator" ) {
name: "separator2"
} )
} )
add( new FormContainer( "javax.swing.JMenuBar", new FormLayoutManager( class javax.swing.JMenuBar ) ) {
name: "menuBar1"
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "menu1"
"text": "text"
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "menuItem1"
"text": "text"
} )
add( new FormComponent( "javax.swing.JCheckBoxMenuItem" ) {
name: "checkBoxMenuItem1"
"text": "text"
} )
add( new FormComponent( "javax.swing.JRadioButtonMenuItem" ) {
name: "radioButtonMenuItem1"
"text": "text"
} )
add( new FormComponent( "javax.swing.JPopupMenu$Separator" ) {
name: "separator3"
} )
} )
} )
}, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 0, 0 )
"size": new java.awt.Dimension( 425, 460 )
} )
}
}

View File

@@ -21,6 +21,10 @@ import java.awt.event.MouseEvent;
import java.util.Random;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.FlatSystemProperties;
import com.formdev.flatlaf.util.Animator;
import com.formdev.flatlaf.util.UIScale;
import net.miginfocom.swing.*;
@@ -43,6 +47,8 @@ public class FlatPopupTest
FlatPopupTest() {
initComponents();
addPopupMenuListener( popupMenu1, "popupMenu1" );
addPopupMenuListener( popupMenu2, "popupMenu2" );
}
private void showPopupMenu() {
@@ -114,6 +120,46 @@ public class FlatPopupTest
}
}
private void showDirectPopup() {
DirectPopupContent content = new DirectPopupContent();
content.putClientProperty( FlatClientProperties.POPUP_FORCE_HEAVY_WEIGHT, true );
Point pt = showDirectPopupButton.getLocationOnScreen();
System.setProperty( FlatSystemProperties.USE_ROUNDED_POPUP_BORDER, "false" );
UIManager.put( "Popup.dropShadowColor", Color.red );
UIManager.put( "Popup.dropShadowInsets", new Insets( 5, 5, 5, 5 ) );
UIManager.put( "Popup.dropShadowOpacity", 1f );
Popup popup = PopupFactory.getSharedInstance().getPopup( showDirectPopupButton,
content, pt.x, pt.y + showDirectPopupButton.getHeight() + 10 );
content.popup = popup;
popup.show();
System.clearProperty( FlatSystemProperties.USE_ROUNDED_POPUP_BORDER );
UIManager.put( "Popup.dropShadowColor", null );
UIManager.put( "Popup.dropShadowInsets", null );
UIManager.put( "Popup.dropShadowOpacity", null );
}
private void addPopupMenuListener( JPopupMenu popupMenu, String name ) {
popupMenu.addPopupMenuListener( new PopupMenuListener() {
@Override
public void popupMenuWillBecomeVisible( PopupMenuEvent e ) {
System.out.println( "popupMenuWillBecomeVisible " + name );
}
@Override
public void popupMenuWillBecomeInvisible( PopupMenuEvent e ) {
System.out.println( "popupMenuWillBecomeInvisible " + name );
}
@Override
public void popupMenuCanceled( PopupMenuEvent e ) {
System.out.println( "popupMenuCanceled " + name );
}
} );
}
@Override
public void updateUI() {
super.updateUI();
@@ -128,15 +174,12 @@ public class FlatPopupTest
}
}
private void countChanged() {
// TODO add your code here
}
private void initComponents() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
label1 = new JLabel();
label2 = new JLabel();
showPopupMenuButton = new JButton();
showDirectPopupButton = new JButton();
showLargePopupMenuButton = new JButton();
showPopupButton = new JButton();
hidePopupButton = new JButton();
@@ -209,6 +252,11 @@ public class FlatPopupTest
showPopupMenuButton.addActionListener(e -> showPopupMenu());
add(showPopupMenuButton, "cell 0 2");
//---- showDirectPopupButton ----
showDirectPopupButton.setText("show direct move/resize popup");
showDirectPopupButton.addActionListener(e -> showDirectPopup());
add(showDirectPopupButton, "cell 2 2 2 1");
//---- showLargePopupMenuButton ----
showLargePopupMenuButton.setText("show heavy-weight JPopupMenu");
showLargePopupMenuButton.addActionListener(e -> showLargePopupMenu());
@@ -240,7 +288,6 @@ public class FlatPopupTest
//---- countField ----
countField.setModel(new SpinnerNumberModel(1, 1, null, 1));
countField.addChangeListener(e -> countChanged());
add(countField, "cell 5 4");
//---- label4 ----
@@ -366,6 +413,7 @@ public class FlatPopupTest
private JLabel label1;
private JLabel label2;
private JButton showPopupMenuButton;
private JButton showDirectPopupButton;
private JButton showLargePopupMenuButton;
private JButton showPopupButton;
private JButton hidePopupButton;
@@ -444,4 +492,69 @@ public class FlatPopupTest
private JLabel label6;
// JFormDesigner - End of variables declaration //GEN-END:variables @formatter:on
}
//---- class MyPopupContent -----------------------------------------------
private static class DirectPopupContent
extends JPanel
{
Popup popup;
DirectPopupContent() {
initComponents();
}
private void resizePopup() {
Window popupWindow = SwingUtilities.windowForComponent( this );
popupWindow.setSize( popupWindow.getWidth() + 20, popupWindow.getHeight() + 50 );
}
private void movePopup() {
Window popupWindow = SwingUtilities.windowForComponent( this );
popupWindow.setLocation( popupWindow.getX() + 20, popupWindow.getY() + 50 );
}
private void hidePopup() {
popup.hide();
}
private void initComponents() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents @formatter:off
resizeButton = new JButton();
moveButton = new JButton();
hideButton = new JButton();
//======== this ========
setLayout(new MigLayout(
"hidemode 3",
// columns
"[fill]" +
"[fill]" +
"[fill]",
// rows
"[]"));
//---- resizeButton ----
resizeButton.setText("Resize");
resizeButton.addActionListener(e -> resizePopup());
add(resizeButton, "cell 0 0");
//---- moveButton ----
moveButton.setText("Move");
moveButton.addActionListener(e -> movePopup());
add(moveButton, "cell 1 0");
//---- hideButton ----
hideButton.setText("Hide");
hideButton.addActionListener(e -> hidePopup());
add(hideButton, "cell 2 0");
// JFormDesigner - End of component initialization //GEN-END:initComponents @formatter:on
}
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables @formatter:off
private JButton resizeButton;
private JButton moveButton;
private JButton hideButton;
// JFormDesigner - End of variables declaration //GEN-END:variables @formatter:on
}
}

View File

@@ -1,4 +1,4 @@
JFDML JFormDesigner: "8.2.3.0.386" Java: "21" encoding: "UTF-8"
JFDML JFormDesigner: "8.3" encoding: "UTF-8"
new FormModel {
contentType: "form/swing"
@@ -30,6 +30,13 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 2"
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "showDirectPopupButton"
"text": "show direct move/resize popup"
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showDirectPopup", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 2 2 2 1"
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "showLargePopupMenuButton"
"text": "show heavy-weight JPopupMenu"
@@ -77,7 +84,6 @@ new FormModel {
minimum: 1
value: 1
}
addEvent( new FormEvent( "javax.swing.event.ChangeListener", "stateChanged", "countChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 5 4"
} )
@@ -215,5 +221,39 @@ new FormModel {
}, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 5, 505 )
} )
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "hidemode 3"
"$columnConstraints": "[fill][fill][fill]"
"$rowConstraints": "[]"
} ) {
name: "panel1"
auxiliary() {
"JavaCodeGenerator.className": "DirectPopupContent"
}
add( new FormComponent( "javax.swing.JButton" ) {
name: "resizeButton"
"text": "Resize"
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "resizePopup", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 0"
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "moveButton"
"text": "Move"
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "movePopup", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 0"
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "hideButton"
"text": "Hide"
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "hidePopup", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 2 0"
} )
}, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 180, 395 )
"size": new java.awt.Dimension( 270, 100 )
} )
}
}

View File

@@ -142,6 +142,9 @@ public class FlatSingleComponentTest
// register Alt+Shift+F1, F2, ... keys to change system scale factor
DemoPrefs.registerSystemScaleFactors( this );
// register Alt+Shift+S to enable/disable interprocess Laf sync
DemoPrefs.initLafSync( this );
// register Alt+R key to toggle component orientation
registerKey( "alt R", () -> {
applyComponentOrientation( getComponentOrientation().isLeftToRight()

View File

@@ -176,6 +176,9 @@ public class FlatTestFrame
// register Alt+Shift+F1, F2, ... keys to change system scale factor
DemoPrefs.registerSystemScaleFactors( this );
// register Alt+Shift+S to enable/disable interprocess Laf sync
DemoPrefs.initLafSync( this );
// register Ctrl+0, Ctrl++ and Ctrl+- to change font size
registerKey( SystemInfo.isMacOS ? "meta 0" : "ctrl 0", () -> restoreFont() );
registerKey( SystemInfo.isMacOS ? "meta PLUS" : "ctrl PLUS", () -> incrFont() );
@@ -579,7 +582,7 @@ public class FlatTestFrame
UIManager.put( "defaultFont", null );
LookAndFeel lookAndFeel = UIManager.getLookAndFeel();
IntelliJTheme theme = (lookAndFeel instanceof IntelliJTheme.ThemeLaf)
IntelliJTheme theme = (lookAndFeel.getClass() == IntelliJTheme.ThemeLaf.class)
? ((IntelliJTheme.ThemeLaf)lookAndFeel).getTheme()
: null;
String nameForProperties = null;

View File

@@ -24,6 +24,9 @@ import javax.swing.table.*;
import net.miginfocom.swing.*;
import org.jdesktop.swingx.*;
import org.jdesktop.swingx.table.DatePickerCellEditor;
import org.jdesktop.swingx.tips.DefaultTip;
import org.jdesktop.swingx.tips.DefaultTipOfTheDayModel;
import org.jdesktop.swingx.tips.TipOfTheDayModel.Tip;
import com.formdev.flatlaf.testing.FlatTestFrame;
import com.formdev.flatlaf.testing.FlatTestPanel;
@@ -69,6 +72,10 @@ public class FlatSwingXTest
JProgressBar statusProgressBar = new JProgressBar();
statusProgressBar.setValue( 50 );
statusBar1.add( statusProgressBar, new JXStatusBar.Constraint( JXStatusBar.Constraint.ResizeBehavior.FILL ) );
xTipOfTheDay1.setModel( new DefaultTipOfTheDayModel( new Tip[] {
new DefaultTip( "testTip", "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." )
} ) );
}
private void busyChanged() {
@@ -77,6 +84,11 @@ public class FlatSwingXTest
xBusyLabel2.setBusy( busy );
}
private void showTipOfTheDayDialog() {
JXTipOfTheDay tipOfTheDay = new JXTipOfTheDay( xTipOfTheDay1.getModel() );
tipOfTheDay.showDialog( this );
}
private void initComponents() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
JLabel label1 = new JLabel();
@@ -138,6 +150,9 @@ public class FlatSwingXTest
JXSearchField xSearchField4 = new JXSearchField();
JLabel label12 = new JLabel();
statusBar1 = new JXStatusBar();
JLabel label13 = new JLabel();
xTipOfTheDay1 = new JXTipOfTheDay();
JButton showTipOfTheDayDialogButton = new JButton();
JButton button1 = new JButton();
JButton button2 = new JButton();
@@ -163,6 +178,7 @@ public class FlatSwingXTest
"[]" +
"[]" +
"[]" +
"[top]" +
"[37]"));
//---- label1 ----
@@ -354,14 +370,14 @@ public class FlatSwingXTest
//---- table ----
table.setModel(new DefaultTableModel(
new Object[][] {
{new Date(1574636400000L) /* 25.11.2019, 00:00:00 */},
{new Date(1517439600000L) /* 01.02.2018, 00:00:00 */},
{new Date(1574636400000L) /* 2019-11-25 */},
{new Date(1517439600000L) /* 2018-02-01 */},
},
new String[] {
"Date"
}
) {
Class<?>[] columnTypes = new Class<?>[] {
Class<?>[] columnTypes = {
Date.class
};
@Override
@@ -471,6 +487,16 @@ public class FlatSwingXTest
add(label12, "cell 0 11");
add(statusBar1, "cell 1 11 3 1,grow");
//---- label13 ----
label13.setText("JXTipOfTheDay:");
add(label13, "cell 0 12");
add(xTipOfTheDay1, "cell 1 12 3 1");
//---- showTipOfTheDayDialogButton ----
showTipOfTheDayDialogButton.setText("Show Dialog...");
showTipOfTheDayDialogButton.addActionListener(e -> showTipOfTheDayDialog());
add(showTipOfTheDayDialogButton, "cell 1 12 3 1");
//---- button1 ----
button1.setText("<");
@@ -492,5 +518,6 @@ public class FlatSwingXTest
private JCheckBox busyCheckBox;
private JTable table;
private JXStatusBar statusBar1;
private JXTipOfTheDay xTipOfTheDay1;
// JFormDesigner - End of variables declaration //GEN-END:variables
}

View File

@@ -1,4 +1,4 @@
JFDML JFormDesigner: "7.0.5.0.404" Java: "17" encoding: "UTF-8"
JFDML JFormDesigner: "8.3" encoding: "UTF-8"
new FormModel {
contentType: "form/swing"
@@ -9,7 +9,7 @@ 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][][][][fill]"
"$rowConstraints": "[]0[][]0[top][][][][][][][][][37]"
"$rowConstraints": "[]0[][]0[top][][][][][][][][][top][37]"
} ) {
name: "this"
add( new FormComponent( "javax.swing.JLabel" ) {
@@ -402,9 +402,30 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 11 3 1,grow"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "label13"
"text": "JXTipOfTheDay:"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 12"
} )
add( new FormComponent( "org.jdesktop.swingx.JXTipOfTheDay" ) {
name: "xTipOfTheDay1"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 12 3 1"
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "showTipOfTheDayDialogButton"
"text": "Show Dialog..."
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showTipOfTheDayDialog", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 12 3 1"
} )
}, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 0, 0 )
"size": new java.awt.Dimension( 795, 600 )
"size": new java.awt.Dimension( 900, 820 )
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "button1"

View File

@@ -38,6 +38,7 @@ import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
@@ -45,6 +46,7 @@ import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Predicate;
import javax.swing.*;
import javax.swing.UIDefaults.ActiveValue;
@@ -58,11 +60,13 @@ import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicLookAndFeel;
import javax.swing.table.JTableHeader;
import com.formdev.flatlaf.*;
import com.formdev.flatlaf.demo.intellijthemes.IJThemesDump;
import com.formdev.flatlaf.intellijthemes.FlatAllIJThemes;
import com.formdev.flatlaf.testing.FlatTestLaf;
import com.formdev.flatlaf.themes.*;
import com.formdev.flatlaf.ui.FlatLineBorder;
import com.formdev.flatlaf.ui.FlatUIUtils;
import com.formdev.flatlaf.util.ColorFunctions;
import com.formdev.flatlaf.util.ColorFunctions.ColorFunction;
import com.jidesoft.plaf.LookAndFeelFactory;
import com.formdev.flatlaf.util.DerivedColor;
@@ -102,9 +106,9 @@ public class UIDefaultsDump
dump( FlatMacLightLaf.class.getName(), dir, false );
dump( FlatMacDarkLaf.class.getName(), dir, false );
}
dump( FlatTestLaf.class.getName(), dir, false );
dump( FlatTestLaf.class.getName(), dir, false );
}
// dump( MyBasicLookAndFeel.class.getName(), dir, false );
// dump( MetalLookAndFeel.class.getName(), dir, false );
@@ -152,6 +156,8 @@ public class UIDefaultsDump
private static void dumpIntelliJThemes( File dir ) {
dir = new File( dir, "intellijthemes" );
IJThemesDump.enablePropertiesRecording();
for( LookAndFeelInfo info : FlatAllIJThemes.INFOS ) {
String lafClassName = info.getClassName();
String relativeLafClassName = StringUtils.removeLeading( lafClassName, "com.formdev.flatlaf.intellijthemes." );
@@ -164,6 +170,8 @@ public class UIDefaultsDump
}
private static void dump( String lookAndFeelClassName, File dir, boolean jide ) {
System.out.println( "---- "+lookAndFeelClassName+" -------------------------------" );
try {
UIManager.setLookAndFeel( lookAndFeelClassName );
if( jide )
@@ -181,20 +189,32 @@ public class UIDefaultsDump
// the lazy color InternalFrame.closeHoverBackground is resolved)
defaults = (UIDefaults) defaults.clone();
dump( dir, "", lookAndFeel, defaults, key -> !key.contains( "InputMap" ) );
dump( dir, "", lookAndFeel, defaults, key -> !key.contains( "InputMap" ), true );
if( lookAndFeel.getClass() == FlatLightLaf.class || !(lookAndFeel instanceof FlatLaf) ) {
dump( dir, "_InputMap", lookAndFeel, defaults, key -> key.contains( "InputMap" ) );
dumpActionMaps( dir, "_ActionMap", lookAndFeel, defaults );
if( SystemInfo.isWindows || SystemInfo.isMacOS )
dump( dir, "_InputMap", lookAndFeel, defaults, key -> key.contains( "InputMap" ), false );
if( SystemInfo.isWindows )
dumpActionMaps( dir, "_ActionMap", lookAndFeel, defaults );
}
if( lookAndFeel instanceof IntelliJTheme.ThemeLaf ) {
File cdir = new File( dir.getPath().replace( "intellijthemes", "intellijthemes-colors" ) );
dumpColorsToProperties( cdir, lookAndFeel, defaults );
// dump as .properties
File pdir = new File( dir.getPath().replace( "intellijthemes", "intellijthemes-properties" ) );
IJThemesDump.dumpProperties( pdir, lookAndFeel.getClass().getSimpleName(), defaults );
}
}
private static void dump( File dir, String nameSuffix,
LookAndFeel lookAndFeel, UIDefaults defaults, Predicate<String> keyFilter )
LookAndFeel lookAndFeel, UIDefaults defaults, Predicate<String> keyFilter, boolean contrastRatios )
{
// dump to string
StringWriter stringWriter = new StringWriter( 100000 );
new UIDefaultsDump( lookAndFeel, defaults ).dump( new PrintWriter( stringWriter ), keyFilter );
new UIDefaultsDump( lookAndFeel, defaults ).dump( new PrintWriter( stringWriter ), keyFilter, contrastRatios );
String name = lookAndFeel instanceof MyBasicLookAndFeel
? BasicLookAndFeel.class.getSimpleName()
@@ -226,8 +246,8 @@ public class UIDefaultsDump
if( origFile != null ) {
try {
Map<String, String> defaults1 = parse( new InputStreamReader(
new FileInputStream( origFile ), StandardCharsets.UTF_8 ) );
Map<String, String> defaults2 = parse( new StringReader( stringWriter.toString() ) );
new FileInputStream( origFile ), StandardCharsets.UTF_8 ), false );
Map<String, String> defaults2 = parse( new StringReader( stringWriter.toString() ), false );
content = diff( defaults1, defaults2 );
} catch( Exception ex ) {
@@ -275,6 +295,45 @@ public class UIDefaultsDump
}
}
private static void dumpColorsToProperties( File dir, LookAndFeel lookAndFeel, UIDefaults defaults ) {
// dump to string
StringWriter stringWriter = new StringWriter( 100000 );
new UIDefaultsDump( lookAndFeel, defaults ).dumpColorsAsProperties( new PrintWriter( stringWriter ) );
String name = lookAndFeel instanceof MyBasicLookAndFeel
? BasicLookAndFeel.class.getSimpleName()
: lookAndFeel.getClass().getSimpleName();
File file = new File( dir, name + ".properties" );
// build and append differences
if( file.exists() ) {
try {
Map<String, String> defaults1 = parse( new InputStreamReader(
new FileInputStream( file ), StandardCharsets.UTF_8 ), true );
Map<String, String> defaults2 = parse( new StringReader( stringWriter.toString() ), true );
String diff = diff( defaults1, defaults2 );
if( !diff.isEmpty() ) {
stringWriter.write( "\n\n\n\n#==== Differences ==============================================================\n\n" );
stringWriter.write( diff );
}
} catch( Exception ex ) {
ex.printStackTrace();
return;
}
}
// write to file
file.getParentFile().mkdirs();
try( Writer fileWriter = new OutputStreamWriter(
new FileOutputStream( file ), StandardCharsets.UTF_8 ) )
{
fileWriter.write( stringWriter.toString().replace( "\r", "" ) );
} catch( IOException ex ) {
ex.printStackTrace();
}
}
private static String diff( Map<String, String> defaults1, Map<String, String> defaults2 ) {
TreeSet<String> keys = new TreeSet<>();
keys.addAll( defaults1.keySet() );
@@ -350,19 +409,25 @@ public class UIDefaultsDump
buf.append( '\n' );
}
private static Map<String, String> parse( Reader in ) throws IOException {
private static Map<String, String> parse( Reader in, boolean ignoreDiffs ) throws IOException {
Map<String, String> defaults = new LinkedHashMap<>();
try( BufferedReader reader = new BufferedReader( in ) ) {
String lastKey = null;
boolean inContrastRatios = false;
String line;
while( (line = reader.readLine()) != null ) {
String trimmedLine = line.trim();
if( trimmedLine.isEmpty() || trimmedLine.startsWith( "#" ) ) {
lastKey = null;
if( trimmedLine.contains( "#-------- Contrast Ratios --------" ) )
inContrastRatios = true;
continue;
}
if( ignoreDiffs && (trimmedLine.startsWith( "- " ) || trimmedLine.startsWith( "+ " )) )
continue;
if( Character.isWhitespace( line.charAt( 0 ) ) ) {
String value = defaults.get( lastKey );
value += '\n' + line;
@@ -374,6 +439,8 @@ public class UIDefaultsDump
String key = line.substring( 0, sep );
String value = line.substring( sep );
if( inContrastRatios )
key = "contrast ratio: " + key;
defaults.put( key, value );
lastKey = key;
@@ -403,12 +470,12 @@ public class UIDefaultsDump
out.printf( "OS %s%n", System.getProperty( "os.name" ) );
}
private void dump( PrintWriter out, Predicate<String> keyFilter ) {
private void dump( PrintWriter out, Predicate<String> keyFilter, boolean contrastRatios ) {
dumpHeader( out );
defaults.entrySet().stream()
.sorted( (key1, key2) -> {
return String.valueOf( key1 ).compareTo( String.valueOf( key2 ) );
.sorted( (e1, e2) -> {
return String.valueOf( e1.getKey() ).compareTo( String.valueOf( e2.getKey() ) );
} )
.forEach( entry -> {
Object key = entry.getKey();
@@ -428,6 +495,33 @@ public class UIDefaultsDump
dumpValue( out, strKey, value );
out.println();
} );
if( contrastRatios )
dumpContrastRatios( out );
}
private void dumpColorsAsProperties( PrintWriter out ) {
defaults.keySet().stream()
.sorted( (key1, key2) -> {
return String.valueOf( key1 ).compareTo( String.valueOf( key2 ) );
} )
.forEach( key -> {
Color color = defaults.getColor( key );
if( color == null )
return;
String strKey = String.valueOf( key );
String prefix = keyPrefix( strKey );
if( !prefix.equals( lastPrefix ) ) {
lastPrefix = prefix;
out.printf( "%n%n#---- %s ----%n%n", prefix );
}
out.printf( "%-50s = #%06x", strKey, color.getRGB() & 0xffffff );
if( color.getAlpha() != 255 )
out.printf( "%02x", (color.getRGB() >> 24) & 0xff );
out.println();
} );
}
private void dumpActionMaps( PrintWriter out ) {
@@ -829,6 +923,161 @@ public class UIDefaultsDump
return new Color( newColor.getRGB(), true );
}
private void dumpContrastRatios( PrintWriter out ) {
out.printf( "%n%n#-------- Contrast Ratios --------%n%n" );
out.println( "# WCAG 2 Contrast Requirements: minimum 4.5; enhanced 7.0" );
out.println( "# https://webaim.org/articles/contrast/#sc143" );
out.println();
HashMap<String, String> fg2bgMap = new HashMap<>();
defaults.keySet().stream()
.filter( key -> key instanceof String && ((String)key).endsWith( "ackground" ) )
.map( key -> (String) key )
.forEach( bgKey -> {
String fgKey = bgKey.replace( "Background", "Foreground" ).replace( "background", "foreground" );
fg2bgMap.put( fgKey, bgKey );
} );
// special cases
fg2bgMap.remove( "Button.disabledForeground" );
fg2bgMap.put( "Button.disabledText", "Button.disabledBackground" );
fg2bgMap.remove( "ToggleButton.disabledForeground" );
fg2bgMap.put( "ToggleButton.disabledText", "ToggleButton.disabledBackground" );
fg2bgMap.put( "CheckBox.foreground", "Panel.background" );
fg2bgMap.put( "CheckBox.disabledText", "Panel.background" );
fg2bgMap.put( "Label.foreground", "Panel.background" );
fg2bgMap.put( "Label.disabledForeground", "Panel.background" );
fg2bgMap.remove( "ProgressBar.foreground" );
fg2bgMap.put( "ProgressBar.selectionForeground", "ProgressBar.foreground" );
fg2bgMap.put( "ProgressBar.selectionBackground", "ProgressBar.background" );
fg2bgMap.put( "RadioButton.foreground", "Panel.background" );
fg2bgMap.put( "RadioButton.disabledText", "Panel.background" );
fg2bgMap.remove( "ScrollBar.foreground" );
fg2bgMap.remove( "ScrollBar.hoverButtonForeground" );
fg2bgMap.remove( "ScrollBar.pressedButtonForeground" );
fg2bgMap.remove( "ScrollPane.foreground" );
fg2bgMap.remove( "Separator.foreground" );
fg2bgMap.remove( "Slider.foreground" );
fg2bgMap.remove( "SplitPane.foreground" );
fg2bgMap.remove( "TextArea.disabledForeground" );
fg2bgMap.put( "TextArea.inactiveForeground", "TextArea.disabledBackground" );
fg2bgMap.remove( "TextPane.disabledForeground" );
fg2bgMap.put( "TextPane.inactiveForeground", "TextPane.disabledBackground" );
fg2bgMap.remove( "EditorPane.disabledForeground" );
fg2bgMap.put( "EditorPane.inactiveForeground", "EditorPane.disabledBackground" );
fg2bgMap.remove( "TextField.disabledForeground" );
fg2bgMap.put( "TextField.inactiveForeground", "TextField.disabledBackground" );
fg2bgMap.remove( "FormattedTextField.disabledForeground" );
fg2bgMap.put( "FormattedTextField.inactiveForeground", "FormattedTextField.disabledBackground" );
fg2bgMap.remove( "PasswordField.disabledForeground" );
fg2bgMap.put( "PasswordField.inactiveForeground", "PasswordField.disabledBackground" );
fg2bgMap.remove( "ToolBar.dockingForeground" );
fg2bgMap.remove( "ToolBar.floatingForeground" );
fg2bgMap.remove( "ToolBar.foreground" );
fg2bgMap.remove( "ToolBar.hoverButtonGroupForeground" );
fg2bgMap.remove( "Viewport.foreground" );
fg2bgMap.remove( "InternalFrame.closeHoverForeground" );
fg2bgMap.remove( "InternalFrame.closePressedForeground" );
fg2bgMap.remove( "TabbedPane.closeHoverForeground" );
fg2bgMap.remove( "TabbedPane.closePressedForeground" );
fg2bgMap.remove( "TitlePane.closeHoverForeground" );
fg2bgMap.remove( "TitlePane.closePressedForeground" );
// non-text
HashMap<String, String> nonTextMap = new HashMap<>();
nonTextMap.put( "Menu.icon.arrowColor", "Panel.background" );
nonTextMap.put( "Menu.icon.disabledArrowColor", "Panel.background" );
nonTextMap.put( "CheckBoxMenuItem.icon.checkmarkColor", "Panel.background" );
nonTextMap.put( "CheckBoxMenuItem.icon.disabledCheckmarkColor", "Panel.background" );
nonTextMap.put( "ProgressBar.foreground", "Panel.background" );
nonTextMap.put( "ProgressBar.background", "Panel.background" );
nonTextMap.put( "Separator.foreground", "Separator.background" );
nonTextMap.put( "Slider.trackColor", "Panel.background" );
nonTextMap.put( "Slider.trackValueColor", "Panel.background" );
nonTextMap.put( "Slider.disabledTrackColor", "Panel.background" );
nonTextMap.put( "TabbedPane.contentAreaColor", "Panel.background" );
nonTextMap.put( "ToolBar.separatorColor", "ToolBar.background" );
// out.println();
// fg2bgMap.entrySet().stream()
// .sorted( (e1, e2) -> e1.getKey().compareTo( e2.getKey() ) )
// .forEach( e -> {
// out.printf( "%-50s %s%n", e.getKey(), e.getValue() );
// } );
// out.println();
AtomicReference<String> lastSubkey = new AtomicReference<>();
fg2bgMap.entrySet().stream()
.sorted( (e1, e2) -> {
String key1 = e1.getKey();
String key2 = e2.getKey();
int dot1 = key1.lastIndexOf( '.' );
int dot2 = key2.lastIndexOf( '.' );
if( dot1 < 0 || dot2 < 0 )
return key1.compareTo( key2 );
int r = key1.substring( dot1 + 1 ).compareTo( key2.substring( dot2 + 1 ) );
if( r != 0 )
return r;
return key1.substring( 0, dot1 ).compareTo( key2.substring( 0, dot2 ) );
} )
.forEach( e -> {
dumpContrastRatio( out, e.getKey(), e.getValue(), lastSubkey );
} );
out.println();
out.println( "#-- non-text --" );
nonTextMap.entrySet().stream()
.sorted( (e1, e2) -> {
return e1.getKey().compareTo( e2.getKey() );
} )
.forEach( e -> {
dumpContrastRatio( out, e.getKey(), e.getValue(), null );
} );
}
private void dumpContrastRatio( PrintWriter out, String fgKey, String bgKey, AtomicReference<String> lastSubkey ) {
Color background = defaults.getColor( bgKey );
Color foreground = defaults.getColor( fgKey );
if( background == null || foreground == null )
return;
String subkey = fgKey.substring( fgKey.lastIndexOf( '.' ) + 1 );
if( lastSubkey != null && !subkey.equals( lastSubkey.get() ) ) {
lastSubkey.set( subkey );
out.println();
out.println( "#-- " + subkey + " --" );
}
Color translucentForeground = null;
if( foreground.getAlpha() != 255 ) {
translucentForeground = foreground;
float weight = foreground.getAlpha() / 255f;
foreground = ColorFunctions.mix( new Color( foreground.getRGB() ), background, weight );
}
float luma1 = ColorFunctions.luma( background );
float luma2 = ColorFunctions.luma( foreground );
float contrastRatio = (luma1 > luma2)
? (luma1 + 0.05f) / (luma2 + 0.05f)
: (luma2 + 0.05f) / (luma1 + 0.05f);
String rateing =
contrastRatio < 1.95f ? " !!!!!!" :
contrastRatio < 2.95f ? " !!!!!" :
contrastRatio < 3.95f ? " !!!!" :
contrastRatio < 4.95f ? " !!!" :
contrastRatio < 5.95f ? " !!" :
contrastRatio < 6.95f ? " !" :
"";
out.printf( "%-50s #%06x #%06x %4.1f%s%s%n", fgKey,
foreground.getRGB() & 0xffffff, background.getRGB() & 0xffffff,
contrastRatio, rateing,
translucentForeground != null ? " " + dumpColorHex( translucentForeground ) : "" );
}
//---- class MyBasicLookAndFeel -------------------------------------------
public static class MyBasicLookAndFeel

View File

@@ -463,6 +463,24 @@ TitlePane.foreground = #00f
TitlePane.inactiveForeground = #fff
TitlePane.borderColor = #f00
TitlePane.buttonBackground = #fff
TitlePane.buttonForeground = #000
TitlePane.buttonInactiveBackground = #ddd
TitlePane.buttonInactiveForeground = #00f
TitlePane.buttonHoverBackground = #bbb
TitlePane.buttonHoverForeground = #0f0
TitlePane.buttonPressedBackground = #999
TitlePane.buttonPressedForeground = #f00
TitlePane.closeBackground = #f00
TitlePane.closeForeground = #000
TitlePane.closeInactiveBackground = #d00
TitlePane.closeInactiveForeground = #0ff
TitlePane.closeHoverBackground = #b00
TitlePane.closeHoverForeground = #f0f
TitlePane.closePressedBackground = #900
TitlePane.closePressedForeground = #0f0
#---- ToggleButton ----