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 }