001    /*
002      Copyright (C) 2003 Renaud Pawlak <renaud@aopsys.com>
003      
004      This program is free software; you can redistribute it and/or modify
005      it under the terms of the GNU Lesser General Public License as
006      published by the Free Software Foundation; either version 2 of the
007      License, or (at your option) any later version.
008    
009      This program is distributed in the hope that it will be useful, but
010      WITHOUT ANY WARRANTY; without even the implied warranty of
011      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
012      Lesser General Public License for more details.
013    
014      You should have received a copy of the GNU Lesser General Public
015      License along with this program; if not, write to the Free Software
016      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
017      USA */
018    
019    package org.objectweb.jac.aspects.gui.swing;
020    
021    import java.util.Collection;
022    import java.util.Iterator;
023    import java.util.List;
024    import java.util.Vector;
025    import org.apache.log4j.Logger;
026    
027    /**
028     * This class must be subclassed to implement specific completion
029     * engines for code editors. 
030     */
031    public abstract class CompletionEngine {
032        static Logger logger = Logger.getLogger("completion");
033    
034        public static final int BACKWARD=-1;
035        public static final int FORWARD=1;
036    
037        protected List baseWords = new Vector();
038    
039       /**
040        * Returns the list of the words that are potential completions for
041        * a given context. Implement this methods for specific language
042        * editors.
043        *
044        * @param text the editor's full text
045        * @param position the cursor position
046        * @param writtenText the already written text 
047        * @return a list of strings which <b>must not contain duplicates</b>
048        */
049        public abstract List getContextualChoices(String text, int position, 
050                                                  String writtenText);
051       
052        /**
053        * Returns a proposal from a current text's state.
054        *
055        * @param text the editor's full text
056        * @param position the cursor position
057        * @param writtenText the already written text of the
058        * completionable word if any
059        * @param currentProposal the proposal that is currently made to
060        * the user ("" if none)
061        * @param direction BACKWARD || FORWARD 
062        * @return the proposed completion, starting with writtenText
063        */
064        public String getProposal(String text, 
065                                  int position,
066                                  String writtenText,
067                                  String currentProposal,
068                                  int direction) {
069            logger.info("getProposal("+position+","+
070                         ","+writtenText+","+currentProposal+","+direction+")");
071            String ret = "";
072            List words = getContextualChoices(text,position,writtenText);
073            logger.debug("Proposals = "+words);
074            if (words.size()==0) 
075                return ret;
076            if (currentProposal.equals("") && writtenText.equals("")) {
077                ret = (String)words.get(0);
078            } else {
079                // Finds the position of currentProposal in words
080                // We cannot use List.indexOf() because we want case insensitiveness
081                int i = -1;
082                int pos = 0;
083                Iterator it = words.iterator();
084                while (it.hasNext() && i==-1) {
085                    if (currentProposal.compareToIgnoreCase((String)it.next())==0)
086                        i = pos;
087                    pos++;
088                }
089                if (i!=-1 || currentProposal.equals("")) {
090                    if (writtenText.equals("")) {
091                        ret = (String) words.get(next(words,i,direction));
092                    } else {
093                        int count = 0;
094                        logger.debug("before search: "+i);
095                        while(count <= words.size() && 
096                              !((String)words.get(i=next(words,i,direction))).toLowerCase()
097                              .startsWith(writtenText.toLowerCase())) {
098                            count++;
099                        }
100                        logger.debug("after search: "+i);
101                        if (((String)words.get(i)).toLowerCase()
102                            .startsWith(writtenText.toLowerCase())) {
103                            ret = ((String)words.get(i));//.substring(writtenText.length());
104                        }
105                    }
106                }
107            }
108            return ret;
109        }
110    
111        public abstract void runAutomaticCompletion(SHEditor editor,
112                                                    String text, 
113                                                    int position,
114                                                    char c);
115       
116        public abstract boolean isAutomaticCompletionChar(char c);
117    
118        int next(List l,int i, int direction) {
119            if(direction==FORWARD) {
120                if(i==l.size()-1)
121                    return 0;
122                else
123                    return i+1;
124            } else if (direction==BACKWARD) {
125                if(i==0)
126                    return l.size()-1;
127                else
128                    return i-1;
129            } else {
130                return i;
131            }
132        }
133    
134        public List getBaseWords() {
135            return baseWords;
136        }
137    
138        public void addBaseWord(String baseWord) {
139            if (!baseWords.contains(baseWord)) {
140                baseWords.add(baseWord);
141            }
142        }
143    
144        public void addBaseWords(Collection baseWords) {
145            logger.debug("addBaseWords "+baseWords);
146            Iterator it = baseWords.iterator();
147            while (it.hasNext()) {
148                Object cur = it.next();
149                if (!this.baseWords.contains(cur)) {
150                    this.baseWords.add(cur);
151                }
152            }
153        }
154    
155        public void clearBaseWords() {
156            baseWords.clear();
157        }
158    
159    }