Package open.dolphin.ui

Source Code of open.dolphin.ui.CompletableJTextField$Completer

package open.dolphin.ui;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.List;
import java.util.prefs.Preferences;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.BoxLayout;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.JWindow;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import org.apache.commons.lang.StringUtils;

/**
* CompletableJTextField
* modified from JAVA SWING HACKS
* @author pns
*/
public class CompletableJTextField extends JTextField implements ListSelectionListener, FocusListener, KeyListener, ComponentListener {
    private static final long serialVersionUID = 1L;
    private static final String PREFS = "prefs";
   
    private Completer completer;
    private JList completionList;
    private DefaultListModel completionListModel;
    private JWindow listWindow;
    private Window parentFrame;
    private int keyCode;
    private Preferences prefs;
   
    public CompletableJTextField(int col) {
        super(col);
        initComponents();
        connect();
    }
   
    private void initComponents() {
        completer = new Completer();
        completionListModel = new DefaultListModel();
        completionList = new JList(completionListModel);
        completionList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        listWindow = new JWindow();
        com.sun.awt.AWTUtilities.setWindowOpacity(listWindow, 0.9f);
        listWindow.getContentPane().add(completionList);     
    }
   
    private void connect() {
        completionList.addListSelectionListener(this);
        getDocument().addDocumentListener(completer);
        addFocusListener(this);
        addKeyListener(this);
        addComponentListener(this);
    }
   
    /**
     * 補完した内容を保存する preferences をセットする
     * @param prefs
     */
    public void setPreferences(Preferences prefs) {
        this.prefs = prefs;
        loadPrefs();
    }
   
    private void savePrefs() {
        StringBuilder sb = new StringBuilder();
        List<String> items = getCompletions();
        for (String s : items) {
            sb.append(s).append("\t");
        }
        prefs.put(PREFS, StringUtils.chop(sb.toString()));
    }
   
    private void loadPrefs() {
        String str = prefs.get(PREFS, "");
        String[] items = str.split("\t");
        for(String s : items) {
            if (! s.equals("")) { completer.addCompletion(s); }
        }
    }

    public void addCompletion(String s) {
        completer.addCompletion(s);
        if (prefs != null) { savePrefs(); }
    }
   
    public void removeCompletion(String s) {
        completer.removeCompletion(s);
    }
   
    public void clearCompletions(String s ) {
        completer.clearCompletions();
    }
   
    public List<String> getCompletions() {
        return completer.getCompletions();
    }
   
    /**
     * 補完ウインドウを適切な場所に表示する
     */
    private void showListWindow() {
        // figure out where the text field is,
        // and where its bottom left is
        java.awt.Point los = getLocationOnScreen();
        int popX = los.x;
        int popY = los.y + getHeight();
        listWindow.pack();
        int h = listWindow.getHeight();
        listWindow.setBounds(popX+5, popY, getWidth()-10, h);
        listWindow.setVisible(true);
    }

    /**
     * リストが選択されたときの処理
     * @param e
     */
    @Override
    public void valueChanged(final ListSelectionEvent e) {
        if (e.getValueIsAdjusting() || completionList.getModel().getSize() == 0) { return; }
       
        final String completionString = (String) completionList.getSelectedValue();
        if (completionString == null) { return; }
       
        SwingUtilities.invokeLater(new Runnable(){
            @Override
            public void run() {
                // リストが選択されたら,選択された文字を text field に挿入
                // その間,completer には止まっていてもらう必要がある
                completer.setUpdate(false);
                setText(completionString);
                completer.setUpdate(true);
            }           
        });
    }

    /**
     * フォーカスを取ったら補完ウインドウを出す
     * @param e
     */
    @Override
    public void focusGained(FocusEvent e) {
        completer.buildAndShowPopup();
    }

    /**
     * フォーカスを失ったら補完ウインドウは消す
     * @param e
     */
    @Override
    public void focusLost(FocusEvent e) {
        listWindow.setVisible(false);
    }

    /**
     * キー入力を監視
     * リストが選択された状態でリターン:リストの文字をフィールドにセット
     * 上キー:選択を上へ,下キー:選択を下へ
     * @param e
     */
    @Override
    public void keyTyped(KeyEvent e) {

        if (keyCode == KeyEvent.VK_ENTER) {
            // リストが選択されている時の enter の処理
            if (completionList.getSelectedIndex() != -1) {
                completer.setUpdate(true);
                completionList.getSelectionModel().clearSelection();
                listWindow.setVisible(false);
                e.consume();
            } else {
                // リストが選択されていないとき
                addCompletion(getText());
            }
        }
    }

    @Override
    public void keyPressed(KeyEvent e) {
        keyCode = e.getKeyCode();

        // リストが表示されているとき       
        if (listWindow.isVisible()) {
            int size = completionListModel.getSize();
            int selection = completionList.getSelectedIndex();
           
            if (keyCode == KeyEvent.VK_UP) {
                if (selection > 0) {
                    selection --;
                    completionList.getSelectionModel().setSelectionInterval(selection, selection);
                }
                e.consume();

            } else if (keyCode == KeyEvent.VK_DOWN) {
                if (selection < size - 1){
                    selection ++;
                    completionList.getSelectionModel().setSelectionInterval(selection, selection);
                } else if (selection == -1) {
                    // ウインドウが表示されていて選択されていない状態
                    selection = 0;
                    completionList.getSelectionModel().setSelectionInterval(selection, selection);                   
                }
                e.consume();
            }
        }
    }
   
    @Override
    public void keyReleased(KeyEvent e) {
        e.consume();
    }

    // window が動いたら listWindow は消す
    @Override
    public void componentResized(ComponentEvent e) {
        if (parentFrame == null) {
            parentFrame = SwingUtilities.getWindowAncestor(this);
            removeComponentListener(this);
            parentFrame.addComponentListener(this);
        }
        listWindow.setVisible(false);
    }

    @Override
    public void componentMoved(ComponentEvent e) {
        listWindow.setVisible(false);
    }

    @Override
    public void componentShown(ComponentEvent e) {
    }

    @Override
    public void componentHidden(ComponentEvent e) {
        listWindow.setVisible(false);
    }
   
    /**
     * inner class does the matching of the JTextField's
     * document to completion strings kept in an ArrayList
     */
    private class Completer implements DocumentListener {
       
        private boolean update = true;       
        private Pattern pattern;
        private ArrayList<String> completions;
        public Completer() {
            completions = new ArrayList<String>();
        }
       
        public void addCompletion(String s) {
            // 新しく追加したものが最初に来る
            if (! completions.contains(s)) {
                completions.add(0, s);
            }
            // 50項目まで保存
            if (completions.size() > 50) {
                completions.remove(50);
            }
           
            buildAndShowPopup();
        }
       
        public void removeCompletion(String s) {
            completions.remove(s);
            buildAndShowPopup();
        }
       
        public void clearCompletions() {
            completions.clear();
            buildPopup();
            listWindow.setVisible(false);
        }
       
        public List<String> getCompletions() {
            return completions;
        }
       
        public void setUpdate(boolean b) {
            update = b;
        }
       
        private void buildPopup() {
            completionListModel.clear();
            //System.out.println("buildPopup for " + completions.size() + " completions");
            //pattern = Pattern.compile(getText() + ".*");
            pattern = Pattern.compile(getText() + ".+");
           
            for(String completion: completions) {
                Matcher matcher = pattern.matcher(completion);
                 if (matcher.matches()) {
                    //System.out.println("matched "+ completion);
                    completionListModel.add(completionListModel.getSize(), completion);
                } else {
                    //System.out.println("pattern " + pattern.pattern() + " does not match " + completion);
                }
            }
        }
       
        private void showPopup() {
            if (completionListModel.getSize() == 0) {
                listWindow.setVisible(false);
                return;
            }
            showListWindow();           
        }
       
        private void buildAndShowPopup() {
            if (! update) { return; }
           
            if (getText().length() < 1) {
                listWindow.setVisible(false);
                return;
            }
            buildPopup();
            showPopup();
        }
       
        // DocumentListener implementation
        @Override
        public void insertUpdate(DocumentEvent e) {
            buildAndShowPopup();
        }
        @Override
        public void removeUpdate(DocumentEvent e) {
            buildAndShowPopup();
        }
        @Override
        public void changedUpdate(DocumentEvent e) {
            buildAndShowPopup();
        }
       
    }
   
    public static void main(String[] argv) {
        try {
            UIManager.setLookAndFeel("ch.randelshofer.quaqua.QuaquaLookAndFeel");
        } catch (ClassNotFoundException e) { System.out.println("Dolphin.java: " + e);
        } catch (IllegalAccessException e) { System.out.println("Dolphin.java: " + e);
        } catch (UnsupportedLookAndFeelException e) { System.out.println("Dolphin.java: " + e);
        } catch (InstantiationException e) { System.out.println("Dolphin.java: " + e);}
       
        JPanel panel = new JPanel();
        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
        final CompletableJTextField completableField = new CompletableJTextField(75) {
            @Override
            protected void paintBorder(Graphics g) {
                super.paintBorder(g);
                Graphics2D g2d = (Graphics2D) g;
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
                g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.1f));
                g2d.setColor(getBackground());
                g2d.fillRect(5, 5, getWidth()-11, getHeight()-11);
            }
        };
               
        // quaqua doesn't support textfield background color
        completableField.setBackground(new Color(255,255,0));
       
        panel.add(completableField);
        JPanel bottom = new JPanel();
        bottom.add(new JLabel("Completion:"));
        final JTextField completionField = new JTextField(40);
        completionField.addActionListener(new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent e) {
                completableField.addCompletion(completionField.getText());
                completionField.setText("");
            }
        });
        bottom.add(completionField);
        JButton addButton = new JButton("Add");
        addButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                completableField.addCompletion(completionField.getText());
                completionField.setText("");
            }           
        });
        bottom.add(addButton);
        panel.add(bottom);
        
        JFrame f = new JFrame("HACK #47: Completions...");
        //f.getContentPane().add(panel);
        //f.pack();
        f.setSize(800, 100);
        f.setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        f.setVisible(true);
       
        JOptionPane jop = new JOptionPane(
                panel,
                JOptionPane.PLAIN_MESSAGE,
                JOptionPane.DEFAULT_OPTION,
                null,
                new String[]{"A", "B"}
               
                );
        MyJSheet sheet = MyJSheet.createDialog(jop, f);
        sheet.setVisible(true);
       
        Preferences prefs = Preferences.userNodeForPackage(CompletableJTextField.class);
        completableField.setPreferences(prefs);
    }
}
TOP

Related Classes of open.dolphin.ui.CompletableJTextField$Completer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.