1 11 package org.eclipse.pde.internal.ui.editor.contentassist; 12 13 import java.util.ArrayList ; 14 import java.util.Arrays ; 15 import java.util.Collection ; 16 import java.util.Comparator ; 17 import java.util.HashMap ; 18 import java.util.HashSet ; 19 import java.util.Map ; 20 import java.util.StringTokenizer ; 21 22 import org.eclipse.core.resources.IProject; 23 import org.eclipse.jdt.core.IJavaProject; 24 import org.eclipse.jdt.core.IPackageFragment; 25 import org.eclipse.jdt.core.JavaCore; 26 import org.eclipse.jdt.core.search.IJavaSearchConstants; 27 import org.eclipse.jdt.launching.JavaRuntime; 28 import org.eclipse.jdt.launching.environments.IExecutionEnvironment; 29 import org.eclipse.jface.resource.ImageDescriptor; 30 import org.eclipse.jface.text.BadLocationException; 31 import org.eclipse.jface.text.IDocument; 32 import org.eclipse.jface.text.IRegion; 33 import org.eclipse.jface.text.ITextViewer; 34 import org.eclipse.jface.text.contentassist.ContentAssistEvent; 35 import org.eclipse.jface.text.contentassist.ICompletionListener; 36 import org.eclipse.jface.text.contentassist.ICompletionProposal; 37 import org.eclipse.osgi.service.resolver.BundleDescription; 38 import org.eclipse.osgi.service.resolver.ExportPackageDescription; 39 import org.eclipse.osgi.util.ManifestElement; 40 import org.eclipse.pde.core.IBaseModel; 41 import org.eclipse.pde.core.plugin.IPluginModelBase; 42 import org.eclipse.pde.core.plugin.ModelEntry; 43 import org.eclipse.pde.core.plugin.PluginRegistry; 44 import org.eclipse.pde.internal.core.ICoreConstants; 45 import org.eclipse.pde.internal.core.ibundle.IBundleModel; 46 import org.eclipse.pde.internal.core.util.HeaderMap; 47 import org.eclipse.pde.internal.core.util.PDEJavaHelper; 48 import org.eclipse.pde.internal.ui.PDEPluginImages; 49 import org.eclipse.pde.internal.ui.editor.PDEFormEditor; 50 import org.eclipse.pde.internal.ui.editor.PDESourcePage; 51 import org.eclipse.pde.internal.ui.editor.plugin.ManifestEditor; 52 import org.eclipse.pde.internal.ui.util.ImageOverlayIcon; 53 import org.eclipse.pde.internal.ui.util.PDEJavaHelperUI; 54 import org.eclipse.swt.graphics.Image; 55 import org.osgi.framework.BundleException; 56 import org.osgi.framework.Constants; 57 import org.osgi.framework.Version; 58 59 public class ManifestContentAssistProcessor extends TypePackageCompletionProcessor implements ICompletionListener { 60 61 protected PDESourcePage fSourcePage; 62 private IJavaProject fJP; 63 64 private static final String [] fHeader = { 66 Constants.BUNDLE_ACTIVATOR, 67 Constants.BUNDLE_ACTIVATIONPOLICY, 68 Constants.BUNDLE_CATEGORY, 69 Constants.BUNDLE_CLASSPATH, 70 Constants.BUNDLE_CONTACTADDRESS, 71 Constants.BUNDLE_COPYRIGHT, 72 Constants.BUNDLE_DESCRIPTION, 73 Constants.BUNDLE_DOCURL, 74 Constants.BUNDLE_LOCALIZATION, 75 Constants.BUNDLE_MANIFESTVERSION, 76 Constants.BUNDLE_NAME, 77 Constants.BUNDLE_NATIVECODE, 78 Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT, 79 Constants.BUNDLE_SYMBOLICNAME, 80 Constants.BUNDLE_UPDATELOCATION, 81 Constants.BUNDLE_VENDOR, 82 Constants.BUNDLE_VERSION, 83 Constants.DYNAMICIMPORT_PACKAGE, 84 ICoreConstants.ECLIPSE_BUDDY_POLICY, 85 ICoreConstants.ECLIPSE_GENERIC_CAPABILITY, 86 ICoreConstants.ECLIPSE_GENERIC_REQUIRED, 87 ICoreConstants.ECLIPSE_LAZYSTART, 88 Constants.EXPORT_PACKAGE, 89 ICoreConstants.PLATFORM_FILTER, 90 ICoreConstants.ECLIPSE_REGISTER_BUDDY, 91 ICoreConstants.EXPORT_SERVICE, 92 Constants.IMPORT_PACKAGE, 93 ICoreConstants.IMPORT_SERVICE, 94 Constants.REQUIRE_BUNDLE, 95 Constants.FRAGMENT_HOST 96 }; 97 98 private static final String BAUMAN = "Brian Bauman"; private static final String ANISZCZYK = "Chris Aniszczyk"; private static final String LASOCKI_BICZYSKO = "Janek Lasocki-Biczysko"; private static final String PAWLOWSKI = "Mike Pawlowski"; private static final String MELHEM = "Wassim Melhem"; 104 private static final String [] fNames = { 105 BAUMAN, 106 ANISZCZYK, 107 LASOCKI_BICZYSKO, 108 PAWLOWSKI, 109 MELHEM 110 }; 111 112 protected static final short 113 F_TYPE_HEADER = 0, F_TYPE_PKG = 1, F_TYPE_BUNDLE = 2, F_TYPE_CLASS = 3, F_TYPE_DIRECTIVE = 4, F_TYPE_ATTRIBUTE = 5, F_TYPE_VALUE = 6, F_TYPE_EXEC_ENV = 7, 122 F_TOTAL_TYPES = 8; 123 124 private final Image[] fImages = new Image[F_TOTAL_TYPES]; 125 126 private static final String [] fExecEnvs; 127 static { 128 IExecutionEnvironment[] envs = JavaRuntime.getExecutionEnvironmentsManager().getExecutionEnvironments(); 129 fExecEnvs = new String [envs.length]; 130 for (int i = 0; i < envs.length; i++) 131 fExecEnvs[i] = envs[i].getId(); 132 Arrays.sort(fExecEnvs, new Comparator () { 133 public int compare(Object o1, Object o2) { 134 return ((String )o1).compareToIgnoreCase((String )o2); 135 } 136 }); 137 } 138 139 Map fHeaders; 140 141 public ManifestContentAssistProcessor(PDESourcePage sourcePage) { 142 fSourcePage = sourcePage; 143 } 144 145 public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, 146 int offset) { 147 IDocument doc = fSourcePage.getDocumentProvider().getDocument(fSourcePage.getInputContext().getInput()); 148 if (fHeaders == null) { 149 parseDocument(doc); 150 } 151 try { 152 int lineNum = doc.getLineOfOffset(offset); 153 int lineStart = doc.getLineOffset(lineNum); 154 return computeCompletionProposals(doc, lineStart, offset); 155 } catch (BadLocationException e) { 156 } 157 return null; 158 } 159 160 protected final void parseDocument(IDocument doc) { 161 fHeaders = new HeaderMap(); 162 int numLines = doc.getNumberOfLines(); 163 int offset = 0; 164 for (int i = 0; i < numLines; i++) { 165 try { 166 IRegion line = doc.getLineInformation(i); 167 String value = doc.get(offset, line.getOffset() + line.getLength() - offset); 168 if (value.indexOf(':') != value.lastIndexOf(':')|| i == (numLines - 1)) { 169 value = doc.get(offset, line.getOffset() - offset - 1).trim(); 170 int index = value.indexOf(':'); 171 String header = (index == -1) ? value : value.substring(0, index); 172 try { 173 if (value.endsWith(",")) value = value.substring(0, value.length() - 1); 175 ManifestElement[] elems = ManifestElement.parseHeader(header, value.substring(index + 1)); 176 if (shouldStoreSet(header)) { 177 HashSet set = new HashSet ((4/3) * elems.length + 1); 178 for (int j = 0; j < elems.length; j++) 179 set.add(elems[j].getValue()); 180 fHeaders.put(header, set); 181 } else 182 fHeaders.put(header, elems); 183 } catch (BundleException e) { 184 } 185 offset = line.getOffset(); 186 } 187 } catch (BadLocationException e) { 188 } 189 } 190 } 191 192 protected final boolean shouldStoreSet(String header) { 193 return header.equalsIgnoreCase(Constants.IMPORT_PACKAGE) || header.equalsIgnoreCase(Constants.EXPORT_PACKAGE) || 194 header.equalsIgnoreCase(Constants.REQUIRE_BUNDLE) || header.equalsIgnoreCase(Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT); 195 } 196 197 protected ICompletionProposal[] computeCompletionProposals(IDocument doc, int startOffset, int offset) { 198 try { 199 if (!isHeader(doc, startOffset, offset)) 200 return computeValue(doc, startOffset, offset); 201 return computeHeader(doc.get(startOffset, offset - startOffset), startOffset, offset); 202 } catch (BadLocationException e) { 203 } 204 return new ICompletionProposal[0]; 205 } 206 207 protected final boolean isHeader(IDocument doc, int startOffset, int offset) throws BadLocationException { 208 String value = doc.get(startOffset, offset - startOffset); 209 if (value.indexOf(':') != -1) 210 return false; 211 for (--startOffset; startOffset >= 0; --startOffset) { 212 char ch = doc.getChar(startOffset); 213 if (!Character.isWhitespace(ch)) 214 return ch != ',' && ch != ':' && ch != ';'; 215 } 216 return true; 217 } 218 219 protected ICompletionProposal[] computeHeader(String currentValue, int startOffset, int offset) { 220 ArrayList completions = new ArrayList (); 221 IBaseModel model = fSourcePage.getInputContext().getModel(); 222 int length = fHeader.length; 223 if (model instanceof IBundleModel && !((IBundleModel)model).isFragmentModel()) 224 --length; 225 for (int i = 0; i < fHeader.length; i++) { 226 if (fHeader[i].regionMatches(true, 0, currentValue, 0, currentValue.length()) && fHeaders.get(fHeader[i]) == null) { 227 TypeCompletionProposal proposal = new TypeCompletionProposal(fHeader[i] + ": ", getImage(F_TYPE_HEADER), fHeader[i], startOffset, currentValue.length()); 229 proposal.setAdditionalProposalInfo(getJavaDoc(fHeader[i])); 230 completions.add(proposal); } 232 } 233 return (ICompletionProposal[]) completions.toArray(new ICompletionProposal[completions.size()]); 234 } 235 236 protected ICompletionProposal[] computeValue(IDocument doc, int startOffset, int offset) throws BadLocationException { 237 String value = doc.get(startOffset, offset - startOffset); 238 int lineNum = doc.getLineOfOffset(startOffset) - 1; 239 int index; 240 while((index = value.indexOf(':')) == -1 || ((value.length() - 1 != index) && (value.charAt(index + 1 ) == '='))) { 241 int startLine = doc.getLineOffset(lineNum); 242 value = doc.get(startLine, offset-startLine); 243 lineNum--; 244 } 245 246 int length = value.length(); 247 if (value.regionMatches(true, 0, Constants.IMPORT_PACKAGE, 0, Math.min(length, Constants.IMPORT_PACKAGE.length()))) 248 return handleImportPackageCompletion(value.substring(Constants.IMPORT_PACKAGE.length() + 1), offset); 249 if (value.regionMatches(true, 0, Constants.FRAGMENT_HOST, 0, Math.min(length, Constants.FRAGMENT_HOST.length()))) 250 return handleFragmentHostCompletion(value.substring(Constants.FRAGMENT_HOST.length() + 1), offset); 251 if (value.regionMatches(true, 0, Constants.REQUIRE_BUNDLE, 0, Math.min(length, Constants.REQUIRE_BUNDLE.length()))) 252 return handleRequireBundleCompletion(value.substring(Constants.REQUIRE_BUNDLE.length() + 1), offset); 253 if (value.regionMatches(true, 0, Constants.EXPORT_PACKAGE, 0, Math.min(length, Constants.EXPORT_PACKAGE.length()))) 254 return handleExportPackageCompletion(value.substring(Constants.EXPORT_PACKAGE.length() + 1), offset); 255 if (value.regionMatches(true, 0, Constants.BUNDLE_ACTIVATOR, 0, Math.min(length, Constants.BUNDLE_ACTIVATOR.length()))) 256 return handleBundleActivatorCompletion(removeLeadingSpaces(value.substring(Constants.BUNDLE_ACTIVATOR.length() + 1)), offset); 257 if (value.regionMatches(true, 0, Constants.BUNDLE_SYMBOLICNAME, 0, Math.min(length, Constants.BUNDLE_SYMBOLICNAME.length()))) 258 return handleBundleSymbolicNameCompletion(value.substring(Constants.BUNDLE_SYMBOLICNAME.length() + 1), offset); 259 if (value.regionMatches(true, 0, Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT, 0, 260 Math.min(length, Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT.length()))) 261 return handleRequiredExecEnv(value.substring(Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT.length() + 1), offset); 262 if (value.regionMatches(true, 0, ICoreConstants.ECLIPSE_LAZYSTART, 0, Math.min(length, ICoreConstants.ECLIPSE_LAZYSTART.length()))) 263 return handleTrueFalseValue(value.substring(ICoreConstants.ECLIPSE_LAZYSTART.length() + 1), offset); 264 if (value.regionMatches(true, 0, Constants.BUNDLE_NAME, 0, Math.min(length, Constants.BUNDLE_NAME.length()))) 265 return handleBundleNameCompletion(value.substring(Constants.BUNDLE_NAME.length() + 1), offset); 266 if (value.regionMatches(true, 0, Constants.BUNDLE_ACTIVATIONPOLICY, 0, Math.min(length, Constants.BUNDLE_ACTIVATIONPOLICY.length()))) 267 return handleBundleActivationPolicyCompletion(value.substring(Constants.BUNDLE_ACTIVATIONPOLICY.length() + 1), offset); 268 if (value.regionMatches(true, 0, ICoreConstants.ECLIPSE_BUDDY_POLICY, 0, Math.min(length, ICoreConstants.ECLIPSE_BUDDY_POLICY.length()))) 269 return handleBuddyPolicyCompletion(value.substring(ICoreConstants.ECLIPSE_BUDDY_POLICY.length() + 1), offset); 270 return new ICompletionProposal[0]; 271 } 272 273 276 protected ICompletionProposal[] handleBundleNameCompletion(String currentValue, int offset) { 277 currentValue = removeLeadingSpaces(currentValue); 278 int length = currentValue.length(); 279 280 if(length == 0) { 282 return new ICompletionProposal[] { 283 new TypeCompletionProposal(BAUMAN, null, BAUMAN, offset - length, length), 284 new TypeCompletionProposal(ANISZCZYK, null, ANISZCZYK, offset - length, length), 285 new TypeCompletionProposal(LASOCKI_BICZYSKO, null, LASOCKI_BICZYSKO, offset - length, length), 286 new TypeCompletionProposal(PAWLOWSKI, null, PAWLOWSKI, offset - length, length), 287 new TypeCompletionProposal(MELHEM, null, MELHEM, offset - length, length) 288 }; 289 } 290 291 for (int i = 0; i < fNames.length; i++) { 293 StringTokenizer tokenizer = new StringTokenizer (currentValue, " "); while (tokenizer.hasMoreTokens()) { 295 String token = tokenizer.nextToken(); 296 if (fNames[i].regionMatches(true, 0, token, 0, token.length())) { 297 return new ICompletionProposal[] { 298 new TypeCompletionProposal( 299 fNames[i], null, fNames[i], offset - token.length(), token.length()) 300 }; 301 } 302 } 303 } 304 return new ICompletionProposal[0]; 305 } 306 307 protected ICompletionProposal[] handleImportPackageCompletion(String currentValue, int offset) { 308 int comma = currentValue.lastIndexOf(','); 309 int semicolon = currentValue.lastIndexOf(';'); 310 String value = comma != -1 ? currentValue.substring(comma + 1) : currentValue; 311 if (comma > semicolon || comma == semicolon) { 312 HashSet set = (HashSet ) fHeaders.get(Constants.IMPORT_PACKAGE); 313 if (set == null) 314 set = parseHeaderForValues(currentValue, offset); 315 HashSet importedBundles = (HashSet ) fHeaders.get(Constants.REQUIRE_BUNDLE); 316 if (importedBundles == null) importedBundles = new HashSet (0); 317 value = removeLeadingSpaces(value); 318 int length = value.length(); 319 set.remove(value); 320 ArrayList completions = new ArrayList (); 321 IPluginModelBase[] bases = PluginRegistry.getActiveModels(); 322 323 for (int j = 0; j < bases.length; j++) { BundleDescription desc = bases[j].getBundleDescription(); 325 if (desc == null || importedBundles.contains(desc.getSymbolicName())) 326 continue; 327 ExportPackageDescription[] expPkgs = desc.getExportPackages(); 328 for (int i = 0; i < expPkgs.length; i++) { 329 String pkgName = expPkgs[i].getName(); 330 if (pkgName.regionMatches(true, 0, value, 0, length) && !set.contains(pkgName)) { 331 completions.add(new TypeCompletionProposal(pkgName, getImage(F_TYPE_PKG), pkgName, offset - length, length)); 332 set.add(pkgName); 333 } 334 } 335 } 336 ICompletionProposal[] proposals = (ICompletionProposal[]) completions.toArray(new ICompletionProposal[completions.size()]); 337 sortCompletions(proposals); 338 return proposals; 339 } 340 int equals = currentValue.lastIndexOf('='); 341 if (equals == -1 || semicolon > equals) { 342 String [] validAtts = new String [] {Constants.RESOLUTION_DIRECTIVE, Constants.VERSION_ATTRIBUTE}; 343 Integer [] validTypes = new Integer [] {new Integer (F_TYPE_DIRECTIVE), new Integer (F_TYPE_ATTRIBUTE)}; 344 return handleAttrsAndDirectives(value, initializeNewList(validAtts), initializeNewList(validTypes), offset); 345 } 346 String attributeValue = removeLeadingSpaces(currentValue.substring(semicolon + 1)); 347 if (Constants.RESOLUTION_DIRECTIVE.regionMatches(true, 0, attributeValue, 0, Constants.RESOLUTION_DIRECTIVE.length())) 348 return matchValueCompletion(currentValue.substring(equals + 1), new String [] { 349 Constants.RESOLUTION_MANDATORY, Constants.RESOLUTION_OPTIONAL} , new int[] {F_TYPE_VALUE, F_TYPE_VALUE}, offset, "RESOLUTION_"); if (Constants.VERSION_ATTRIBUTE.regionMatches(true, 0, attributeValue, 0, Constants.VERSION_ATTRIBUTE.length())) { 351 value = removeLeadingSpaces(currentValue.substring(equals + 1)); 352 if (value.length() == 0) 353 return new ICompletionProposal[] {new TypeCompletionProposal("\"\"", getImage(F_TYPE_VALUE), "\"\"", offset, 0)}; } 355 return new ICompletionProposal[0]; 356 } 357 358 private ICompletionProposal[] handleXFriendsCompletion(String value, final int offset) { 359 ManifestElement[] elems = (ManifestElement[])fHeaders.get(Constants.BUNDLE_SYMBOLICNAME); 360 HashSet set = new HashSet (); 361 if (elems != null && elems.length > 0) 362 set.add(elems[0].getValue()); 363 value = removeLeadingSpaces(value); 364 if (value.length() == 0) 365 return new ICompletionProposal[] {new TypeCompletionProposal("\"\"", getImage(F_TYPE_VALUE), "\"\"", offset, 0)}; if (value.charAt(0) == '"') 367 value = value.substring(1); 368 int index = value.lastIndexOf(','); 369 StringTokenizer tokenizer = new StringTokenizer (value, ","); while (tokenizer.hasMoreTokens()) 371 set.add(tokenizer.nextToken()); 372 return handleBundleCompletions(value.substring((index == -1) ? 0 : index + 1), set, F_TYPE_VALUE, offset, true); 373 } 374 375 protected ICompletionProposal[] handleFragmentHostCompletion(String currentValue, int offset) { 376 int index = currentValue.lastIndexOf(';'); 377 if (index == -1) { 378 HashMap completions = new HashMap (); 379 IPluginModelBase base = PluginRegistry.findModel(((ManifestEditor)fSourcePage.getEditor()).getCommonProject()); 380 BundleDescription desc = base.getBundleDescription(); 381 String currentId = desc != null ? desc.getSymbolicName() : null; 382 383 String pluginStart = removeLeadingSpaces(currentValue); 384 int length = pluginStart.length(); 385 IPluginModelBase [] bases = PluginRegistry.getActiveModels(); 386 for (int i = 0; i < bases.length; i++) { 387 desc = bases[i].getBundleDescription(); 388 if (desc != null && desc.getHost() == null) { 389 String pluginID = bases[i].getBundleDescription().getSymbolicName(); 390 if (!completions.containsKey(pluginID) && pluginID.regionMatches(true, 0, pluginStart, 0, length) && !pluginID.equals(currentId)) 391 completions.put(pluginID, new TypeCompletionProposal(pluginID, getImage(F_TYPE_BUNDLE), pluginID, offset - length, length)); 392 } 393 } 394 return (ICompletionProposal[]) completions.values().toArray(new ICompletionProposal[completions.size()]); 395 } 396 int equals = currentValue.lastIndexOf('='); 397 if (equals == -1 || index > equals) 398 return matchValueCompletion(removeLeadingSpaces(currentValue.substring(index + 1)), new String [] { 399 Constants.BUNDLE_VERSION_ATTRIBUTE }, new int[] {F_TYPE_ATTRIBUTE}, offset); 400 String attributeValue = removeLeadingSpaces(currentValue.substring(index + 1)); 401 if (Constants.BUNDLE_VERSION_ATTRIBUTE.regionMatches(true, 0, attributeValue, 0, Constants.BUNDLE_VERSION_ATTRIBUTE.length())) { 402 return getBundleVersionCompletions(currentValue.substring(0, index).trim(), removeLeadingSpaces(currentValue.substring(equals + 1)), offset); 403 } 404 return new ICompletionProposal[0]; 405 } 406 407 protected ICompletionProposal[] handleRequireBundleCompletion(String currentValue, int offset) { 408 int comma = currentValue.lastIndexOf(','); 409 int semicolon = currentValue.lastIndexOf(';'); 410 String value = comma != -1 ? currentValue.substring(comma + 1) : currentValue; 411 if (comma > semicolon || comma == semicolon) { 412 HashSet set = (HashSet ) fHeaders.get(Constants.REQUIRE_BUNDLE); 413 if (set == null) 414 set = parseHeaderForValues(currentValue, offset); 415 return handleBundleCompletions(value, set, F_TYPE_BUNDLE, offset, false); 416 } 417 int equals = currentValue.lastIndexOf('='); 418 if (equals == -1 || semicolon > equals) { 419 String [] validAttrs = new String [] {Constants.BUNDLE_VERSION_ATTRIBUTE, Constants.RESOLUTION_DIRECTIVE, Constants.VISIBILITY_DIRECTIVE}; 420 Integer [] validTypes = new Integer [] {new Integer (F_TYPE_ATTRIBUTE), new Integer (F_TYPE_DIRECTIVE), new Integer (F_TYPE_DIRECTIVE)}; 421 return handleAttrsAndDirectives(value, initializeNewList(validAttrs), initializeNewList(validTypes), offset); 422 } 423 String attributeValue = removeLeadingSpaces(currentValue.substring(semicolon + 1)); 424 if (Constants.VISIBILITY_DIRECTIVE.regionMatches(true, 0, attributeValue, 0, Constants.VISIBILITY_DIRECTIVE.length())) 425 return matchValueCompletion(currentValue.substring(equals + 1), new String [] { 426 Constants.VISIBILITY_PRIVATE, Constants.VISIBILITY_REEXPORT}, new int[] {F_TYPE_VALUE, F_TYPE_VALUE}, offset, "VISIBILITY_"); if (Constants.RESOLUTION_DIRECTIVE.regionMatches(true, 0, attributeValue, 0, Constants.RESOLUTION_DIRECTIVE.length())) 428 return matchValueCompletion(currentValue.substring(equals + 1), new String [] { 429 Constants.RESOLUTION_MANDATORY, Constants.RESOLUTION_OPTIONAL} , new int[] {F_TYPE_VALUE, F_TYPE_VALUE}, offset, "RESOLUTION_"); if (Constants.BUNDLE_VERSION_ATTRIBUTE.regionMatches(true, 0, attributeValue, 0, Constants.RESOLUTION_DIRECTIVE.length())) { 431 String pluginId = removeLeadingSpaces(currentValue.substring((comma == -1) ? 0 : comma + 1, semicolon)); 432 return getBundleVersionCompletions(pluginId, removeLeadingSpaces(currentValue.substring(equals + 1)), offset); 433 } 434 return new ICompletionProposal[0]; 435 } 436 437 private ICompletionProposal[] getBundleVersionCompletions(String pluginID, String existingValue, int offset) { 438 ModelEntry entry = PluginRegistry.findEntry(pluginID); 439 if (entry != null) { 440 IPluginModelBase[] hosts = entry.getActiveModels(); 441 ArrayList proposals = new ArrayList (hosts.length); 442 for (int i = 0; i < hosts.length; i++) { 443 String proposalValue = getVersionProposal(hosts[i]); 444 if (proposalValue.regionMatches(0, existingValue, 0, existingValue.length())) 445 proposals.add(new TypeCompletionProposal(proposalValue.substring(existingValue.length()), 446 getImage(F_TYPE_VALUE), proposalValue, offset, 0)); 447 } 448 return (ICompletionProposal[])proposals.toArray(new ICompletionProposal[proposals.size()]); 449 } else if (existingValue.length() == 0) 450 return new ICompletionProposal[] {new TypeCompletionProposal("\"\"", getImage(F_TYPE_VALUE), "\"\"", offset, 0)}; return new ICompletionProposal[0]; 452 } 453 454 private String getVersionProposal(IPluginModelBase base) { 455 StringBuffer buffer = new StringBuffer ("\""); BundleDescription desc = base.getBundleDescription(); 457 if (desc != null) { 458 Version version = desc.getVersion(); 459 buffer.append(version.getMajor()); 460 buffer.append('.'); 461 buffer.append(version.getMinor()); 462 buffer.append('.'); 463 buffer.append(version.getMicro()); 464 } else { 465 char[] chars = base.getPluginBase().getVersion().toCharArray(); 466 int periodCount = 0; 467 for (int i = 0; i < chars.length; i++) { 468 if (chars[i] == '.') { 469 if (periodCount == 2) 470 break; 471 ++periodCount; 472 } 473 buffer.append(chars[i]); 474 } 475 } 476 return buffer.append('\"').toString(); 477 } 478 479 private ICompletionProposal[] handleBundleCompletions(String value, Collection doNotInclude, int type, int offset, boolean includeFragments) { 480 value = removeLeadingSpaces(value); 481 int length = value.length(); 482 doNotInclude.remove(value); 483 ArrayList completions = new ArrayList (); 484 IPluginModelBase [] bases = PluginRegistry.getActiveModels(); 485 for (int i = 0; i < bases.length; i++) { 486 BundleDescription desc = bases[i].getBundleDescription(); 487 if (desc != null) { 488 if (!includeFragments && desc.getHost() != null) 489 continue; 490 String bundleId = desc.getSymbolicName(); 491 if (bundleId.regionMatches(true, 0, value, 0, value.length()) && 492 !doNotInclude.contains(bundleId)) 493 completions.add(new TypeCompletionProposal(bundleId, getImage(type), bundleId, offset - length, length)); 494 } 495 } 496 return (ICompletionProposal[]) completions.toArray(new ICompletionProposal[completions.size()]); 497 } 498 499 protected ICompletionProposal[] handleExportPackageCompletion(String currentValue, int offset) { 500 int comma = currentValue.lastIndexOf(','); 501 int semicolon = currentValue.lastIndexOf(';'); 502 ArrayList list = new ArrayList (); 503 if (!insideQuotes(currentValue) && comma > semicolon || comma == semicolon) { 504 String value = comma != -1 ? currentValue.substring(comma + 1) : currentValue; 505 HashSet set = (HashSet ) fHeaders.get(Constants.EXPORT_PACKAGE); 506 if (set == null) 507 set = parseHeaderForValues(currentValue, offset); 508 value = removeLeadingSpaces(value); 509 int length = value.length(); 510 IProject proj = ((PDEFormEditor)fSourcePage.getEditor()).getCommonProject(); 511 if (proj != null) { 512 IJavaProject jp = JavaCore.create(proj); 513 IPackageFragment[] frags = PDEJavaHelper.getPackageFragments(jp, set, false); 514 for (int i = 0; i < frags.length; i++) { 515 String name = frags[i].getElementName(); 516 if (name.regionMatches(true, 0, value, 0, length)) 517 list.add(new TypeCompletionProposal(name, getImage(F_TYPE_PKG), name, offset - length, length)); 518 } 519 } 520 } else { 521 String value = currentValue; 522 if (comma > 0) { 523 do { 524 String prefix = currentValue.substring(0, comma); 525 if (!insideQuotes(prefix)) { 526 value = currentValue.substring(comma + 1); 527 break; 528 } 529 comma = currentValue.lastIndexOf(',', comma - 1); 530 } while (comma > 0); 531 } 532 int equals = currentValue.lastIndexOf('='); 533 if (equals == -1 || semicolon > equals) { 534 String [] validAttrs = new String [] {Constants.VERSION_ATTRIBUTE, ICoreConstants.INTERNAL_DIRECTIVE, 535 ICoreConstants.FRIENDS_DIRECTIVE}; 536 Integer [] validTypes = new Integer [] {new Integer (F_TYPE_ATTRIBUTE), new Integer (F_TYPE_DIRECTIVE), new Integer (F_TYPE_DIRECTIVE)}; 537 return handleAttrsAndDirectives(value, initializeNewList(validAttrs), initializeNewList(validTypes), offset); 538 } 539 String attributeValue = removeLeadingSpaces(currentValue.substring(semicolon + 1)); 540 if (ICoreConstants.FRIENDS_DIRECTIVE.regionMatches(true, 0, attributeValue, 0, ICoreConstants.FRIENDS_DIRECTIVE.length())) 541 return handleXFriendsCompletion(currentValue.substring(equals + 1), offset); 542 if (ICoreConstants.INTERNAL_DIRECTIVE.regionMatches(true, 0, attributeValue, 0, ICoreConstants.INTERNAL_DIRECTIVE.length())) 543 return handleTrueFalseValue(currentValue.substring(equals + 1), offset); 544 if (Constants.VERSION_ATTRIBUTE.regionMatches(true, 0, attributeValue, 0, Constants.VERSION_ATTRIBUTE.length())) { 545 value = removeLeadingSpaces(currentValue.substring(equals + 1)); 546 if (value.length() == 0) 547 return new ICompletionProposal[] {new TypeCompletionProposal("\"\"", getImage(F_TYPE_VALUE), "\"\"", offset, 0)}; } 549 } 550 return (ICompletionProposal[]) list.toArray(new ICompletionProposal[list.size()]); 551 } 552 553 protected ICompletionProposal[] handleBundleActivatorCompletion(final String currentValue, final int offset) { 554 ArrayList completions = new ArrayList (); 555 IProject project = ((PDEFormEditor)fSourcePage.getEditor()).getCommonProject(); 556 int startOffset = offset - currentValue.length(); 557 generateTypePackageProposals(currentValue, project, completions, startOffset, IJavaSearchConstants.CLASS); 558 ICompletionProposal[] proposals = (ICompletionProposal[]) completions.toArray(new ICompletionProposal[completions.size()]); 559 sortCompletions(proposals); 560 return proposals; 561 } 562 563 protected ICompletionProposal[] handleBundleSymbolicNameCompletion(String currentValue, int offset) { 564 int semicolon = currentValue.indexOf(';'); 565 if (semicolon != -1) { 566 int equals = currentValue.indexOf('='); 567 if (equals == -1) { 568 String attribute = currentValue.substring(semicolon + 1); 569 attribute = removeLeadingSpaces(attribute); 570 Object o = fHeaders.get(Constants.BUNDLE_MANIFESTVERSION); 571 int type = (o == null || o.toString().equals("1")) ? F_TYPE_ATTRIBUTE : F_TYPE_DIRECTIVE; if (Constants.SINGLETON_DIRECTIVE.regionMatches(true, 0, attribute, 0, attribute.length())) { 573 int length = attribute.length(); 574 TypeCompletionProposal proposal = new TypeCompletionProposal(Constants.SINGLETON_DIRECTIVE + ":=", getImage(type), Constants.SINGLETON_DIRECTIVE, offset - length, length); 576 proposal.setAdditionalProposalInfo(getJavaDoc("SINGLETON_DIRECTIVE")); return new ICompletionProposal[] {proposal}; 578 } 579 } else if (equals > semicolon) 580 return handleTrueFalseValue(currentValue.substring(equals + 1), offset); 581 } 582 return new ICompletionProposal[0]; 583 } 584 585 protected ICompletionProposal[] handleBundleActivationPolicyCompletion(final String currentValue, final int offset) { 586 int comma = currentValue.lastIndexOf(','); 587 int semicolon = currentValue.lastIndexOf(';'); 588 if (!insideQuotes(currentValue) && comma > semicolon || comma == semicolon) { 589 String value = removeLeadingSpaces(currentValue); 590 String lazyValue = "lazy"; int length = value.length(); 592 if (lazyValue.regionMatches(0, value, 0, length)) 593 return new ICompletionProposal[] {new TypeCompletionProposal(lazyValue, null, lazyValue, offset - length, length)}; 594 } 595 return new ICompletionProposal[0]; 596 } 597 598 protected ICompletionProposal[] handleBuddyPolicyCompletion(String currentValue, int offset) { 599 String value = removeLeadingSpaces(currentValue); 600 ArrayList validValues = initializeNewList(new String [] {"dependent", "global", "registered", "app", "ext", "boot", "parent"}); ArrayList types = initializeNewList(new Object [] {new Integer (F_TYPE_VALUE), new Integer (F_TYPE_VALUE), new Integer (F_TYPE_VALUE), 604 new Integer (F_TYPE_VALUE), new Integer (F_TYPE_VALUE), new Integer (F_TYPE_VALUE), new Integer (F_TYPE_VALUE)}); 605 return handleAttrsAndDirectives(value, validValues, types, offset); 606 } 607 608 protected ICompletionProposal[] handleRequiredExecEnv(String currentValue, int offset) { 609 int comma = currentValue.lastIndexOf(','); 610 if (comma != -1) 611 currentValue = currentValue.substring(comma + 1); 612 currentValue = removeLeadingSpaces(currentValue); 613 ArrayList completions = new ArrayList (); 614 HashSet set = (HashSet )fHeaders.get(Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT); 615 if (set == null) set = new HashSet (0); 616 int length = currentValue.length(); 617 for (int i = 0; i < fExecEnvs.length; i++) 618 if (fExecEnvs[i].regionMatches(true, 0, currentValue, 0, length) && 619 !set.contains(fExecEnvs[i])) 620 completions.add(new TypeCompletionProposal(fExecEnvs[i], getImage(F_TYPE_EXEC_ENV), fExecEnvs[i], offset - length, length)); 621 return (ICompletionProposal[]) completions.toArray(new ICompletionProposal[completions.size()]); 622 } 623 624 protected ICompletionProposal[] handleTrueFalseValue(String currentValue, int offset) { 625 currentValue = removeLeadingSpaces(currentValue); 626 int length = currentValue.length(); 627 if (length == 0) 628 return new ICompletionProposal[] { 629 new TypeCompletionProposal("true", getImage(F_TYPE_VALUE), "true", offset, 0), new TypeCompletionProposal("false", getImage(F_TYPE_VALUE), "false", offset, 0) }; 632 else if (length < 5 && "true".regionMatches(true, 0, currentValue, 0, length)) return new ICompletionProposal[] { 634 new TypeCompletionProposal("true", getImage(F_TYPE_VALUE), "true", offset - length, length) }; 636 else if (length < 6 && "false".regionMatches(true, 0, currentValue, 0, length)) return new ICompletionProposal[] { 638 new TypeCompletionProposal("false", getImage(F_TYPE_VALUE), "false", offset - length, length) }; 640 return new ICompletionProposal[0]; 641 } 642 643 protected ICompletionProposal[] matchValueCompletion(String value, String [] attrs, int[] types, int offset) { 644 return matchValueCompletion(value, attrs, types, offset, ""); } 646 647 protected ICompletionProposal[] matchValueCompletion(String value, String [] attrs, int[] types, int offset, String prefixCostant) { 648 ArrayList list = new ArrayList (); 649 int length = value.length(); 650 TypeCompletionProposal proposal = null; 651 for (int i = 0; i < attrs.length; i++) 652 if (attrs[i].regionMatches(true, 0, value, 0, length)) { 653 if (types[i] == F_TYPE_ATTRIBUTE) { 654 proposal = new TypeCompletionProposal(attrs[i] + "=", getImage(F_TYPE_ATTRIBUTE), attrs[i], offset - length, length); proposal.setAdditionalProposalInfo(getJavaDoc(attrs[i] + "_ATTRIBUTE")); } else if (types[i] == F_TYPE_DIRECTIVE) { 657 proposal = new TypeCompletionProposal(attrs[i] + ":=", getImage(F_TYPE_DIRECTIVE), attrs[i], offset - length, length); proposal.setAdditionalProposalInfo(getJavaDoc(attrs[i] + "_DIRECTIVE")); } else { 660 proposal = new TypeCompletionProposal(attrs[i], getImage(types[i]), attrs[i], offset - length, length); 661 proposal.setAdditionalProposalInfo(getJavaDoc(prefixCostant + attrs[i])); 662 } 663 list.add(proposal); 664 } 665 return (ICompletionProposal[]) list.toArray(new ICompletionProposal[list.size()]); 666 } 667 668 protected ICompletionProposal[] handleAttrsAndDirectives(String value, ArrayList attrs, ArrayList types, int offset) { 669 String fullValue = findFullLine(value, offset, false); 670 int semicolon = value.lastIndexOf(';'); 671 value = removeLeadingSpaces(value.substring(semicolon + 1)); 672 StringTokenizer tokenizer = new StringTokenizer (fullValue, ";"); tokenizer.nextToken(); 674 while (tokenizer.hasMoreTokens()) { 675 String tokenValue = removeLeadingSpaces(tokenizer.nextToken()); 676 int index = tokenValue.indexOf('='); 677 if (index == -1) 678 continue; 679 if (tokenValue.charAt(index - 1) == ':') 680 --index; 681 tokenValue = tokenValue.substring(0, index); 682 int indexOfObject = attrs.indexOf(tokenValue); 683 if (indexOfObject >= 0) { 684 attrs.remove(indexOfObject); 685 types.remove(indexOfObject); 686 } 687 } 688 return matchValueCompletion(value, (String [])attrs.toArray(new String [attrs.size()]), toIntArray(types), offset); 689 } 690 691 private HashSet parseHeaderForValues(String currentValue, int offset) { 692 HashSet set = new HashSet (); 693 String fullValue = findFullLine(currentValue, offset, true); 694 StringTokenizer tokenizer = new StringTokenizer (fullValue, ","); while(tokenizer.hasMoreTokens()) { 696 String pkgValue = tokenizer.nextToken(); 697 int index = pkgValue.indexOf(';'); 698 set.add(index == -1 ? pkgValue.trim() : pkgValue.substring(0, index).trim()); 699 } 700 return set; 701 } 702 703 private String findFullLine(String value, int offset, boolean entireHeader) { 704 IDocument doc = fSourcePage.getDocumentProvider().getDocument(fSourcePage.getInputContext().getInput()); 705 try { 706 int line = doc.getLineOfOffset(offset); 707 String newValue = ""; int startOfLine = 0; 709 int colon = -1; 710 do { 711 startOfLine = doc.getLineOffset(line); 712 newValue = doc.get(offset, doc.getLineLength(line) - offset + startOfLine); 713 ++line; 714 colon = newValue.lastIndexOf(':'); 715 } while ((colon == -1 || (newValue.length() > colon && newValue.charAt(colon + 1) == '=')) && 716 (entireHeader || newValue.indexOf(',') == -1) && !(doc.getNumberOfLines() == line)); 717 if (colon > 0 && newValue.charAt(colon +1) != '=') { 718 newValue = doc.get(offset, startOfLine - 1 - offset); 719 } else { 720 int comma = newValue.indexOf(','); 721 newValue = (comma != -1) ? newValue.substring(0, comma) : newValue; 722 } 723 return value.concat(newValue); 724 } catch (BadLocationException e) { 725 } 726 return ""; } 728 729 private int[] toIntArray(ArrayList list) { 730 int[] result = new int[list.size()]; 731 int i = -1; 732 while (++i < result.length) { 733 Object o = list.get(i); 734 if (!(o instanceof Integer )) 735 return new int[0]; 736 result[i] = ((Integer )o).intValue(); 737 } 738 return result; 739 } 740 741 protected final ArrayList initializeNewList(Object [] values) { 743 ArrayList list = new ArrayList (values.length); 744 for (int i = 0; i < values.length; i++) 745 list.add(values[i]); 746 return list; 747 } 748 749 private boolean insideQuotes(String value) { 750 char[] chars = value.toCharArray(); 751 int numOfQuotes = 0; 752 for (int i = 0; i < chars.length; i++) 753 if (chars[i] == '\"') 754 ++numOfQuotes; 755 int j = numOfQuotes % 2; 756 return j == 1; 757 } 758 759 public void assistSessionEnded(ContentAssistEvent event) { 760 fHeaders = null; 761 } 762 763 public void assistSessionStarted(ContentAssistEvent event) { 764 } 765 766 public void selectionChanged(ICompletionProposal proposal, boolean smartToggle) { 767 } 768 769 public Image getImage(int type) { 770 if (type >= 0 && type < F_TOTAL_TYPES) 771 if (fImages[type] == null) { 772 switch(type) { 773 case F_TYPE_HEADER: 774 return fImages[type] = PDEPluginImages.DESC_BUILD_VAR_OBJ.createImage(); 775 case F_TYPE_PKG: 776 return PDEPluginImages.get(PDEPluginImages.OBJ_DESC_PACKAGE); 777 case F_TYPE_BUNDLE: 778 return fImages[type] = PDEPluginImages.DESC_PLUGIN_OBJ.createImage(); 779 case F_TYPE_CLASS: 780 return PDEPluginImages.get(PDEPluginImages.OBJ_DESC_GENERATE_CLASS); 781 case F_TYPE_ATTRIBUTE: 782 return fImages[type] = PDEPluginImages.DESC_ATT_URI_OBJ.createImage(); 783 case F_TYPE_DIRECTIVE: 784 fImages[F_TYPE_ATTRIBUTE] = PDEPluginImages.DESC_ATT_URI_OBJ.createImage(); 785 ImageOverlayIcon icon = new ImageOverlayIcon(fImages[F_TYPE_ATTRIBUTE], 786 new ImageDescriptor[][] {new ImageDescriptor[] {PDEPluginImages.DESC_DOC_CO}, null, null, null}); 787 return fImages[type] = icon.createImage(); 788 case F_TYPE_EXEC_ENV: 789 return fImages[type] = PDEPluginImages.DESC_JAVA_LIB_OBJ.createImage(); 790 case F_TYPE_VALUE: 791 return null; 792 } 793 } else 794 return fImages[type]; 795 return null; 796 } 797 798 public void dispose() { 799 for (int i = 0; i < fImages.length; i++) 800 if (fImages[i] != null && !fImages[i].isDisposed()) 801 fImages[i].dispose(); 802 } 803 804 private String getJavaDoc(String constant) { 805 if (fJP == null) { 806 IProject project = ((PDEFormEditor)fSourcePage.getEditor()).getCommonProject(); 807 fJP = JavaCore.create(project); 808 } 809 return PDEJavaHelperUI.getOSGIConstantJavaDoc(constant, fJP); 810 } 811 812 } | Popular Tags |