alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 * 
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 * 
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2003 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.netbeans.editor.ext;

import java.awt.Dialog;
import java.awt.event.*;
import java.util.Map;
import java.util.HashMap;
import java.util.Collections;
import javax.swing.*;
import javax.swing.text.JTextComponent;
import javax.swing.text.BadLocationException;
import org.netbeans.editor.SettingsNames;
import org.netbeans.editor.SettingsUtil;
import org.netbeans.editor.FindSupport;
import org.netbeans.editor.DialogSupport;
import org.netbeans.editor.LocaleSupport;
import org.netbeans.editor.GuardedException;
import org.netbeans.editor.Utilities;
import org.netbeans.editor.WeakTimerListener;
import org.netbeans.editor.BaseCaret;
import java.util.Iterator;
import javax.swing.text.Caret;

/**
* Support for displaying find and replace dialogs
*
* @author Miloslav Metelka
* @version 1.00
*/

public class FindDialogSupport extends WindowAdapter implements ActionListener {
    
    /** This lock is used to create a barrier between showing/hiding/changing
     *  the dialog and testing if the dialog is already shown.
     *  it is used to make test-and-change / test-and-display actions atomic.
     *  It covers the following four fields: findDialog, isReplaceDialog,
     *  findPanel, findButtons
     */
    private static Object dialogLock = new Object();
    
    /** Whether the currently visible dialog is for replace */
    private  static boolean isReplaceDialog = false;

    /** The buttons used in the visible dialog */
    private  static JButton findButtons[];
    
    /** The FindPanel used inside the visible dialog */
    private  static FindPanel findPanel;

    /** Currently visible dialog */
    private  static Dialog findDialog = null;
    
    private Timer incSearchTimer;

    private int caretPosition;

    private static final String MNEMONIC_SUFFIX = "-mnemonic"; // NOI18N
    private static final String A11Y_PREFIX = "ACSD_"; // NOI18N

    private static FindDialogSupport singleton = null;

    public static FindDialogSupport getFindDialogSupport() {
        if (singleton == null) {
            singleton = new FindDialogSupport();
        }
        return singleton;
    }

    private FindDialogSupport() {
        int delay = SettingsUtil.getInteger(null, SettingsNames.FIND_INC_SEARCH_DELAY, 200);
        incSearchTimer = new Timer(delay, new WeakTimerListener(this));
        incSearchTimer.setRepeats(false);
    }

    private void createFindButtons() {
        if (findButtons == null) {
            findButtons = new JButton[] {
                new JButton(LocaleSupport.getString("find-button-find")), // NOI18N
                new JButton(LocaleSupport.getString("find-button-replace")), // NOI18N
                new JButton(LocaleSupport.getString("find-button-replace-all")), // NOI18N
                new JButton(LocaleSupport.getString("find-button-cancel")) // NOI18N
            };

            findButtons[1].setMnemonic( LocaleSupport.getChar(
                    "find-button-replace" + MNEMONIC_SUFFIX, 'R') ); // NOI18N

            findButtons[2].setMnemonic( LocaleSupport.getChar(
                    "find-button-replace-all" + MNEMONIC_SUFFIX, 'A' ) ); // NOI18N

            findButtons[0].getAccessibleContext().setAccessibleDescription(LocaleSupport.getString(A11Y_PREFIX + "find-button-find")); // NOI18N
            findButtons[1].getAccessibleContext().setAccessibleDescription(LocaleSupport.getString(A11Y_PREFIX + "find-button-replace")); // NOI18N
            findButtons[2].getAccessibleContext().setAccessibleDescription(LocaleSupport.getString(A11Y_PREFIX + "find-button-replace-all")); // NOI18N
            findButtons[3].getAccessibleContext().setAccessibleDescription(LocaleSupport.getString(A11Y_PREFIX + "find-button-cancel")); // NOI18N
        }
    }

    private void createFindPanel() {
        if (findPanel == null) {
            findPanel = new FindPanel();
        }
    }

    private Dialog createFindDialog(JPanel findPanel, final JButton[] buttons,
                                      final ActionListener l) {
        Dialog d = DialogSupport.createDialog(
                isReplaceDialog ? 
                    LocaleSupport.getString ("replace-title") : LocaleSupport.getString ("find-title" ), // NOI18N
                findPanel, false, // non-modal
                buttons, true, // sidebuttons,
                0, // defaultIndex = 0 => findButton
                3, // cancelIndex = 3 => cancelButton
                l //listener
        );

        return d;
    }

    private void showFindDialogImpl( boolean isReplace, KeyEventBlocker blocker) {
        synchronized( dialogLock ) {
            if (findDialog != null) { // we have a dialog, change and raise
                if( isReplaceDialog != isReplace ) {
                    isReplaceDialog = isReplace;
                    findButtons[1].setVisible( isReplace );
                    findButtons[2].setVisible( isReplace );
                    findPanel.changeVisibility(isReplace);
                    findDialog.setTitle (isReplace ? LocaleSupport.getString ("replace-title") : LocaleSupport.getString ("find-title")); // NOI18N
                }
                findDialog.toFront();
            } else { // create and show new dialog of required type
                isReplaceDialog = isReplace;
                createFindButtons();
                findButtons[1].setVisible( isReplace );
                findButtons[2].setVisible( isReplace );
                createFindPanel();
                findPanel.changeVisibility(isReplace);
                findDialog = createFindDialog( findPanel, findButtons, this );
                findDialog.addWindowListener( this );
                ((JDialog)findDialog).getRootPane().setFocusable(false);
            }
        } // end of synchronized section
        
        findDialog.pack();
        findPanel.init(isReplace, blocker);
        findDialog.setVisible(true);
        findPanel.showNotify();
        JTextComponent c = Utilities.getLastActiveComponent();
        if (c != null) {
            caretPosition = c.getCaret().getDot();
        }
    }

    public void windowActivated(WindowEvent evt) {
        incSearchTimer.start();
    }
       
    public void windowDeactivated(WindowEvent evt) {
        incSearchTimer.stop();
        FindSupport.getFindSupport().incSearchReset();
    }

    public void windowClosing(WindowEvent e) {
        hideDialog();
    }

    public void windowClosed(WindowEvent e) {
        incSearchTimer.stop();
        FindSupport.getFindSupport().incSearchReset();
        Utilities.returnFocus();
    }

    public void showFindDialog(KeyEventBlocker blocker) {
        showFindDialogImpl(false, blocker);
    }

    public void showReplaceDialog(KeyEventBlocker blocker) {
        showFindDialogImpl(true, blocker);
    }

    public void hideDialog() {
        synchronized (dialogLock) {
            if (findDialog != null)
                findDialog.dispose();
            findDialog = null;
        }
    }

    public void actionPerformed(ActionEvent evt) {
        if( findButtons == null ) return;
        
        Object src = evt.getSource();
        FindSupport fSup = FindSupport.getFindSupport();
        if (src == findButtons[0]) { // Find button
            incSearchTimer.stop();
            findPanel.updateFindHistory();
            fSup.putFindProperties(findPanel.getFindProps());
            fSup.find(null, false);
            if (!isReplaceDialog) {
                hideDialog();
            }
        } else if (src == findButtons[1]) { // Replace button
            incSearchTimer.stop();
            findPanel.updateFindHistory();
            findPanel.updateReplaceHistory();
            fSup.putFindProperties(findPanel.getFindProps());
            try {
                if (fSup.replace(null, false)) { // replaced
                    fSup.find(null, false);
                }
            } catch (GuardedException e) {
                // replace in guarded block
            } catch (BadLocationException e) {
                e.printStackTrace();
            }
        } else if (src == findButtons[2]) { // Replace All button
            incSearchTimer.stop();
            findPanel.updateFindHistory();
            findPanel.updateReplaceHistory();
            fSup.putFindProperties(findPanel.getFindProps());
            fSup.replaceAll(null);
        } else if (src == findButtons[3]) { // Cancel button
            findPanel.getFindProps().putAll(fSup.getFindProperties());
            hideDialog();
            // fix for issue 13502
            // canceling dialog must scroll back to the caret position in the document
            // (in case the visible area of document has changed because of incremental search)
            JTextComponent c = Utilities.getLastActiveComponent();
            if (c != null){
                Caret caret = c.getCaret();
                if (caret instanceof BaseCaret){
                    ((BaseCaret)caret).setDot(caretPosition, false);
                }else{
                    caret.setDot(caretPosition);
                }
            }
        } else if (src == incSearchTimer) {
            fSup.incSearch(findPanel.getFindProps(), caretPosition);
        } else {
            findPanel.getFindProps().putAll(fSup.getFindProperties());
            // fix for issue 13502
            // canceling dialog must scroll back to the caret position in the document
            // (in case the visible area of document has changed because of incremental search)
            JTextComponent c = Utilities.getLastActiveComponent();
            if (c != null){
                Caret caret = c.getCaret();
                if (caret instanceof BaseCaret){
                    ((BaseCaret)caret).setDot(caretPosition, false);
                }else{
                    caret.setDot(caretPosition);
                }
            }
        }

    }

    /** Panel that holds the find logic */
    private class FindPanel extends FindDialogPanel
        implements ItemListener, KeyListener, ActionListener, FocusListener {

        private Map findProps = Collections.synchronizedMap(new HashMap(20));
        private Map objToProps = Collections.synchronizedMap(new HashMap(20));

        private javax.swing.DefaultComboBoxModel findHistory = new javax.swing.DefaultComboBoxModel();
        private javax.swing.DefaultComboBoxModel replaceHistory = new javax.swing.DefaultComboBoxModel();

        private KeyEventBlocker blocker;

        FindPanel() {
            objToProps.put(findWhat, SettingsNames.FIND_WHAT);
            objToProps.put(replaceWith, SettingsNames.FIND_REPLACE_WITH);
            objToProps.put(highlightSearch, SettingsNames.FIND_HIGHLIGHT_SEARCH);
            objToProps.put(incSearch, SettingsNames.FIND_INC_SEARCH);
            objToProps.put(matchCase, SettingsNames.FIND_MATCH_CASE);
            objToProps.put(smartCase, SettingsNames.FIND_SMART_CASE);
            objToProps.put(wholeWords, SettingsNames.FIND_WHOLE_WORDS);
            objToProps.put(regExp, SettingsNames.FIND_REG_EXP);
            objToProps.put(bwdSearch, SettingsNames.FIND_BACKWARD_SEARCH);
            objToProps.put(wrapSearch, SettingsNames.FIND_WRAP_SEARCH);

            findProps.putAll(FindSupport.getFindSupport().getFindProperties());
            revertMap();

            findWhat.setModel(findHistory);
            findWhat.getEditor().setItem(getProperty(findWhat));
            replaceWith.setModel(replaceHistory);
            replaceWith.getEditor().setItem(getProperty(replaceWith));
            highlightSearch.setSelected(getBooleanProperty(highlightSearch));
            incSearch.setSelected(getBooleanProperty(incSearch));
            matchCase.setSelected(getBooleanProperty(matchCase));
            smartCase.setSelected(getBooleanProperty(smartCase));
            wholeWords.setSelected(getBooleanProperty(wholeWords));
            regExp.setSelected(getBooleanProperty(regExp));
            bwdSearch.setSelected(getBooleanProperty(bwdSearch));
            wrapSearch.setSelected(getBooleanProperty(wrapSearch));
            regExp.setEnabled(false); // !!! remove when regexp search is fine
            regExp.setVisible(false);

            findWhat.getEditor().getEditorComponent().addKeyListener(this);
            findWhat.addActionListener(this);
            replaceWith.getEditor().getEditorComponent().addKeyListener(this);
            replaceWith.addActionListener(this);
            highlightSearch.addItemListener(this);
            incSearch.addItemListener(this);
            matchCase.addItemListener(this);
            smartCase.addItemListener(this);
            wholeWords.addItemListener(this);
            regExp.addItemListener(this);
            bwdSearch.addItemListener(this);
            wrapSearch.addItemListener(this);
        }

        protected Map getFindProps() {
            return findProps;
        }

        private void putProperty(Object component, Object value) {
            String prop = (String)objToProps.get(component);
            if (prop != null) {
                findProps.put(prop, value);
                incSearchTimer.restart();
            }
        }

        private Object getProperty(Object component) {
            String prop = (String)objToProps.get(component);
            return (prop != null) ? findProps.get(prop) : null;
        }

        private boolean getBooleanProperty(Object component) {
            Object prop = getProperty(component);
            return (prop != null) ? ((Boolean)prop).booleanValue() : false;
        }

        protected void changeVisibility(boolean v) {
            replaceWith.setVisible(v);
            replaceWithLabel.setVisible(v);
        }

        protected void init(boolean isReplace, KeyEventBlocker blocker) {
            this.blocker = blocker;
            findHistory.setSelectedItem(null);
            replaceHistory.setSelectedItem(null);
            findWhat.getEditor().getEditorComponent().addFocusListener(this);
            if (isReplace) {
                replaceWith.getEditor().getEditorComponent().addFocusListener(this);
            }

            JTextComponent c = Utilities.getLastActiveComponent();
            String selText = null;
            if (c != null) {
                selText = c.getSelectedText();
                if (selText != null) {
                    int n = selText.indexOf( '\n' );
                    if (n >= 0 ) selText = selText.substring(0, n);
                    findWhat.getEditor().setItem(selText.trim());
                    changeFindWhat();
                }
            }

            findProps.putAll(FindSupport.getFindSupport().getFindProperties());

            highlightSearch.setSelected(getBooleanProperty(highlightSearch));
            incSearch.setSelected(getBooleanProperty(incSearch));
            matchCase.setSelected(getBooleanProperty(matchCase));
            smartCase.setSelected(getBooleanProperty(smartCase));
            wholeWords.setSelected(getBooleanProperty(wholeWords));
            regExp.setSelected(getBooleanProperty(regExp));
            bwdSearch.setSelected(getBooleanProperty(bwdSearch));
            wrapSearch.setSelected(getBooleanProperty(wrapSearch));
        }

        protected void showNotify() {
            findWhat.getEditor().getEditorComponent().requestFocus();
        }

        private void updateHistory(JComboBox c, javax.swing.DefaultComboBoxModel history) {
            Object item = c.getEditor().getItem();
            if( item != null && !item.equals("")) {
                history.removeElement(item);
                history.insertElementAt(item, 0);
                history.setSelectedItem(null);
            }
            c.getEditor().setItem(item);
        }
        
        protected void updateFindHistory() {
            updateHistory(findWhat, findHistory);
        }

        protected void updateReplaceHistory() {
            updateHistory(replaceWith, replaceHistory);
        }

        private void revertMap(){
            Object prop = findProps.get(FindSupport.REVERT_MAP);
            if (!(prop instanceof Map)) return;
            Map revertMap = (Map)prop;

            for( Iterator i = revertMap.keySet().iterator(); i.hasNext(); ) {
                String key = (String)i.next();
                
                Object obj = findProps.get(key);
                boolean value = ( obj != null ) ? ((Boolean)obj).booleanValue() : false; 
                value = !value;
                
                findProps.put(key, value ? Boolean.TRUE : Boolean.FALSE);
            }
            
            findProps.put(FindSupport.REVERT_MAP, null);
        }

        private void changeFindWhat() {
            Object old = getProperty(findWhat);
            Object cur = findWhat.getEditor().getItem();
            if (old == null || !old.equals(cur)) {
                putProperty(findWhat, cur);
            }
        }

        private void changeReplaceWith() {
            Object old = getProperty(replaceWith);
            Object cur = replaceWith.getEditor().getItem();
            if (old == null || !old.equals(cur)) {
                putProperty(replaceWith, cur);
            }
        }

        private void postChangeCombos() {
            SwingUtilities.invokeLater(
                new Runnable() {
                    public void run() {
                        changeFindWhat();
                        changeReplaceWith();
                    }
                }
            );
        }

        public void keyPressed(KeyEvent evt) {
            if (evt.getKeyChar() == '\n') {
                evt.consume();
            }
        }

        public void keyReleased(KeyEvent evt) {
            if (evt.getKeyChar() == '\n') {
                evt.consume();
            } else {
                postChangeCombos();
            }
        }

        public void keyTyped(KeyEvent evt) {
            if (evt.getKeyChar() == '\n') {
                findButtons[0].doClick(20);
                evt.consume();
                ((JComboBox)((JTextField)evt.getSource()).getParent()).hidePopup();
            }
        }

        public void itemStateChanged(ItemEvent evt)  {
            Boolean val = (evt.getStateChange() == ItemEvent.SELECTED) ? Boolean.TRUE
                          : Boolean.FALSE;
            putProperty(evt.getSource(), val);
        }

        public void actionPerformed(ActionEvent evt) {
            postChangeCombos();
        }

        public void focusGained(FocusEvent e) {
            if (e.getSource() instanceof JTextField) {
                ((JTextField)e.getSource()).selectAll();
                if (blocker != null)
                    blocker.stopBlocking();
            }
            ((JComponent)e.getSource()).removeFocusListener(this);
        }

        public void focusLost(FocusEvent e) {
        }



    }

}
... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.