1 11 12 package org.eclipse.jdt.internal.ui.text.correction; 13 14 import java.util.Iterator ; 15 16 import org.eclipse.text.edits.MalformedTreeException; 17 import org.eclipse.text.edits.MultiTextEdit; 18 import org.eclipse.text.edits.TextEdit; 19 20 import org.eclipse.core.runtime.CoreException; 21 import org.eclipse.core.runtime.IStatus; 22 import org.eclipse.core.runtime.NullProgressMonitor; 23 import org.eclipse.core.runtime.Status; 24 25 import org.eclipse.swt.events.VerifyEvent; 26 import org.eclipse.swt.graphics.Image; 27 import org.eclipse.swt.graphics.Point; 28 29 import org.eclipse.jface.dialogs.ErrorDialog; 30 31 import org.eclipse.jface.text.BadLocationException; 32 import org.eclipse.jface.text.Document; 33 import org.eclipse.jface.text.DocumentEvent; 34 import org.eclipse.jface.text.IDocument; 35 import org.eclipse.jface.text.IRegion; 36 import org.eclipse.jface.text.ITextViewer; 37 import org.eclipse.jface.text.contentassist.ICompletionProposalExtension2; 38 import org.eclipse.jface.text.contentassist.IContextInformation; 39 import org.eclipse.jface.text.link.ILinkedModeListener; 40 import org.eclipse.jface.text.link.LinkedModeModel; 41 import org.eclipse.jface.text.link.LinkedModeUI; 42 import org.eclipse.jface.text.link.LinkedPosition; 43 import org.eclipse.jface.text.link.LinkedPositionGroup; 44 import org.eclipse.jface.text.link.ProposalPosition; 45 import org.eclipse.jface.text.link.LinkedModeUI.ExitFlags; 46 47 import org.eclipse.ui.IEditorPart; 48 import org.eclipse.ui.IWorkbenchPage; 49 import org.eclipse.ui.texteditor.ITextEditor; 50 import org.eclipse.ui.texteditor.link.EditorLinkedModeUI; 51 52 import org.eclipse.compare.rangedifferencer.IRangeComparator; 53 import org.eclipse.compare.rangedifferencer.RangeDifference; 54 import org.eclipse.compare.rangedifferencer.RangeDifferencer; 55 56 import org.eclipse.ltk.core.refactoring.Change; 57 import org.eclipse.ltk.core.refactoring.DocumentChange; 58 import org.eclipse.ltk.core.refactoring.TextChange; 59 import org.eclipse.ltk.core.refactoring.TextFileChange; 60 61 import org.eclipse.jdt.core.ICompilationUnit; 62 import org.eclipse.jdt.core.JavaModelException; 63 64 import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility; 65 import org.eclipse.jdt.internal.corext.fix.LinkedProposalPositionGroup; 66 import org.eclipse.jdt.internal.corext.fix.LinkedProposalModel; 67 import org.eclipse.jdt.internal.corext.refactoring.changes.CompilationUnitChange; 68 import org.eclipse.jdt.internal.corext.util.Resources; 69 import org.eclipse.jdt.internal.corext.util.Strings; 70 71 import org.eclipse.jdt.ui.JavaUI; 72 import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal; 73 74 import org.eclipse.jdt.internal.ui.JavaPlugin; 75 import org.eclipse.jdt.internal.ui.JavaUIStatus; 76 import org.eclipse.jdt.internal.ui.compare.JavaTokenComparator; 77 import org.eclipse.jdt.internal.ui.javaeditor.EditorHighlightingSynchronizer; 78 import org.eclipse.jdt.internal.ui.javaeditor.EditorUtility; 79 import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor; 80 import org.eclipse.jdt.internal.ui.util.ExceptionHandler; 81 82 92 public class CUCorrectionProposal extends ChangeCorrectionProposal { 93 94 private ICompilationUnit fCompilationUnit; 95 private LinkedProposalModel fLinkedProposalModel; 96 97 98 110 public CUCorrectionProposal(String name, ICompilationUnit cu, TextChange change, int relevance, Image image) { 111 super(name, change, relevance, image); 112 if (cu == null) { 113 throw new IllegalArgumentException ("Compilation unit must not be null"); } 115 fCompilationUnit= cu; 116 fLinkedProposalModel= null; 117 } 118 119 131 protected CUCorrectionProposal(String name, ICompilationUnit cu, int relevance, Image image) { 132 this(name, cu, null, relevance, image); 133 } 134 135 145 protected void addEdits(IDocument document, TextEdit editRoot) throws CoreException { 146 if (false) { 147 throw new CoreException(JavaUIStatus.createError(IStatus.ERROR, "Implementors can throw an exception", null)); } 149 } 150 151 protected LinkedProposalModel getLinkedProposalModel() { 152 if (fLinkedProposalModel == null) { 153 fLinkedProposalModel= new LinkedProposalModel(); 154 } 155 return fLinkedProposalModel; 156 } 157 158 protected void setLinkedProposalModel(LinkedProposalModel model) { 159 fLinkedProposalModel= model; 160 } 161 162 165 public String getAdditionalProposalInfo() { 166 StringBuffer buf= new StringBuffer (); 167 168 try { 169 TextChange change= getTextChange(); 170 171 IDocument previewContent= change.getPreviewDocument(new NullProgressMonitor()); 172 String currentConentString= change.getCurrentContent(new NullProgressMonitor()); 173 174 179 Object leftSide= new JavaTokenComparator(previewContent.get()); 180 Object rightSide= new JavaTokenComparator(currentConentString); 181 182 RangeDifference[] differences= RangeDifferencer.findRanges((IRangeComparator)leftSide, (IRangeComparator)rightSide); 183 for (int i= 0; i < differences.length; i++) { 184 RangeDifference curr= differences[i]; 185 int start= ((JavaTokenComparator)leftSide).getTokenStart(curr.leftStart()); 186 int end= ((JavaTokenComparator)leftSide).getTokenStart(curr.leftEnd()); 187 if (curr.kind() == RangeDifference.CHANGE && curr.leftLength() > 0) { 188 buf.append("<b>"); appendContent(previewContent, start, end, buf, false); 190 buf.append("</b>"); } else if (curr.kind() == RangeDifference.NOCHANGE) { 192 appendContent(previewContent, start, end, buf, true); 193 } 194 } 195 } catch (CoreException e) { 196 JavaPlugin.log(e); 197 } catch (BadLocationException e) { 198 JavaPlugin.log(e); 199 } 200 return buf.toString(); 201 } 202 203 private final int surroundLines= 1; 204 205 private void appendContent(IDocument text, int startOffset, int endOffset, StringBuffer buf, boolean surroundLinesOnly) throws BadLocationException { 206 int startLine= text.getLineOfOffset(startOffset); 207 int endLine= text.getLineOfOffset(endOffset); 208 209 boolean dotsAdded= false; 210 if (surroundLinesOnly && startOffset == 0) { startLine= Math.max(endLine - surroundLines, 0); 212 buf.append("...<br>"); dotsAdded= true; 214 } 215 216 for (int i= startLine; i <= endLine; i++) { 217 if (surroundLinesOnly) { 218 if ((i - startLine > surroundLines) && (endLine - i > surroundLines)) { 219 if (!dotsAdded) { 220 buf.append("...<br>"); dotsAdded= true; 222 } else if (endOffset == text.getLength()) { 223 return; } 225 continue; 226 } 227 } 228 229 IRegion lineInfo= text.getLineInformation(i); 230 int start= lineInfo.getOffset(); 231 int end= start + lineInfo.getLength(); 232 233 int from= Math.max(start, startOffset); 234 int to= Math.min(end, endOffset); 235 String content= text.get(from, to - from); 236 if (surroundLinesOnly && (from == start) && Strings.containsOnlyWhitespaces(content)) { 237 continue; } 239 for (int k= 0; k < content.length(); k++) { 240 char ch= content.charAt(k); 241 if (ch == '<') { 242 buf.append("<"); } else if (ch == '>') { 244 buf.append(">"); } else { 246 buf.append(ch); 247 } 248 } 249 if (to == end && to != endOffset) { buf.append("<br>"); } 252 } 253 } 254 255 258 public void apply(IDocument document) { 259 try { 260 ICompilationUnit unit= getCompilationUnit(); 261 IEditorPart part= null; 262 if (unit.getResource().exists()) { 263 boolean canEdit= performValidateEdit(unit); 264 if (!canEdit) { 265 return; 266 } 267 part= EditorUtility.isOpenInEditor(unit); 268 if (part == null) { 269 part= JavaUI.openInEditor(unit); 270 if (part != null) { 271 document= JavaUI.getDocumentProvider().getDocument(part.getEditorInput()); 272 } 273 } 274 IWorkbenchPage page= JavaPlugin.getActivePage(); 275 if (page != null && part != null) { 276 page.bringToTop(part); 277 } 278 if (part != null) { 279 part.setFocus(); 280 } 281 } 282 performChange(part, document); 283 } catch (CoreException e) { 284 ExceptionHandler.handle(e, CorrectionMessages.CUCorrectionProposal_error_title, CorrectionMessages.CUCorrectionProposal_error_message); 285 } 286 } 287 288 private boolean performValidateEdit(ICompilationUnit unit) { 289 IStatus status= Resources.makeCommittable(unit.getResource(), JavaPlugin.getActiveWorkbenchShell()); 290 if (!status.isOK()) { 291 String label= CorrectionMessages.CUCorrectionProposal_error_title; 292 String message= CorrectionMessages.CUCorrectionProposal_error_message; 293 ErrorDialog.openError(JavaPlugin.getActiveWorkbenchShell(), label, message, status); 294 return false; 295 } 296 return true; 297 } 298 299 302 protected void performChange(IEditorPart part, IDocument document) throws CoreException { 303 try { 304 super.performChange(part, document); 305 if (part == null) { 306 return; 307 } 308 309 if (fLinkedProposalModel != null) { 310 if (fLinkedProposalModel.hasLinkedPositions() && part instanceof JavaEditor) { 311 ITextViewer viewer= ((JavaEditor) part).getViewer(); 313 enterLinkedMode(viewer, part); 314 } else if (part instanceof ITextEditor) { 315 LinkedProposalPositionGroup.PositionInformation endPosition= fLinkedProposalModel.getEndPosition(); 316 if (endPosition != null) { 317 int pos= endPosition.getOffset() + endPosition.getLength(); 319 ((ITextEditor) part).selectAndReveal(pos, 0); 320 } 321 } 322 } 323 } catch (BadLocationException e) { 324 throw new CoreException(JavaUIStatus.createError(IStatus.ERROR, e)); 325 } 326 327 } 328 329 private void enterLinkedMode(ITextViewer viewer, IEditorPart editor) throws BadLocationException { 330 IDocument document= viewer.getDocument(); 331 332 LinkedModeModel model= new LinkedModeModel(); 333 boolean added= false; 334 335 Iterator iterator= fLinkedProposalModel.getPositionGroupIterator(); 336 while (iterator.hasNext()) { 337 LinkedProposalPositionGroup curr= (LinkedProposalPositionGroup) iterator.next(); 338 339 LinkedPositionGroup group= new LinkedPositionGroup(); 340 341 LinkedProposalPositionGroup.PositionInformation[] positions= curr.getPositions(); 342 if (positions.length > 0) { 343 LinkedProposalPositionGroup.Proposal[] linkedModeProposals= curr.getProposals(); 344 if (linkedModeProposals.length <= 1) { 345 for (int i= 0; i < positions.length; i++) { 346 LinkedProposalPositionGroup.PositionInformation pos= positions[i]; 347 if (pos.getOffset() != -1) { 348 group.addPosition(new LinkedPosition(document, pos.getOffset(), pos.getLength(), pos.getSequenceRank())); 349 } 350 } 351 } else { 352 LinkedPositionProposalImpl[] proposalImpls= new LinkedPositionProposalImpl[linkedModeProposals.length]; 353 for (int i= 0; i < linkedModeProposals.length; i++) { 354 proposalImpls[i]= new LinkedPositionProposalImpl(linkedModeProposals[i], model); 355 } 356 357 for (int i= 0; i < positions.length; i++) { 358 LinkedProposalPositionGroup.PositionInformation pos= positions[i]; 359 if (pos.getOffset() != -1) { 360 group.addPosition(new ProposalPosition(document, pos.getOffset(), pos.getLength(), pos.getSequenceRank(), proposalImpls)); 361 } 362 } 363 } 364 model.addGroup(group); 365 added= true; 366 } 367 } 368 369 model.forceInstall(); 370 371 if (editor instanceof JavaEditor) { 372 model.addLinkingListener(new EditorHighlightingSynchronizer((JavaEditor) editor)); 373 } 374 375 if (added) { LinkedModeUI ui= new EditorLinkedModeUI(model, viewer); 377 LinkedProposalPositionGroup.PositionInformation endPosition= fLinkedProposalModel.getEndPosition(); 378 if (endPosition != null && endPosition.getOffset() != -1) { 379 ui.setExitPosition(viewer, endPosition.getOffset() + endPosition.getLength(), 0, Integer.MAX_VALUE); 380 } else { 381 int cursorPosition= viewer.getSelectedRange().x; 382 if (cursorPosition != 0) { 383 ui.setExitPosition(viewer, cursorPosition, 0, Integer.MAX_VALUE); 384 } 385 } 386 ui.setExitPolicy(new LinkedModeExitPolicy()); 387 ui.enter(); 388 389 IRegion region= ui.getSelectedRegion(); 390 viewer.setSelectedRange(region.getOffset(), region.getLength()); 391 viewer.revealRange(region.getOffset(), region.getLength()); 392 } 393 } 394 395 396 404 protected TextChange createTextChange() throws CoreException { 405 ICompilationUnit cu= getCompilationUnit(); 406 String name= getName(); 407 TextChange change; 408 if (!cu.getResource().exists()) { 409 String source; 410 try { 411 source= cu.getSource(); 412 } catch (JavaModelException e) { 413 JavaPlugin.log(e); 414 source= new String (); } 416 Document document= new Document(source); 417 document.setInitialLineDelimiter(StubUtility.getLineDelimiterUsed(cu)); 418 change= new DocumentChange(name, document); 419 } else { 420 CompilationUnitChange cuChange = new CompilationUnitChange(name, cu); 421 cuChange.setSaveMode(TextFileChange.LEAVE_DIRTY); 422 change= cuChange; 423 } 424 TextEdit rootEdit= new MultiTextEdit(); 425 change.setEdit(rootEdit); 426 427 IDocument document= change.getCurrentDocument(new NullProgressMonitor()); 429 addEdits(document, rootEdit); 430 return change; 431 } 432 433 434 437 protected final Change createChange() throws CoreException { 438 return createTextChange(); } 440 441 447 public final TextChange getTextChange() throws CoreException { 448 return (TextChange) getChange(); 449 } 450 451 456 public final ICompilationUnit getCompilationUnit() { 457 return fCompilationUnit; 458 } 459 460 466 public String getPreviewContent() throws CoreException { 467 return getTextChange().getPreviewContent(new NullProgressMonitor()); 468 } 469 470 473 public String toString() { 474 try { 475 return getPreviewContent(); 476 } catch (CoreException e) { 477 } 478 return super.toString(); 479 } 480 481 482 private static class LinkedModeExitPolicy implements LinkedModeUI.IExitPolicy { 483 public ExitFlags doExit(LinkedModeModel model, VerifyEvent event, int offset, int length) { 484 if (event.character == '=') { 485 return new ExitFlags(ILinkedModeListener.EXIT_ALL, true); 486 } 487 return null; 488 } 489 } 490 491 private static class LinkedPositionProposalImpl implements ICompletionProposalExtension2, IJavaCompletionProposal { 492 493 private final LinkedProposalPositionGroup.Proposal fProposal; 494 private final LinkedModeModel fLinkedPositionModel; 495 496 497 public LinkedPositionProposalImpl(LinkedProposalPositionGroup.Proposal proposal, LinkedModeModel model) { 498 fProposal= proposal; 499 fLinkedPositionModel= model; 500 } 501 502 505 public void apply(ITextViewer viewer, char trigger, int stateMask, int offset) { 506 IDocument doc= viewer.getDocument(); 507 LinkedPosition position= fLinkedPositionModel.findPosition(new LinkedPosition(doc, offset, 0)); 508 if (position != null) { 509 try { 510 try { 511 TextEdit edit= fProposal.computeEdits(offset, position, trigger, stateMask, fLinkedPositionModel); 512 if (edit != null) { 513 edit.apply(position.getDocument(), 0); 514 } 515 } catch (MalformedTreeException e) { 516 throw new CoreException(new Status(IStatus.ERROR, JavaUI.ID_PLUGIN, IStatus.ERROR, "Unexpected exception applying edit", e)); } catch (BadLocationException e) { 518 throw new CoreException(new Status(IStatus.ERROR, JavaUI.ID_PLUGIN, IStatus.ERROR, "Unexpected exception applying edit", e)); } 520 } catch (CoreException e) { 521 JavaPlugin.log(e); 522 } 523 } 524 } 525 526 529 public String getDisplayString() { 530 return fProposal.getDisplayString(); 531 } 532 533 536 public Image getImage() { 537 return fProposal.getImage(); 538 } 539 540 543 public int getRelevance() { 544 return fProposal.getRelevance(); 545 } 546 547 550 public void apply(IDocument document) { 551 } 553 554 557 public String getAdditionalProposalInfo() { 558 return fProposal.getAdditionalProposalInfo(); 559 } 560 561 public Point getSelection(IDocument document) { return null; } 562 public IContextInformation getContextInformation() { return null; } 563 public void selected(ITextViewer viewer, boolean smartToggle) {} 564 public void unselected(ITextViewer viewer) {} 565 566 569 public boolean validate(IDocument document, int offset, DocumentEvent event) { 570 String insert= getDisplayString(); 572 573 int off; 574 LinkedPosition pos= fLinkedPositionModel.findPosition(new LinkedPosition(document, offset, 0)); 575 if (pos != null) { 576 off= pos.getOffset(); 577 } else { 578 off= Math.max(0, offset - insert.length()); 579 } 580 int length= offset - off; 581 582 if (offset <= document.getLength()) { 583 try { 584 String content= document.get(off, length); 585 if (insert.startsWith(content)) 586 return true; 587 } catch (BadLocationException e) { 588 JavaPlugin.log(e); 589 } 591 } 592 return false; 593 } 594 } 595 } 596 | Popular Tags |