diff options
author | Gilles Debunne <debunne@google.com> | 2010-08-27 11:39:34 -0700 |
---|---|---|
committer | Gilles Debunne <debunne@google.com> | 2010-09-08 09:43:46 -0700 |
commit | 468394fc6d1cb0c9078c2f98aa056860f7e0d743 (patch) | |
tree | 95a9140c4e9c30fe1221071dd9f45ff51a47cfc3 /core | |
parent | 4c7d3f28898f4e0d8e9f54537fb92948e650df7f (diff) | |
download | frameworks_base-468394fc6d1cb0c9078c2f98aa056860f7e0d743.zip frameworks_base-468394fc6d1cb0c9078c2f98aa056860f7e0d743.tar.gz frameworks_base-468394fc6d1cb0c9078c2f98aa056860f7e0d743.tar.bz2 |
Text Selection: smart word detection. DO NOT MERGE.
Selecting between words selects the spaces instead of the closest word, facilitating
paste insertion vs word replacement.
Pasting adds/removes space before and after if needed so that pasted text is not appended to
existing text.
Cut and copy not available when selection is empty.
Change-Id: I331413bdef341a4eceffe76fa2957f388d540b6e
Diffstat (limited to 'core')
-rw-r--r-- | core/java/android/widget/TextView.java | 98 |
1 files changed, 87 insertions, 11 deletions
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index d0dd6cc..3428206 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -5817,7 +5817,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * Return true iff there is a selection inside this text view. */ public boolean hasSelection() { - return getSelectionStart() != getSelectionEnd(); + final int selectionStart = getSelectionStart(); + final int selectionEnd = getSelectionEnd(); + + return selectionStart >= 0 && selectionStart != selectionEnd; } /** @@ -7005,7 +7008,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return false; } - if (mText.length() > 0 && getSelectionStart() >= 0) { + if (mText.length() > 0 && hasSelection()) { if (mText instanceof Editable && mInput != null) { return true; } @@ -7019,7 +7022,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return false; } - if (mText.length() > 0 && getSelectionStart() >= 0) { + if (mText.length() > 0 && hasSelection()) { return true; } @@ -7140,6 +7143,49 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener int minOffset = selectionModifierCursorController.getMinTouchOffset(); int maxOffset = selectionModifierCursorController.getMaxTouchOffset(); + if (minOffset == maxOffset) { + int offset = Math.max(0, Math.min(minOffset, mTransformed.length())); + + // Tolerance, number of charaters around tapped position + final int range = 1; + final int max = mTransformed.length() - 1; + + // 'Smart' word selection: detect position between words + for (int i = -range; i <= range; i++) { + int index = offset + i; + if (index >= 0 && index <= max) { + if (Character.isSpaceChar(mTransformed.charAt(index))) { + // Select current space + selectionStart = index; + selectionEnd = selectionStart + 1; + + // Extend selection to maximum space range + while (selectionStart > 0 && + Character.isSpaceChar(mTransformed.charAt(selectionStart - 1))) { + selectionStart--; + } + while (selectionEnd < max && + Character.isSpaceChar(mTransformed.charAt(selectionEnd))) { + selectionEnd++; + } + + Selection.setSelection((Spannable) mText, selectionStart, selectionEnd); + return; + } + } + } + + // 'Smart' word selection: detect position at beginning or end of text. + if (offset <= range) { + Selection.setSelection((Spannable) mText, 0, 0); + return; + } + if (offset >= (max - range)) { + Selection.setSelection((Spannable) mText, max + 1, max + 1); + return; + } + } + long wordLimits = getWordLimitsAt(minOffset); if (wordLimits >= 0) { selectionStart = (int) (wordLimits >>> 32); @@ -7220,21 +7266,22 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener menu.add(0, ID_CUT, 0, com.android.internal.R.string.cut). setOnMenuItemClickListener(handler). setAlphabeticShortcut('x'); + added = true; } if (canCopy()) { menu.add(0, ID_COPY, 0, com.android.internal.R.string.copy). setOnMenuItemClickListener(handler). setAlphabeticShortcut('c'); + added = true; } if (canPaste()) { menu.add(0, ID_PASTE, 0, com.android.internal.R.string.paste). setOnMenuItemClickListener(handler). setAlphabeticShortcut('v'); + added = true; } - - added = true; } else { /* if (!isFocused()) { @@ -7313,11 +7360,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private boolean textIsOnlySpaces() { final int length = mTransformed.length(); - for (int i=0; i<length; i++) { - final char c = mTransformed.charAt(i); - final int type = Character.getType(c); - if (type != Character.SPACE_SEPARATOR) + for (int i = 0; i < length; i++) { + if (!Character.isSpaceChar(mTransformed.charAt(i))) { return false; + } } return true; } @@ -7350,7 +7396,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener /** * Called when a context menu option for the text view is selected. Currently * this will be one of: {@link android.R.id#selectAll}, - * {@link android.R.id#startSelectingText}, {@link android.R.id#stopSelectingText}, + * {@link android.R.id#startSelectingText}, * {@link android.R.id#cut}, {@link android.R.id#copy}, * {@link android.R.id#paste}, {@link android.R.id#copyUrl}, * or {@link android.R.id#switchInputMethod}. @@ -7394,7 +7440,37 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener case ID_PASTE: CharSequence paste = clip.getText(); - if (paste != null) { + if (paste != null && paste.length() > 0) { + // Paste adds/removes spaces before or after insertion as needed. + + if (Character.isSpaceChar(paste.charAt(0))) { + if (min > 0 && Character.isSpaceChar(mTransformed.charAt(min - 1))) { + // Two spaces at beginning of paste: remove one + ((Editable) mText).replace(min - 1, min, ""); + min = min - 1; + max = max - 1; + } + } else { + if (min > 0 && !Character.isSpaceChar(mTransformed.charAt(min - 1))) { + // No space at beginning of paste: add one + ((Editable) mText).replace(min, min, " "); + min = min + 1; + max = max + 1; + } + } + + if (Character.isSpaceChar(paste.charAt(paste.length() - 1))) { + if (max < mText.length() && Character.isSpaceChar(mTransformed.charAt(max))) { + // Two spaces at end of paste: remove one + ((Editable) mText).replace(max, max + 1, ""); + } + } else { + if (max < mText.length() && !Character.isSpaceChar(mTransformed.charAt(max))) { + // No space at end of paste: add one + ((Editable) mText).replace(max, max, " "); + } + } + Selection.setSelection((Spannable) mText, max); ((Editable) mText).replace(min, max, paste); stopTextSelectionMode(); |