SwingX: JXDatePicker support (#8)

This commit is contained in:
Karl Tauber
2019-10-19 09:35:01 +02:00
parent ffef71d6db
commit 0970dceee2
8 changed files with 435 additions and 26 deletions

View File

@@ -6,7 +6,7 @@ FlatLaf Change Log
- ComboBox: Use small border if used as table editor.
- ToolBar: Disable focusability of buttons in toolbar.
- OptionPane: Fixed rendering of longer HTML text. (issue #12)
- SwingX: Support `JXBusyLabel`, `JXHeader`, `JXHyperlink`,
- SwingX: Support `JXBusyLabel`, `JXDatePicker`, `JXHeader`, `JXHyperlink`,
`JXTaskPaneContainer` and `JXTaskPane`. (issue #8)

View File

@@ -19,6 +19,7 @@ package com.formdev.flatlaf.ui;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
@@ -62,6 +63,12 @@ public class FlatUIUtils
r.height - insets.top - insets.bottom );
}
public static Dimension addInsets( Dimension dim, Insets insets ) {
return new Dimension(
dim.width + insets.left + insets.right,
dim.height + insets.top + insets.bottom );
}
public static Color getUIColor( String key, int defaultColorRGB ) {
Color color = UIManager.getColor( key );
return (color != null) ? color : new Color( defaultColorRGB );

View File

@@ -236,6 +236,8 @@ public class FlatInspector
}
}
text += "Enabled: " + c.isEnabled() + '\n';
text += "Opaque: " + c.isOpaque() + '\n';
text += "Focusable: " + c.isFocusable() + '\n';
text += "Parent: " + c.getParent().getClass().getName();

View File

@@ -0,0 +1,38 @@
/*
* Copyright 2019 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
*
* http://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.swingx.ui;
import java.awt.Component;
import org.jdesktop.swingx.JXDatePicker;
import com.formdev.flatlaf.ui.FlatRoundBorder;
/**
* Border for {@link org.jdesktop.swingx.JXDatePicker}.
*
* @author Karl Tauber
*/
public class FlatDatePickerBorder
extends FlatRoundBorder
{
@Override
protected boolean isFocused( Component c ) {
if( c instanceof JXDatePicker )
return ((JXDatePicker)c).getEditor().hasFocus();
return super.isFocused( c );
}
}

View File

@@ -0,0 +1,250 @@
/*
* Copyright 2019 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
*
* http://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.swingx.ui;
import static com.formdev.flatlaf.util.UIScale.scale;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.geom.Rectangle2D;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFormattedTextField;
import javax.swing.LookAndFeel;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource;
import org.jdesktop.swingx.plaf.basic.BasicDatePickerUI;
import com.formdev.flatlaf.ui.FlatArrowButton;
import com.formdev.flatlaf.ui.FlatBorder;
import com.formdev.flatlaf.ui.FlatRoundBorder;
import com.formdev.flatlaf.ui.FlatUIUtils;
import com.formdev.flatlaf.ui.MigLayoutVisualPadding;
import com.formdev.flatlaf.util.UIScale;
/**
* Provides the Flat LaF UI delegate for {@link org.jdesktop.swingx.JXDatePicker}.
*
* @author Karl Tauber
*/
public class FlatDatePickerUI
extends BasicDatePickerUI
{
protected Insets padding;
protected int focusWidth;
protected int arc;
protected String arrowType;
protected Color borderColor;
protected Color disabledBorderColor;
protected Color disabledBackground;
protected Color buttonBackground;
protected Color buttonArrowColor;
protected Color buttonDisabledArrowColor;
protected Color buttonHoverArrowColor;
private JButton popupButton;
public static ComponentUI createUI( JComponent c ) {
return new FlatDatePickerUI();
}
@Override
public void installUI( JComponent c ) {
// must get UI defaults here because installDefaults() is invoked after
// installComponents(), which uses these values to create popup button
padding = UIManager.getInsets( "ComboBox.padding" );
focusWidth = UIManager.getInt( "Component.focusWidth" );
arc = UIManager.getInt( "Component.arc" );
arrowType = UIManager.getString( "Component.arrowType" );
borderColor = UIManager.getColor( "Component.borderColor" );
disabledBorderColor = UIManager.getColor( "Component.disabledBorderColor" );
disabledBackground = UIManager.getColor( "ComboBox.disabledBackground" );
buttonBackground = UIManager.getColor( "ComboBox.buttonBackground" );
buttonArrowColor = UIManager.getColor( "ComboBox.buttonArrowColor" );
buttonDisabledArrowColor = UIManager.getColor( "ComboBox.buttonDisabledArrowColor" );
buttonHoverArrowColor = UIManager.getColor( "ComboBox.buttonHoverArrowColor" );
super.installUI( c );
}
@Override
protected void installDefaults() {
super.installDefaults();
LookAndFeel.installColors( datePicker, "ComboBox.background", "ComboBox.foreground" );
LookAndFeel.installBorder( datePicker, "JXDatePicker.border" );
LookAndFeel.installProperty( datePicker, "opaque", Boolean.TRUE );
MigLayoutVisualPadding.install( datePicker, focusWidth );
}
@Override
protected void uninstallDefaults() {
super.uninstallDefaults();
borderColor = null;
disabledBorderColor = null;
disabledBackground = null;
buttonBackground = null;
buttonArrowColor = null;
buttonDisabledArrowColor = null;
buttonHoverArrowColor = null;
if( datePicker.getBorder() instanceof UIResource )
datePicker.setBorder( null );
MigLayoutVisualPadding.uninstall( datePicker );
}
@Override
protected JFormattedTextField createEditor() {
JFormattedTextField editor = super.createEditor();
editor.setBorder( BorderFactory.createEmptyBorder() );
editor.setOpaque( false );
editor.addFocusListener( new FocusListener() {
@Override
public void focusLost( FocusEvent e ) {
if( datePicker != null )
datePicker.repaint();
}
@Override
public void focusGained( FocusEvent e ) {
if( datePicker != null )
datePicker.repaint();
}
} );
return editor;
}
@Override
protected JButton createPopupButton() {
popupButton = new FlatArrowButton( SwingConstants.SOUTH, arrowType, buttonArrowColor,
buttonDisabledArrowColor, buttonHoverArrowColor, null );
popupButton.setName( "popupButton" );
return popupButton;
}
@Override
protected LayoutManager createLayoutManager() {
return new LayoutManager() {
@Override
public void addLayoutComponent( String name, Component comp ) {}
@Override
public void removeLayoutComponent( Component comp ) {}
@Override
public Dimension preferredLayoutSize( Container parent ) {
return parent.getPreferredSize();
}
@Override
public Dimension minimumLayoutSize( Container parent ) {
return parent.getMinimumSize();
}
@Override
public void layoutContainer( Container parent ) {
Insets insets = datePicker.getInsets();
int x = insets.left;
int y = insets.top;
int width = datePicker.getWidth() - insets.left - insets.right;
int height = datePicker.getHeight() - insets.top - insets.bottom;
int popupButtonWidth = popupButton != null ? height : 0;
boolean ltr = datePicker.getComponentOrientation().isLeftToRight();
Rectangle r = new Rectangle( x + (ltr ? 0 : popupButtonWidth), y, width - popupButtonWidth, height );
r = FlatUIUtils.subtractInsets( r, UIScale.scale( padding ) );
datePicker.getEditor().setBounds( r );
if( popupButton != null )
popupButton.setBounds( x + (ltr ? width - popupButtonWidth : 0), y, popupButtonWidth, height );
}
};
}
@Override
public Dimension getPreferredSize( JComponent c ) {
Dimension dim = datePicker.getEditor().getPreferredSize();
dim = FlatUIUtils.addInsets( dim, UIScale.scale( padding ) );
if( popupButton != null )
dim.width += dim.height;
return FlatUIUtils.addInsets( dim, datePicker.getInsets() );
}
@Override
public void update( Graphics g, JComponent c ) {
if( c.isOpaque() ) {
FlatUIUtils.paintParentBackground( g, c );
Graphics2D g2 = (Graphics2D) g;
FlatUIUtils.setRenderingHints( g2 );
int width = c.getWidth();
int height = c.getHeight();
float focusWidth = (c.getBorder() instanceof FlatBorder) ? scale( (float) this.focusWidth ) : 0;
float arc = (c.getBorder() instanceof FlatRoundBorder) ? scale( (float) this.arc ) : 0;
int arrowX = popupButton.getX();
int arrowWidth = popupButton.getWidth();
boolean enabled = c.isEnabled();
boolean isLeftToRight = c.getComponentOrientation().isLeftToRight();
// paint background
g2.setColor( enabled ? c.getBackground() : disabledBackground );
FlatUIUtils.fillRoundRectangle( g2, 0, 0, width, height, focusWidth, arc );
// paint arrow button background
if( enabled ) {
g2.setColor( buttonBackground );
Shape oldClip = g2.getClip();
if( isLeftToRight )
g2.clipRect( arrowX, 0, width - arrowX, height );
else
g2.clipRect( 0, 0, arrowX + arrowWidth, height );
FlatUIUtils.fillRoundRectangle( g2, 0, 0, width, height, focusWidth, arc );
g2.setClip( oldClip );
}
// paint vertical line between value and arrow button
g2.setColor( enabled ? borderColor : disabledBorderColor );
float lw = scale( 1f );
float lx = isLeftToRight ? arrowX : arrowX + arrowWidth - lw;
g2.fill( new Rectangle2D.Float( lx, focusWidth, lw, height - (focusWidth * 2) ) );
}
paint( g, c );
}
}

View File

@@ -17,6 +17,12 @@
#---- UI delegates ----
BusyLabelUI=com.formdev.flatlaf.swingx.ui.FlatBusyLabelUI
DatePickerUI=com.formdev.flatlaf.swingx.ui.FlatDatePickerUI
HeaderUI=com.formdev.flatlaf.swingx.ui.FlatHeaderUI
HyperlinkUI=com.formdev.flatlaf.swingx.ui.FlatHyperlinkUI
swingx/TaskPaneUI=com.formdev.flatlaf.swingx.ui.FlatTaskPaneUI
#---- DatePicker ----
JXDatePicker.border=com.formdev.flatlaf.swingx.ui.FlatDatePickerBorder

View File

@@ -17,6 +17,7 @@
package com.formdev.flatlaf.swingx;
import java.awt.*;
import java.util.Date;
import javax.swing.*;
import net.miginfocom.swing.*;
import org.jdesktop.swingx.*;
@@ -45,6 +46,15 @@ public class FlatSwingXTest
private void initComponents() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
JLabel label1 = new JLabel();
JLabel label3 = new JLabel();
JLabel label4 = new JLabel();
JLabel label5 = new JLabel();
JLabel datePickerLabel = new JLabel();
JXDatePicker xDatePicker1 = new JXDatePicker();
JXDatePicker xDatePicker2 = new JXDatePicker();
JXDatePicker xDatePicker3 = new JXDatePicker();
JXDatePicker xDatePicker4 = new JXDatePicker();
JLabel hyperlinkLabel = new JLabel();
JXHyperlink xHyperlink1 = new JXHyperlink();
JXHyperlink xHyperlink2 = new JXHyperlink();
@@ -79,44 +89,81 @@ public class FlatSwingXTest
"[left]" +
"[]" +
"[]" +
"[]",
"[]" +
"[fill]",
// rows
"[]" +
"[]" +
"[]" +
"[]" +
"[]" +
"[]"));
//---- label1 ----
label1.setText("enabled");
add(label1, "cell 1 0");
//---- label3 ----
label3.setText("disabled");
add(label3, "cell 2 0");
//---- label4 ----
label4.setText("not editable");
add(label4, "cell 3 0");
//---- label5 ----
label5.setText("not editable disabled");
add(label5, "cell 4 0");
//---- datePickerLabel ----
datePickerLabel.setText("JXDatePicker:");
add(datePickerLabel, "cell 0 1");
add(xDatePicker1, "cell 1 1,growx");
//---- xDatePicker2 ----
xDatePicker2.setEnabled(false);
add(xDatePicker2, "cell 2 1");
//---- xDatePicker3 ----
xDatePicker3.setEditable(false);
add(xDatePicker3, "cell 3 1");
//---- xDatePicker4 ----
xDatePicker4.setEnabled(false);
xDatePicker4.setEditable(false);
add(xDatePicker4, "cell 4 1");
//---- hyperlinkLabel ----
hyperlinkLabel.setText("JXHyperlink:");
add(hyperlinkLabel, "cell 0 0");
add(hyperlinkLabel, "cell 0 2");
//---- xHyperlink1 ----
xHyperlink1.setText("enabled");
add(xHyperlink1, "cell 1 0");
add(xHyperlink1, "cell 1 2");
//---- xHyperlink2 ----
xHyperlink2.setText("disabled");
xHyperlink2.setEnabled(false);
add(xHyperlink2, "cell 2 0");
add(xHyperlink2, "cell 2 2");
//---- label2 ----
label2.setText("JXBusyLabel:");
add(label2, "cell 0 1");
add(label2, "cell 0 3");
//---- xBusyLabel1 ----
xBusyLabel1.setText("enabled");
add(xBusyLabel1, "cell 1 1");
add(xBusyLabel1, "cell 1 3");
//---- xBusyLabel2 ----
xBusyLabel2.setText("disabled");
xBusyLabel2.setEnabled(false);
add(xBusyLabel2, "cell 2 1");
add(xBusyLabel2, "cell 2 3");
//---- busyCheckBox ----
busyCheckBox.setText("busy");
busyCheckBox.setMnemonic('B');
busyCheckBox.addActionListener(e -> busyChanged());
add(busyCheckBox, "cell 3 1");
add(busyCheckBox, "cell 3 3");
//======== panel1 ========
{
@@ -136,7 +183,7 @@ public class FlatSwingXTest
taskPaneLabel.setText("JXTaskPane:");
panel1.add(taskPaneLabel, "cell 0 1");
}
add(panel1, "cell 0 2,aligny top,growy 0");
add(panel1, "cell 0 4,aligny top,growy 0");
//======== scrollPane1 ========
{
@@ -209,18 +256,23 @@ public class FlatSwingXTest
}
scrollPane1.setViewportView(xTaskPaneContainer1);
}
add(scrollPane1, "cell 1 2,width 150,height 350");
add(scrollPane1, "cell 1 4,width 150,height 350");
//---- headerLabel ----
headerLabel.setText("JXHeader:");
add(headerLabel, "cell 0 3");
add(headerLabel, "cell 0 5");
//---- xHeader1 ----
xHeader1.setTitle("Title");
xHeader1.setDescription("Description\nMore description");
xHeader1.setIcon(new ImageIcon(getClass().getResource("/org/jdesktop/swingx/plaf/windows/resources/tipoftheday.png")));
add(xHeader1, "cell 1 3 2 1,width 200");
add(xHeader1, "cell 1 5 2 1,width 200");
// JFormDesigner - End of component initialization //GEN-END:initComponents
xDatePicker1.setDate( new Date() );
xDatePicker2.setDate( new Date() );
xDatePicker3.setDate( new Date() );
xDatePicker4.setDate( new Date() );
}
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables

View File

@@ -8,34 +8,88 @@ new FormModel {
}
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "hidemode 3,ltr"
"$columnConstraints": "[left][][][]"
"$rowConstraints": "[][][][]"
"$columnConstraints": "[left][][][][fill]"
"$rowConstraints": "[][][][][][]"
} ) {
name: "this"
add( new FormComponent( "javax.swing.JLabel" ) {
name: "label1"
"text": "enabled"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 0"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "label3"
"text": "disabled"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 2 0"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "label4"
"text": "not editable"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 3 0"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "label5"
"text": "not editable disabled"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 4 0"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "datePickerLabel"
"text": "JXDatePicker:"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 1"
} )
add( new FormComponent( "org.jdesktop.swingx.JXDatePicker" ) {
name: "xDatePicker1"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 1,growx"
} )
add( new FormComponent( "org.jdesktop.swingx.JXDatePicker" ) {
name: "xDatePicker2"
"enabled": false
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 2 1"
} )
add( new FormComponent( "org.jdesktop.swingx.JXDatePicker" ) {
name: "xDatePicker3"
"editable": false
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 3 1"
} )
add( new FormComponent( "org.jdesktop.swingx.JXDatePicker" ) {
name: "xDatePicker4"
"enabled": false
"editable": false
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 4 1"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "hyperlinkLabel"
"text": "JXHyperlink:"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 0"
"value": "cell 0 2"
} )
add( new FormComponent( "org.jdesktop.swingx.JXHyperlink" ) {
name: "xHyperlink1"
"text": "enabled"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 0"
"value": "cell 1 2"
} )
add( new FormComponent( "org.jdesktop.swingx.JXHyperlink" ) {
name: "xHyperlink2"
"text": "disabled"
"enabled": false
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 2 0"
"value": "cell 2 2"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "label2"
"text": "JXBusyLabel:"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 1"
"value": "cell 0 3"
} )
add( new FormComponent( "org.jdesktop.swingx.JXBusyLabel" ) {
name: "xBusyLabel1"
@@ -44,7 +98,7 @@ new FormModel {
"JavaCodeGenerator.variableLocal": false
}
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 1"
"value": "cell 1 3"
} )
add( new FormComponent( "org.jdesktop.swingx.JXBusyLabel" ) {
name: "xBusyLabel2"
@@ -54,7 +108,7 @@ new FormModel {
"JavaCodeGenerator.variableLocal": false
}
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 2 1"
"value": "cell 2 3"
} )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "busyCheckBox"
@@ -65,7 +119,7 @@ new FormModel {
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "busyChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 3 1"
"value": "cell 3 3"
} )
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$columnConstraints": "[left]"
@@ -86,7 +140,7 @@ new FormModel {
"value": "cell 0 1"
} )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 2,aligny top,growy 0"
"value": "cell 0 4,aligny top,growy 0"
} )
add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) {
name: "scrollPane1"
@@ -145,13 +199,13 @@ new FormModel {
} )
} )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 2,width 150,height 350"
"value": "cell 1 4,width 150,height 350"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "headerLabel"
"text": "JXHeader:"
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 3"
"value": "cell 0 5"
} )
add( new FormComponent( "org.jdesktop.swingx.JXHeader" ) {
name: "xHeader1"
@@ -159,7 +213,7 @@ new FormModel {
"description": "Description\nMore description"
"icon": new com.jformdesigner.model.SwingIcon( 0, "/org/jdesktop/swingx/plaf/windows/resources/tipoftheday.png" )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 3 2 1,width 200"
"value": "cell 1 5 2 1,width 200"
} )
}, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 0, 0 )