diff --git a/flatlaf-theme-editor/build.gradle.kts b/flatlaf-theme-editor/build.gradle.kts index e759f118..31a6fc02 100644 --- a/flatlaf-theme-editor/build.gradle.kts +++ b/flatlaf-theme-editor/build.gradle.kts @@ -30,8 +30,9 @@ dependencies { implementation( project( ":flatlaf-extras" ) ) implementation( "com.miglayout:miglayout-swing:5.3-SNAPSHOT" ) - implementation( "com.fifesoft:rsyntaxtextarea:3.1.1" ) - implementation( "com.fifesoft:autocomplete:3.1.0" ) + implementation( "com.fifesoft:rsyntaxtextarea:3.1.2" ) + implementation( "com.fifesoft:autocomplete:3.1.1" ) + implementation( "com.fifesoft:rstaui:3.1.1" ) } tasks { diff --git a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatFindReplaceBar.java b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatFindReplaceBar.java new file mode 100644 index 00000000..141b0614 --- /dev/null +++ b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatFindReplaceBar.java @@ -0,0 +1,213 @@ +/* + * Copyright 2020 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.themeeditor; + +import java.awt.Container; +import javax.swing.*; +import org.fife.rsta.ui.CollapsibleSectionPanel; +import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; +import org.fife.ui.rtextarea.SearchContext; +import org.fife.ui.rtextarea.SearchEngine; +import org.fife.ui.rtextarea.SearchResult; +import com.formdev.flatlaf.extras.FlatSVGIcon; +import net.miginfocom.swing.*; + +/** + * @author Karl Tauber + */ +class FlatFindReplaceBar + extends JPanel +{ + private final RSyntaxTextArea textArea; + + private SearchContext context; + + FlatFindReplaceBar( RSyntaxTextArea textArea ) { + this.textArea = textArea; + + initComponents(); + + findPreviousButton.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/themeeditor/icons/findAndShowPrevMatches.svg" ) ); + findNextButton.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/themeeditor/icons/findAndShowNextMatches.svg" ) ); + matchCaseToggleButton.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/themeeditor/icons/matchCase.svg" ) ); + matchWholeWordToggleButton.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/themeeditor/icons/words.svg" ) ); + regexToggleButton.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/themeeditor/icons/regex.svg" ) ); + closeButton.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/themeeditor/icons/close.svg" ) ); + + SearchContext context = new SearchContext(); + context.setSearchWrap( true ); + setSearchContext( context ); + } + + SearchContext getSearchContext() { + return context; + } + + void setSearchContext( SearchContext context ) { + this.context = context; + + findField.setText( context.getSearchFor() ); + matchCaseToggleButton.setSelected( context.getMatchCase() ); + matchWholeWordToggleButton.setSelected( context.getWholeWord() ); + regexToggleButton.setSelected( context.isRegularExpression() ); + } + + @Override + public boolean requestFocusInWindow() { + return findField.requestFocusInWindow(); + } + + private void findNext() { + context.setSearchForward( true ); + find(); + } + + private void findPrevious() { + context.setSearchForward( false ); + find(); + } + + private void find() { + // update search context + context.setSearchFor( findField.getText() ); + + // find + SearchResult result = SearchEngine.find( textArea, context ); + + // update matches info label + matchesLabel.setText( result.getMarkedCount() + " matches" ); + } + + private void matchCaseChanged() { + context.setMatchCase( matchCaseToggleButton.isSelected() ); + find(); + } + + private void matchWholeWordChanged() { + context.setWholeWord( matchWholeWordToggleButton.isSelected() ); + find(); + } + + private void regexChanged() { + context.setRegularExpression( regexToggleButton.isSelected() ); + find(); + } + + private void close() { + Container parent = getParent(); + if( parent instanceof CollapsibleSectionPanel ) + ((CollapsibleSectionPanel)parent).hideBottomComponent(); + else if( parent != null ) + parent.remove( this ); + } + + private void initComponents() { + // JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents + findLabel = new JLabel(); + findField = new JTextField(); + findToolBar = new JToolBar(); + findPreviousButton = new JButton(); + findNextButton = new JButton(); + matchCaseToggleButton = new JToggleButton(); + matchWholeWordToggleButton = new JToggleButton(); + regexToggleButton = new JToggleButton(); + matchesLabel = new JLabel(); + hSpacer1 = new JPanel(null); + closeButton = new JButton(); + + //======== this ======== + setFocusCycleRoot(true); + setLayout(new MigLayout( + "insets 3,hidemode 3", + // columns + "[fill]" + + "[fill]0" + + "[grow,fill]", + // rows + "[]")); + + //---- findLabel ---- + findLabel.setText("Find:"); + findLabel.setDisplayedMnemonic('F'); + findLabel.setLabelFor(findField); + add(findLabel, "cell 0 0"); + + //---- findField ---- + findField.setColumns(16); + findField.addActionListener(e -> find()); + add(findField, "cell 1 0"); + + //======== findToolBar ======== + { + findToolBar.setFloatable(false); + findToolBar.setBorder(null); + + //---- findPreviousButton ---- + findPreviousButton.setToolTipText("Previous Occurrence"); + findPreviousButton.addActionListener(e -> findPrevious()); + findToolBar.add(findPreviousButton); + + //---- findNextButton ---- + findNextButton.setToolTipText("Next Occurrence"); + findNextButton.addActionListener(e -> findNext()); + findToolBar.add(findNextButton); + findToolBar.addSeparator(); + + //---- matchCaseToggleButton ---- + matchCaseToggleButton.setToolTipText("Match Case"); + matchCaseToggleButton.addActionListener(e -> matchCaseChanged()); + findToolBar.add(matchCaseToggleButton); + + //---- matchWholeWordToggleButton ---- + matchWholeWordToggleButton.setToolTipText("Match Whole Word"); + matchWholeWordToggleButton.addActionListener(e -> matchWholeWordChanged()); + findToolBar.add(matchWholeWordToggleButton); + + //---- regexToggleButton ---- + regexToggleButton.setToolTipText("Regex"); + regexToggleButton.addActionListener(e -> regexChanged()); + findToolBar.add(regexToggleButton); + findToolBar.addSeparator(); + + //---- matchesLabel ---- + matchesLabel.setEnabled(false); + findToolBar.add(matchesLabel); + findToolBar.add(hSpacer1); + + //---- closeButton ---- + closeButton.setToolTipText("Close"); + closeButton.addActionListener(e -> close()); + findToolBar.add(closeButton); + } + add(findToolBar, "cell 2 0"); + // JFormDesigner - End of component initialization //GEN-END:initComponents + } + + // JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables + private JLabel findLabel; + private JTextField findField; + private JToolBar findToolBar; + private JButton findPreviousButton; + private JButton findNextButton; + private JToggleButton matchCaseToggleButton; + private JToggleButton matchWholeWordToggleButton; + private JToggleButton regexToggleButton; + private JLabel matchesLabel; + private JPanel hSpacer1; + private JButton closeButton; + // JFormDesigner - End of variables declaration //GEN-END:variables +} diff --git a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatFindReplaceBar.jfd b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatFindReplaceBar.jfd new file mode 100644 index 00000000..d993c89c --- /dev/null +++ b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatFindReplaceBar.jfd @@ -0,0 +1,83 @@ +JFDML JFormDesigner: "7.0.3.1.342" Java: "15" encoding: "UTF-8" + +new FormModel { + contentType: "form/swing" + root: new FormRoot { + add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { + "$layoutConstraints": "insets 3,hidemode 3" + "$columnConstraints": "[fill][fill]0[grow,fill]" + "$rowConstraints": "[]" + } ) { + name: "this" + "focusCycleRoot": true + add( new FormComponent( "javax.swing.JLabel" ) { + name: "findLabel" + "text": "Find:" + "displayedMnemonic": 70 + "labelFor": new FormReference( "findField" ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 0" + } ) + add( new FormComponent( "javax.swing.JTextField" ) { + name: "findField" + "columns": 16 + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "find", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 0" + } ) + add( new FormContainer( "javax.swing.JToolBar", new FormLayoutManager( class javax.swing.JToolBar ) ) { + name: "findToolBar" + "floatable": false + "border": sfield com.jformdesigner.model.FormObject NULL_VALUE + add( new FormComponent( "javax.swing.JButton" ) { + name: "findPreviousButton" + "toolTipText": "Previous Occurrence" + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "findPrevious", false ) ) + } ) + add( new FormComponent( "javax.swing.JButton" ) { + name: "findNextButton" + "toolTipText": "Next Occurrence" + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "findNext", false ) ) + } ) + add( new FormComponent( "javax.swing.JToolBar$Separator" ) { + name: "separator1" + } ) + add( new FormComponent( "javax.swing.JToggleButton" ) { + name: "matchCaseToggleButton" + "toolTipText": "Match Case" + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "matchCaseChanged", false ) ) + } ) + add( new FormComponent( "javax.swing.JToggleButton" ) { + name: "matchWholeWordToggleButton" + "toolTipText": "Match Whole Word" + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "matchWholeWordChanged", false ) ) + } ) + add( new FormComponent( "javax.swing.JToggleButton" ) { + name: "regexToggleButton" + "toolTipText": "Regex" + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "regexChanged", false ) ) + } ) + add( new FormComponent( "javax.swing.JToolBar$Separator" ) { + name: "separator2" + } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "matchesLabel" + "enabled": false + } ) + add( new FormComponent( "com.jformdesigner.designer.wrapper.HSpacer" ) { + name: "hSpacer1" + } ) + add( new FormComponent( "javax.swing.JButton" ) { + name: "closeButton" + "toolTipText": "Close" + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "close", false ) ) + } ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 2 0" + } ) + }, new FormLayoutConstraints( null ) { + "location": new java.awt.Point( 0, 0 ) + "size": new java.awt.Dimension( 400, 300 ) + } ) + } +} diff --git a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemeEditorPane.java b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemeEditorPane.java index 850ec621..d914af25 100644 --- a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemeEditorPane.java +++ b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemeEditorPane.java @@ -30,6 +30,7 @@ import javax.swing.JLayer; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.SwingUtilities; +import org.fife.rsta.ui.CollapsibleSectionPanel; import org.fife.ui.autocomplete.AutoCompletion; import org.fife.ui.autocomplete.CompletionProvider; import org.fife.ui.rsyntaxtextarea.AbstractTokenMakerFactory; @@ -53,8 +54,10 @@ class FlatThemeEditorPane private static final String FLATLAF_STYLE = "text/flatlaf"; + private final CollapsibleSectionPanel collapsiblePanel; private final RTextScrollPane scrollPane; private final FlatSyntaxTextArea textArea; + private FlatFindReplaceBar findReplaceBar; private File file; @@ -114,7 +117,10 @@ class FlatThemeEditorPane // use same font for line numbers as in editor scrollPane.getGutter().setLineNumberFont( textArea.getFont() ); - add( scrollPane, BorderLayout.CENTER ); + // create collapsible panel + collapsiblePanel = new CollapsibleSectionPanel(); + collapsiblePanel.add( scrollPane ); + add( collapsiblePanel, BorderLayout.CENTER ); } private static Font scaleFont( Font font ) { @@ -198,4 +204,13 @@ class FlatThemeEditorPane Window window = SwingUtilities.windowForComponent( this ); return (window instanceof JFrame) ? ((JFrame)window).getTitle() : null; } + + void showFindReplaceBar() { + if( findReplaceBar == null ) { + findReplaceBar = new FlatFindReplaceBar( textArea ); + collapsiblePanel.addBottomComponent( findReplaceBar ); + } + + collapsiblePanel.showBottomComponent( findReplaceBar ); + } } diff --git a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemeFileEditor.java b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemeFileEditor.java index 5643c4fa..48b6e4ed 100644 --- a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemeFileEditor.java +++ b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemeFileEditor.java @@ -179,12 +179,20 @@ public class FlatThemeFileEditor tabbedPane.setSelectedIndex( index ); } + private void find() { + FlatThemeEditorPane themeEditorPane = (FlatThemeEditorPane) tabbedPane.getSelectedComponent(); + if( themeEditorPane != null ) + themeEditorPane.showFindReplaceBar(); + } + private void initComponents() { // JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents menuBar = new JMenuBar(); fileMenu = new JMenu(); saveAllMenuItem = new JMenuItem(); exitMenuItem = new JMenuItem(); + editMenu = new JMenu(); + findMenuItem = new JMenuItem(); windowMenu = new JMenu(); nextEditorMenuItem = new JMenuItem(); previousEditorMenuItem = new JMenuItem(); @@ -237,6 +245,20 @@ public class FlatThemeFileEditor } menuBar.add(fileMenu); + //======== editMenu ======== + { + editMenu.setText("Edit"); + editMenu.setMnemonic('E'); + + //---- findMenuItem ---- + findMenuItem.setText("Find..."); + findMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); + findMenuItem.setMnemonic('F'); + findMenuItem.addActionListener(e -> find()); + editMenu.add(findMenuItem); + } + menuBar.add(editMenu); + //======== windowMenu ======== { windowMenu.setText("Window"); @@ -294,6 +316,8 @@ public class FlatThemeFileEditor private JMenu fileMenu; private JMenuItem saveAllMenuItem; private JMenuItem exitMenuItem; + private JMenu editMenu; + private JMenuItem findMenuItem; private JMenu windowMenu; private JMenuItem nextEditorMenuItem; private JMenuItem previousEditorMenuItem; diff --git a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemeFileEditor.jfd b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemeFileEditor.jfd index 5dad47f3..d424ce74 100644 --- a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemeFileEditor.jfd +++ b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemeFileEditor.jfd @@ -63,6 +63,18 @@ new FormModel { addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "exit", false ) ) } ) } ) + add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) { + name: "editMenu" + "text": "Edit" + "mnemonic": 69 + add( new FormComponent( "javax.swing.JMenuItem" ) { + name: "findMenuItem" + "text": "Find..." + "accelerator": static javax.swing.KeyStroke getKeyStroke( 70, 4226, false ) + "mnemonic": 70 + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "find", false ) ) + } ) + } ) add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) { name: "windowMenu" "text": "Window" diff --git a/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/icons/LICENSE.txt b/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/icons/LICENSE.txt new file mode 100644 index 00000000..186cd751 --- /dev/null +++ b/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/icons/LICENSE.txt @@ -0,0 +1,3 @@ +The icons in this folder are from IntelliJ IDEA Community Edition, +which is licensed under the Apache 2.0 license. Copyright 2000-2019 JetBrains s.r.o. +See: https://github.com/JetBrains/intellij-community/ diff --git a/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/icons/close.svg b/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/icons/close.svg new file mode 100644 index 00000000..7f63bd7f --- /dev/null +++ b/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/icons/close.svg @@ -0,0 +1,3 @@ + + + diff --git a/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/icons/findAndShowNextMatches.svg b/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/icons/findAndShowNextMatches.svg new file mode 100644 index 00000000..62f0f972 --- /dev/null +++ b/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/icons/findAndShowNextMatches.svg @@ -0,0 +1,3 @@ + + + diff --git a/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/icons/findAndShowPrevMatches.svg b/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/icons/findAndShowPrevMatches.svg new file mode 100644 index 00000000..88d78e89 --- /dev/null +++ b/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/icons/findAndShowPrevMatches.svg @@ -0,0 +1,3 @@ + + + diff --git a/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/icons/matchCase.svg b/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/icons/matchCase.svg new file mode 100644 index 00000000..874ee768 --- /dev/null +++ b/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/icons/matchCase.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/icons/regex.svg b/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/icons/regex.svg new file mode 100644 index 00000000..68316ab9 --- /dev/null +++ b/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/icons/regex.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/icons/words.svg b/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/icons/words.svg new file mode 100644 index 00000000..353e3bb4 --- /dev/null +++ b/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/icons/words.svg @@ -0,0 +1,5 @@ + + + + +