org.executequery.gui.browser.FindAction.java Source code

Java tutorial

Introduction

Here is the source code for org.executequery.gui.browser.FindAction.java

Source

/*
 * FindAction.java
 *
 * Copyright (C) 2002-2015 Takis Diakoumis
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 3
 * of the License, or any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 *
 */

package org.executequery.gui.browser;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.List;
import java.util.Vector;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.ListCellRenderer;
import javax.swing.ListSelectionModel;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.Position;

import org.apache.commons.lang.StringUtils;
import org.executequery.GUIUtilities;
import org.executequery.gui.WidgetFactory;
import org.underworldlabs.swing.plaf.UIUtils;

/**
 *
 * Modified from the original by Santhosh Kumar 
 * from http://www.jroller.com/santhosh/category/Swing
 * 
 * @author   Santhosh Kumar, Takis Diakoumis
 * @version  $Revision: 1487 $
 * @date     $Date: 2015-08-23 22:21:42 +1000 (Sun, 23 Aug 2015) $
 */
@SuppressWarnings("unchecked")
public abstract class FindAction<T> extends AbstractAction implements DocumentListener, KeyListener {

    private JPanel searchPanel;

    private JTextField searchField;

    private JPopupMenu popup;

    private JList resultsList;

    public FindAction() {

        super("Incremental Search");

        putValue(Action.ACCELERATOR_KEY, INVOKE_KEY_STROKE);
        putValue(Action.SMALL_ICON, GUIUtilities.loadIcon("Zoom16.png"));

        init();
    }

    private void init() {

        searchPanel = new JPanel(new GridBagLayout());
        popup = new JPopupMenu();

        searchField = WidgetFactory.createTextField();
        searchField.setPreferredSize(new Dimension(270, 22));

        resultsList = initSearchResultsList();
        JScrollPane scrollPane = new JScrollPane(resultsList);
        scrollPane.setPreferredSize(new Dimension(300, 150));

        JLabel label = new JLabel(" Search: ");

        GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.insets.left = 3;
        gbc.insets.top = 3;
        gbc.insets.bottom = 3;
        searchPanel.add(label, gbc);
        gbc.gridx = 1;
        gbc.insets.right = 3;
        gbc.insets.left = 0;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        searchPanel.add(searchField, gbc);
        gbc.gridx = 0;
        gbc.gridy++;
        gbc.gridwidth = 2;
        gbc.insets.left = 3;
        gbc.insets.top = 0;
        gbc.fill = GridBagConstraints.BOTH;
        searchPanel.add(scrollPane, gbc);

        popup.setBorder(BorderFactory.createLineBorder(UIUtils.getDefaultBorderColour()));
        popup.add(searchPanel);

        // when the window containing the "comp" has registered Esc key
        // then on pressing Esc instead of search popup getting closed
        // the event is sent to the window. to overcome this we
        // register an action for Esc.
        searchField.registerKeyboardAction(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                popup.setVisible(false);
            }
        }, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_FOCUSED);
    }

    private JList initSearchResultsList() {

        final JList list = new JList();
        list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

        ListCellRenderer listCellRenderer = getListCellRenderer();
        if (listCellRenderer != null) {

            list.setCellRenderer(listCellRenderer);
        }

        list.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent e) {
                if (e.getClickCount() >= 2) {
                    listValueSelected((T) list.getSelectedValue());
                }
            }
        });

        list.addKeyListener(new KeyAdapter() {
            public void keyReleased(KeyEvent e) {
                int keyCode = e.getKeyCode();
                if (keyCode == KeyEvent.VK_ENTER) {
                    listValueSelected((T) list.getSelectedValue());
                } else if (keyCode == KeyEvent.VK_BACK_SPACE) {
                    searchField.requestFocus();
                }
            }
        });

        return list;
    }

    private void listValueSelected(T selection) {

        hidePopup();
        listValueSelected(component, selection);
    }

    protected abstract ListCellRenderer getListCellRenderer();

    protected abstract void listValueSelected(JComponent component, T selection);

    protected void foundValues(List<T> values) {

        Vector<T> listData = new Vector<T>(values.size());
        listData.addAll(values);

        resultsList.setListData(listData);
    }

    protected final void hidePopup() {

        popup.setVisible(false);
        clearResultsListData();
    }

    private void clearResultsListData() {

        resultsList.setListData(new Object[0]);
    }

    private JComponent component = null;

    protected final JComponent getInstalledComponent() {

        return component;
    }

    protected boolean ignoreCase() {

        return ignoreCase;
    }

    private boolean ignoreCase;

    /*-------------------------------------------------[ ActionListener ]---------------------------------------------------*/

    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == searchField)
            popup.setVisible(false);
        else {
            //         component = (JComponent) e.getSource();
            ignoreCase = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;

            searchField.removeActionListener(this);
            searchField.removeKeyListener(this);
            searchField.getDocument().removeDocumentListener(this);
            initSearch(e);
            searchField.addActionListener(this);
            searchField.addKeyListener(this);
            searchField.getDocument().addDocumentListener(this);

            clearResultsListData();

            Rectangle rect = component.getVisibleRect();
            //            popup.show(comp, rect.x = 5, rect.y - popup.getPreferredSize().height
            //                    - 10);
            popup.show(component, rect.x = 80, rect.y);
            searchField.requestFocus();
        }
    }

    // can be overridden by subclasses to change initial search text etc.
    protected void initSearch(ActionEvent ae) {
        searchField.setText(""); // NOI18N
        searchField.setForeground(Color.black);
    }

    private void changed(Position.Bias bias) {
        // note: popup.pack() doesn't work for first character insert
        //      popup.setVisible(false);
        popup.setVisible(true);

        String searchText = searchField.getText();

        searchField.requestFocus();
        searchField.setForeground(changed(component, searchText, bias) ? Color.black : Color.red);

        if (StringUtils.isBlank(searchText)) {

            clearResultsListData();
        }

    }

    // should search for given text and select item and
    // return true if search is successfull
    protected abstract boolean changed(JComponent comp, String text, Position.Bias bias);

    /*-----------------[ DocumentListener ]---------------------------*/

    public void insertUpdate(DocumentEvent e) {
        changed(null);
    }

    public void removeUpdate(DocumentEvent e) {
        changed(null);
    }

    public void changedUpdate(DocumentEvent e) {
    }

    /*------------------[ KeyListener ]-------------------------------*/

    /*
    protected boolean shiftDown = false;
    protected boolean controlDown = false;
     */

    public void keyPressed(KeyEvent keyEvent) {

        int keyCode = keyEvent.getKeyCode();

        if (keyCode == KeyEvent.VK_DOWN || keyCode == KeyEvent.VK_TAB) {

            setFirstListItemSelectedAndFocus();
        }
    }

    private void setFirstListItemSelectedAndFocus() {

        if (resultsList.getModel().getSize() > 0) {

            resultsList.setSelectedIndex(0);
            resultsList.requestFocus();
        }

    }

    public void keyTyped(KeyEvent e) {
    }

    public void keyReleased(KeyEvent e) {
    }

    /*--------------[ Installation ]--------------*/

    public void install(JComponent component) {

        this.component = component;

        component.registerKeyboardAction(this, INVOKE_KEY_STROKE, JComponent.WHEN_IN_FOCUSED_WINDOW);

        //      comp.registerKeyboardAction(this, KeyStroke.getKeyStroke('I',
        //            KeyEvent.CTRL_MASK | KeyEvent.SHIFT_MASK),
        //            JComponent.WHEN_FOCUSED);
    }

    public static final KeyStroke INVOKE_KEY_STROKE = KeyStroke.getKeyStroke('I', KeyEvent.CTRL_MASK);

}