001    /*
002      Copyright (C) 2003 Laurent Martelli <laurent@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.ide.swing;
020    
021    import java.io.StringReader;
022    import java.util.Arrays;
023    import java.util.Iterator;
024    import java.util.List;
025    import java.util.Vector;
026    import org.apache.log4j.Logger;
027    import org.objectweb.jac.aspects.gui.swing.DefaultCompletionEngine;
028    import org.objectweb.jac.core.AspectComponent;
029    import org.objectweb.jac.core.parsers.acc.NonTerminal;
030    import org.objectweb.jac.core.parsers.acc.SyntaxElement;
031    import org.objectweb.jac.core.parsers.acc.Terminal;
032    import org.objectweb.jac.core.parsers.acc.ToolParserWrapper;
033    import org.objectweb.jac.core.rtti.AbstractMethodItem;
034    import org.objectweb.jac.core.rtti.ClassItem;
035    import org.objectweb.jac.core.rtti.FieldItem;
036    import org.objectweb.jac.core.rtti.MemberItem;
037    import org.objectweb.jac.ide.Class;
038    import org.objectweb.jac.ide.Field;
039    import org.objectweb.jac.ide.Method;
040    import org.objectweb.jac.ide.Package;
041    import org.objectweb.jac.ide.Project;
042    import org.objectweb.jac.ide.RelationRole;
043    
044    /**
045     * This class implements a completion engine for method acc
046     * configuration code of the UMLAF IDE.  
047     */
048    public class AccCompletionEngine extends DefaultCompletionEngine {
049        static final Logger logger = Logger.getLogger("completion");
050    
051        Project project;
052        /**
053         * Creates a new AccCompletionEngine using a given parser.
054         * @param parser the parser to use
055         */
056        public AccCompletionEngine(ToolParserWrapper parser, Project project) {
057            this.project = project;
058            this.parser = parser;
059        }
060    
061        SyntaxElement currentSyntaxElement;
062        public SyntaxElement getCurrentSyntaxElement() {
063            return currentSyntaxElement;
064        }
065    
066        AspectComponent aspectInstance;
067        /**
068         * Sets the aspect instance associated with the completion engine
069         * @param instance the AspectComponent instance
070         */
071        public void setAspectInstance(AspectComponent instance) {
072            this.aspectInstance = instance;
073        }
074    
075        ToolParserWrapper parser;
076        public List getContextualChoices(String text, int position, 
077                                         String writtenText) {
078            NonTerminal elements = parser.parse(new StringReader(text),"");
079            if (writtenText.length()>0)
080                position = position+writtenText.length()-1;
081            logger.debug("Syntax elements = "+elements);
082            logger.debug("position = "+position);
083            logger.debug("writtenText = "+writtenText);
084    
085            SyntaxElement se = parser.getSyntaxElementAt(position);
086            currentSyntaxElement = se;
087            logger.debug("Syntax element = "+se);
088            if (se!=null && (se.getName().equals("CONF_METHOD") || 
089                             se.getName().equals("EOL") ||
090                             se.getName().equals("class_block"))) {
091                logger.debug("Completing!");
092                NonTerminal block = (NonTerminal)se.findParent("class_block");
093                if (block!=null) {
094                    Terminal keyword = (Terminal)block.getChild("BLOCK_KEYWORD");
095                    if (keyword!=null) {
096                        // Completion inside a block
097                        if (keyword.getValue().equals("attribute")) {
098                            logger.debug("  Completing in attribute block");
099                            return aspectInstance.getConfigurationMethodsName(
100                                FieldItem.class);
101                        } else if (keyword.getValue().equals("method")) {
102                            logger.debug("  Completing in method block");
103                            return aspectInstance.getConfigurationMethodsName(
104                                AbstractMethodItem.class);
105                        } else if (keyword.getValue().equals("member")) {
106                            logger.debug("  Completing in member block");
107                            return aspectInstance.getConfigurationMethodsName(
108                                MemberItem.class);
109                        } else if (keyword.getValue().equals("class")) {
110                            logger.debug("  Completing in class block");
111                            Vector result = new Vector();
112                            result.addAll(
113                                aspectInstance.getConfigurationMethodsName(ClassItem.class));
114                            result.addAll(
115                                aspectInstance.getConfigurationMethodsName(MemberItem.class));
116                            result.addAll(Arrays.asList(
117                                new String[] {"attribute","method","member"}));
118                            return result;
119                        } else {
120                            logger.debug("  Unknown block keyword");
121                            return baseWords;
122                        }
123                    } else {
124                        logger.debug("  No keyword in block");
125                        return baseWords;
126                    }
127                } else {
128                    logger.debug("  No block keyword");
129                    return baseWords;
130                }
131            } else {
132                Terminal term = parser.getTerminalAt(position);
133                logger.debug("  SyntaxElement before: "+term);
134                if (term!=null && term.getName().equals("BLOCK_PARAM")) {
135                    return completeBlockParam(term);
136                } else if (se==null) {
137                    logger.debug("  No current syntax element");
138                    return baseWords;
139                } else {
140                    NonTerminal confMethod = (NonTerminal)se.findParent("conf_method");
141                    if (confMethod!=null) {
142                        String methodName = confMethod.getChild(0).getName();
143                        logger.debug("  completing arg of method "+methodName);
144                        String className = getClassName(confMethod);
145                        if (className!=null) {
146                            logger.debug("   className = "+className);                        
147                        }
148                    }
149                }
150            }
151            return new Vector();
152        }
153    
154        protected List completeConfMethodParam() {
155            return null;
156        }
157    
158        /**
159         * Gets completion for a block parameter
160         * @param term the Terminal syntax element to complete
161         */
162        protected List completeBlockParam(Terminal term) {
163            logger.debug("complete block param "+term);
164            Vector result = new Vector();
165            NonTerminal block = (NonTerminal)term.findParent("class_block");
166            if (block!=null) {
167                Terminal keyword = (Terminal)block.getChild("BLOCK_KEYWORD");
168                if (keyword!=null) {
169                    if (keyword.getValue().equals("attribute")) {
170                        String className = getClassName(block);
171                        if (className!=null) {
172                            logger.debug("completing attribute for class "+className);
173                            Class cl = project.findClass(className);
174                            if (cl!=null) {
175                                completeAttributeName(term.getValue(),cl,result);
176                            }
177                        }
178                    } else if (keyword.getValue().equals("method")) {
179                        String className = getClassName(block);
180                        if (className!=null) {
181                            logger.debug("completing method for class "+className);
182                            Class cl = project.findClass(className);
183                            if (cl!=null) {
184                                completeMethodName(term.getValue(),cl,result);
185                            }
186                        }
187                    } else if (keyword.getValue().equals("member")) {
188                        String className = getClassName(block);
189                        if (className!=null) {
190                            logger.debug("completing member for class "+className);
191                            Class cl = project.findClass(className);
192                            if (cl!=null) {
193                                completeAttributeName(term.getValue(),cl,result);
194                                completeMethodName(term.getValue(),cl,result);
195                            } else {
196                                logger.warn("No such class in project: "+className);
197                            }
198                        }
199                    } else if (keyword.getValue().equals("class")) {
200                        completeClassName(term.getValue(),result);
201                    } else {
202                        logger.debug("BLOCK_KEYWORD is "+keyword.getValue());
203                    }
204                } else {
205                    logger.debug("No child BLOCK_KEYWORD "+term);
206                }
207            } else {
208                logger.debug("No parent class_block "+term);
209            }
210    
211            return result;
212        } 
213    
214        /**
215         * Gets the className for a member,method or attribute block
216         * @param block Non terminal of the block keyword
217         * @return the class name, or null if it cannot be computed
218         */
219        protected String getClassName(NonTerminal block) {
220            String className = null;
221            block = (NonTerminal)block.getParent().findParent("class_block");
222            if (block!=null) {
223                Terminal keyword = (Terminal)block.getChild("BLOCK_KEYWORD");
224                if (keyword!=null && keyword.getValue().equals("class")) {
225                    NonTerminal blockParams = 
226                        (NonTerminal)block.getChild("block_params");
227                    if (blockParams!=null) {
228                        Terminal param = (Terminal)blockParams.getChild(0);
229                        className = param.getValue();
230                    }
231                }
232            }
233            return className;
234        }
235    
236        protected String getMemberName(NonTerminal block) {
237            String memberName = null;
238            block = (NonTerminal)block.getParent().findParent("class_block");
239            if (block!=null) {
240                Terminal keyword = (Terminal)block.getChild("BLOCK_KEYWORD");
241                if (keyword!=null && 
242                    (keyword.getValue().equals("method") || 
243                     keyword.getValue().equals("attribute"))) {
244                    NonTerminal blockParams = 
245                        (NonTerminal)block.getChild("block_params");
246                    if (blockParams!=null) {
247                        Terminal param = (Terminal)blockParams.getChild(0);
248                        memberName = param.getValue();
249                    }
250                }
251            }
252            return memberName;        
253        }
254    
255        protected void completeAttributeName(String start, Class cl, List result) {
256            Iterator it = cl.getAllFields().iterator();
257            while(it.hasNext()) {
258                Field field = (Field)it.next();
259                if (field.getName().startsWith(start)) {
260                    result.add(field.getGenerationName());
261                }
262            }
263            it = cl.getAllNavigableRoles().iterator();
264            while(it.hasNext()) {
265                RelationRole role = (RelationRole)it.next();
266                if (role.getGenerationName().startsWith(start)) {
267                    result.add(role.getGenerationName());
268                }
269            }
270        }
271    
272        protected void completeMethodName(String start, Class cl, List result) {
273            Iterator it = cl.getMethods().iterator();
274            while(it.hasNext()) {
275                Method method = (Method)it.next();
276                if (method.getName().startsWith(start)) {
277                    result.add(method.getGenerationName());
278                }
279            }
280        }
281    
282        protected void completeClassName(String start, List result) {
283            logger.debug("completing class name "+start);
284            int dot = start.lastIndexOf('.');
285            if (dot==-1) {
286                Iterator it = project.getPackages().iterator();
287                while (it.hasNext()) {
288                    Package pkg = (Package)it.next();
289                    if (pkg.getGenerationName().startsWith(start)) {
290                        result.add(pkg.getPPath());
291                    }
292                }
293             
294            } else {
295                String end = start.substring(dot+1);
296                Package pkg = project.findPackage(start.substring(0,dot));
297    
298                if (pkg!=null) {
299                    logger.debug("Looking for "+end+" in package "+pkg.getPPath());
300                    Iterator it = pkg.getClasses().iterator();
301                    while (it.hasNext()) {
302                        Class cl = (Class)it.next();
303                        if (cl.getGenerationName().startsWith(end)) {
304                            logger.debug("Found class "+cl.getFullName());
305                            result.add(cl.getGenerationFullName());
306                        }
307                    }
308                    it = pkg.getSubPackages().iterator();
309                    while (it.hasNext()) {
310                        Package subPkg = (Package)it.next();
311                        if (subPkg.getGenerationName().startsWith(end)) {
312                            logger.debug("Found package "+subPkg.getPPath());
313                            result.add(subPkg.getPPath());
314                        }
315                    }
316                }
317            }
318        }
319    }