TextComponents: keep selection when switching theme

This commit is contained in:
Karl Tauber
2021-10-21 22:57:28 +02:00
parent e36f942129
commit e13fb25f14

View File

@@ -42,9 +42,12 @@ public class FlatCaret
extends DefaultCaret extends DefaultCaret
implements UIResource implements UIResource
{ {
private static final String KEY_CARET_INFO = "FlatLaf.internal.caretInfo";
private final String selectAllOnFocusPolicy; private final String selectAllOnFocusPolicy;
private final boolean selectAllOnMouseClick; private final boolean selectAllOnMouseClick;
private boolean inInstall;
private boolean wasFocused; private boolean wasFocused;
private boolean wasTemporaryLost; private boolean wasTemporaryLost;
private boolean isMousePressed; private boolean isMousePressed;
@@ -59,16 +62,60 @@ public class FlatCaret
@Override @Override
public void install( JTextComponent c ) { public void install( JTextComponent c ) {
super.install( c ); // get caret info if switched theme
long[] ci = (long[]) c.getClientProperty( KEY_CARET_INFO );
if( ci != null ) {
c.putClientProperty( KEY_CARET_INFO, null );
// the dot and mark are lost when switching LaF // if caret info is too old assume that switched from FlatLaf
// --> move dot to end of text so that all text may be selected when it gains focus // to another Laf and back to FlatLaf
Document doc = c.getDocument(); if( System.currentTimeMillis() - 500 > ci[3] )
if( doc != null && getDot() == 0 && getMark() == 0 ) { ci = null;
int length = doc.getLength();
if( length > 0 )
setDot( length );
} }
if( ci != null ) {
// when switching theme, it is necessary to set blink rate before
// invoking super.install() otherwise the caret does not blink
setBlinkRate( (int) ci[2] );
}
inInstall = true;
try {
super.install( c );
} finally {
inInstall = false;
}
if( ci != null ) {
// restore selection
select( (int) ci[1], (int) ci[0] );
// if text component is focused, then caret and selection are visible,
// but when switching theme, the component does not yet have
// an highlighter and the selection is not painted
// --> make selection temporary invisible later, then the caret
// adds selection highlights to the text component highlighter
if( isSelectionVisible() ) {
EventQueue.invokeLater( () -> {
if( isSelectionVisible() ) {
setSelectionVisible( false );
setSelectionVisible( true );
}
} );
}
}
}
@Override
public void deinstall( JTextComponent c ) {
// remember dot and mark (the selection) when switching theme
c.putClientProperty( KEY_CARET_INFO, new long[] {
getDot(),
getMark(),
getBlinkRate(),
System.currentTimeMillis(),
} );
super.deinstall( c );
} }
@Override @Override
@@ -87,7 +134,7 @@ public class FlatCaret
@Override @Override
public void focusGained( FocusEvent e ) { public void focusGained( FocusEvent e ) {
if( !wasTemporaryLost && (!isMousePressed || selectAllOnMouseClick) ) if( !inInstall && !wasTemporaryLost && (!isMousePressed || selectAllOnMouseClick) )
selectAllOnFocusGained(); selectAllOnFocusGained();
wasTemporaryLost = false; wasTemporaryLost = false;
wasFocused = true; wasFocused = true;
@@ -144,10 +191,7 @@ public class FlatCaret
mark = beginInitialWord; mark = beginInitialWord;
dot = endInitialWord; dot = endInitialWord;
} }
if( mark != getMark() ) select( mark, dot );
setDot( mark );
if( dot != getDot() )
moveDot( dot );
} catch( BadLocationException ex ) { } catch( BadLocationException ex ) {
UIManager.getLookAndFeel().provideErrorFeedback( c ); UIManager.getLookAndFeel().provideErrorFeedback( c );
} }
@@ -185,15 +229,20 @@ public class FlatCaret
// select all // select all
if( c instanceof JFormattedTextField ) { if( c instanceof JFormattedTextField ) {
EventQueue.invokeLater( () -> { EventQueue.invokeLater( () -> {
setDot( 0 ); select( 0, doc.getLength() );
moveDot( doc.getLength() );
} ); } );
} else { } else {
setDot( 0 ); select( 0, doc.getLength() );
moveDot( doc.getLength() );
} }
} }
private void select( int mark, int dot ) {
if( mark != getMark() )
setDot( mark );
if( dot != getDot() )
moveDot( dot );
}
/** @since 1.4 */ /** @since 1.4 */
public void scrollCaretToVisible() { public void scrollCaretToVisible() {
JTextComponent c = getComponent(); JTextComponent c = getComponent();