001package jmri.util.swing;
002
003import java.awt.*;
004import java.awt.event.*;
005
006import javax.swing.*;
007
008/**
009 * Provides a standard "search bar" for addition to
010 * other panels.  Actual search is via call-back.
011 *
012 * @author Bob Jacobsen
013 */
014public class SearchBar extends javax.swing.JPanel {
015
016    Runnable forward;
017    Runnable backward;
018    Runnable done;
019
020    JTextField textField = new JTextField();
021    JButton rightButton = new JButton(">");
022    JButton leftButton = new JButton("<");
023    JButton doneButton = new JButton(Bundle.getMessage("ButtonDone"));
024
025    public SearchBar(Runnable forward, Runnable backward, Runnable done) {
026        super();
027        this.forward = forward;
028        this.backward = backward;
029        this.done = done;
030
031        // create GUI
032        setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
033        add(textField);
034        add(Box.createHorizontalGlue());
035        add(leftButton);
036        add(rightButton);
037        add(doneButton);
038
039        leftButton.setToolTipText("Search backwards");
040        rightButton.setToolTipText("Search forwards");
041        doneButton.setToolTipText("Close search bar");
042
043        // add actions
044        doneButton.addActionListener(new java.awt.event.ActionListener() {
045            @Override
046            public void actionPerformed(ActionEvent e) {
047                if (done != null) {
048                    log.debug("firing done");
049                    done.run();
050                } else {
051                    log.warn("no search done defined, setting invisible");
052                    SearchBar.this.setVisible(false);
053                }
054            }
055        });
056
057        leftButton.addActionListener(new java.awt.event.ActionListener() {
058            @Override
059            public void actionPerformed(ActionEvent e) {
060                if (backward != null) {
061                    log.debug("firing backward");
062                    backward.run();
063                } else {
064                    log.warn("no backward search defined");
065                }
066            }
067        });
068
069        rightButton.addActionListener(new java.awt.event.ActionListener() {
070            @Override
071            public void actionPerformed(ActionEvent e) {
072                if (forward != null) {
073                    log.debug("firing forward");
074                    forward.run();
075                } else {
076                    log.warn("no forward search defined");
077                }
078            }
079        });
080
081        // Enter in the text field does a forward search
082        // and then leaves forward search selected for the next one
083        textField.addActionListener(new java.awt.event.ActionListener() {
084            @Override
085            public void actionPerformed(ActionEvent e) {
086                if (forward != null) {
087                    log.debug("firing forward");
088                    forward.run();
089                } else {
090                    log.warn("no forward search defined");
091                }
092                rightButton.requestFocusInWindow();
093            }
094        });
095
096    }
097
098    public String getSearchString() {
099        return textField.getText();
100    }
101
102    /**
103     * A service routine to connect the SearchBar to
104     * the usual modifier keys
105     * @param frame JFrame containing this search bar; used to set key maps
106     */
107    @SuppressWarnings("deprecation")  // getMenuShortcutKeyMask()
108    public void configureKeyModifiers(JFrame frame) {
109        JRootPane rootPane = frame.getRootPane();
110
111        rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
112            KeyStroke.getKeyStroke(KeyEvent.VK_F, Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()), "openSearch");
113
114        rootPane.getActionMap().put("openSearch", new AbstractAction() {
115            @Override
116            public void actionPerformed(ActionEvent e) {
117
118                // don't retain last text?
119                textField.setText("");
120
121                // alternate visible
122                SearchBar.this.setVisible(! SearchBar.this.isVisible());
123
124                // if visible, move focus
125                if (SearchBar.this.isVisible()) {
126                    SearchBar.this.textField.requestFocusInWindow();
127                }
128            }
129        });
130
131        rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
132            KeyStroke.getKeyStroke(KeyEvent.VK_G, Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()|java.awt.event.InputEvent.SHIFT_DOWN_MASK), "forwardSearch");
133
134        rootPane.getActionMap().put("forwardSearch", new AbstractAction() {
135            @Override
136            public void actionPerformed(ActionEvent e) {
137
138                // same as button
139                leftButton.doClick();
140                }
141        });
142
143        rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
144            KeyStroke.getKeyStroke(KeyEvent.VK_G, Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()), "backwardSearch");
145
146        rootPane.getActionMap().put("backwardSearch", new AbstractAction() {
147            @Override
148            public void actionPerformed(ActionEvent e) {
149
150                // same as button
151                rightButton.doClick();
152                }
153        });
154    }
155
156    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(SearchBar.class);
157}