/** * Create Span for matches in paragraph's. Note that this will highlight the full matched pattern * (including optionals) if no group parameters are given. * * @param editable Text editable * @param pattern The pattern to match * @param creator A ParcelableSpanCreator for ParcelableSpan * @param groupsToMatch (optional) groups to be matched, indexes start at 1. */ protected void createSpanForMatchesP(final Editable editable, final Pattern pattern, final ParagraphStyleCreator creator, int... groupsToMatch) { if (groupsToMatch == null || groupsToMatch.length < 1) { groupsToMatch = new int[]{0}; } int i = 0; for (Matcher m = pattern.matcher(editable); m.find(); i++) { ParagraphStyle span = creator.create(m, i); if (span != null) { for (int g : groupsToMatch) { if (g == 0 || g <= m.groupCount()) { editable.setSpan(span, m.start(g), m.end(g), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } } } } }
private void init(CharSequence source, int start, int end) { int initial = 20; mSpans = new Object[initial]; mSpanData = new int[initial * 3]; if (source instanceof Spanned) { Spanned sp = (Spanned) source; for (Object span : sp.getSpans(start, end, Object.class)) { if (span instanceof CharacterStyle || span instanceof ParagraphStyle) { int st = sp.getSpanStart(span); int en = sp.getSpanEnd(span); int fl = sp.getSpanFlags(span); if (st < start) st = start; if (en > end) en = end; setSpan(span, st - start, en - start, fl); } } } }
@Override /* SpanWatcher */ public void onSpanAdded(Spannable text, Object what, int start, int end) { mTextChanged = true; // we need to keep track of ordered list spans if (what instanceof BulletSpan) { mIsBulletSpanSelected = true; // if text was empty then append zero width char // in order for the bullet to be shown when the span is selected if (text.toString().isEmpty()) { this.append("\u200B"); } } else if (what instanceof NumberSpan) { mIsNumberSpanSelected = true; // if text was empty then append zero width char // in order for the number to be shown when the span is selected if (text.toString().isEmpty()) { this.append("\u200B"); } } if (what instanceof RTSpan && what instanceof ParagraphStyle) { setParagraphsAreUp2Date(false); } }
private <T extends ParagraphStyle> void clearParagraphSpanType(Editable editable, Class<T> spanType) { ParagraphStyle[] spans = editable.getSpans(0, editable.length(), spanType); for (int n = spans.length; n-- > 0; ) { editable.removeSpan(spans[n]); } }
private static void encodeTextAlignmentByDiv(Context context, StringBuilder out, Spanned text, int option) { int len = text.length(); int next; for (int i = 0; i < len; i = next) { next = text.nextSpanTransition(i, len, ParagraphStyle.class); ParagraphStyle[] styles = text.getSpans(i, next, ParagraphStyle.class); String elements = " "; boolean needDiv = false; for (ParagraphStyle style : styles) { if (style instanceof AlignmentSpan) { Layout.Alignment align = ((AlignmentSpan) style).getAlignment(); needDiv = true; if (align == Layout.Alignment.ALIGN_CENTER) { elements = "align=\"center\" " + elements; } else if (align == Layout.Alignment.ALIGN_OPPOSITE) { elements = "align=\"right\" " + elements; } else { elements = "align=\"left\" " + elements; } } } if (needDiv) { out.append("<div ").append(elements).append(">"); } withinDiv(context, out, text, i, next, option); if (needDiv) { out.append("</div>"); } } }
private static void encodeTextAlignmentByDiv(StringBuilder out, Spanned text, int option) { int len = text.length(); int next; for (int i = 0; i < len; i = next) { next = text.nextSpanTransition(i, len, ParagraphStyle.class); ParagraphStyle[] style = text.getSpans(i, next, ParagraphStyle.class); String elements = " "; boolean needDiv = false; for (int j = 0; j < style.length; j++) { if (style[j] instanceof AlignmentSpan) { Layout.Alignment align = ((AlignmentSpan) style[j]).getAlignment(); needDiv = true; if (align == Layout.Alignment.ALIGN_CENTER) { elements = "align=\"center\" " + elements; } else if (align == Layout.Alignment.ALIGN_OPPOSITE) { elements = "align=\"right\" " + elements; } else { elements = "align=\"left\" " + elements; } } } if (needDiv) { out.append("<div ").append(elements).append(">"); } withinDiv(out, text, i, next, option); if (needDiv) { out.append("</div>"); } } }
private Set<SingleParagraphStyle> getParagraphStyles(final Spanned text, Selection selection) { Set<SingleParagraphStyle> styles = new HashSet<>(); for (ParagraphStyle style : text.getSpans(selection.start(), selection.end(), ParagraphStyle.class)) { ParagraphType type = ParagraphType.getInstance(style); if (type != null) { styles.add(new SingleParagraphStyle(type, style)); } } return styles; }
@Override /* SpanWatcher */ public void onSpanAdded(Spannable text, Object what, int start, int end) { mTextChanged = true; if (what instanceof RTSpan && what instanceof ParagraphStyle) { setParagraphsAreUp2Date(false); } }
@Override /* SpanWatcher */ public void onSpanChanged(Spannable text, Object what, int ostart, int oend, int nstart, int nend) { mTextChanged = true; if (what instanceof RTSpan && what instanceof ParagraphStyle) { setParagraphsAreUp2Date(false); } }
@Override /* SpanWatcher */ public void onSpanRemoved(Spannable text, Object what, int start, int end) { mTextChanged = true; if (what instanceof RTSpan && what instanceof ParagraphStyle) { setParagraphsAreUp2Date(false); } }
private Set<SingleParagraphStyle> getParagraphStyles(final Spanned text, Selection selection) { Set<SingleParagraphStyle> styles = new HashSet<SingleParagraphStyle>(); for (ParagraphStyle style : text.getSpans(selection.start(), selection.end(), ParagraphStyle.class)) { ParagraphType type = ParagraphType.getInstance(style); if (type != null) { styles.add(new SingleParagraphStyle(type, style)); } } return styles; }
public Spanned convert() { mReader.setContentHandler(this); try { mReader.parse(new InputSource(new StringReader(text))); } catch (SAXException | IOException e) { // We are reading from a string. There should not be IO problems. throw new RuntimeException(e); } // Fix flags and range for paragraph-type markup. Object[] obj = mSpannableStringBuilder.getSpans(0, mSpannableStringBuilder.length(), ParagraphStyle.class); for (Object ob : obj) { int start = mSpannableStringBuilder.getSpanStart(ob); int end = mSpannableStringBuilder.getSpanEnd(ob); // If the last line of the range is blank, back off by one. if (end - 2 >= 0) { if (mSpannableStringBuilder.charAt(end - 1) == '\n' && mSpannableStringBuilder.charAt(end - 2) == '\n') { end--; } } if (end == start) { mSpannableStringBuilder.removeSpan(ob); } else { mSpannableStringBuilder.setSpan(ob, start, end, Spannable.SPAN_PARAGRAPH); } } return mSpannableStringBuilder; }
public Spanned convert() { try{ SAXParserFactory saxFactory = SAXParserFactory.newInstance(); SAXParser saxParser = saxFactory.newSAXParser();//利用获取到的对象创建一个解析器 XMLReader xmlReader =saxFactory.newSAXParser().getXMLReader(); //获取一个XMLReader xmlReader.setContentHandler(this); xmlReader.parse(new InputSource(new StringReader(mSource))); }catch (Exception e){ e.printStackTrace(); } // Fix flags and range for paragraph-type markup. Object[] obj = mSpannableStringBuilder.getSpans(0, mSpannableStringBuilder.length(), ParagraphStyle.class); for (int i = 0; i < obj.length; i++) { int start = mSpannableStringBuilder.getSpanStart(obj[i]); int end = mSpannableStringBuilder.getSpanEnd(obj[i]); // If the last line of the range is blank, back off by one. if (end - 2 >= 0) { if (mSpannableStringBuilder.charAt(end - 1) == '\n' && mSpannableStringBuilder.charAt(end - 2) == '\n') { end--; } } if (end == start) { mSpannableStringBuilder.removeSpan(obj[i]); } else { mSpannableStringBuilder.setSpan(obj[i], start, end, Spannable.SPAN_PARAGRAPH); } } return mSpannableStringBuilder; }
private static void withinHtml(StringBuilder out, Spanned text) { int len = text.length(); int next; for (int i = 0; i < text.length(); i = next) { next = text.nextSpanTransition(i, len, ParagraphStyle.class); ParagraphStyle[] style = text.getSpans(i, next, ParagraphStyle.class); String elements = " "; boolean needDiv = false; for(int j = 0; j < style.length; j++) { if (style[j] instanceof AlignmentSpan) { Layout.Alignment align = ((AlignmentSpan) style[j]).getAlignment(); needDiv = true; if (align == Layout.Alignment.ALIGN_CENTER) { elements = "align=\"center\" " + elements; } else if (align == Layout.Alignment.ALIGN_OPPOSITE) { elements = "align=\"right\" " + elements; } else { elements = "align=\"left\" " + elements; } } } if (needDiv) { out.append("<div ").append(elements).append(">"); } withinDiv(out, text, i, next); if (needDiv) { out.append("</div>"); } } }
public SpannableStringBuilder convert() { mReader.setContentHandler(this); try { mReader.parse(new InputSource(new StringReader(mSource))); } catch (IOException | SAXException e) { // We are reading from a string. There should not be IO problems. throw new RuntimeException(e); } // Fix flags and range for paragraph-type markup. Object[] obj = mSpannableStringBuilder.getSpans(0, mSpannableStringBuilder.length(), ParagraphStyle.class); for (int i = 0; i < obj.length; i++) { int start = mSpannableStringBuilder.getSpanStart(obj[i]); int end = mSpannableStringBuilder.getSpanEnd(obj[i]); // If the last line of the range is blank, back off by one. if (end - 2 >= 0) { if (mSpannableStringBuilder.charAt(end - 1) == '\n' && mSpannableStringBuilder.charAt(end - 2) == '\n') { end--; } } if (end == start) { mSpannableStringBuilder.removeSpan(obj[i]); } else { mSpannableStringBuilder.setSpan(obj[i], start, end, Spannable.SPAN_PARAGRAPH); } } return mSpannableStringBuilder; }
@Override /* SpanWatcher */ public void onSpanRemoved(Spannable text, Object what, int start, int end) { mTextChanged = true; // we need to keep track of ordered list spans if (what instanceof BulletSpan) { mIsBulletSpanSelected = false; } else if (what instanceof NumberSpan) { mIsNumberSpanSelected = false; } if (what instanceof RTSpan && what instanceof ParagraphStyle) { setParagraphsAreUp2Date(false); } }
public Spanned convert() { mReader.setContentHandler(this); try { mReader.parse(new InputSource(new StringReader(mSource))); } catch (IOException | SAXException e) { // We are reading from a string. There should not be IO problems. throw new RuntimeException(e); } // Fix flags and range for paragraph-type markup. Object[] obj = mSpannableStringBuilder.getSpans(0, mSpannableStringBuilder.length(), ParagraphStyle.class); for (int i = 0; i < obj.length; i++) { int start = mSpannableStringBuilder.getSpanStart(obj[i]); int end = mSpannableStringBuilder.getSpanEnd(obj[i]); // If the last line of the range is blank, back off by one. if (end - 2 >= 0 && mSpannableStringBuilder.charAt(end - 1) == '\n' && mSpannableStringBuilder.charAt(end - 2) == '\n') { end--; } if (end == start) { mSpannableStringBuilder.removeSpan(obj[i]); } else { mSpannableStringBuilder.setSpan(obj[i], start, end, Spannable.SPAN_PARAGRAPH); } } return mSpannableStringBuilder; }
/** * serialize Spanned to DataOutputStream * @param dos * @throws IOException */ public void serialize(DataOutputStream dos) throws IOException { CharacterStyle[] styles = mString.getSpans(0, mString.length(), CharacterStyle.class); ParagraphStyle[] paragraphs = mString.getSpans(0, mString.length(), ParagraphStyle.class); dos.writeInt(VERSION); dos.writeInt(getClassNameHash()); dos.writeUTF(mString.toString()); dos.writeInt(0x1030); writeStyles(styles, dos); dos.writeInt(0x1030); writeParagraphs(paragraphs,dos); dos.writeInt(0x1030); }
private void writeParagraphs(ParagraphStyle paragraphStyle[], DataOutputStream dos) throws IOException { dos.writeInt(paragraphStyle.length); for (ParagraphStyle style : paragraphStyle) { writeSingleParagraphStyle(style, dos); dos.writeInt(0xe00e); // sync mark } }
private void writeSingleParagraphStyle(ParagraphStyle style, DataOutputStream dos) throws IOException { Class clazz = style.getClass(); dos.writeInt(mString.getSpanStart(style)); dos.writeInt(mString.getSpanEnd(style)); dos.writeInt(mString.getSpanFlags(style)); if (mCharacterStylesTags.containsKey(clazz.getSimpleName())) { int tag = mCharacterStylesTags.get(clazz.getSimpleName()); if (mCharacterStylesTags.containsKey(clazz.getSimpleName())) { dos.writeInt(tag); } switch (tag) { case 24: // AligmentSpan.Standard AlignmentSpan.Standard as2 = (AlignmentSpan.Standard)style; dos.writeInt(as2.getAlignment().ordinal()); break; case 25: // BulletSpan BulletSpan bs = (BulletSpan)style; dos.writeInt(bs.getLeadingMargin(true)); dos.writeInt(bs.getLeadingMargin(false)); break; case 30: // LeadingMarginSpan.Sandard LeadingMarginSpan.Standard lms = (LeadingMarginSpan.Standard)style; dos.writeInt(lms.getLeadingMargin(true)); dos.writeInt(lms.getLeadingMargin(false)); break; case 34: // QuoteSpan QuoteSpan qs = (QuoteSpan)style; dos.writeInt(qs.getColor()); break; case 36: // TabStopSpan.Standard TabStopSpan.Standard tss = (TabStopSpan.Standard)style; dos.writeInt(tss.getTabStop()); break; default: } } else { write(style,dos); } }
private static void withinHtml(StringBuilder out, Spanned text) { int len = text.length(); int next; for (int i = 0; i < text.length(); i = next) { next = text.nextSpanTransition(i, len, ParagraphStyle.class); /*ParagraphStyle[] style = text.getSpans(i, next, ParagraphStyle.class); String elements = " "; boolean needDiv = false; for (int j = 0; j < style.length; j++) { if (style[j] instanceof AlignmentSpan) { Layout.Alignment align = ((AlignmentSpan) style[j]) .getAlignment(); needDiv = true; if (align == Layout.Alignment.ALIGN_CENTER) { elements = "align=\"center\" " + elements; } else if (align == Layout.Alignment.ALIGN_OPPOSITE) { elements = "align=\"right\" " + elements; } else { elements = "align=\"left\" " + elements; } } } if (needDiv) { out.append("<div " + elements + ">"); }*/ withinDiv(out, text, i, next); /*if (needDiv) { out.append("</div>"); }*/ } }
private boolean hasStyleSpan(Spanned spanned) { // Only check against those three classes below, which could affect text appearance, since // there are other kind of classes won't affect appearance. Class<?>[] styleClasses = { CharacterStyle.class, ParagraphStyle.class, UpdateAppearance.class}; for (Class<?> clazz : styleClasses) { if (spanned.nextSpanTransition(-1, spanned.length(), clazz) < spanned.length()) { return true; } } return false; }
private boolean hasStyleSpan(Spanned spanned) { Class<?>[] styleClasses = { CharacterStyle.class, ParagraphStyle.class, UpdateAppearance.class}; for (Class<?> clazz : styleClasses) { if (spanned.nextSpanTransition(-1, spanned.length(), clazz) < spanned.length()) { return true; } } return false; }
private static void withinHtml(StringBuilder out, Spanned text) { int next; for (int i = 0; i < text.length(); i = next) { next = text.nextSpanTransition(i, text.length(), ParagraphStyle.class); ParagraphStyle[] styles = text.getSpans(i, next, ParagraphStyle.class); if (styles.length == 2) { if (styles[0] instanceof BulletSpan && styles[1] instanceof QuoteSpan) { // Let a <br> follow the BulletSpan or QuoteSpan end, so next++ withinBulletThenQuote(out, text, i, next++); } else if (styles[0] instanceof QuoteSpan && styles[1] instanceof BulletSpan) { withinQuoteThenBullet(out, text, i, next++); } else { withinContent(out, text, i, next); } } else if (styles.length == 1) { if (styles[0] instanceof BulletSpan) { withinBullet(out, text, i, next++); } else if (styles[0] instanceof QuoteSpan) { withinQuote(out, text, i, next++); } else { withinContent(out, text, i, next); } } else { withinContent(out, text, i, next); } } }
private static void withinHtml(StringBuilder out, Spanned text) { int len = text.length(); int next; for (int i = 0; i < text.length(); i = next) { next = text.nextSpanTransition(i, len, ParagraphStyle.class); ParagraphStyle[] style = text.getSpans(i, next, ParagraphStyle.class); String elements = " "; boolean needDiv = false; for(int j = 0; j < style.length; j++) { if (style[j] instanceof AlignmentSpan) { Layout.Alignment align = ((AlignmentSpan) style[j]).getAlignment(); needDiv = true; if (align == Layout.Alignment.ALIGN_CENTER) { elements = "align=\"center\" " + elements; } else if (align == Layout.Alignment.ALIGN_OPPOSITE) { elements = "align=\"right\" " + elements; } else { elements = "align=\"left\" " + elements; } } } if (needDiv) { out.append("<div " + elements + ">"); } withinDiv(out, text, i, next); if (needDiv) { out.append("</div>"); } } }
private void onSpanAdded(Object span) { if (span instanceof MetricAffectingSpan) { mHasMetricAffectingSpan = true; } if (span instanceof ReplacementSpan) { mHasReplacementSpan = true; } if (span instanceof ParagraphStyle) { mHasParagraphStyle = true; } }