1 11 package org.eclipse.jdt.internal.ui.text.template.contentassist; 12 13 import org.eclipse.core.runtime.Assert; 14 import org.eclipse.core.runtime.CoreException; 15 import org.eclipse.core.runtime.IStatus; 16 import org.eclipse.core.runtime.Status; 17 18 import org.eclipse.swt.SWT; 19 import org.eclipse.swt.graphics.Image; 20 import org.eclipse.swt.graphics.Point; 21 import org.eclipse.swt.widgets.Shell; 22 23 import org.eclipse.jface.dialogs.MessageDialog; 24 25 import org.eclipse.jface.text.BadLocationException; 26 import org.eclipse.jface.text.BadPositionCategoryException; 27 import org.eclipse.jface.text.Document; 28 import org.eclipse.jface.text.DocumentEvent; 29 import org.eclipse.jface.text.IDocument; 30 import org.eclipse.jface.text.IInformationControlCreator; 31 import org.eclipse.jface.text.IRegion; 32 import org.eclipse.jface.text.IRewriteTarget; 33 import org.eclipse.jface.text.ITextViewer; 34 import org.eclipse.jface.text.ITextViewerExtension; 35 import org.eclipse.jface.text.Position; 36 import org.eclipse.jface.text.Region; 37 import org.eclipse.jface.text.contentassist.ICompletionProposal; 38 import org.eclipse.jface.text.contentassist.ICompletionProposalExtension2; 39 import org.eclipse.jface.text.contentassist.ICompletionProposalExtension3; 40 import org.eclipse.jface.text.contentassist.ICompletionProposalExtension4; 41 import org.eclipse.jface.text.contentassist.IContextInformation; 42 import org.eclipse.jface.text.link.ILinkedModeListener; 43 import org.eclipse.jface.text.link.LinkedModeModel; 44 import org.eclipse.jface.text.link.LinkedModeUI; 45 import org.eclipse.jface.text.link.LinkedPosition; 46 import org.eclipse.jface.text.link.LinkedPositionGroup; 47 import org.eclipse.jface.text.link.ProposalPosition; 48 import org.eclipse.jface.text.source.LineRange; 49 import org.eclipse.jface.text.templates.DocumentTemplateContext; 50 import org.eclipse.jface.text.templates.GlobalTemplateVariables; 51 import org.eclipse.jface.text.templates.Template; 52 import org.eclipse.jface.text.templates.TemplateBuffer; 53 import org.eclipse.jface.text.templates.TemplateContext; 54 import org.eclipse.jface.text.templates.TemplateException; 55 import org.eclipse.jface.text.templates.TemplateVariable; 56 57 import org.eclipse.ui.IEditorPart; 58 import org.eclipse.ui.part.IWorkbenchPartOrientation; 59 import org.eclipse.ui.texteditor.link.EditorLinkedModeUI; 60 61 import org.eclipse.jdt.internal.corext.template.java.CompilationUnitContext; 62 import org.eclipse.jdt.internal.corext.template.java.JavaDocContext; 63 import org.eclipse.jdt.internal.corext.util.Messages; 64 65 import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal; 66 67 import org.eclipse.jdt.internal.ui.JavaPlugin; 68 import org.eclipse.jdt.internal.ui.javaeditor.EditorHighlightingSynchronizer; 69 import org.eclipse.jdt.internal.ui.javaeditor.IndentUtil; 70 import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor; 71 import org.eclipse.jdt.internal.ui.util.ExceptionHandler; 72 73 76 public class TemplateProposal implements IJavaCompletionProposal, ICompletionProposalExtension2, ICompletionProposalExtension3, ICompletionProposalExtension4 { 77 78 private final Template fTemplate; 79 private final TemplateContext fContext; 80 private final Image fImage; 81 private IRegion fRegion; 82 private int fRelevance; 83 84 private IRegion fSelectedRegion; private String fDisplayString; 86 87 95 public TemplateProposal(Template template, TemplateContext context, IRegion region, Image image) { 96 Assert.isNotNull(template); 97 Assert.isNotNull(context); 98 Assert.isNotNull(region); 99 100 fTemplate= template; 101 fContext= context; 102 fImage= image; 103 fRegion= region; 104 105 fDisplayString= null; 106 107 fRelevance= computeRelevance(); 108 } 109 110 116 private int computeRelevance() { 117 final int R_DEFAULT= 0; 119 final int R_INTERESTING= 5; 120 final int R_CASE= 10; 121 final int R_NON_RESTRICTED= 3; 122 final int R_EXACT_NAME = 4; 123 final int R_INLINE_TAG = 31; 124 125 int base= R_DEFAULT + R_INTERESTING + R_NON_RESTRICTED; 126 127 try { 128 if (fContext instanceof DocumentTemplateContext) { 129 DocumentTemplateContext templateContext= (DocumentTemplateContext) fContext; 130 IDocument document= templateContext.getDocument(); 131 132 String content= document.get(fRegion.getOffset(), fRegion.getLength()); 133 if (fTemplate.getName().startsWith(content)) 134 base += R_CASE; 135 if (fTemplate.getName().equalsIgnoreCase(content)) 136 base += R_EXACT_NAME; 137 if (fContext instanceof JavaDocContext) 138 base += R_INLINE_TAG; 139 } 140 } catch (BadLocationException e) { 141 } 143 144 final int TEMPLATE_RELEVANCE= 1; 147 return base * 16 + TEMPLATE_RELEVANCE; 148 } 149 150 153 public final void apply(IDocument document) { 154 } 156 157 160 public void apply(ITextViewer viewer, char trigger, int stateMask, int offset) { 161 162 try { 163 164 fContext.setReadOnly(false); 165 int start; 166 IDocument document; 167 TemplateBuffer templateBuffer; 168 try { 169 beginCompoundChange(viewer); 170 171 try { 172 templateBuffer= fContext.evaluate(fTemplate); 174 } catch (TemplateException e1) { 175 fSelectedRegion= fRegion; 176 return; 177 } 178 179 start= getReplaceOffset(); 180 int end= getReplaceEndOffset(); 181 end= Math.max(end, offset); 182 183 document= viewer.getDocument(); 185 if (end > document.getLength()) 186 end= offset; 187 String templateString= templateBuffer.getString(); 188 document.replace(start, end - start, templateString); 189 } finally { 190 endCompoundChange(viewer); 191 } 192 193 LinkedModeModel model= new LinkedModeModel(); 195 TemplateVariable[] variables= templateBuffer.getVariables(); 196 197 MultiVariableGuess guess= fContext instanceof CompilationUnitContext ? ((CompilationUnitContext) fContext).getMultiVariableGuess() : null; 198 199 boolean hasPositions= false; 200 for (int i= 0; i != variables.length; i++) { 201 TemplateVariable variable= variables[i]; 202 203 if (variable.isUnambiguous()) 204 continue; 205 206 LinkedPositionGroup group= new LinkedPositionGroup(); 207 208 int[] offsets= variable.getOffsets(); 209 int length= variable.getLength(); 210 211 LinkedPosition first; 212 if (guess != null && variable instanceof MultiVariable) { 213 first= new VariablePosition(document, offsets[0] + start, length, guess, (MultiVariable) variable); 214 guess.addSlave((VariablePosition) first); 215 } else { 216 String [] values= variable.getValues(); 217 ICompletionProposal[] proposals= new ICompletionProposal[values.length]; 218 for (int j= 0; j < values.length; j++) { 219 ensurePositionCategoryInstalled(document, model); 220 Position pos= new Position(offsets[0] + start, length); 221 document.addPosition(getCategory(), pos); 222 proposals[j]= new PositionBasedCompletionProposal(values[j], pos, length); 223 } 224 225 if (proposals.length > 1) 226 first= new ProposalPosition(document, offsets[0] + start, length, proposals); 227 else 228 first= new LinkedPosition(document, offsets[0] + start, length); 229 } 230 231 for (int j= 0; j != offsets.length; j++) 232 if (j == 0) 233 group.addPosition(first); 234 else 235 group.addPosition(new LinkedPosition(document, offsets[j] + start, length)); 236 237 model.addGroup(group); 238 hasPositions= true; 239 } 240 241 if (hasPositions) { 242 model.forceInstall(); 243 JavaEditor editor= getJavaEditor(); 244 if (editor != null) { 245 model.addLinkingListener(new EditorHighlightingSynchronizer(editor)); 246 } 247 248 LinkedModeUI ui= new EditorLinkedModeUI(model, viewer); 249 ui.setExitPosition(viewer, getCaretOffset(templateBuffer) + start, 0, Integer.MAX_VALUE); 250 ui.enter(); 251 252 fSelectedRegion= ui.getSelectedRegion(); 253 } else 254 fSelectedRegion= new Region(getCaretOffset(templateBuffer) + start, 0); 255 256 } catch (BadLocationException e) { 257 JavaPlugin.log(e); 258 openErrorDialog(viewer.getTextWidget().getShell(), e); 259 fSelectedRegion= fRegion; 260 } catch (BadPositionCategoryException e) { 261 JavaPlugin.log(e); 262 openErrorDialog(viewer.getTextWidget().getShell(), e); 263 fSelectedRegion= fRegion; 264 } 265 266 } 267 268 private void endCompoundChange(ITextViewer viewer) { 269 if (viewer instanceof ITextViewerExtension) { 270 ITextViewerExtension extension= (ITextViewerExtension) viewer; 271 IRewriteTarget target= extension.getRewriteTarget(); 272 target.endCompoundChange(); 273 } 274 } 275 276 private void beginCompoundChange(ITextViewer viewer) { 277 if (viewer instanceof ITextViewerExtension) { 278 ITextViewerExtension extension= (ITextViewerExtension) viewer; 279 IRewriteTarget target= extension.getRewriteTarget(); 280 target.beginCompoundChange(); 281 } 282 } 283 284 290 private JavaEditor getJavaEditor() { 291 IEditorPart part= JavaPlugin.getActivePage().getActiveEditor(); 292 if (part instanceof JavaEditor) 293 return (JavaEditor) part; 294 else 295 return null; 296 } 297 298 305 private int getReplaceOffset() { 306 int start; 307 if (fContext instanceof DocumentTemplateContext) { 308 DocumentTemplateContext docContext = (DocumentTemplateContext)fContext; 309 start= docContext.getStart(); 310 } else { 311 start= fRegion.getOffset(); 312 } 313 return start; 314 } 315 316 323 private int getReplaceEndOffset() { 324 int end; 325 if (fContext instanceof DocumentTemplateContext) { 326 DocumentTemplateContext docContext = (DocumentTemplateContext)fContext; 327 end= docContext.getEnd(); 328 } else { 329 end= fRegion.getOffset() + fRegion.getLength(); 330 } 331 return end; 332 } 333 334 private void ensurePositionCategoryInstalled(final IDocument document, LinkedModeModel model) { 335 if (!document.containsPositionCategory(getCategory())) { 336 document.addPositionCategory(getCategory()); 337 final InclusivePositionUpdater updater= new InclusivePositionUpdater(getCategory()); 338 document.addPositionUpdater(updater); 339 340 model.addLinkingListener(new ILinkedModeListener() { 341 342 345 public void left(LinkedModeModel environment, int flags) { 346 try { 347 document.removePositionCategory(getCategory()); 348 } catch (BadPositionCategoryException e) { 349 } 351 document.removePositionUpdater(updater); 352 } 353 354 public void suspend(LinkedModeModel environment) {} 355 public void resume(LinkedModeModel environment, int flags) {} 356 }); 357 } 358 } 359 360 private String getCategory() { 361 return "TemplateProposalCategory_" + toString(); } 363 364 private int getCaretOffset(TemplateBuffer buffer) { 365 366 TemplateVariable[] variables= buffer.getVariables(); 367 for (int i= 0; i != variables.length; i++) { 368 TemplateVariable variable= variables[i]; 369 if (variable.getType().equals(GlobalTemplateVariables.Cursor.NAME)) 370 return variable.getOffsets()[0]; 371 } 372 373 return buffer.getString().length(); 374 } 375 376 379 public Point getSelection(IDocument document) { 380 return new Point(fSelectedRegion.getOffset(), fSelectedRegion.getLength()); 381 } 382 383 386 public String getAdditionalProposalInfo() { 387 try { 388 fContext.setReadOnly(true); 389 TemplateBuffer templateBuffer; 390 try { 391 templateBuffer= fContext.evaluate(fTemplate); 392 } catch (TemplateException e1) { 393 return null; 394 } 395 396 IDocument document= new Document(templateBuffer.getString()); 397 IndentUtil.indentLines(document, new LineRange(0, document.getNumberOfLines()), null, null); 398 return document.get(); 399 400 } catch (BadLocationException e) { 401 handleException(JavaPlugin.getActiveWorkbenchShell(), new CoreException(new Status(IStatus.ERROR, JavaPlugin.getPluginId(), IStatus.OK, "", e))); return null; 403 } 404 } 405 406 409 public String getDisplayString() { 410 if (fDisplayString == null) { 411 String [] arguments= new String [] { fTemplate.getName(), fTemplate.getDescription() }; 412 fDisplayString= Messages.format(TemplateContentAssistMessages.TemplateProposal_displayString, arguments); 413 } 414 return fDisplayString; 415 } 416 417 public void setDisplayString(String displayString) { 418 fDisplayString= displayString; 419 } 420 421 424 public Image getImage() { 425 return fImage; 426 } 427 428 431 public IContextInformation getContextInformation() { 432 return null; 433 } 434 435 private void openErrorDialog(Shell shell, Exception e) { 436 MessageDialog.openError(shell, TemplateContentAssistMessages.TemplateEvaluator_error_title, e.getMessage()); 437 } 438 439 private void handleException(Shell shell, CoreException e) { 440 ExceptionHandler.handle(e, shell, TemplateContentAssistMessages.TemplateEvaluator_error_title, null); 441 } 442 443 446 public int getRelevance() { 447 return fRelevance; 448 } 449 450 public void setRelevance(int relevance) { 451 fRelevance= relevance; 452 } 453 454 public Template getTemplate() { 455 return fTemplate; 456 } 457 458 461 public IInformationControlCreator getInformationControlCreator() { 462 int orientation; 463 IEditorPart editor= getJavaEditor(); 464 if (editor instanceof IWorkbenchPartOrientation) 465 orientation= ((IWorkbenchPartOrientation)editor).getOrientation(); 466 else 467 orientation= SWT.LEFT_TO_RIGHT; 468 return new TemplateInformationControlCreator(orientation); 469 } 470 471 474 public void selected(ITextViewer viewer, boolean smartToggle) { 475 } 476 477 480 public void unselected(ITextViewer viewer) { 481 } 482 483 486 public boolean validate(IDocument document, int offset, DocumentEvent event) { 487 try { 488 int replaceOffset= getReplaceOffset(); 489 if (offset >= replaceOffset) { 490 String content= document.get(replaceOffset, offset - replaceOffset); 491 String templateName= fTemplate.getName().toLowerCase(); 492 boolean valid= templateName.startsWith(content.toLowerCase()); 493 if (!valid && fContext instanceof JavaDocContext && templateName.startsWith("<")) { valid= templateName.startsWith(content.toLowerCase(), 1); 495 } 496 return valid; 497 } 498 } catch (BadLocationException e) { 499 } 501 return false; 502 } 503 504 507 public CharSequence getPrefixCompletionText(IDocument document, int completionOffset) { 508 if (isSelectionTemplate()) 510 return ""; return fTemplate.getName(); 512 } 513 514 517 public int getPrefixCompletionStart(IDocument document, int completionOffset) { 518 return getReplaceOffset(); 519 } 520 521 524 public boolean isAutoInsertable() { 525 if (isSelectionTemplate()) 526 return false; 527 return fTemplate.isAutoInsertable(); 528 } 529 530 536 private boolean isSelectionTemplate() { 537 if (fContext instanceof DocumentTemplateContext) { 538 DocumentTemplateContext ctx= (DocumentTemplateContext) fContext; 539 if (ctx.getCompletionLength() > 0) 540 return true; 541 } 542 return false; 543 } 544 } 545 | Popular Tags |