Compare commits

...

7 Commits
1.0-rc3 ... 1.0

9 changed files with 187 additions and 34 deletions

View File

@@ -33,6 +33,8 @@ jobs:
steps:
- uses: actions/checkout@v2
- uses: gradle/wrapper-validation-action@v1
- name: Setup Java ${{ matrix.java }}
uses: actions/setup-java@v1
with:

View File

@@ -1,6 +1,24 @@
FlatLaf Change Log
==================
## 1.0
#### New features and improvements
- Extras: UI Inspector: Tooltip is no longer limited to window bounds.
#### Fixed bugs
- TabbedPane: Custom `TabbedPane.selectedForeground` color did not work when
`TabbedPane.foreground` has also custom color. (issue #257)
- FileChooser: Fixed display of date in details view if current user is selected
in "Look in" combobox. (Windows 10 only; issue #249)
- Table: Fixed wrong grid line thickness in dragged column on HiDPI screens on
Java 9+. (issue #236)
- PopupFactory: Fixed `NullPointerException` when `PopupFactory.getPopup()` is
invoked with parameter `owner` set to `null`.
## 1.0-rc3
#### New features and improvements

View File

@@ -14,8 +14,8 @@
* limitations under the License.
*/
val releaseVersion = "1.0-rc3"
val developmentVersion = "1.0-rc4-SNAPSHOT"
val releaseVersion = "1.0"
val developmentVersion = "1.1-SNAPSHOT"
version = if( java.lang.Boolean.getBoolean( "release" ) ) releaseVersion else developmentVersion

View File

@@ -31,13 +31,17 @@ import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JToggleButton;
import javax.swing.UIManager;
import javax.swing.filechooser.FileView;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.metal.MetalFileChooserUI;
import javax.swing.table.TableCellRenderer;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.util.ScaledImageIcon;
import com.formdev.flatlaf.util.SystemInfo;
import com.formdev.flatlaf.util.UIScale;
/**
@@ -190,6 +194,62 @@ public class FlatFileChooserUI
}
}
@Override
protected JPanel createDetailsView( JFileChooser fc ) {
JPanel p = super.createDetailsView( fc );
if( !SystemInfo.isWindows )
return p;
// find scroll pane
JScrollPane scrollPane = null;
for( Component c : p.getComponents() ) {
if( c instanceof JScrollPane ) {
scrollPane = (JScrollPane) c;
break;
}
}
if( scrollPane == null )
return p;
// get scroll view, which should be a table
Component view = scrollPane.getViewport().getView();
if( !(view instanceof JTable) )
return p;
JTable table = (JTable) view;
// on Windows 10, the date may contain left-to-right (0x200e) and right-to-left (0x200f)
// mark characters (see https://en.wikipedia.org/wiki/Left-to-right_mark)
// when the "current user" item is selected in the "look in" combobox
// --> remove them
TableCellRenderer defaultRenderer = table.getDefaultRenderer( Object.class );
table.setDefaultRenderer( Object.class, new TableCellRenderer() {
@Override
public Component getTableCellRendererComponent( JTable table, Object value, boolean isSelected,
boolean hasFocus, int row, int column )
{
// remove left-to-right and right-to-left mark characters
if( value instanceof String && ((String)value).startsWith( "\u200e" ) ) {
String str = (String) value;
char[] buf = new char[str.length()];
int j = 0;
for( int i = 0; i < buf.length; i++ ) {
char ch = str.charAt( i );
if( ch != '\u200e' && ch != '\u200f' )
buf[j++] = ch;
}
value = new String( buf, 0, j );
}
return defaultRenderer.getTableCellRendererComponent( table, value, isSelected, hasFocus, row, column );
}
} );
return p;
}
@Override
public Dimension getPreferredSize( JComponent c ) {
return UIScale.scale( super.getPreferredSize( c ) );

View File

@@ -62,7 +62,7 @@ public class FlatPopupFactory
public Popup getPopup( Component owner, Component contents, int x, int y )
throws IllegalArgumentException
{
Point pt = fixToolTipLocation( owner, contents, x, y );
Point pt = fixToolTipLocation( contents, x, y );
if( pt != null ) {
x = pt.x;
y = pt.y;
@@ -111,6 +111,7 @@ public class FlatPopupFactory
// check whether heavy weight popup window is on same screen as owner component
if( popupWindow == null ||
owner == null ||
popupWindow.getGraphicsConfiguration() == owner.getGraphicsConfiguration() )
return popup;
@@ -211,7 +212,7 @@ public class FlatPopupFactory
* This method checks whether the current mouse location is within tooltip bounds
* and corrects the y-location so that the tooltip is placed above the mouse location.
*/
private Point fixToolTipLocation( Component owner, Component contents, int x, int y ) {
private Point fixToolTipLocation( Component contents, int x, int y ) {
if( !(contents instanceof JToolTip) || !wasInvokedFromToolTipManager() )
return null;
@@ -450,10 +451,10 @@ public class FlatPopupFactory
mediumWeightShown = true;
Window window = SwingUtilities.windowForComponent( owner );
if( window == null )
if( owner == null )
return;
Window window = SwingUtilities.windowForComponent( owner );
if( !(window instanceof RootPaneContainer) )
return;

View File

@@ -893,7 +893,7 @@ public class FlatTabbedPaneUI
Color color;
if( tabPane.isEnabled() && tabPane.isEnabledAt( tabIndex ) ) {
color = tabPane.getForegroundAt( tabIndex );
if( isSelected && (color instanceof UIResource) && selectedForeground != null )
if( isSelected && selectedForeground != null && color == tabPane.getForeground() )
color = selectedForeground;
} else
color = disabledForeground;

View File

@@ -33,7 +33,9 @@ import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicTableUI;
import javax.swing.table.JTableHeader;
import com.formdev.flatlaf.util.Graphics2DProxy;
import com.formdev.flatlaf.util.SystemInfo;
import com.formdev.flatlaf.util.UIScale;
/**
@@ -213,15 +215,18 @@ public class FlatTableUI
// - do not paint last vertical grid line if line is on right edge of scroll pane
// - fix unstable grid line thickness when scaled at 125%, 150%, 175%, 225%, ...
// which paints either 1px or 2px lines depending on location
// - on Java 9+, fix wrong grid line thickness in dragged column
boolean hideLastVerticalLine = hideLastVerticalLine();
int tableWidth = table.getWidth();
JTableHeader header = table.getTableHeader();
boolean isDragging = (header != null && header.getDraggedColumn() != null);
double systemScaleFactor = UIScale.getSystemScaleFactor( (Graphics2D) g );
double lineThickness = (1. / systemScaleFactor) * (int) systemScaleFactor;
// Java 8 uses drawLine() to paint grid lines
// Java 9+ uses fillRect() to paint grid lines
// Java 9+ uses fillRect() to paint grid lines (except for dragged column)
g = new Graphics2DProxy( (Graphics2D) g ) {
@Override
public void drawLine( int x1, int y1, int x2, int y2 ) {
@@ -231,6 +236,22 @@ public class FlatTableUI
wasInvokedFromPaintGrid() )
return;
// on Java 9+, fix wrong grid line thickness in dragged column
if( isDragging &&
SystemInfo.isJava_9_orLater &&
((horizontalLines && y1 == y2) || (verticalLines && x1 == x2)) &&
wasInvokedFromPaintDraggedArea() )
{
if( y1 == y2 ) {
// horizontal grid line
super.fill( new Rectangle2D.Double( x1, y1, x2 - x1 + 1, lineThickness ) );
} else if( x1 == x2 ) {
// vertical grid line
super.fill( new Rectangle2D.Double( x1, y1, lineThickness, y2 - y1 + 1 ) );
}
return;
}
super.drawLine( x1, y1, x2, y2 );
}
@@ -258,11 +279,23 @@ public class FlatTableUI
}
private boolean wasInvokedFromPaintGrid() {
return wasInvokedFromMethod( "paintGrid" );
}
private boolean wasInvokedFromPaintDraggedArea() {
return wasInvokedFromMethod( "paintDraggedArea" );
}
private boolean wasInvokedFromMethod( String methodName ) {
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
for( int i = 0; i < 10 || i < stackTrace.length; i++ ) {
if( "javax.swing.plaf.basic.BasicTableUI".equals( stackTrace[i].getClassName() ) &&
"paintGrid".equals( stackTrace[i].getMethodName() ) )
return true;
if( "javax.swing.plaf.basic.BasicTableUI".equals( stackTrace[i].getClassName() ) ) {
String methodName2 = stackTrace[i].getMethodName();
if( "paintCell".equals( methodName2 ) )
return false;
if( methodName.equals( methodName2 ) )
return true;
}
}
return false;
}

View File

@@ -38,6 +38,9 @@ import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.MouseMotionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.lang.reflect.Field;
@@ -48,6 +51,8 @@ import javax.swing.JRootPane;
import javax.swing.JToolBar;
import javax.swing.JToolTip;
import javax.swing.KeyStroke;
import javax.swing.Popup;
import javax.swing.PopupFactory;
import javax.swing.RootPaneContainer;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
@@ -55,6 +60,7 @@ import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import javax.swing.plaf.UIResource;
import javax.swing.text.JTextComponent;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.ui.FlatUIUtils;
import com.formdev.flatlaf.util.UIScale;
@@ -82,7 +88,6 @@ import com.formdev.flatlaf.util.UIScale;
public class FlatInspector
{
private static final Integer HIGHLIGHT_LAYER = 401;
private static final Integer TOOLTIP_LAYER = 402;
private static final int KEY_MODIFIERS_MASK = InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK | InputEvent.ALT_DOWN_MASK | InputEvent.META_DOWN_MASK;
@@ -90,6 +95,8 @@ public class FlatInspector
private final MouseMotionListener mouseMotionListener;
private final AWTEventListener keyListener;
private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport( this );
private final WindowListener windowListener;
private Window window;
private boolean enabled;
private Component lastComponent;
@@ -99,7 +106,7 @@ public class FlatInspector
private boolean wasCtrlOrShiftKeyPressed;
private JComponent highlightFigure;
private JToolTip tip;
private Popup popup;
/**
* Installs a key listener into the application that allows enabling and disabling
@@ -189,6 +196,18 @@ public class FlatInspector
}
}
};
windowListener = new WindowAdapter() {
@Override
public void windowActivated( WindowEvent e ) {
update();
}
@Override
public void windowDeactivated( WindowEvent e ) {
hidePopup();
}
};
}
private void uninstall() {
@@ -221,12 +240,28 @@ public class FlatInspector
rootPane.getGlassPane().setVisible( enabled );
// add/remove key listener
Toolkit toolkit = Toolkit.getDefaultToolkit();
if( enabled )
toolkit.addAWTEventListener( keyListener, AWTEvent.KEY_EVENT_MASK );
else
toolkit.removeAWTEventListener( keyListener );
// add/remove window listener
if( enabled ) {
System.out.println( "add "+window );
window = SwingUtilities.windowForComponent( rootPane );
if( window != null )
window.addWindowListener( windowListener );
} else {
System.out.println( "rem" );
if( window != null ) {
window.removeWindowListener( windowListener );
window = null;
}
}
// show/hide popup
if( enabled ) {
Point pt = new Point( MouseInfo.getPointerInfo().getLocation() );
SwingUtilities.convertPointFromScreen( pt, rootPane );
@@ -242,14 +277,19 @@ public class FlatInspector
highlightFigure.getParent().remove( highlightFigure );
highlightFigure = null;
if( tip != null )
tip.getParent().remove( tip );
tip = null;
hidePopup();
}
propertyChangeSupport.firePropertyChange( "enabled", !enabled, enabled );
}
private void hidePopup() {
if( popup != null ) {
popup.hide();
popup = null;
}
}
public void update() {
if( !rootPane.getGlassPane().isVisible() )
return;
@@ -303,7 +343,7 @@ public class FlatInspector
continue;
// ignore highlight figure and tooltip
if( c == highlightFigure || c == tip )
if( c == highlightFigure )
continue;
// ignore glass pane
@@ -357,26 +397,24 @@ public class FlatInspector
}
private void showToolTip( Component c, int x, int y, int parentLevel ) {
if( c == null ) {
if( tip != null )
tip.setVisible( false );
hidePopup();
if( c == null || (window != null && !window.isActive()) )
return;
}
if( tip == null ) {
tip = new JToolTip();
rootPane.getLayeredPane().add( tip, TOOLTIP_LAYER );
} else
tip.setVisible( true );
JToolTip tip = new JToolTip();
tip.setTipText( buildToolTipText( c, parentLevel ) );
tip.putClientProperty( FlatClientProperties.POPUP_FORCE_HEAVY_WEIGHT, true );
Point pt = new Point( x, y );
SwingUtilities.convertPointToScreen( pt, rootPane.getGlassPane() );
int tx = pt.x + UIScale.scale( 8 );
int ty = pt.y + UIScale.scale( 16 );
int tx = x + UIScale.scale( 8 );
int ty = y + UIScale.scale( 16 );
Dimension size = tip.getPreferredSize();
// position the tip in the visible area
Rectangle visibleRect = rootPane.getVisibleRect();
Rectangle visibleRect = rootPane.getGraphicsConfiguration().getBounds();
if( tx + size.width > visibleRect.x + visibleRect.width )
tx -= size.width + UIScale.scale( 16 );
if( ty + size.height > visibleRect.y + visibleRect.height )
@@ -386,8 +424,9 @@ public class FlatInspector
if( ty < visibleRect.y )
ty = visibleRect.y;
tip.setBounds( tx, ty, size.width, size.height );
tip.repaint();
PopupFactory popupFactory = PopupFactory.getSharedInstance();
popup = popupFactory.getPopup( c, tip, tx, ty );
popup.show();
}
private static String buildToolTipText( Component c, int parentLevel ) {
@@ -473,9 +512,9 @@ public class FlatInspector
}
private static void appendRow( StringBuilder buf, String key, String value ) {
buf.append( "<tr><td><b>" )
buf.append( "<tr><td>" )
.append( key )
.append( ":</b></td><td>" )
.append( ":</td><td>" )
.append( value )
.append( "</td></tr>" );
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 8.4 KiB