Theme Editor: find/replace bar improvements:

- always use editor selection to search if `Ctrl+F` is pressed
- keep find/replace bar open if switching to another editor
- mark matches when switching to another editor
This commit is contained in:
Karl Tauber
2022-07-08 17:52:08 +02:00
parent a372da22f3
commit 5cd0b2403c
4 changed files with 93 additions and 38 deletions

View File

@@ -25,7 +25,6 @@ dependencies {
implementation( "com.miglayout:miglayout-swing:5.3" ) implementation( "com.miglayout:miglayout-swing:5.3" )
implementation( "com.fifesoft:rsyntaxtextarea:3.1.4" ) implementation( "com.fifesoft:rsyntaxtextarea:3.1.4" )
implementation( "com.fifesoft:autocomplete:3.1.3" ) implementation( "com.fifesoft:autocomplete:3.1.3" )
implementation( "com.fifesoft:rstaui:3.1.3" )
} }
tasks { tasks {

View File

@@ -16,7 +16,7 @@
package com.formdev.flatlaf.themeeditor; package com.formdev.flatlaf.themeeditor;
import java.awt.Container; import java.awt.EventQueue;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent; import java.awt.event.KeyEvent;
import java.util.List; import java.util.List;
@@ -26,7 +26,6 @@ import javax.swing.border.MatteBorder;
import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener; import javax.swing.event.DocumentListener;
import com.formdev.flatlaf.extras.components.*; import com.formdev.flatlaf.extras.components.*;
import org.fife.rsta.ui.CollapsibleSectionPanel;
import org.fife.ui.rsyntaxtextarea.DocumentRange; import org.fife.ui.rsyntaxtextarea.DocumentRange;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rsyntaxtextarea.RSyntaxUtilities; import org.fife.ui.rsyntaxtextarea.RSyntaxUtilities;
@@ -44,9 +43,13 @@ import net.miginfocom.swing.*;
class FlatFindReplaceBar class FlatFindReplaceBar
extends JPanel extends JPanel
{ {
static final String PROP_CLOSED = "closed";
private final RSyntaxTextArea textArea; private final RSyntaxTextArea textArea;
private SearchContext context; private SearchContext context;
private boolean inSetContext;
private boolean markAllPending;
FlatFindReplaceBar( RSyntaxTextArea textArea ) { FlatFindReplaceBar( RSyntaxTextArea textArea ) {
this.textArea = textArea; this.textArea = textArea;
@@ -74,6 +77,10 @@ class FlatFindReplaceBar
regexToggleButton.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/themeeditor/icons/regex.svg" ) ); regexToggleButton.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/themeeditor/icons/regex.svg" ) );
closeButton.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/themeeditor/icons/close.svg" ) ); closeButton.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/themeeditor/icons/close.svg" ) );
registerKeyboardAction( e -> close(),
KeyStroke.getKeyStroke( KeyEvent.VK_ESCAPE, 0, false ),
JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT );
SearchContext context = new SearchContext(); SearchContext context = new SearchContext();
context.setSearchWrap( true ); context.setSearchWrap( true );
setSearchContext( context ); setSearchContext( context );
@@ -93,29 +100,32 @@ class FlatFindReplaceBar
void setSearchContext( SearchContext context ) { void setSearchContext( SearchContext context ) {
this.context = context; this.context = context;
findField.setText( context.getSearchFor() ); inSetContext = true;
replaceField.setText( context.getReplaceWith() ); try {
matchCaseToggleButton.setSelected( context.getMatchCase() ); findField.setText( context.getSearchFor() );
matchWholeWordToggleButton.setSelected( context.getWholeWord() ); replaceField.setText( context.getReplaceWith() );
regexToggleButton.setSelected( context.isRegularExpression() ); matchCaseToggleButton.setSelected( context.getMatchCase() );
matchWholeWordToggleButton.setSelected( context.getWholeWord() );
regexToggleButton.setSelected( context.isRegularExpression() );
} finally {
inSetContext = false;
}
} }
@Override void activate( boolean findEditorSelection ) {
public boolean requestFocusInWindow() { // use selected text of editor for searching
// invoked from CollapsibleSectionPanel if( findEditorSelection ) {
String selectedText = textArea.getSelectedText();
// use selected text in editor for searching if( !StringUtils.isEmpty( selectedText ) && selectedText.indexOf( '\n' ) < 0 )
String selectedText = textArea.getSelectedText(); findField.setText( selectedText );
if( !StringUtils.isEmpty( selectedText ) && selectedText.indexOf( '\n' ) < 0 ) else
findField.setText( selectedText ); findField.selectAll();
else }
findField.selectAll();
// if showing bar, highlight matches in editor // if showing bar, highlight matches in editor
// (not invoking this from addNotify() because this would break the slide-in animation)
markAll(); markAll();
return findField.requestFocusInWindow(); findField.requestFocusInWindow();
} }
@Override @Override
@@ -142,7 +152,20 @@ class FlatFindReplaceBar
} }
void markAll() { void markAll() {
findOrMarkAll( false ); if( inSetContext )
return;
// do mark all only once
if( markAllPending )
return;
markAllPending = true;
EventQueue.invokeLater( () -> {
markAllPending = false;
findOrMarkAll( false );
} );
} }
private void findOrMarkAll( boolean find ) { private void findOrMarkAll( boolean find ) {
@@ -254,11 +277,8 @@ class FlatFindReplaceBar
} }
private void close() { private void close() {
Container parent = getParent(); setVisible( false );
if( parent instanceof CollapsibleSectionPanel ) firePropertyChange( PROP_CLOSED, false, true );
((CollapsibleSectionPanel)parent).hideBottomComponent();
else if( parent != null )
parent.remove( this );
} }
private void initComponents() { private void initComponents() {

View File

@@ -34,7 +34,6 @@ import javax.swing.JPanel;
import javax.swing.KeyStroke; import javax.swing.KeyStroke;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import javax.swing.UIManager; import javax.swing.UIManager;
import org.fife.rsta.ui.CollapsibleSectionPanel;
import org.fife.ui.autocomplete.AutoCompletion; import org.fife.ui.autocomplete.AutoCompletion;
import org.fife.ui.autocomplete.CompletionProvider; import org.fife.ui.autocomplete.CompletionProvider;
import org.fife.ui.rsyntaxtextarea.AbstractTokenMakerFactory; import org.fife.ui.rsyntaxtextarea.AbstractTokenMakerFactory;
@@ -48,6 +47,7 @@ import org.fife.ui.rsyntaxtextarea.TokenTypes;
import org.fife.ui.rtextarea.Gutter; import org.fife.ui.rtextarea.Gutter;
import org.fife.ui.rtextarea.RTextArea; import org.fife.ui.rtextarea.RTextArea;
import org.fife.ui.rtextarea.RTextScrollPane; import org.fife.ui.rtextarea.RTextScrollPane;
import org.fife.ui.rtextarea.SearchContext;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
/** /**
@@ -62,7 +62,10 @@ class FlatThemeEditorPane
private static final String FLATLAF_STYLE = "text/flatlaf"; private static final String FLATLAF_STYLE = "text/flatlaf";
private final CollapsibleSectionPanel collapsiblePanel; private static boolean findReplaceVisible;
private static SearchContext findReplaceContext;
private final JPanel editorPanel;
private final RTextScrollPane scrollPane; private final RTextScrollPane scrollPane;
private final FlatSyntaxTextArea textArea; private final FlatSyntaxTextArea textArea;
private final ErrorStrip errorStrip; private final ErrorStrip errorStrip;
@@ -115,11 +118,11 @@ class FlatThemeEditorPane
// create error strip // create error strip
errorStrip = new ErrorStrip( textArea ); errorStrip = new ErrorStrip( textArea );
// create collapsible panel // create editor panel
collapsiblePanel = new CollapsibleSectionPanel(); editorPanel = new JPanel( new BorderLayout() );
collapsiblePanel.add( scrollPane ); editorPanel.add( scrollPane );
collapsiblePanel.add( errorStrip, BorderLayout.LINE_END ); editorPanel.add( errorStrip, BorderLayout.LINE_END );
add( collapsiblePanel, BorderLayout.CENTER ); add( editorPanel, BorderLayout.CENTER );
updateTheme(); updateTheme();
} }
@@ -166,6 +169,13 @@ class FlatThemeEditorPane
scrollPane.getGutter().setLineNumberFont( font ); scrollPane.getGutter().setLineNumberFont( font );
} }
void selected() {
if( findReplaceVisible )
showFindReplaceBar( false );
else
hideFindReplaceBar();
}
void windowActivated() { void windowActivated() {
if( preview != null ) if( preview != null )
preview.repaint(); preview.repaint();
@@ -261,13 +271,30 @@ class FlatThemeEditorPane
return (window instanceof JFrame) ? ((JFrame)window).getTitle() : null; return (window instanceof JFrame) ? ((JFrame)window).getTitle() : null;
} }
void showFindReplaceBar() { void showFindReplaceBar( boolean findEditorSelection ) {
if( findReplaceBar == null ) { if( findReplaceBar == null ) {
findReplaceBar = new FlatFindReplaceBar( textArea ); findReplaceBar = new FlatFindReplaceBar( textArea );
collapsiblePanel.addBottomComponent( findReplaceBar ); findReplaceBar.addPropertyChangeListener( FlatFindReplaceBar.PROP_CLOSED, e -> {
findReplaceVisible = false;
textArea.requestFocusInWindow();
} );
editorPanel.add( findReplaceBar, BorderLayout.SOUTH );
editorPanel.revalidate();
} }
collapsiblePanel.showBottomComponent( findReplaceBar ); findReplaceVisible = true;
if( findReplaceContext == null )
findReplaceContext = findReplaceBar.getSearchContext();
else
findReplaceBar.setSearchContext( findReplaceContext );
findReplaceBar.setVisible( true );
findReplaceBar.activate( findEditorSelection );
}
void hideFindReplaceBar() {
if( findReplaceBar != null )
findReplaceBar.setVisible( false );
} }
void showPreview( boolean show ) { void showPreview( boolean show ) {

View File

@@ -336,6 +336,7 @@ class FlatThemeFileEditor
SwingUtilities.invokeLater( () -> { SwingUtilities.invokeLater( () -> {
activateEditor(); activateEditor();
notifyEditorSelected();
} ); } );
saveState(); saveState();
enableDisableActions(); enableDisableActions();
@@ -448,11 +449,13 @@ class FlatThemeFileEditor
FlatThemeEditorPane themeEditorPane = (FlatThemeEditorPane) tabbedPane.getSelectedComponent(); FlatThemeEditorPane themeEditorPane = (FlatThemeEditorPane) tabbedPane.getSelectedComponent();
String filename = (themeEditorPane != null) ? themeEditorPane.getFile().getName() : null; String filename = (themeEditorPane != null) ? themeEditorPane.getFile().getName() : null;
putPrefsString( state, KEY_RECENT_FILE, filename ); putPrefsString( state, KEY_RECENT_FILE, filename );
notifyEditorSelected();
} }
private void enableDisableActions() { private void enableDisableActions() {
boolean dirOpen = (directoryField.getSelectedItem() != null); boolean dirOpen = (directoryField.getSelectedItem() != null);
boolean editorOpen = (dirOpen &&tabbedPane.getSelectedIndex() >= 0); boolean editorOpen = (dirOpen && tabbedPane.getSelectedIndex() >= 0);
// enable/disable buttons // enable/disable buttons
newButton.setEnabled( dirOpen ); newButton.setEnabled( dirOpen );
@@ -687,6 +690,12 @@ class FlatThemeFileEditor
return result; return result;
} }
private void notifyEditorSelected() {
FlatThemeEditorPane themeEditorPane = (FlatThemeEditorPane) tabbedPane.getSelectedComponent();
if( themeEditorPane != null )
themeEditorPane.selected();
}
private void activateEditor() { private void activateEditor() {
FlatThemeEditorPane themeEditorPane = (FlatThemeEditorPane) tabbedPane.getSelectedComponent(); FlatThemeEditorPane themeEditorPane = (FlatThemeEditorPane) tabbedPane.getSelectedComponent();
if( themeEditorPane != null ) if( themeEditorPane != null )
@@ -709,7 +718,7 @@ class FlatThemeFileEditor
private void find() { private void find() {
FlatThemeEditorPane themeEditorPane = (FlatThemeEditorPane) tabbedPane.getSelectedComponent(); FlatThemeEditorPane themeEditorPane = (FlatThemeEditorPane) tabbedPane.getSelectedComponent();
if( themeEditorPane != null ) if( themeEditorPane != null )
themeEditorPane.showFindReplaceBar(); themeEditorPane.showFindReplaceBar( true );
} }
private void insertColor() { private void insertColor() {