| /******************************************************************************* |
| * Copyright (c) 2009, 2012 Avaloq Evolution AG and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Tom Eicher (Avaloq Evolution AG) - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jface.internal.text; |
| |
| import java.util.Arrays; |
| |
| import org.eclipse.swt.custom.StyledText; |
| import org.eclipse.swt.graphics.GC; |
| |
| import org.eclipse.core.runtime.Assert; |
| |
| import org.eclipse.text.edits.DeleteEdit; |
| import org.eclipse.text.edits.InsertEdit; |
| import org.eclipse.text.edits.MalformedTreeException; |
| import org.eclipse.text.edits.MultiTextEdit; |
| import org.eclipse.text.edits.ReplaceEdit; |
| import org.eclipse.text.edits.TextEdit; |
| |
| import org.eclipse.jface.viewers.ISelection; |
| import org.eclipse.jface.viewers.ISelectionProvider; |
| |
| import org.eclipse.jface.text.BadLocationException; |
| import org.eclipse.jface.text.BlockTextSelection; |
| import org.eclipse.jface.text.IBlockTextSelection; |
| import org.eclipse.jface.text.IDocument; |
| import org.eclipse.jface.text.IRegion; |
| import org.eclipse.jface.text.IRewriteTarget; |
| import org.eclipse.jface.text.ITextSelection; |
| import org.eclipse.jface.text.ITextViewer; |
| import org.eclipse.jface.text.ITextViewerExtension; |
| import org.eclipse.jface.text.Region; |
| import org.eclipse.jface.text.TextSelection; |
| import org.eclipse.jface.text.TextUtilities; |
| |
| /** |
| * Processes {@link ITextSelection}s. |
| * |
| * @since 3.5 |
| */ |
| public final class SelectionProcessor { |
| private static class Implementation { |
| /** |
| * Returns a text edit describing the text modification that would be executed if the given |
| * selection was replaced by <code>replacement</code>. |
| * |
| * @param selection the selection to replace |
| * @param replacement the replacement text |
| * @return a text edit describing the operation needed to replace <code>selection</code> |
| * @throws BadLocationException if computing the edit failed |
| */ |
| TextEdit replace(ISelection selection, String replacement) throws BadLocationException { |
| return new MultiTextEdit(); |
| } |
| |
| /** |
| * Returns the text covered by <code>selection</code> |
| * |
| * @param selection the selection |
| * @return the text covered by <code>selection</code> |
| * @throws BadLocationException if computing the edit failed |
| */ |
| String getText(ISelection selection) throws BadLocationException { |
| return ""; //$NON-NLS-1$ |
| } |
| |
| /** |
| * Returns <code>true</code> if the text covered by <code>selection</code> does not contain any |
| * characters. Note the difference to {@link ITextSelection#isEmpty()}, which returns |
| * <code>true</code> only for invalid selections. |
| * |
| * @param selection the selection |
| * @return <code>true</code> if <code>selection</code> does not contain any text, |
| * <code>false</code> otherwise |
| * @throws BadLocationException if accessing the document failed |
| */ |
| boolean isEmpty(ISelection selection) throws BadLocationException { |
| return selection.isEmpty(); |
| } |
| |
| /** |
| * Returns <code>true</code> if <code>selection</code> covers text on two or more lines, |
| * <code>false</code> otherwise. |
| * |
| * @param selection the selection |
| * @return <code>true</code> if <code>selection</code> covers text on two or more lines, |
| * <code>false</code> otherwise |
| * @throws BadLocationException if selection is not a valid selection on the target document |
| */ |
| boolean isMultiline(ISelection selection) throws BadLocationException { |
| if (selection == null) |
| throw new NullPointerException(); |
| return false; |
| } |
| |
| TextEdit delete(ISelection selection) throws BadLocationException { |
| return replace(selection, ""); //$NON-NLS-1$ |
| } |
| |
| TextEdit backspace(ISelection selection) throws BadLocationException { |
| return replace(selection, ""); //$NON-NLS-1$ |
| } |
| |
| /** |
| * Returns a selection similar to <code>selection</code> but {@linkplain #isEmpty(ISelection) |
| * empty}. Typically, the selection is reduced to its left-most offset. |
| * |
| * @param selection the selection |
| * @param beginning <code>true</code> to collapse the selection to its smallest position |
| * (i.e. its left-most offset), <code>false</code> to collapse it to its greatest |
| * position (e.g its right-most offset) |
| * @return an empty variant of <code>selection</code> |
| * @throws BadLocationException if accessing the document failed |
| */ |
| ISelection makeEmpty(ISelection selection, boolean beginning) throws BadLocationException { |
| return selection; |
| } |
| |
| /** |
| * Returns the text regions covered by the given selection. |
| * |
| * @param selection the selection |
| * @return the text regions corresponding to <code>selection</code> |
| * @throws BadLocationException if accessing the document failed |
| */ |
| IRegion[] getRanges(ISelection selection) throws BadLocationException { |
| return new IRegion[0]; |
| } |
| |
| /** |
| * Returns the number of lines touched by <code>selection</code>. |
| * |
| * @param selection the selection |
| * @return the number of lines touched by <code>selection</code> |
| * @throws BadLocationException if accessing the document failed |
| */ |
| int getCoveredLines(ISelection selection) throws BadLocationException { |
| return 0; |
| } |
| |
| /** |
| * Returns the selection after replacing <code>selection</code> by <code>replacement</code>. |
| * |
| * @param selection the selection to be replaced |
| * @param replacement the replacement text |
| * @return the selection that the user expects after the specified replacement operation |
| * @throws BadLocationException if accessing the document failed |
| */ |
| ISelection makeReplaceSelection(ISelection selection, String replacement) throws BadLocationException { |
| return makeEmpty(selection, false); |
| } |
| } |
| |
| private final Implementation NULL_IMPLEMENTATION= new Implementation(); |
| |
| private final Implementation RANGE_IMPLEMENTATION= new Implementation() { |
| TextEdit replace(ISelection selection, String replacement) { |
| ITextSelection ts= (ITextSelection)selection; |
| return new ReplaceEdit(ts.getOffset(), ts.getLength(), replacement); |
| } |
| |
| String getText(ISelection selection) { |
| ITextSelection ts= (ITextSelection)selection; |
| return ts.getText(); |
| } |
| |
| boolean isEmpty(ISelection selection) { |
| ITextSelection ts= (ITextSelection)selection; |
| return ts.getLength() <= 0; |
| } |
| |
| boolean isMultiline(ISelection selection) throws BadLocationException { |
| ITextSelection ts= (ITextSelection)selection; |
| return fDocument.getLineOfOffset(ts.getOffset()) < fDocument.getLineOfOffset(ts.getOffset() + ts.getLength()); |
| } |
| |
| TextEdit delete(ISelection selection) { |
| ITextSelection ts= (ITextSelection)selection; |
| if (isEmpty(selection)) |
| return new DeleteEdit(ts.getOffset(), 1); |
| return new DeleteEdit(ts.getOffset(), ts.getLength()); |
| } |
| |
| TextEdit backspace(ISelection selection) throws BadLocationException { |
| ITextSelection ts= (ITextSelection)selection; |
| if (isEmpty(selection)) |
| return new DeleteEdit(ts.getOffset() - 1, 1); |
| return new DeleteEdit(ts.getOffset(), ts.getLength()); |
| } |
| |
| ISelection makeEmpty(ISelection selection, boolean beginning) { |
| ITextSelection ts= (ITextSelection)selection; |
| return beginning ? |
| new TextSelection(fDocument, ts.getOffset(), 0) |
| : new TextSelection(fDocument, ts.getOffset() + ts.getLength(), 0); |
| } |
| |
| IRegion[] getRanges(ISelection selection) { |
| ITextSelection ts= (ITextSelection)selection; |
| return new IRegion[] { new Region(ts.getOffset(), ts.getLength()) }; |
| } |
| |
| int getCoveredLines(ISelection selection) throws BadLocationException { |
| ITextSelection ts= (ITextSelection)selection; |
| return ts.getEndLine() - ts.getStartLine() + 1; |
| } |
| |
| ISelection makeReplaceSelection(ISelection selection, String replacement) { |
| ITextSelection ts= (ITextSelection)selection; |
| return new TextSelection(fDocument, ts.getOffset() + replacement.length(), 0); |
| } |
| }; |
| |
| private final Implementation COLUMN_IMPLEMENTATION= new Implementation() { |
| private TextEdit replace(ISelection selection, String replacement, boolean delete) throws BadLocationException { |
| try { |
| MultiTextEdit root; |
| IBlockTextSelection cts= (IBlockTextSelection)selection; |
| int startLine= cts.getStartLine(); |
| int endLine= cts.getEndLine(); |
| int startColumn= cts.getStartColumn(); |
| int endColumn= cts.getEndColumn(); |
| int visualStartColumn= computeVisualColumn(startLine, startColumn); |
| int visualEndColumn= computeVisualColumn(endLine, endColumn); |
| root= new MultiTextEdit(); |
| String[] delimiters= fDocument.getLegalLineDelimiters(); |
| |
| int lastDelim= 0; |
| for (int line= startLine; line <= endLine; line++) { |
| String string; |
| if (lastDelim == -1) { |
| string= ""; //$NON-NLS-1$ |
| } else { |
| int[] index= TextUtilities.indexOf(delimiters, replacement, lastDelim); |
| if (index[0] == -1) { |
| string= replacement.substring(lastDelim); |
| lastDelim= -1; |
| } else { |
| string= replacement.substring(lastDelim, index[0]); |
| lastDelim= index[0] + delimiters[index[1]].length(); |
| } |
| } |
| TextEdit replace= createReplaceEdit(line, visualStartColumn, visualEndColumn, string, delete); |
| root.addChild(replace); |
| } |
| while (lastDelim != -1) { |
| // more stuff to insert |
| String string; |
| int[] index= TextUtilities.indexOf(delimiters, replacement, lastDelim); |
| if (index[0] == -1) { |
| string= replacement.substring(lastDelim); |
| lastDelim= -1; |
| } else { |
| string= replacement.substring(lastDelim, index[0]); |
| lastDelim= index[0] + delimiters[index[1]].length(); |
| } |
| endLine++; |
| TextEdit edit; |
| if (endLine < fDocument.getNumberOfLines()) { |
| edit= createReplaceEdit(endLine, visualStartColumn, visualEndColumn, string, delete); |
| } else { |
| // insertion reaches beyond the last line |
| int insertLocation= root.getExclusiveEnd(); |
| int spaces= visualStartColumn; |
| char[] array= new char[spaces]; |
| Arrays.fill(array, ' '); |
| string= TextUtilities.getDefaultLineDelimiter(fDocument) + String.valueOf(array) + string; |
| edit= new InsertEdit(insertLocation, string); |
| insertLocation+= string.length(); |
| } |
| root.addChild(edit); |
| } |
| return root; |
| } catch (MalformedTreeException x) { |
| Assert.isTrue(false); |
| return null; |
| } |
| } |
| |
| TextEdit replace(ISelection selection, String replacement) throws BadLocationException { |
| return replace(selection, replacement, false); |
| } |
| |
| String getText(ISelection selection) throws BadLocationException { |
| IBlockTextSelection cts= (IBlockTextSelection)selection; |
| StringBuffer buf= new StringBuffer(cts.getLength()); |
| int startLine= cts.getStartLine(); |
| int endLine= cts.getEndLine(); |
| int startColumn= cts.getStartColumn(); |
| int endColumn= cts.getEndColumn(); |
| int visualStartColumn= computeVisualColumn(startLine, startColumn); |
| int visualEndColumn= computeVisualColumn(endLine, endColumn); |
| |
| for (int line= startLine; line <= endLine; line++) { |
| appendColumnRange(buf, line, visualStartColumn, visualEndColumn); |
| if (line != endLine) |
| buf.append(fDocument.getLineDelimiter(line)); |
| } |
| |
| return buf.toString(); |
| } |
| |
| boolean isEmpty(ISelection selection) throws BadLocationException { |
| IBlockTextSelection cts= (IBlockTextSelection)selection; |
| int startLine= cts.getStartLine(); |
| int endLine= cts.getEndLine(); |
| int startColumn= cts.getStartColumn(); |
| int endColumn= cts.getEndColumn(); |
| int visualStartColumn= computeVisualColumn(startLine, startColumn); |
| int visualEndColumn= computeVisualColumn(endLine, endColumn); |
| return visualEndColumn == visualStartColumn; |
| } |
| |
| boolean isMultiline(ISelection selection) { |
| ITextSelection ts= (ITextSelection)selection; |
| return ts.getEndLine() > ts.getStartLine(); |
| } |
| |
| TextEdit delete(ISelection selection) throws BadLocationException { |
| if (isEmpty(selection)) { |
| IBlockTextSelection cts= (IBlockTextSelection)selection; |
| selection= new BlockTextSelection(fDocument, cts.getStartLine(), cts.getStartColumn(), cts.getEndLine(), cts.getEndColumn() + 1, fTabWidth); |
| } |
| return replace(selection, "", true); //$NON-NLS-1$ |
| } |
| |
| TextEdit backspace(ISelection selection) throws BadLocationException { |
| IBlockTextSelection cts= (IBlockTextSelection)selection; |
| if (isEmpty(selection) && cts.getStartColumn() > 0) { |
| selection= new BlockTextSelection(fDocument, cts.getStartLine(), cts.getStartColumn() - 1, cts.getEndLine(), cts.getEndColumn(), fTabWidth); |
| } |
| return replace(selection, ""); //$NON-NLS-1$ |
| } |
| |
| ISelection makeEmpty(ISelection selection, boolean beginning) throws BadLocationException { |
| IBlockTextSelection cts= (IBlockTextSelection)selection; |
| int startLine, startColumn, endLine, endColumn; |
| if (beginning) { |
| startLine= cts.getStartLine(); |
| startColumn= cts.getStartColumn(); |
| endLine= cts.getEndLine(); |
| endColumn= computeCharacterColumn(endLine, computeVisualColumn(startLine, startColumn)); |
| } else { |
| endLine= cts.getEndLine(); |
| endColumn= cts.getEndColumn(); |
| startLine= cts.getStartLine(); |
| startColumn= computeCharacterColumn(startLine, computeVisualColumn(endLine, endColumn)); |
| } |
| return new BlockTextSelection(fDocument, startLine, startColumn, endLine, endColumn, fTabWidth); |
| } |
| |
| ISelection makeReplaceSelection(ISelection selection, String replacement) throws BadLocationException { |
| IBlockTextSelection bts= (IBlockTextSelection)selection; |
| String[] delimiters= fDocument.getLegalLineDelimiters(); |
| int[] index= TextUtilities.indexOf(delimiters, replacement, 0); |
| int length; |
| if (index[0] == -1) |
| length= replacement.length(); |
| else |
| length= index[0]; |
| |
| int startLine= bts.getStartLine(); |
| int column= bts.getStartColumn() + length; |
| int endLine= bts.getEndLine(); |
| int endColumn= computeCharacterColumn(endLine, computeVisualColumn(startLine, column)); |
| return new BlockTextSelection(fDocument, startLine, column, endLine, endColumn, fTabWidth); |
| } |
| |
| IRegion[] getRanges(ISelection selection) throws BadLocationException { |
| IBlockTextSelection cts= (IBlockTextSelection)selection; |
| final int startLine= cts.getStartLine(); |
| final int endLine= cts.getEndLine(); |
| int visualStartColumn= computeVisualColumn(startLine, cts.getStartColumn()); |
| int visualEndColumn= computeVisualColumn(endLine, cts.getEndColumn()); |
| IRegion[] ranges= new IRegion[endLine - startLine + 1]; |
| |
| for (int line= startLine; line <= endLine; line++) { |
| int startColumn= computeCharacterColumn(line, visualStartColumn); |
| int endColumn= computeCharacterColumn(line, visualEndColumn); |
| IRegion lineInfo= fDocument.getLineInformation(line); |
| int lineEnd= lineInfo.getLength(); |
| startColumn= Math.min(startColumn, lineEnd); |
| endColumn= Math.min(endColumn, lineEnd); |
| ranges[line - startLine]= new Region(lineInfo.getOffset() + startColumn, endColumn - startColumn); |
| } |
| |
| return ranges; |
| } |
| |
| int getCoveredLines(ISelection selection) throws BadLocationException { |
| ITextSelection ts= (ITextSelection)selection; |
| return ts.getEndLine() - ts.getStartLine() + 1; |
| } |
| |
| private TextEdit createReplaceEdit(int line, int visualStartColumn, int visualEndColumn, String replacement, boolean delete) throws BadLocationException { |
| IRegion info= fDocument.getLineInformation(line); |
| int lineLength= info.getLength(); |
| String content= fDocument.get(info.getOffset(), lineLength); |
| int startColumn= -1; |
| int endColumn= -1; |
| int visual= 0; |
| for (int offset= 0; offset < lineLength; offset++) { |
| if (startColumn == -1) { |
| if (visual == visualStartColumn) |
| if (!delete && isWider(content.charAt(offset), visual) && replacement.length() == 0) |
| startColumn= offset - 1; |
| else |
| startColumn= offset; |
| else if (visual > visualStartColumn) { |
| if (isWider(content.charAt(offset - 1), visual)) |
| startColumn= offset - 1; |
| else |
| startColumn= offset; |
| } |
| } |
| if (startColumn != -1) { |
| if (visual == visualEndColumn) { |
| endColumn= offset; |
| break; |
| } else if (visual > visualEndColumn) { |
| if (!delete && isWider(content.charAt(offset - 1), visual)) |
| endColumn= offset - 1; |
| else |
| endColumn= offset; |
| break; |
| } |
| } |
| visual+= visualSizeIncrement(content.charAt(offset), visual); |
| } |
| if (startColumn == -1) { |
| boolean materializeVirtualSpace= replacement.length() != 0; |
| if (materializeVirtualSpace) { |
| int spaces= Math.max(0, visualStartColumn - visual); |
| char[] array= new char[spaces]; |
| Arrays.fill(array, ' '); |
| return new InsertEdit(info.getOffset() + lineLength, String.valueOf(array) + replacement); |
| } |
| return new MultiTextEdit(); |
| } |
| if (endColumn == -1) |
| endColumn= lineLength; |
| if (replacement.length() == 0) |
| return new DeleteEdit(info.getOffset() + startColumn, endColumn - startColumn); |
| return new ReplaceEdit(info.getOffset() + startColumn, endColumn - startColumn, replacement); |
| } |
| |
| private void appendColumnRange(StringBuffer buf, int line, int visualStartColumn, int visualEndColumn) throws BadLocationException { |
| IRegion info= fDocument.getLineInformation(line); |
| int lineLength= info.getLength(); |
| String content= fDocument.get(info.getOffset(), lineLength); |
| int startColumn= -1; |
| int endColumn= -1; |
| int visual= 0; |
| for (int offset= 0; offset < lineLength; offset++) { |
| if (startColumn == -1 && visual >= visualStartColumn) |
| startColumn= offset; |
| if (visual >= visualEndColumn) { |
| endColumn= offset; |
| break; |
| } |
| visual+= visualSizeIncrement(content.charAt(offset), visual); |
| } |
| if (startColumn != -1) |
| buf.append(content.substring(startColumn, endColumn == -1 ? lineLength : endColumn)); |
| if (endColumn == -1) { |
| int spaces= Math.max(0, visualEndColumn - Math.max(visual, visualStartColumn)); |
| for (int i= 0; i < spaces; i++) |
| buf.append(' '); |
| } |
| } |
| |
| private int computeVisualColumn(final int line, final int column) throws BadLocationException { |
| IRegion info= fDocument.getLineInformation(line); |
| int lineLength= info.getLength(); |
| int to= Math.min(lineLength, column); |
| String content= fDocument.get(info.getOffset(), lineLength); |
| int visual= 0; |
| for (int offset= 0; offset < to; offset++) |
| visual+= visualSizeIncrement(content.charAt(offset), visual); |
| if (column > lineLength) |
| visual+= column - lineLength; // virtual spaces |
| return visual; |
| } |
| |
| private int computeCharacterColumn(int line, int visualColumn) throws BadLocationException { |
| IRegion info= fDocument.getLineInformation(line); |
| int lineLength= info.getLength(); |
| String content= fDocument.get(info.getOffset(), lineLength); |
| int visual= 0; |
| for (int offset= 0; offset < lineLength; offset++) { |
| if (visual >= visualColumn) |
| return offset; |
| visual+= visualSizeIncrement(content.charAt(offset), visual); |
| } |
| return lineLength + Math.max(0, visualColumn - visual); |
| } |
| |
| private boolean isWider(char character, int visual) { |
| return visualSizeIncrement(character, visual) > 1; |
| } |
| |
| /** |
| * Returns the increment in visual length represented by <code>character</code> given the |
| * current visual length. The visual length is <code>1</code> unless <code>character</code> |
| * is a tabulator (<code>\t</code>). |
| * |
| * @param character the character the length of which to compute |
| * @param visual the current visual length |
| * @return the increment in visual length represented by <code>character</code>, which is in |
| * <code>[0,fTabWidth]</code> |
| */ |
| private int visualSizeIncrement(char character, int visual) { |
| if (character > 255 && fStyledText != null) { |
| GC gc= null; |
| try { |
| gc= new GC(fStyledText); |
| int charWidth= gc.stringExtent(new String(Character.toString(character))).x; |
| int singleCharWidth= gc.stringExtent(" ").x; //$NON-NLS-1$ |
| return (int)Math.ceil(charWidth / singleCharWidth); |
| } finally { |
| if (gc != null) |
| gc.dispose(); |
| } |
| } |
| if (character != '\t') |
| return 1; |
| if (fTabWidth <= 0) |
| return 0; |
| return fTabWidth - visual % fTabWidth; |
| } |
| }; |
| |
| private final IDocument fDocument; |
| |
| private final int fTabWidth; |
| |
| private IRewriteTarget fRewriteTarget; |
| |
| private ISelectionProvider fSelectionProvider; |
| |
| private StyledText fStyledText; |
| |
| /** |
| * Creates a new processor on the given viewer. |
| * |
| * @param viewer the viewer |
| */ |
| public SelectionProcessor(ITextViewer viewer) { |
| this(viewer.getDocument(), viewer.getTextWidget().getTabs()); |
| if (viewer instanceof ITextViewerExtension) { |
| ITextViewerExtension ext= (ITextViewerExtension)viewer; |
| fRewriteTarget= ext.getRewriteTarget(); |
| } |
| fSelectionProvider= viewer.getSelectionProvider(); |
| fStyledText= viewer.getTextWidget(); |
| } |
| |
| /** |
| * Creates a new processor on the given document and using the given tab width. |
| * |
| * @param document the document |
| * @param tabWidth the tabulator width in space equivalents, must be <code>>=0</code> |
| */ |
| public SelectionProcessor(IDocument document, int tabWidth) { |
| Assert.isNotNull(document); |
| Assert.isTrue(tabWidth >= 0); |
| fDocument= document; |
| fTabWidth= tabWidth; |
| } |
| |
| /** |
| * Returns a text edit describing the text modification that would be executed if the delete key |
| * was pressed on the given selection. |
| * |
| * @param selection the selection to delete |
| * @return a text edit describing the operation needed to delete <code>selection</code> |
| * @throws BadLocationException if computing the edit failed |
| */ |
| public TextEdit delete(ISelection selection) throws BadLocationException { |
| return getImplementation(selection).delete(selection); |
| } |
| |
| /** |
| * Returns a text edit describing the text modification that would be executed if the backspace |
| * key was pressed on the given selection. |
| * |
| * @param selection the selection to delete |
| * @return a text edit describing the operation needed to delete <code>selection</code> |
| * @throws BadLocationException if computing the edit failed |
| */ |
| public TextEdit backspace(ISelection selection) throws BadLocationException { |
| return getImplementation(selection).backspace(selection); |
| } |
| |
| /** |
| * Returns a text edit describing the text modification that would be executed if the given |
| * selection was replaced by <code>replacement</code>. |
| * |
| * @param selection the selection to replace |
| * @param replacement the replacement text |
| * @return a text edit describing the operation needed to replace <code>selection</code> |
| * @throws BadLocationException if computing the edit failed |
| */ |
| public TextEdit replace(ISelection selection, String replacement) throws BadLocationException { |
| return getImplementation(selection).replace(selection, replacement); |
| } |
| |
| /** |
| * Returns the text covered by <code>selection</code> |
| * |
| * @param selection the selection |
| * @return the text covered by <code>selection</code> |
| * @throws BadLocationException if computing the edit failed |
| */ |
| public String getText(ISelection selection) throws BadLocationException { |
| return getImplementation(selection).getText(selection); |
| } |
| |
| /** |
| * Returns <code>true</code> if the text covered by <code>selection</code> does not contain any |
| * characters. Note the difference to {@link ITextSelection#isEmpty()}, which returns |
| * <code>true</code> only for invalid selections. |
| * |
| * @param selection the selection |
| * @return <code>true</code> if <code>selection</code> does not contain any text, |
| * <code>false</code> otherwise |
| * @throws BadLocationException if accessing the document failed |
| */ |
| public boolean isEmpty(ISelection selection) throws BadLocationException { |
| return getImplementation(selection).isEmpty(selection); |
| } |
| |
| /** |
| * Returns <code>true</code> if <code>selection</code> extends to two or more lines, |
| * <code>false</code> otherwise. |
| * |
| * @param selection the selection |
| * @return <code>true</code> if <code>selection</code> extends to two or more lines, |
| * <code>false</code> otherwise |
| * @throws BadLocationException if <code>selection</code> is not valid regarding the target |
| * document |
| */ |
| public boolean isMultiline(ISelection selection) throws BadLocationException { |
| return getImplementation(selection).isMultiline(selection); |
| } |
| |
| /** |
| * Returns a selection similar to <code>selection</code> but {@linkplain #isEmpty(ISelection) |
| * empty}. Typically, the selection is reduced to its extreme offsets. |
| * |
| * @param selection the selection |
| * @param beginning <code>true</code> to collapse the selection to its smallest position (i.e. |
| * its left-most offset), <code>false</code> to collapse it to its greatest position |
| * (e.g its right-most offset) |
| * @return an empty variant of <code>selection</code> |
| * @throws BadLocationException if accessing the document failed |
| */ |
| public ISelection makeEmpty(ISelection selection, boolean beginning) throws BadLocationException { |
| return getImplementation(selection).makeEmpty(selection, beginning); |
| } |
| |
| private ISelection makeReplaceSelection(ISelection selection, String replacement) throws BadLocationException { |
| return getImplementation(selection).makeReplaceSelection(selection, replacement); |
| } |
| |
| /** |
| * Convenience method that applies the edit returned from {@link #delete(ISelection)} to the |
| * underlying document. |
| * |
| * @param selection the selection to delete |
| * @throws BadLocationException if accessing the document failed |
| */ |
| public void doDelete(ISelection selection) throws BadLocationException { |
| TextEdit edit= delete(selection); |
| boolean complex= edit.hasChildren(); |
| if (complex && fRewriteTarget != null) |
| fRewriteTarget.beginCompoundChange(); |
| try { |
| edit.apply(fDocument, TextEdit.UPDATE_REGIONS); |
| if (fSelectionProvider != null) { |
| ISelection empty= makeEmpty(selection, true); |
| fSelectionProvider.setSelection(empty); |
| } |
| } finally { |
| if (complex && fRewriteTarget != null) |
| fRewriteTarget.endCompoundChange(); |
| } |
| } |
| |
| /** |
| * Convenience method that applies the edit returned from {@link #replace(ISelection, String)} |
| * to the underlying document and adapts the selection accordingly. |
| * |
| * @param selection the selection to replace |
| * @param replacement the replacement text |
| * @throws BadLocationException if accessing the document failed |
| */ |
| public void doReplace(ISelection selection, String replacement) throws BadLocationException { |
| TextEdit edit= replace(selection, replacement); |
| boolean complex= edit.hasChildren(); |
| if (complex && fRewriteTarget != null) |
| fRewriteTarget.beginCompoundChange(); |
| try { |
| edit.apply(fDocument, TextEdit.UPDATE_REGIONS); |
| |
| if (fSelectionProvider != null) { |
| ISelection empty= makeReplaceSelection(selection, replacement); |
| fSelectionProvider.setSelection(empty); |
| } |
| } finally { |
| if (complex && fRewriteTarget != null) |
| fRewriteTarget.endCompoundChange(); |
| } |
| } |
| |
| /** |
| * Returns the text regions covered by the given selection. |
| * |
| * @param selection the selection |
| * @return the text regions corresponding to <code>selection</code> |
| * @throws BadLocationException if accessing the document failed |
| */ |
| public IRegion[] getRanges(ISelection selection) throws BadLocationException { |
| return getImplementation(selection).getRanges(selection); |
| } |
| |
| /** |
| * Returns the number of lines touched by <code>selection</code>. Note that for linear |
| * selections, this is the number of contained delimiters plus 1. |
| * |
| * @param selection the selection |
| * @return the number of lines touched by <code>selection</code> |
| * @throws BadLocationException if accessing the document failed |
| */ |
| public int getCoveredLines(ISelection selection) throws BadLocationException { |
| return getImplementation(selection).getCoveredLines(selection); |
| } |
| |
| /** |
| * Returns the implementation. |
| * |
| * @param selection the selection |
| * @return the corresponding processor implementation |
| */ |
| private Implementation getImplementation(ISelection selection) { |
| if (selection instanceof IBlockTextSelection) |
| return COLUMN_IMPLEMENTATION; |
| else if (selection instanceof ITextSelection) |
| return RANGE_IMPLEMENTATION; |
| else |
| return NULL_IMPLEMENTATION; |
| } |
| } |