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-2000 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.netbeans.editor;

import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;
import javax.swing.Action;
import javax.swing.text.BadLocationException;
import javax.swing.text.JTextComponent;
import javax.swing.text.Caret;

/** Abbreviation support allowing to expand defined character sequences
* into the expanded strings or call the arbitrary action.
*
* @author Miloslav Metelka
* @version 1.00
*/

public class Abbrev implements SettingsChangeListener, PropertyChangeListener {

    /** Abbreviation accounting string. Here the characters forming
    * abbreviation are stored.
    */
    private StringBuffer abbrevSB = new StringBuffer();

    /** Check whether the document text matches the abbreviation accounting
    * string.
    */
    private boolean checkDocText;

    /** Additional check whether the character right before the abbreviation
    * string in the text is not accepted by the addTypedAcceptor.
    * This test is only performed if checkDocText is true.
    */
    private boolean checkTextDelimiter;

    /** Extended UI to which this abbreviation is associated to */
    protected EditorUI editorUI;

    /** Chars on which to expand acceptor */
    private Acceptor doExpandAcceptor;

    /** Whether add the typed char */
    private Acceptor addTypedAcceptor;

    /** Which chars reset abbreviation accounting */
    private Acceptor resetAcceptor;

    /** Abbreviation map */
    private HashMap abbrevMap;

    public Abbrev(EditorUI editorUI, boolean checkDocText, boolean checkTextDelimiter) {
        this.editorUI = editorUI;
        this.checkDocText = checkDocText;
        this.checkTextDelimiter = checkTextDelimiter;

        Settings.addSettingsChangeListener(this);

        synchronized (editorUI.getComponentLock()) {
            // if component already installed in EditorUI simulate installation
            JTextComponent component = editorUI.getComponent();
            if (component != null) {
                propertyChange(new PropertyChangeEvent(editorUI,
                                                       EditorUI.COMPONENT_PROPERTY, null, component));
            }

            editorUI.addPropertyChangeListener(this);
        }
    }

    /** Called when settings were changed. The method is called
    * by editorUI when settings were changed and from constructor.
    */
    public void settingsChange(SettingsChangeEvent evt) {
        Class kitClass = Utilities.getKitClass(editorUI.getComponent());

        if (kitClass != null) {
            String settingName = (evt != null) ? evt.getSettingName() : null;

            if (settingName == null || SettingsNames.ABBREV_ACTION_MAP.equals(settingName)
                || SettingsNames.ABBREV_MAP.equals(settingName) 
            ) {
                abbrevMap = new HashMap();
                // Inspect action abbrevs
                Map m = (Map)Settings.getValue(kitClass, SettingsNames.ABBREV_ACTION_MAP);
                if (m != null) {
                    BaseKit kit = Utilities.getKit(editorUI.getComponent());
                    Iterator iter = m.entrySet().iterator();
                    while (iter.hasNext()) {
                        Map.Entry me = (Map.Entry)iter.next();
                        Object value = me.getValue();
                        Action a = null;
                        if (value instanceof String) {
                            a = kit.getActionByName((String)value);
                        } else if (value instanceof Action) {
                            a = (Action)value;
                        }

                        if (a != null) {
                            abbrevMap.put(me.getKey(), a);
                        }
                    }
                }
                
                m = (Map)Settings.getValue(kitClass, SettingsNames.ABBREV_MAP);
                if (m != null) {
                    Iterator iter = m.entrySet().iterator();
                    while (iter.hasNext()) {
                        Map.Entry me = (Map.Entry)iter.next();
                        Object value = me.getValue();
                        if (value != null) {
                            abbrevMap.put(me.getKey(), value);
                        }
                    }
                }
            }

            if (settingName == null || SettingsNames.ABBREV_EXPAND_ACCEPTOR.equals(settingName)) {
                doExpandAcceptor = SettingsUtil.getAcceptor(kitClass, SettingsNames.ABBREV_EXPAND_ACCEPTOR, AcceptorFactory.FALSE);
            }
            if (settingName == null || SettingsNames.ABBREV_ADD_TYPED_CHAR_ACCEPTOR.equals(settingName)) {
                addTypedAcceptor = SettingsUtil.getAcceptor(kitClass, SettingsNames.ABBREV_ADD_TYPED_CHAR_ACCEPTOR, AcceptorFactory.FALSE);
            }
            if (settingName == null || SettingsNames.ABBREV_RESET_ACCEPTOR.equals(settingName)) {
                resetAcceptor = SettingsUtil.getAcceptor(kitClass, SettingsNames.ABBREV_RESET_ACCEPTOR, AcceptorFactory.TRUE);
            }
        }
    }

    public void propertyChange(PropertyChangeEvent evt) {
        String propName = evt.getPropertyName();

        if (EditorUI.COMPONENT_PROPERTY.equals(propName)) {
            JTextComponent component = (JTextComponent)evt.getNewValue();
            if (component != null) { // just installed

                settingsChange(null);

            } else { // just deinstalled
                //        component = (JTextComponent)evt.getOldValue();

            }

        }
    }

    /** Reset abbreviation accounting. */
    public void reset() {
        abbrevSB.setLength(0);
    }

    /** Add typed character to abbreviation accounting string. */
    public void addChar(char ch) {
        abbrevSB.append(ch);
    }

    /** Get current abbreviation string */
    public String getAbbrevString() {
        return abbrevSB.toString();
    }

    /** Get mapping table [abbrev, expanded-abbrev] */
    public Map getAbbrevMap() {
        return abbrevMap;
    }

    /** Translate string using abbreviation table
    * @param abbrev string to translate. Pass null to translate current abbreviation
    *    string
    * @return expanded abbreviation
    */
    public Object translateAbbrev(String abbrev) {
        String abbStr = (abbrev != null) ? abbrev : abbrevSB.toString();
        return getAbbrevMap().get(abbStr);
    }

    /** Checks whether there's valid string to expand and if so it returns it.
    */
    public String getExpandString(char typedChar) {
        return (doExpandAcceptor.accept(typedChar)) ? getExpandString() : null;
    }

    public String getExpandString() {
        BaseDocument doc = (BaseDocument)editorUI.getDocument();
        String abbrevStr = getAbbrevString();
        int abbrevStrLen = abbrevStr.length();
        Object expansion = translateAbbrev(abbrevStr);
        Caret caret = editorUI.getComponent().getCaret();
        int dotPos = caret.getDot();
        if (abbrevStr != null && expansion != null
                && dotPos >= abbrevStrLen
           ) {
            if (checkDocText) {
                try {
                    String prevChars = doc.getText(dotPos - abbrevStrLen, abbrevStrLen);
                    if (prevChars.equals(abbrevStr)) { // abbrev chars really match text
                        if (!checkTextDelimiter || dotPos == abbrevStrLen
                                || resetAcceptor.accept(
                                    doc.getChars(dotPos - abbrevStrLen - 1, 1)[0])
                           ) {
                            return abbrevStr;
                        }
                    }
                } catch (BadLocationException e) {
                }
            }
        }
        return null;
    }

    protected boolean doExpansion(int dotPos, String expandStr, ActionEvent evt)
    throws BadLocationException {
        Object expansion = translateAbbrev(expandStr);
        boolean expanded = false;
        if (expansion instanceof String) { // expand to string
            BaseDocument doc = editorUI.getDocument();
            String ins = (String)expansion;
            int offset = ins.indexOf('|');
            if (offset >= 0) {
                if (offset > 0) doc.insertString(dotPos, ins.substring(0, offset), null);
                if (offset+1 < ins.length()) doc.insertString(dotPos + offset,
                        ins.substring(offset + 1), null);
                Caret caret = editorUI.getComponent().getCaret();
                caret.setDot(dotPos + offset);
            } else {
                doc.insertString(dotPos, ins, null);
            }

            if(ins.indexOf("\n") != -1) { // NOI18N
                Formatter formatter = doc.getFormatter();
                formatter.reformat(doc, dotPos, dotPos + ins.length());
            }
            
            expanded = true;
        } else if (expansion instanceof Action) {
            ((Action)expansion).actionPerformed(evt);
            expanded = true;
        }
        return expanded;
    }

    public boolean expandString(char typedChar, String expandStr, ActionEvent evt)
    throws BadLocationException {
        if (expandString(expandStr, evt)) {
            if (addTypedAcceptor.accept(typedChar)) {
                int dotPos = editorUI.getComponent().getCaret().getDot();
                editorUI.getDocument().insertString(dotPos, String.valueOf(typedChar), null);
            }
            return true;
        }
        return false;
    }

    /** Expand abbreviation on current caret position.
    * Remove characters back to the word start and insert expanded abbreviation.
    * @return whether the typed character should be added to the abbreviation or not
    */
    public boolean expandString(String expandStr, ActionEvent evt)
    throws BadLocationException {
        boolean expanded = false;
        BaseDocument doc = editorUI.getDocument();
        doc.atomicLock();
        try {
            Caret caret = editorUI.getComponent().getCaret();
            int pos = caret.getDot() - expandStr.length();
            doc.remove(pos, expandStr.length());
            expanded = doExpansion(pos, expandStr, evt);
        } finally {
            if (expanded) {
                reset();
            } else {
                doc.breakAtomicLock();
            }
            doc.atomicUnlock();
        }
        return expanded;
    }

    public boolean checkReset(char typedChar) {
        if (resetAcceptor.accept(typedChar)) {
            reset();
            return true;
        }
        return false;
    }

    public boolean checkAndExpand(char typedChar, ActionEvent evt)
    throws BadLocationException {
        boolean doInsert = true;
        String expandStr = getExpandString(typedChar);
        if (expandStr != null) { // should expand
            doInsert = false;
            expandString(typedChar, expandStr, evt);
        } else {
            addChar(typedChar);
        }
        checkReset(typedChar);
        return doInsert;
    }

    public void checkAndExpand(ActionEvent evt)
    throws BadLocationException {
        String expandStr = getExpandString();
        if (expandStr != null) {
            expandString(expandStr, evt);
        }
    }

}
... 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.