Loading core/java/android/text/SpannableStringBuilder.java +46 −21 Original line number Diff line number Diff line Loading @@ -50,8 +50,6 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable public SpannableStringBuilder(CharSequence text, int start, int end) { int srclen = end - start; if (srclen < 0) throw new StringIndexOutOfBoundsException(); int len = ArrayUtils.idealCharArraySize(srclen + 1); mText = new char[len]; mGapStart = srclen; Loading Loading @@ -155,7 +153,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable if (where == mGapStart) return; boolean atEnd = (where == length()); boolean atend = (where == length()); if (where < mGapStart) { int overlap = mGapStart - where; Loading @@ -181,7 +179,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable else if (start == where) { int flag = (mSpanFlags[i] & START_MASK) >> START_SHIFT; if (flag == POINT || (atEnd && flag == PARAGRAPH)) if (flag == POINT || (atend && flag == PARAGRAPH)) start += mGapLength; } Loading @@ -192,7 +190,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable else if (end == where) { int flag = (mSpanFlags[i] & END_MASK); if (flag == POINT || (atEnd && flag == PARAGRAPH)) if (flag == POINT || (atend && flag == PARAGRAPH)) end += mGapLength; } Loading Loading @@ -421,26 +419,53 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable TextWatcher[] textWatchers = getSpans(start, start + origLen, TextWatcher.class); sendBeforeTextChanged(textWatchers, start, origLen, newLen); // Try to keep the cursor / selection at the same relative position during // a text replacement. If replaced or replacement text length is zero, this // is already taken care of. boolean adjustSelection = origLen != 0 && newLen != 0; int selstart = 0; int selend = 0; if (adjustSelection) { selstart = Selection.getSelectionStart(this); selend = Selection.getSelectionEnd(this); } if (origLen == 0 || newLen == 0) { change(start, end, tb, tbstart, tbend); } else { int selstart = Selection.getSelectionStart(this); int selend = Selection.getSelectionEnd(this); // XXX just make the span fixups in change() do the right thing // instead of this madness! checkRange("replace", start, end); moveGapTo(end); change(start, end, tb, tbstart, tbend); if (mGapLength < 2) resizeFor(length() + 1); for (int i = mSpanCount - 1; i >= 0; i--) { if (mSpanStarts[i] == mGapStart) mSpanStarts[i]++; if (adjustSelection) { if (mSpanEnds[i] == mGapStart) mSpanEnds[i]++; } mText[mGapStart] = ' '; mGapStart++; mGapLength--; if (mGapLength < 1) { new Exception("mGapLength < 1").printStackTrace(); } change(start + 1, start + 1, tb, tbstart, tbend); change(start, start + 1, "", 0, 0); change(start + newLen, start + newLen + origLen, "", 0, 0); /* * Special case to keep the cursor in the same position * if it was somewhere in the middle of the replaced region. * If it was at the start or the end or crossing the whole * replacement, it should already be where it belongs. * TODO: Is there some more general mechanism that could * accomplish this? */ if (selstart > start && selstart < end) { long off = selstart - start; off = off * newLen / origLen; off = off * newLen / (end - start); selstart = (int) off + start; setSpan(false, Selection.SELECTION_START, selstart, selstart, Loading @@ -449,7 +474,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable if (selend > start && selend < end) { long off = selend - start; off = off * newLen / origLen; off = off * newLen / (end - start); selend = (int) off + start; setSpan(false, Selection.SELECTION_END, selend, selend, Spanned.SPAN_POINT_POINT); Loading Loading
core/java/android/text/SpannableStringBuilder.java +46 −21 Original line number Diff line number Diff line Loading @@ -50,8 +50,6 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable public SpannableStringBuilder(CharSequence text, int start, int end) { int srclen = end - start; if (srclen < 0) throw new StringIndexOutOfBoundsException(); int len = ArrayUtils.idealCharArraySize(srclen + 1); mText = new char[len]; mGapStart = srclen; Loading Loading @@ -155,7 +153,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable if (where == mGapStart) return; boolean atEnd = (where == length()); boolean atend = (where == length()); if (where < mGapStart) { int overlap = mGapStart - where; Loading @@ -181,7 +179,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable else if (start == where) { int flag = (mSpanFlags[i] & START_MASK) >> START_SHIFT; if (flag == POINT || (atEnd && flag == PARAGRAPH)) if (flag == POINT || (atend && flag == PARAGRAPH)) start += mGapLength; } Loading @@ -192,7 +190,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable else if (end == where) { int flag = (mSpanFlags[i] & END_MASK); if (flag == POINT || (atEnd && flag == PARAGRAPH)) if (flag == POINT || (atend && flag == PARAGRAPH)) end += mGapLength; } Loading Loading @@ -421,26 +419,53 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable TextWatcher[] textWatchers = getSpans(start, start + origLen, TextWatcher.class); sendBeforeTextChanged(textWatchers, start, origLen, newLen); // Try to keep the cursor / selection at the same relative position during // a text replacement. If replaced or replacement text length is zero, this // is already taken care of. boolean adjustSelection = origLen != 0 && newLen != 0; int selstart = 0; int selend = 0; if (adjustSelection) { selstart = Selection.getSelectionStart(this); selend = Selection.getSelectionEnd(this); } if (origLen == 0 || newLen == 0) { change(start, end, tb, tbstart, tbend); } else { int selstart = Selection.getSelectionStart(this); int selend = Selection.getSelectionEnd(this); // XXX just make the span fixups in change() do the right thing // instead of this madness! checkRange("replace", start, end); moveGapTo(end); change(start, end, tb, tbstart, tbend); if (mGapLength < 2) resizeFor(length() + 1); for (int i = mSpanCount - 1; i >= 0; i--) { if (mSpanStarts[i] == mGapStart) mSpanStarts[i]++; if (adjustSelection) { if (mSpanEnds[i] == mGapStart) mSpanEnds[i]++; } mText[mGapStart] = ' '; mGapStart++; mGapLength--; if (mGapLength < 1) { new Exception("mGapLength < 1").printStackTrace(); } change(start + 1, start + 1, tb, tbstart, tbend); change(start, start + 1, "", 0, 0); change(start + newLen, start + newLen + origLen, "", 0, 0); /* * Special case to keep the cursor in the same position * if it was somewhere in the middle of the replaced region. * If it was at the start or the end or crossing the whole * replacement, it should already be where it belongs. * TODO: Is there some more general mechanism that could * accomplish this? */ if (selstart > start && selstart < end) { long off = selstart - start; off = off * newLen / origLen; off = off * newLen / (end - start); selstart = (int) off + start; setSpan(false, Selection.SELECTION_START, selstart, selstart, Loading @@ -449,7 +474,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable if (selend > start && selend < end) { long off = selend - start; off = off * newLen / origLen; off = off * newLen / (end - start); selend = (int) off + start; setSpan(false, Selection.SELECTION_END, selend, selend, Spanned.SPAN_POINT_POINT); Loading