/******************************************************************************* * Copyright (c) 2000, 2011 IBM Corporation 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: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.jface.text; import java.text.CharacterIterator; import java.util.Locale; import com.ibm.icu.text.BreakIterator; /** * Standard implementation of * {@link org.eclipse.jface.text.ITextDoubleClickStrategy}. *
* Selects words using java.text.BreakIterator
for the default
* locale.
IDocument
. Used to collaborate with
* the break iterator.
*
* @see IDocument
* @since 2.0
*/
static class DocumentCharacterIterator implements CharacterIterator {
/** Document to iterate over. */
private IDocument fDocument;
/** Start offset of iteration. */
private int fOffset= -1;
/** End offset of iteration. */
private int fEndOffset= -1;
/** Current offset of iteration. */
private int fIndex= -1;
/** Creates a new document iterator. */
public DocumentCharacterIterator() {
}
/**
* Configures this document iterator with the document section to be visited.
*
* @param document the document to be iterated
* @param iteratorRange the range in the document to be iterated
*/
public void setDocument(IDocument document, IRegion iteratorRange) {
fDocument= document;
fOffset= iteratorRange.getOffset();
fEndOffset= fOffset + iteratorRange.getLength();
}
@Override
public char first() {
fIndex= fOffset;
return current();
}
@Override
public char last() {
fIndex= fOffset < fEndOffset ? fEndOffset -1 : fEndOffset;
return current();
}
@Override
public char current() {
if (fOffset <= fIndex && fIndex < fEndOffset) {
try {
return fDocument.getChar(fIndex);
} catch (BadLocationException x) {
}
}
return DONE;
}
@Override
public char next() {
++fIndex;
int end= getEndIndex();
if (fIndex >= end) {
fIndex= end;
return DONE;
}
return current();
}
@Override
public char previous() {
if (fIndex == fOffset)
return DONE;
if (fIndex > fOffset)
-- fIndex;
return current();
}
@Override
public char setIndex(int index) {
fIndex= index;
return current();
}
@Override
public int getBeginIndex() {
return fOffset;
}
@Override
public int getEndIndex() {
return fEndOffset;
}
@Override
public int getIndex() {
return fIndex;
}
@Override
public Object clone() {
DocumentCharacterIterator i= new DocumentCharacterIterator();
i.fDocument= fDocument;
i.fIndex= fIndex;
i.fOffset= fOffset;
i.fEndOffset= fEndOffset;
return i;
}
}
/**
* The document character iterator used by this strategy.
* @since 2.0
*/
private DocumentCharacterIterator fDocIter= new DocumentCharacterIterator();
/**
* The locale specific word break iterator.
* @since 3.7
*/
private BreakIterator fWordBreakIterator;
/**
* The POSIX word break iterator.
* * Used to workaround ICU bug not treating '.' as word boundary, see * http://bugs.icu-project.org/trac/ticket/8371 for details. *
* * @since 3.7 */ private BreakIterator fPOSIXWordBreakIterator; /** * Creates a new default text double click strategy. */ public DefaultTextDoubleClickStrategy() { } @Override public void doubleClicked(ITextViewer text) { int offset= text.getSelectedRange().x; if (offset < 0) return; final IDocument document= text.getDocument(); IRegion region= findExtendedDoubleClickSelection(document, offset); if (region == null) region= findWord(document, offset); if (region != null) text.setSelectedRange(region.getOffset(), region.getLength()); } /** * Tries to find a suitable double click selection for the given offset. *
* Note: This method must return null
if it simply selects the word at
* the given offset.
*
null
if none to indicate simple word selection
* @since 3.5
*/
protected IRegion findExtendedDoubleClickSelection(IDocument document, int offset) {
return null;
}
/**
* Tries to find the word at the given offset.
*
* @param document the document
* @param offset the offset
* @return the word or null
if none
* @since 3.5
*/
protected IRegion findWord(IDocument document, int offset) {
return findWord(document, offset, getWordBreakIterator());
}
/**
* Returns the locale specific word break iterator.
*
* @return the locale specific word break iterator
* @since 3.7
*/
private BreakIterator getWordBreakIterator() {
if (fWordBreakIterator == null)
fWordBreakIterator= BreakIterator.getWordInstance();
return fWordBreakIterator;
}
/**
* Returns the POSIX word break iterator.
*
* * Used to workaround ICU bug not treating '.' as word boundary, see * http://bugs.icu-project.org/trac/ticket/8371 for details. *
* * @return the POSIX word break iterator. * @since 3.7 */ private BreakIterator getPOSIXWordBreakIterator() { if (fPOSIXWordBreakIterator == null) fPOSIXWordBreakIterator= BreakIterator.getWordInstance(new Locale("en", "US", "POSIX")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ return fPOSIXWordBreakIterator; } /** * Tries to find the word at the given offset. * * @param document the document * @param offset the offset * @param wordBreakIterator the word break iterator * @return the word ornull
if none
* @since 3.7
*/
private IRegion findWord(IDocument document, int offset, BreakIterator wordBreakIterator) {
IRegion line;
try {
line= document.getLineInformationOfOffset(offset);
} catch (BadLocationException e) {
return null;
}
if (offset == line.getOffset() + line.getLength())
return null;
fDocIter.setDocument(document, line);
wordBreakIterator.setText(fDocIter);
int start= wordBreakIterator.preceding(offset);
if (start == BreakIterator.DONE)
start= line.getOffset();
int end= wordBreakIterator.following(offset);
if (end == BreakIterator.DONE)
end= line.getOffset() + line.getLength();
if (wordBreakIterator.isBoundary(offset)) {
if (end - offset > offset - start)
start= offset;
else
end= offset;
}
if (end == start)
return null;
int length= end - start;
try {
// Workaround for ICU bug not treating '.' as word boundary, see http://bugs.icu-project.org/trac/ticket/8371 for details.
if (fPOSIXWordBreakIterator != wordBreakIterator && document.get(start, length).indexOf('.') != -1) {
IRegion wordRegion= findWord(document, offset, getPOSIXWordBreakIterator());
if (wordRegion != null) {
int wordStart= wordRegion.getOffset();
int wordEnd= wordStart + wordRegion.getLength();
// Check that no additional breaks besides '.' are introduced
if ((wordStart == start || wordStart > start && document.getChar(wordStart - 1) == '.') && (wordEnd == end || wordEnd < end && document.getChar(wordEnd) == '.'))
return wordRegion;
}
}
} catch (BadLocationException e) {
// Use previously computed word region
}
return new Region(start, length);
}
}