1 11 12 package org.eclipse.pde.internal.ui.editor.contentassist; 13 14 import java.util.HashSet ; 15 import java.util.Stack ; 16 17 import org.eclipse.core.runtime.CoreException; 18 import org.eclipse.core.runtime.IProgressMonitor; 19 import org.eclipse.jface.text.AbstractReusableInformationControlCreator; 20 import org.eclipse.jface.text.BadLocationException; 21 import org.eclipse.jface.text.IDocument; 22 import org.eclipse.jface.text.IInformationControl; 23 import org.eclipse.jface.text.IInformationControlCreator; 24 import org.eclipse.jface.text.ITextSelection; 25 import org.eclipse.jface.text.TextUtilities; 26 import org.eclipse.jface.text.contentassist.ICompletionProposal; 27 import org.eclipse.jface.text.contentassist.ICompletionProposalExtension3; 28 import org.eclipse.jface.text.contentassist.ICompletionProposalExtension5; 29 import org.eclipse.jface.text.contentassist.IContextInformation; 30 import org.eclipse.pde.core.IBaseModel; 31 import org.eclipse.pde.core.plugin.IPluginAttribute; 32 import org.eclipse.pde.core.plugin.IPluginBase; 33 import org.eclipse.pde.core.plugin.IPluginElement; 34 import org.eclipse.pde.core.plugin.IPluginExtension; 35 import org.eclipse.pde.core.plugin.IPluginModelBase; 36 import org.eclipse.pde.core.plugin.IPluginObject; 37 import org.eclipse.pde.core.plugin.IPluginParent; 38 import org.eclipse.pde.internal.core.ischema.ISchemaAttribute; 39 import org.eclipse.pde.internal.core.ischema.ISchemaElement; 40 import org.eclipse.pde.internal.core.ischema.ISchemaObject; 41 import org.eclipse.pde.internal.core.text.AbstractEditingModel; 42 import org.eclipse.pde.internal.core.text.IDocumentAttribute; 43 import org.eclipse.pde.internal.core.text.IDocumentNode; 44 import org.eclipse.pde.internal.core.text.IDocumentRange; 45 import org.eclipse.pde.internal.core.text.IReconcilingParticipant; 46 import org.eclipse.pde.internal.core.text.plugin.PluginAttribute; 47 import org.eclipse.pde.internal.ui.PDEPlugin; 48 import org.eclipse.pde.internal.ui.PDEUIMessages; 49 import org.eclipse.pde.internal.ui.editor.PDESourcePage; 50 import org.eclipse.pde.internal.ui.editor.contentassist.display.BrowserInformationControl; 51 import org.eclipse.pde.internal.ui.editor.text.HTMLPrinter; 52 import org.eclipse.pde.internal.ui.editor.text.XMLUtil; 53 import org.eclipse.pde.internal.ui.util.TextUtil; 54 import org.eclipse.swt.SWT; 55 import org.eclipse.swt.graphics.Image; 56 import org.eclipse.swt.graphics.Point; 57 import org.eclipse.swt.widgets.Shell; 58 59 public class XMLCompletionProposal implements ICompletionProposal, ICompletionProposalExtension5, ICompletionProposalExtension3 { 60 61 private static final String F_DEF_ATTR_INDENT = " "; 63 private ISchemaObject fSchemaObject; 64 private IDocumentRange fRange; 65 private int fOffset; 66 private int fLen; 67 private int fSelOffset; 68 private int fSelLen; 69 private XMLContentAssistProcessor fProcessor; 70 private String fAddInfo; 71 private IInformationControlCreator fCreator; 72 73 private IPluginParent fPluginParent; 74 private ISchemaElement fSchemaElement; 75 76 public XMLCompletionProposal(IDocumentRange node, ISchemaObject object, int offset, XMLContentAssistProcessor processor) { 77 fLen = -1; 78 fSelOffset = -1; 79 fSelLen = 0; 80 fRange = node; 81 fSchemaObject = object; 82 fOffset = offset; 83 fProcessor = processor; 84 } 85 86 public void apply(IDocument document) { 87 ITextSelection sel = fProcessor.getCurrentSelection(); 88 if (sel == null) { 89 return; 90 } 91 fLen = sel.getLength() + sel.getOffset() - fOffset; 92 String delim = TextUtilities.getDefaultLineDelimiter(document); 93 StringBuffer documentInsertBuffer = new StringBuffer (); 94 boolean doInternalWork = false; 95 if (fSchemaObject instanceof ISchemaAttribute) { 97 applyAttribute(documentInsertBuffer); 98 } else if (fSchemaObject instanceof ISchemaElement) { 99 applyElement(getIndent(document, fOffset), delim, documentInsertBuffer); 100 doInternalWork = true; 101 } else if (fSchemaObject instanceof VirtualSchemaObject) { 102 doInternalWork = applyVirtual(document, sel, delim, documentInsertBuffer, doInternalWork); 103 } 104 if (documentInsertBuffer.length() == 0) { 106 return; 107 } 108 try { 110 document.replace(fOffset, fLen, documentInsertBuffer.toString()); 111 } catch (BadLocationException e) { 112 PDEPlugin.log(e); 113 } 114 if (doInternalWork) { 116 modifyModel(document); 117 } 118 } 119 120 128 private boolean applyVirtual(IDocument document, ITextSelection sel, String delim, StringBuffer documentInsertBuffer, boolean doInternalWork) { 129 int type = ((VirtualSchemaObject)fSchemaObject).getVType(); 130 switch (type) { 131 case XMLContentAssistProcessor.F_ATTRIBUTE: 132 applyAttribute(documentInsertBuffer); 133 break; 134 case XMLContentAssistProcessor.F_CLOSE_TAG: 135 fOffset = sel.getOffset(); 136 fLen = 0; 137 documentInsertBuffer.append(" />"); break; 139 case XMLContentAssistProcessor.F_EXTENSION: 140 applyExtension(document, delim, documentInsertBuffer); 141 break; 142 case XMLContentAssistProcessor.F_EXTENSION_POINT: 143 applyExtensionPoint(documentInsertBuffer); 144 break; 145 case XMLContentAssistProcessor.F_EXTENSION_POINT_AND_VALUE: 146 doInternalWork = true; applyExtensionFullPoint(document, delim, documentInsertBuffer); 148 break; 149 case XMLContentAssistProcessor.F_EXTENSION_ATTRIBUTE_POINT_VALUE: 150 doInternalWork = true; case XMLContentAssistProcessor.F_ATTRIBUTE_VALUE: 152 applyAttributeValue(document, documentInsertBuffer); 153 break; 154 } 155 return doInternalWork; 156 } 157 158 162 private void applyAttributeValue(IDocument document, StringBuffer documentInsertBuffer) { 163 if (fRange instanceof IDocumentAttribute) { 164 fOffset = ((IDocumentAttribute)fRange).getValueOffset(); 165 String value = fSchemaObject.getName(); 166 try { 167 int off = fOffset; 169 int docLen = document.getLength(); 170 fLen = 0; 171 while (off < docLen) { 172 char c = document.getChar(off++); 173 if (c == '"') 174 break; 175 fLen += 1; 176 } 177 } catch (BadLocationException e) { 178 } 179 documentInsertBuffer.append(value); 180 fSelOffset = fOffset + value.length(); 181 } 182 } 183 184 187 private void applyExtensionPoint(StringBuffer documentInsertBuffer) { 188 String id = "id"; documentInsertBuffer.append("<extension-point id=\""); fSelOffset = fOffset + documentInsertBuffer.length(); 191 fSelLen = id.length(); 192 documentInsertBuffer.append(id); 193 documentInsertBuffer.append("\" name=\"name\" />"); } 195 196 201 private void applyExtension(IDocument document, String delim, StringBuffer documentInsertBuffer) { 202 documentInsertBuffer.append("<extension"); documentInsertBuffer.append(delim); 204 String indent = getIndent(document, fOffset); 205 documentInsertBuffer.append(indent); 206 documentInsertBuffer.append(F_DEF_ATTR_INDENT); 207 documentInsertBuffer.append("point=\"\">"); fSelOffset = fOffset + documentInsertBuffer.length() - 2; documentInsertBuffer.append(delim); 210 documentInsertBuffer.append(indent); 211 documentInsertBuffer.append("</extension>"); } 213 214 219 private void applyExtensionFullPoint(IDocument document, String delim, 220 StringBuffer documentInsertBuffer) { 221 222 String pointID = fSchemaObject.getName(); 223 String indent = getIndent(document, fOffset); 224 documentInsertBuffer.append('<'); 227 documentInsertBuffer.append("extension"); documentInsertBuffer.append(delim); 229 documentInsertBuffer.append(indent); 230 documentInsertBuffer.append(F_DEF_ATTR_INDENT); 231 documentInsertBuffer.append("point"); documentInsertBuffer.append('='); 233 documentInsertBuffer.append('"'); 234 fSelOffset = fOffset + documentInsertBuffer.length(); 238 fSelLen = pointID.length(); 240 documentInsertBuffer.append(pointID); 243 documentInsertBuffer.append('"'); 244 documentInsertBuffer.append('>'); 245 documentInsertBuffer.append(delim); 246 documentInsertBuffer.append(indent); 247 documentInsertBuffer.append('<'); 248 documentInsertBuffer.append('/'); 249 documentInsertBuffer.append("extension"); documentInsertBuffer.append('>'); 251 } 252 253 258 private void applyElement(String indent, String delim, StringBuffer documentInsertBuffer) { 259 documentInsertBuffer.append('<'); 260 documentInsertBuffer.append(((ISchemaElement)fSchemaObject).getName()); 261 documentInsertBuffer.append('>'); 262 documentInsertBuffer.append(delim); 263 documentInsertBuffer.append(indent); 264 documentInsertBuffer.append('<'); 265 documentInsertBuffer.append('/'); 266 documentInsertBuffer.append(((ISchemaElement)fSchemaObject).getName()); 267 documentInsertBuffer.append('>'); 268 } 269 270 273 private void applyAttribute(StringBuffer documentInsertBuffer) { 274 if (fRange == null) { 275 fLen -= 1; 278 fOffset += 1; 279 } 280 String attName = fSchemaObject.getName(); 281 documentInsertBuffer.append(attName); 282 documentInsertBuffer.append("=\""); fSelOffset = fOffset + documentInsertBuffer.length(); 284 String value = attName; if (fSchemaObject instanceof ISchemaAttribute) { 286 value = XMLInsertionComputer.generateAttributeValue( 287 (ISchemaAttribute) fSchemaObject, fProcessor.getModel(), 288 attName); 289 } 290 documentInsertBuffer.append(value); 291 fSelLen = value.length(); 292 documentInsertBuffer.append('"'); 293 } 294 295 private void modifyModel(IDocument document) { 296 IBaseModel model = fProcessor.getModel(); 300 if (model instanceof IReconcilingParticipant) 301 ((IReconcilingParticipant)model).reconciled(document); 302 303 if (model instanceof IPluginModelBase) { 304 IPluginBase base = ((IPluginModelBase)model).getPluginBase(); 305 306 fPluginParent = null; 307 fSchemaElement = null; 308 309 if (fSchemaObject instanceof VirtualSchemaObject) { 310 switch (((VirtualSchemaObject)fSchemaObject).getVType()) { 311 case XMLContentAssistProcessor.F_EXTENSION_ATTRIBUTE_POINT_VALUE: 312 if (!(fRange instanceof IDocumentAttribute)) 313 break; 314 int offset = ((IDocumentAttribute)fRange).getEnclosingElement().getOffset(); 315 IPluginExtension[] extensions = base.getExtensions(); 316 for (int i = 0; i < extensions.length; i++) { 317 if (((IDocumentNode)extensions[i]).getOffset() == offset) { 318 if (extensions[i].getChildCount() != 0) 319 break; fPluginParent = extensions[i]; 321 fSchemaElement = XMLUtil.getSchemaElement( 322 (IDocumentNode)extensions[i], 323 extensions[i].getPoint()); 324 break; 325 } 326 } 327 break; 328 case XMLContentAssistProcessor.F_EXTENSION_POINT_AND_VALUE: 329 findExtensionVirtualPointValue(base); 330 break; 331 } 332 } else if (fRange instanceof IDocumentNode && base instanceof IDocumentNode) { 333 Stack s = new Stack (); 334 IDocumentNode node = (IDocumentNode)fRange; 335 IDocumentNode newSearch = (IDocumentNode)base; 336 while (node != null && !(node instanceof IPluginBase)) { 338 s.push(node); 339 node = node.getParentNode(); 340 } 341 342 while (!s.isEmpty()) { 344 node = (IDocumentNode)s.pop(); 345 int nodeIndex = 0; 346 while ((node = node.getPreviousSibling()) != null) 347 nodeIndex += 1; 348 newSearch = newSearch.getChildAt(nodeIndex); 349 } 350 if (newSearch != null) { 351 IDocumentNode[] children = newSearch.getChildNodes(); 352 for (int i = 0; i < children.length; i++) { 353 if (children[i].getOffset() == fOffset && 354 children[i] instanceof IPluginElement) { 355 fPluginParent = (IPluginElement)children[i]; 356 fSchemaElement = (ISchemaElement)fSchemaObject; 357 break; 358 } 359 } 360 } 361 } 362 363 if (fPluginParent != null && fSchemaElement != null) { 364 XMLInsertionComputer.computeInsertion(fSchemaElement, fPluginParent); 365 fProcessor.flushDocument(); 366 if (model instanceof AbstractEditingModel) { 367 try { 368 ((AbstractEditingModel)model).adjustOffsets(document); 369 } catch (CoreException e) { 370 } 371 setSelectionOffsets(document, fSchemaElement, fPluginParent); 372 } 373 } 374 } 375 } 376 377 381 private void findExtensionVirtualPointValue(IPluginBase base) { 382 383 IDocumentRange range = null; 384 PDESourcePage page = fProcessor.getSourcePage(); 385 if (page == null) { 387 return; 388 } 389 range = page.getRangeElement(fOffset, true); 394 if ((range == null) || 396 (range instanceof IDocumentNode) == false) { 397 return; 398 } 399 int targetOffset = ((IDocumentNode)range).getOffset(); 401 IPluginExtension[] extensions = base.getExtensions(); 403 for (int i = 0; i < extensions.length; i++) { 404 int extensionOffset = ((IDocumentNode)extensions[i]).getOffset(); 406 if ((extensionOffset == targetOffset) && 409 (extensions[i].getChildCount() == 0)) { 410 fPluginParent = extensions[i]; 411 fSchemaElement = XMLUtil.getSchemaElement( 413 (IDocumentNode)extensions[i], 414 extensions[i].getPoint()); 415 break; 416 } 417 } 418 } 419 420 private void setSelectionOffsets(IDocument document, ISchemaElement schemaElement, IPluginParent pluginParent) { 421 if (pluginParent instanceof IPluginExtension) { 422 String point = ((IPluginExtension)pluginParent).getPoint(); 423 IPluginObject[] children = ((IPluginExtension)pluginParent).getChildren(); 424 if (children != null && children.length > 0 && children[0] instanceof IPluginParent) { 425 pluginParent = (IPluginParent)children[0]; 426 schemaElement = XMLUtil.getSchemaElement((IDocumentNode)pluginParent, point); 427 } 428 } 429 430 if (pluginParent instanceof IPluginElement) { 431 int offset = ((IDocumentNode)pluginParent).getOffset(); 432 int len = ((IDocumentNode)pluginParent).getLength(); 433 String value = null; 434 try { 435 value = document.get(offset, len); 436 } catch (BadLocationException e) { 437 } 438 if (((IPluginElement)pluginParent).getAttributeCount() > 0) { 439 IPluginAttribute att = ((IPluginElement)pluginParent).getAttributes()[0]; 441 if (att instanceof PluginAttribute) { 442 fSelOffset = ((PluginAttribute)att).getValueOffset(); 443 fSelLen = ((PluginAttribute)att).getValueLength(); 444 } 445 } else if (XMLInsertionComputer.hasOptionalChildren(schemaElement, false, new HashSet ()) && value != null) { 446 int ind = value.indexOf('>'); 447 if (ind > 0) { 448 fSelOffset = offset + ind + 1; 449 fSelLen = 0; 450 } 451 } else if (XMLInsertionComputer.hasOptionalAttributes(schemaElement) && value != null) { 452 int ind = value.indexOf('>'); 453 if (ind != -1) { 454 fSelOffset = offset + ind; 455 fSelLen = 0; 456 } 457 } else { 458 fSelOffset = offset + len; 460 fSelLen = 0; 461 } 462 } 463 } 464 465 private String getIndent(IDocument document, int offset) { 466 StringBuffer indBuff = new StringBuffer (); 467 try { 468 int line = document.getLineOfOffset(offset); 470 int lineOffset = document.getLineOffset(line); 471 int indent = offset - lineOffset; 472 char[] indentChars = document.get(lineOffset, indent).toCharArray(); 473 for (int i = 0; i < indentChars.length; i++) 475 indBuff.append(indentChars[i] == '\t' ? '\t' : ' '); 476 } catch (BadLocationException e) { 477 } 478 return indBuff.toString(); 479 } 480 481 public String getAdditionalProposalInfo() { 482 if (fAddInfo == null) { 483 if (fSchemaObject == null) 484 return null; 485 StringBuffer sb = new StringBuffer (); 486 HTMLPrinter.insertPageProlog(sb, 0, TextUtil.getJavaDocStyleSheerURL()); 487 String desc = null; 488 if (fSchemaObject == null) 489 desc = PDEUIMessages.BaseWizardSelectionPage_noDesc; 490 else { 491 desc = fSchemaObject.getDescription(); 492 if (desc == null || desc.trim().length() == 0) 493 desc = PDEUIMessages.BaseWizardSelectionPage_noDesc; 494 } 495 sb.append(desc); 496 HTMLPrinter.addPageEpilog(sb); 497 fAddInfo = sb.toString(); 498 } 499 return fAddInfo; 500 } 501 502 public IContextInformation getContextInformation() { 503 return null; 504 } 505 506 public String getDisplayString() { 507 if (fSchemaObject instanceof VirtualSchemaObject) { 508 switch (((VirtualSchemaObject)fSchemaObject).getVType()) { 509 case XMLContentAssistProcessor.F_CLOSE_TAG: 510 return "... />"; case XMLContentAssistProcessor.F_EXTENSION_POINT_AND_VALUE: 512 case XMLContentAssistProcessor.F_EXTENSION_ATTRIBUTE_POINT_VALUE: 513 case XMLContentAssistProcessor.F_ATTRIBUTE_VALUE: 514 return fSchemaObject.getName(); 515 } 516 } 517 if (fSchemaObject instanceof ISchemaAttribute) 518 return fSchemaObject.getName(); 519 if (fSchemaObject != null) 520 return fSchemaObject.getName(); 521 if (fRange instanceof IDocumentNode) 522 return "...> </" + ((IDocumentNode)fRange).getXMLTagName() + ">"; return null; 524 } 525 526 public Image getImage() { 527 if (fSchemaObject instanceof VirtualSchemaObject) 528 return fProcessor.getImage(((VirtualSchemaObject)fSchemaObject).getVType()); 529 if (fSchemaObject instanceof ISchemaAttribute) 530 return fProcessor.getImage(XMLContentAssistProcessor.F_ATTRIBUTE); 531 if (fSchemaObject instanceof ISchemaElement || fSchemaObject == null) 532 return fProcessor.getImage(XMLContentAssistProcessor.F_ELEMENT); 533 return null; 534 } 535 536 public Point getSelection(IDocument document) { 537 if (fSelOffset == -1) 538 return null; 539 return new Point(fSelOffset, fSelLen); 540 } 541 542 public Object getAdditionalProposalInfo(IProgressMonitor monitor) { 543 return getAdditionalProposalInfo(); 544 } 545 546 public IInformationControlCreator getInformationControlCreator() { 547 if (!BrowserInformationControl.isAvailable(null)) 548 return null; 549 550 if (fCreator == null) { 551 fCreator = new AbstractReusableInformationControlCreator() { 552 public IInformationControl doCreateInformationControl(Shell parent) { 553 return new BrowserInformationControl(parent, SWT.NO_TRIM | SWT.TOOL, SWT.NONE); 554 } 555 }; 556 } 557 return fCreator; 558 } 559 560 public int getPrefixCompletionStart(IDocument document, int completionOffset) { 561 return 0; 562 } 563 564 public CharSequence getPrefixCompletionText(IDocument document, int completionOffset) { 565 return null; 566 } 567 568 } 569 | Popular Tags |