1 11 package org.eclipse.jdt.internal.ui.javaeditor; 12 13 import java.util.ResourceBundle ; 14 15 import org.eclipse.core.runtime.Assert; 16 17 import org.eclipse.swt.custom.StyledText; 18 import org.eclipse.swt.graphics.Point; 19 import org.eclipse.swt.widgets.Event; 20 21 import org.eclipse.jface.text.BadLocationException; 22 import org.eclipse.jface.text.IDocument; 23 import org.eclipse.jface.text.IRegion; 24 import org.eclipse.jface.text.IRewriteTarget; 25 import org.eclipse.jface.text.ITextSelection; 26 import org.eclipse.jface.text.ITextViewer; 27 import org.eclipse.jface.text.ITextViewerExtension5; 28 import org.eclipse.jface.text.Region; 29 import org.eclipse.jface.text.TextSelection; 30 import org.eclipse.jface.text.TextUtilities; 31 import org.eclipse.jface.text.source.ILineRange; 32 import org.eclipse.jface.text.source.ISourceViewer; 33 import org.eclipse.jface.text.source.LineRange; 34 35 import org.eclipse.ui.IEditorInput; 36 import org.eclipse.ui.texteditor.IEditorStatusLine; 37 import org.eclipse.ui.texteditor.ITextEditor; 38 import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds; 39 import org.eclipse.ui.texteditor.TextEditorAction; 40 41 import org.eclipse.jdt.core.ICompilationUnit; 42 import org.eclipse.jdt.core.IJavaProject; 43 44 import org.eclipse.jdt.internal.ui.JavaPlugin; 45 import org.eclipse.jdt.internal.ui.javaeditor.IndentUtil.IndentResult; 46 47 51 public class JavaMoveLinesAction extends TextEditorAction { 52 53 57 private static final class SharedState { 58 59 public CompilationUnitEditor fEditor; 60 63 public IndentResult fResult= null; 64 67 boolean fIsChanging= false; 68 69 70 private boolean fEditInProgress= false; 71 72 private final CompoundEditExitStrategy fExitStrategy; 73 74 public SharedState(CompilationUnitEditor editor) { 75 fEditor= editor; 76 fExitStrategy= new CompoundEditExitStrategy(new String [] {ITextEditorActionDefinitionIds.MOVE_LINES_UP, ITextEditorActionDefinitionIds.MOVE_LINES_DOWN, ITextEditorActionDefinitionIds.COPY_LINES_UP, ITextEditorActionDefinitionIds.COPY_LINES_DOWN}); 77 fExitStrategy.addCompoundListener(new ICompoundEditListener() { 78 public void endCompoundEdit() { 79 SharedState.this.endCompoundEdit(); 80 } 81 }); 82 } 83 84 87 public void beginCompoundEdit() { 88 if (fEditInProgress || fEditor == null) 89 return; 90 91 fEditInProgress= true; 92 93 fExitStrategy.arm(fEditor.getViewer()); 94 95 IRewriteTarget target= (IRewriteTarget)fEditor.getAdapter(IRewriteTarget.class); 96 if (target != null) { 97 target.beginCompoundChange(); 98 } 99 } 100 103 public void endCompoundEdit() { 104 if (!fEditInProgress || fEditor == null) 105 return; 106 107 fExitStrategy.disarm(); 108 109 IRewriteTarget target= (IRewriteTarget)fEditor.getAdapter(IRewriteTarget.class); 110 if (target != null) { 111 target.endCompoundChange(); 112 } 113 114 fResult= null; 115 fEditInProgress= false; 116 } 117 } 118 119 120 121 122 123 124 125 126 private final boolean fUpwards; 127 128 private final boolean fCopy; 129 130 private final SharedState fSharedState; 131 132 143 public static JavaMoveLinesAction[] createMoveCopyActionSet(ResourceBundle bundle, CompilationUnitEditor editor) { 144 SharedState state= new SharedState(editor); 145 JavaMoveLinesAction[] actions= new JavaMoveLinesAction[4]; 146 actions[0]= new JavaMoveLinesAction(bundle, "Editor.MoveLinesUp.", true, false, state); actions[1]= new JavaMoveLinesAction(bundle, "Editor.MoveLinesDown.", false, false, state); actions[2]= new JavaMoveLinesAction(bundle, "Editor.CopyLineUp.", true, true, state); actions[3]= new JavaMoveLinesAction(bundle, "Editor.CopyLineDown.", false, true, state); return actions; 151 } 152 153 156 public void setEditor(ITextEditor editor) { 157 Assert.isTrue(editor instanceof CompilationUnitEditor); 158 super.setEditor(editor); 159 if (fSharedState != null) 160 fSharedState.fEditor= (CompilationUnitEditor) editor; 161 } 162 163 177 private JavaMoveLinesAction(ResourceBundle bundle, String prefix, boolean upwards, boolean copy, SharedState state) { 178 super(bundle, prefix, state.fEditor); 179 fUpwards= upwards; 180 fCopy= copy; 181 fSharedState= state; 182 update(); 183 } 184 185 194 private boolean containedByVisibleRegion(ITextSelection selection, ISourceViewer viewer) { 195 int min= selection.getOffset(); 196 int max= min + selection.getLength(); 197 IDocument document= viewer.getDocument(); 198 199 IRegion visible; 200 if (viewer instanceof ITextViewerExtension5) 201 visible= ((ITextViewerExtension5) viewer).getModelCoverage(); 202 else 203 visible= viewer.getVisibleRegion(); 204 205 int visOffset= visible.getOffset(); 206 try { 207 if (visOffset > min) { 208 if (document.getLineOfOffset(visOffset) != selection.getStartLine()) 209 return false; 210 if (!isWhitespace(document.get(min, visOffset - min))) { 211 showStatus(); 212 return false; 213 } 214 } 215 int visEnd= visOffset + visible.getLength(); 216 if (visEnd < max) { 217 if (document.getLineOfOffset(visEnd) != selection.getEndLine()) 218 return false; 219 if (!isWhitespace(document.get(visEnd, max - visEnd))) { 220 showStatus(); 221 return false; 222 } 223 } 224 return true; 225 } catch (BadLocationException e) { 226 } 227 return false; 228 } 229 230 249 private ITextSelection getMovingSelection(IDocument document, ITextSelection selection, ISourceViewer viewer) throws BadLocationException { 250 int low= document.getLineOffset(selection.getStartLine()); 251 int endLine= selection.getEndLine(); 252 int high= document.getLineOffset(endLine) + document.getLineLength(endLine); 253 254 String delim= document.getLineDelimiter(endLine); 256 if (delim != null) 257 high -= delim.length(); 258 259 return new TextSelection(document, low, high - low); 260 } 261 262 271 private ITextSelection getSkippedLine(IDocument document, ITextSelection selection) { 272 int skippedLineN= (fUpwards ? selection.getStartLine() - 1 : selection.getEndLine() + 1); 273 if (skippedLineN > document.getNumberOfLines() || (!fCopy && (skippedLineN < 0 || skippedLineN == document.getNumberOfLines()))) 274 return null; 275 try { 276 if (fCopy && skippedLineN == -1) 277 skippedLineN= 0; 278 IRegion line= document.getLineInformation(skippedLineN); 279 return new TextSelection(document, line.getOffset(), line.getLength()); 280 } catch (BadLocationException e) { 281 return null; 283 } 284 } 285 286 293 private boolean isWhitespace(String string) { 294 return string == null ? true : string.trim().length() == 0; 295 } 296 297 300 public void runWithEvent(Event event) { 301 302 if (fSharedState.fEditor == null) 304 return; 305 306 if (!validateEditorInputState()) 307 return; 308 309 ISourceViewer viewer= fSharedState.fEditor.getViewer(); 310 if (viewer == null) 311 return; 312 313 IDocument document= viewer.getDocument(); 314 if (document == null) 315 return; 316 317 StyledText widget= viewer.getTextWidget(); 318 if (widget == null) 319 return; 320 321 Point p= viewer.getSelectedRange(); 323 if (p == null) 324 return; 325 326 ITextSelection sel= new TextSelection(document, p.x, p.y); 327 328 ITextSelection skippedLine= getSkippedLine(document, sel); 329 if (skippedLine == null) 330 return; 331 332 try { 333 334 ITextSelection movingArea= getMovingSelection(document, sel, viewer); 335 336 if (!containedByVisibleRegion(movingArea, viewer) || !containedByVisibleRegion(skippedLine, viewer)) 339 return; 340 341 String moving= movingArea.getText(); 343 String skipped= skippedLine.getText(); 344 if (moving == null || skipped == null || document.getLength() == 0) 345 return; 346 347 String delim; 348 String insertion; 349 int offset; 350 if (fUpwards) { 351 delim= document.getLineDelimiter(skippedLine.getEndLine()); 352 if (fCopy) { 353 delim= TextUtilities.getDefaultLineDelimiter(document); 354 insertion= moving + delim; 355 offset= movingArea.getOffset(); 356 } else { 357 Assert.isNotNull(delim); 358 insertion= moving + delim + skipped; 359 offset= skippedLine.getOffset(); 360 } 361 } else { 362 delim= document.getLineDelimiter(movingArea.getEndLine()); 363 if (fCopy) { 364 if (delim == null) { 365 delim= TextUtilities.getDefaultLineDelimiter(document); 366 insertion= delim + moving; 367 } else 368 insertion= moving + delim; 369 offset= skippedLine.getOffset(); 370 } else { 371 Assert.isNotNull(delim); 372 insertion= skipped + delim + moving; 373 offset= movingArea.getOffset(); 374 } 375 } 376 int lenght= fCopy ? 0 : insertion.length(); 377 378 ILineRange selectionBefore= getLineRange(document, movingArea); 380 381 if (fCopy) 382 fSharedState.endCompoundEdit(); 383 fSharedState.beginCompoundEdit(); 384 fSharedState.fIsChanging= true; 385 386 document.replace(offset, lenght, insertion); 387 388 ILineRange selectionAfter; 389 if (fUpwards && fCopy) 390 selectionAfter= selectionBefore; 391 else if (fUpwards) 392 selectionAfter= new LineRange(selectionBefore.getStartLine() - 1, selectionBefore.getNumberOfLines()); 393 else if (fCopy) 394 selectionAfter= new LineRange(selectionBefore.getStartLine() + selectionBefore.getNumberOfLines(), selectionBefore.getNumberOfLines()); 395 else 396 selectionAfter= new LineRange(selectionBefore.getStartLine() + 1, selectionBefore.getNumberOfLines()); 397 398 fSharedState.fResult= IndentUtil.indentLines(document, selectionAfter, getProject(), fSharedState.fResult); 399 400 IRegion region= getRegion(document, selectionAfter); 402 selectAndReveal(viewer, region.getOffset(), region.getLength()); 403 404 } catch (BadLocationException x) { 405 return; 407 } finally { 408 fSharedState.fIsChanging= false; 409 if (fCopy) 410 fSharedState.endCompoundEdit(); 411 } 412 } 413 414 private IJavaProject getProject() { 415 IEditorInput editorInput= fSharedState.fEditor.getEditorInput(); 416 ICompilationUnit unit= JavaPlugin.getDefault().getWorkingCopyManager().getWorkingCopy(editorInput); 417 if (unit != null) 418 return unit.getJavaProject(); 419 return null; 420 } 421 422 private ILineRange getLineRange(IDocument document, ITextSelection selection) throws BadLocationException { 423 final int offset= selection.getOffset(); 424 int startLine= document.getLineOfOffset(offset); 425 int endOffset= offset + selection.getLength(); 426 int endLine= document.getLineOfOffset(endOffset); 427 final int nLines= endLine - startLine + 1; 428 return new LineRange(startLine, nLines); 429 } 430 431 private IRegion getRegion(IDocument document, ILineRange lineRange) throws BadLocationException { 432 final int startLine= lineRange.getStartLine(); 433 int offset= document.getLineOffset(startLine); 434 final int numberOfLines= lineRange.getNumberOfLines(); 435 if (numberOfLines < 1) 436 return new Region(offset, 0); 437 int endLine= startLine + numberOfLines - 1; 438 int endOffset= document.getLineOffset(endLine) + document.getLineLength(endLine); 439 return new Region(offset, endOffset - offset); 440 } 441 442 450 private void selectAndReveal(ITextViewer viewer, int offset, int length) { 451 viewer.setSelectedRange(offset + length, -length); 453 StyledText st= viewer.getTextWidget(); 455 if (st != null) 456 st.showSelection(); } 458 459 462 private void showStatus() { 463 IEditorStatusLine status= (IEditorStatusLine) fSharedState.fEditor.getAdapter(IEditorStatusLine.class); 464 if (status == null) 465 return; 466 status.setMessage(false, JavaEditorMessages.Editor_MoveLines_IllegalMove_status, null); 467 } 468 469 472 public void update() { 473 super.update(); 474 475 if (isEnabled()) 476 setEnabled(canModifyEditor()); 477 478 } 479 } 480 | Popular Tags |