1 11 package org.eclipse.jdt.internal.ui.actions; 12 13 import java.util.ResourceBundle ; 14 15 import org.eclipse.core.runtime.Assert; 16 import org.eclipse.core.runtime.IStatus; 17 import org.eclipse.core.runtime.Status; 18 19 import org.eclipse.swt.custom.BusyIndicator; 20 import org.eclipse.swt.widgets.Display; 21 22 import org.eclipse.jface.viewers.ISelection; 23 import org.eclipse.jface.viewers.ISelectionProvider; 24 25 import org.eclipse.jface.text.BadLocationException; 26 import org.eclipse.jface.text.IDocument; 27 import org.eclipse.jface.text.IRegion; 28 import org.eclipse.jface.text.IRewriteTarget; 29 import org.eclipse.jface.text.ITextSelection; 30 import org.eclipse.jface.text.ITypedRegion; 31 import org.eclipse.jface.text.Position; 32 import org.eclipse.jface.text.TextSelection; 33 import org.eclipse.jface.text.TextUtilities; 34 import org.eclipse.jface.text.source.ISourceViewer; 35 36 import org.eclipse.ui.IEditorInput; 37 import org.eclipse.ui.texteditor.IDocumentProvider; 38 import org.eclipse.ui.texteditor.ITextEditor; 39 import org.eclipse.ui.texteditor.ITextEditorExtension3; 40 import org.eclipse.ui.texteditor.TextEditorAction; 41 42 import org.eclipse.jdt.core.ICompilationUnit; 43 import org.eclipse.jdt.core.IJavaProject; 44 import org.eclipse.jdt.core.JavaCore; 45 import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants; 46 47 import org.eclipse.jdt.ui.text.IJavaPartitions; 48 49 import org.eclipse.jdt.internal.ui.JavaPlugin; 50 import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor; 51 import org.eclipse.jdt.internal.ui.text.JavaHeuristicScanner; 52 import org.eclipse.jdt.internal.ui.text.JavaIndenter; 53 54 55 65 public class IndentAction extends TextEditorAction { 66 67 68 private int fCaretOffset; 69 70 74 private final boolean fIsTabAction; 75 76 84 public IndentAction(ResourceBundle bundle, String prefix, ITextEditor editor, boolean isTabAction) { 85 super(bundle, prefix, editor); 86 fIsTabAction= isTabAction; 87 } 88 89 92 public void run() { 93 if (!isEnabled() || !validateEditorInputState()) 95 return; 96 97 ITextSelection selection= getSelection(); 98 final IDocument document= getDocument(); 99 100 if (document != null) { 101 102 final int offset= selection.getOffset(); 103 final int length= selection.getLength(); 104 final Position end= new Position(offset + length); 105 final int firstLine, nLines; 106 fCaretOffset= -1; 107 108 try { 109 document.addPosition(end); 110 firstLine= document.getLineOfOffset(offset); 111 int minusOne= length == 0 ? 0 : 1; 113 nLines= document.getLineOfOffset(offset + length - minusOne) - firstLine + 1; 114 } catch (BadLocationException e) { 115 JavaPlugin.log(new Status(IStatus.ERROR, JavaPlugin.getPluginId(), IStatus.OK, "", e)); return; 118 } 119 120 Runnable runnable= new Runnable () { 121 public void run() { 122 IRewriteTarget target= (IRewriteTarget)getTextEditor().getAdapter(IRewriteTarget.class); 123 if (target != null) 124 target.beginCompoundChange(); 125 126 try { 127 JavaHeuristicScanner scanner= new JavaHeuristicScanner(document); 128 JavaIndenter indenter= new JavaIndenter(document, scanner, getJavaProject()); 129 final boolean multiLine= nLines > 1; 130 boolean hasChanged= false; 131 for (int i= 0; i < nLines; i++) { 132 hasChanged |= indentLine(document, firstLine + i, offset, indenter, scanner, multiLine); 133 } 134 135 int newOffset, newLength; 138 if (!fIsTabAction && multiLine) { 139 newOffset= offset; 140 newLength= end.getOffset() - offset; 141 } else { 142 newOffset= fCaretOffset; 143 newLength= 0; 144 } 145 146 if (newOffset != -1 && (hasChanged || newOffset != offset || newLength != length)) 149 selectAndReveal(newOffset, newLength); 150 151 document.removePosition(end); 152 } catch (BadLocationException e) { 153 JavaPlugin.log(new Status(IStatus.ERROR, JavaPlugin.getPluginId(), IStatus.OK, "ConcurrentModification in IndentAction", e)); 156 } finally { 157 if (target != null) 158 target.endCompoundChange(); 159 } 160 } 161 }; 162 163 if (nLines > 50) { 164 Display display= getTextEditor().getEditorSite().getWorkbenchWindow().getShell().getDisplay(); 165 BusyIndicator.showWhile(display, runnable); 166 } else 167 runnable.run(); 168 169 } 170 } 171 172 178 private void selectAndReveal(int newOffset, int newLength) { 179 Assert.isTrue(newOffset >= 0); 180 Assert.isTrue(newLength >= 0); 181 ITextEditor editor= getTextEditor(); 182 if (editor instanceof JavaEditor) { 183 ISourceViewer viewer= ((JavaEditor)editor).getViewer(); 184 if (viewer != null) 185 viewer.setSelectedRange(newOffset, newLength); 186 } else 187 getTextEditor().selectAndReveal(newOffset, newLength); 189 190 } 191 192 205 private boolean indentLine(IDocument document, int line, int caret, JavaIndenter indenter, JavaHeuristicScanner scanner, boolean multiLine) throws BadLocationException { 206 IRegion currentLine= document.getLineInformation(line); 207 int offset= currentLine.getOffset(); 208 int wsStart= offset; 210 String indent= null; 211 if (offset < document.getLength()) { 212 ITypedRegion partition= TextUtilities.getPartition(document, IJavaPartitions.JAVA_PARTITIONING, offset, true); 213 ITypedRegion startingPartition= TextUtilities.getPartition(document, IJavaPartitions.JAVA_PARTITIONING, offset, false); 214 String type= partition.getType(); 215 if (type.equals(IJavaPartitions.JAVA_DOC) || type.equals(IJavaPartitions.JAVA_MULTI_LINE_COMMENT)) { 216 indent= computeJavadocIndent(document, line, scanner, startingPartition); 217 } else if (!fIsTabAction && startingPartition.getOffset() == offset && startingPartition.getType().equals(IJavaPartitions.JAVA_SINGLE_LINE_COMMENT)) { 218 219 int max= document.getLength() - offset; 221 int slashes= 2; 222 while (slashes < max - 1 && document.get(offset + slashes, 2).equals("//")) slashes+= 2; 224 225 wsStart= offset + slashes; 226 227 StringBuffer computed= indenter.computeIndentation(offset); 228 if (computed == null) 229 computed= new StringBuffer (0); 230 int tabSize= getTabSize(); 231 while (slashes > 0 && computed.length() > 0) { 232 char c= computed.charAt(0); 233 if (c == '\t') 234 if (slashes > tabSize) 235 slashes-= tabSize; 236 else 237 break; 238 else if (c == ' ') 239 slashes--; 240 else break; 241 242 computed.deleteCharAt(0); 243 } 244 245 indent= document.get(offset, wsStart - offset) + computed; 246 247 } 248 } 249 250 if (indent == null) { 252 StringBuffer computed= indenter.computeIndentation(offset); 253 if (computed != null) 254 indent= computed.toString(); 255 else 256 indent= ""; } 258 259 int lineLength= currentLine.getLength(); 262 int end= scanner.findNonWhitespaceForwardInAnyPartition(wsStart, offset + lineLength); 263 if (end == JavaHeuristicScanner.NOT_FOUND) { 264 end= offset + lineLength; 266 if (multiLine && !indentEmptyLines()) 267 indent= ""; } 269 int length= end - offset; 270 String currentIndent= document.get(offset, length); 271 272 if (fIsTabAction && caret == end && whiteSpaceLength(currentIndent) >= whiteSpaceLength(indent)) { 275 String tab= getTabEquivalent(); 276 document.replace(caret, 0, tab); 277 fCaretOffset= caret + tab.length(); 278 return true; 279 } 280 281 if (caret >= offset && caret <= end) 283 fCaretOffset= offset + indent.length(); 284 else 285 fCaretOffset= -1; 286 287 if (!indent.equals(currentIndent)) { 289 document.replace(offset, length, indent); 290 return true; 291 } else 292 return false; 293 } 294 295 307 private String computeJavadocIndent(IDocument document, int line, JavaHeuristicScanner scanner, ITypedRegion partition) throws BadLocationException { 308 if (line == 0) return null; 310 311 final IRegion lineInfo= document.getLineInformation(line); 314 final int lineStart= lineInfo.getOffset(); 315 final int lineLength= lineInfo.getLength(); 316 final int lineEnd= lineStart + lineLength; 317 int nonWS= scanner.findNonWhitespaceForwardInAnyPartition(lineStart, lineEnd); 318 if (nonWS == JavaHeuristicScanner.NOT_FOUND || document.getChar(nonWS) != '*') { 319 if (nonWS == JavaHeuristicScanner.NOT_FOUND) 320 return document.get(lineStart, lineLength); 321 return document.get(lineStart, nonWS - lineStart); 322 } 323 324 IRegion previousLine= document.getLineInformation(line - 1); 326 int previousLineStart= previousLine.getOffset(); 327 int previousLineLength= previousLine.getLength(); 328 int previousLineEnd= previousLineStart + previousLineLength; 329 330 StringBuffer buf= new StringBuffer (); 331 int previousLineNonWS= scanner.findNonWhitespaceForwardInAnyPartition(previousLineStart, previousLineEnd); 332 if (previousLineNonWS == JavaHeuristicScanner.NOT_FOUND || document.getChar(previousLineNonWS) != '*') { 333 previousLine= document.getLineInformationOfOffset(partition.getOffset()); 335 previousLineStart= previousLine.getOffset(); 336 previousLineLength= previousLine.getLength(); 337 previousLineEnd= previousLineStart + previousLineLength; 338 previousLineNonWS= scanner.findNonWhitespaceForwardInAnyPartition(previousLineStart, previousLineEnd); 339 if (previousLineNonWS == JavaHeuristicScanner.NOT_FOUND) 340 previousLineNonWS= previousLineEnd; 341 342 buf.append(' '); 345 } 346 347 String indentation= document.get(previousLineStart, previousLineNonWS - previousLineStart); 348 buf.insert(0, indentation); 349 return buf.toString(); 350 } 351 352 359 private int whiteSpaceLength(String indent) { 360 if (indent == null) 361 return 0; 362 else { 363 int size= 0; 364 int l= indent.length(); 365 int tabSize= getTabSize(); 366 367 for (int i= 0; i < l; i++) 368 size += indent.charAt(i) == '\t' ? tabSize : 1; 369 return size; 370 } 371 } 372 373 379 private String getTabEquivalent() { 380 String tab; 381 if (JavaCore.SPACE.equals(getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR))) { 382 int size= getTabSize(); 383 StringBuffer buf= new StringBuffer (); 384 for (int i= 0; i< size; i++) 385 buf.append(' '); 386 tab= buf.toString(); 387 } else 388 tab= "\t"; 390 return tab; 391 } 392 393 399 private int getTabSize() { 400 return getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_TAB_SIZE, 4); 401 } 402 403 409 private boolean indentEmptyLines() { 410 return DefaultCodeFormatterConstants.TRUE.equals(getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_INDENT_EMPTY_LINES)); 411 } 412 413 420 private String getCoreFormatterOption(String key) { 421 IJavaProject project= getJavaProject(); 422 if (project == null) 423 return JavaCore.getOption(key); 424 return project.getOption(key, true); 425 } 426 427 436 private int getCoreFormatterOption(String key, int def) { 437 try { 438 return Integer.parseInt(getCoreFormatterOption(key)); 439 } catch (NumberFormatException e) { 440 return def; 441 } 442 } 443 444 452 private IJavaProject getJavaProject() { 453 ITextEditor editor= getTextEditor(); 454 if (editor == null) 455 return null; 456 457 ICompilationUnit cu= JavaPlugin.getDefault().getWorkingCopyManager().getWorkingCopy(editor.getEditorInput()); 458 if (cu == null) 459 return null; 460 return cu.getJavaProject(); 461 } 462 463 468 private ISelectionProvider getSelectionProvider() { 469 ITextEditor editor= getTextEditor(); 470 if (editor != null) { 471 return editor.getSelectionProvider(); 472 } 473 return null; 474 } 475 476 479 public void update() { 480 super.update(); 481 482 if (isEnabled()) 483 if (fIsTabAction) 484 setEnabled(canModifyEditor() && isSmartMode() && isValidSelection()); 485 else 486 setEnabled(canModifyEditor() && !getSelection().isEmpty()); 487 } 488 489 495 private boolean isValidSelection() { 496 ITextSelection selection= getSelection(); 497 if (selection.isEmpty()) 498 return false; 499 500 int offset= selection.getOffset(); 501 int length= selection.getLength(); 502 503 IDocument document= getDocument(); 504 if (document == null) 505 return false; 506 507 try { 508 IRegion firstLine= document.getLineInformationOfOffset(offset); 509 int lineOffset= firstLine.getOffset(); 510 511 if (length == 0) 514 return document.get(lineOffset, offset - lineOffset).trim().length() == 0; 515 else 516 return false; 519 } catch (BadLocationException e) { 520 } 521 522 return false; 523 } 524 525 530 private boolean isSmartMode() { 531 ITextEditor editor= getTextEditor(); 532 533 if (editor instanceof ITextEditorExtension3) 534 return ((ITextEditorExtension3) editor).getInsertMode() == ITextEditorExtension3.SMART_INSERT; 535 536 return false; 537 } 538 539 545 private IDocument getDocument() { 546 547 ITextEditor editor= getTextEditor(); 548 if (editor != null) { 549 550 IDocumentProvider provider= editor.getDocumentProvider(); 551 IEditorInput input= editor.getEditorInput(); 552 if (provider != null && input != null) 553 return provider.getDocument(input); 554 555 } 556 return null; 557 } 558 559 565 private ITextSelection getSelection() { 566 ISelectionProvider provider= getSelectionProvider(); 567 if (provider != null) { 568 569 ISelection selection= provider.getSelection(); 570 if (selection instanceof ITextSelection) 571 return (ITextSelection) selection; 572 } 573 574 return TextSelection.emptySelection(); 576 } 577 578 } 579 | Popular Tags |