signature:
public class WordTokenizer { /** * Given a string and starting index , return true if the first " numCharsToCheck " characters at
 * the starting index are either a letter or a digit .
 * @ param input a { @ link CharSequence } to test
 * @ param numCharsToCheck number of characters to examine at starting position
 * @ param start starting position within the input string
 * @ return true if the first " numCharsToCheck " at the starting index are either letters or digits */
public boolean onlyLettersOrDigits ( final @ NonNull CharSequence input , final int numCharsToCheck , final int start ) { } }

implementation:
// Starting position must be within the input string
if ( start < 0 || start > input . length ( ) ) { return false ; } // Check the first " numCharsToCheck " characters to ensure they are a letter or digit
for ( int i = 0 ; i < numCharsToCheck ; i ++ ) { int positionToCheck = start + i ; // Return false if we would throw an Out - of - Bounds exception
if ( positionToCheck >= input . length ( ) ) { return false ; } // Return false early if current character is not a letter or digit
char charToCheck = input . charAt ( positionToCheck ) ; if ( ! Character . isLetterOrDigit ( charToCheck ) ) { return false ; } } // First " numCharsToCheck " characters are either letters or digits , so return true
return true ;


signature:
public class WordTokenizer { /** * Returns the index of the end of the last span before the cursor or
 * the start of the current line if there are no spans before the cursor .
 * @ param text the { @ link Spanned } to examine
 * @ param cursor position of the cursor in text
 * @ return the furthest in front of the cursor to search for the current keywords */
protected int getSearchStartIndex ( final @ NonNull Spanned text , int cursor ) { } }

implementation:
if ( cursor < 0 || cursor > text . length ( ) ) { cursor = 0 ; } // Get index of the end of the last span before the cursor ( or 0 if does not exist )
MentionSpan [ ] spans = text . getSpans ( 0 , text . length ( ) , MentionSpan . class ) ; int closestToCursor = 0 ; for ( MentionSpan span : spans ) { int end = text . getSpanEnd ( span ) ; if ( end > closestToCursor && end <= cursor ) { closestToCursor = end ; } } // Get the index of the start of the line
String textString = text . toString ( ) . substring ( 0 , cursor ) ; int lineStartIndex = 0 ; if ( textString . contains ( mConfig . LINE_SEPARATOR ) ) { lineStartIndex = textString . lastIndexOf ( mConfig . LINE_SEPARATOR ) + 1 ; } // Return whichever is closer before to the cursor
return Math . max ( closestToCursor , lineStartIndex ) ;


signature:
public class WordTokenizer { /** * Returns the index of the beginning of the first span after the cursor or
 * length of the text if there are no spans after the cursor .
 * @ param text the { @ link Spanned } to examine
 * @ param cursor position of the cursor in text
 * @ return the furthest behind the cursor to search for the current keywords */
protected int getSearchEndIndex ( final @ NonNull Spanned text , int cursor ) { } }

implementation:
if ( cursor < 0 || cursor > text . length ( ) ) { cursor = 0 ; } // Get index of the start of the first span after the cursor ( or text . length ( ) if does not exist )
MentionSpan [ ] spans = text . getSpans ( 0 , text . length ( ) , MentionSpan . class ) ; int closestAfterCursor = text . length ( ) ; for ( MentionSpan span : spans ) { int start = text . getSpanStart ( span ) ; if ( start < closestAfterCursor && start >= cursor ) { closestAfterCursor = start ; } } // Get the index of the end of the line
String textString = text . toString ( ) . substring ( cursor , text . length ( ) ) ; int lineEndIndex = text . length ( ) ; if ( textString . contains ( mConfig . LINE_SEPARATOR ) ) { lineEndIndex = cursor + textString . indexOf ( mConfig . LINE_SEPARATOR ) ; } // Return whichever is closest after the cursor
return Math . min ( closestAfterCursor , lineEndIndex ) ;


signature:
public class WordTokenizer { /** * Ensure the the character before the explicit character is a word - breaking character .
 * Note that the function only uses the input string to determine which explicit character was
 * typed . It uses the complete contents of the { @ link EditText } to determine if there is a
 * word - breaking character before the explicit character , as the input string may start with an
 * explicit character , i . e . with an input string of " @ John Doe " and an { @ link EditText } containing
 * the string " Hello @ John Doe " , this should return true .
 * @ param text the { @ link Spanned } to check for a word - breaking character before the explicit character
 * @ param cursor position of the cursor in text
 * @ return true if there is a space before the explicit character , false otherwise */
protected boolean hasWordBreakingCharBeforeExplicitChar ( final @ NonNull Spanned text , final int cursor ) { } }

implementation:
CharSequence beforeCursor = text . subSequence ( 0 , cursor ) ; // Get the explicit character closest before the cursor and make sure it
// has a word - breaking character in front of it
int i = cursor - 1 ; while ( i >= 0 && i < beforeCursor . length ( ) ) { char c = beforeCursor . charAt ( i ) ; if ( isExplicitChar ( c ) ) { return i == 0 || isWordBreakingChar ( beforeCursor . charAt ( i - 1 ) ) ; } i -- ; } return false ;


signature:
public class RichEditorView { /** * Determine whether the internal { @ link EditText } should match the full height of the { @ link RichEditorView }
 * initially or if it should wrap its content in height and expand to fill it as the user types .
 * Note : The { @ link EditText } will always match the parent ( i . e . the { @ link RichEditorView } in width .
 * Additionally , the { @ link ListView } containing mention suggestions will always fill the rest
 * of the height in the { @ link RichEditorView } .
 * @ param enabled true if the { @ link EditText } should wrap its content in height */
public void setEditTextShouldWrapContent ( boolean enabled ) { } }

implementation: mEditTextShouldWrapContent = enabled ; if ( mMentionsEditText == null ) { return ; } mPrevEditTextParams = mMentionsEditText . getLayoutParams ( ) ; int wrap = ( enabled ) ? LayoutParams . WRAP_CONTENT : LayoutParams . MATCH_PARENT ; if ( mPrevEditTextParams != null && mPrevEditTextParams . height == wrap ) { return ; } ViewGroup . LayoutParams newParams = new LayoutParams ( LayoutParams . MATCH_PARENT , wrap ) ; mMentionsEditText . setLayoutParams ( newParams ) ; requestLayout ( ) ; invalidate ( ) ;


signature:
public class RichEditorView { /** * Show or hide the text counter view .
 * @ param display true to display the text counter view */
public void displayTextCounter ( boolean display ) { } }

implementation: if ( display ) { mTextCounterView . setVisibility ( TextView . VISIBLE ) ; } else { mTextCounterView . setVisibility ( TextView . GONE ) ; }


signature:
public class RichEditorView { /** * { @ inheritDoc } */
@ Override public List < String > onQueryReceived ( @ NonNull QueryToken queryToken ) { } }

implementation:
List < String > buckets = null ; // Pass the query token to a host receiver
if ( mHostQueryTokenReceiver != null ) { buckets = mHostQueryTokenReceiver . onQueryReceived ( queryToken ) ; mSuggestionsAdapter . notifyQueryTokenReceived ( queryToken , buckets ) ; } return buckets ;


signature:
public class RichEditorView { /** * { @ inheritDoc } */
@ Override public void onReceiveSuggestionsResult ( final @ NonNull SuggestionsResult result , final @ NonNull String bucket ) { } }

implementation:
// Add the mentions and notify the editor / dropdown of the changes on the UI thread
post ( new Runnable ( ) { @ Override public void run ( ) { if ( mSuggestionsAdapter != null ) { mSuggestionsAdapter . addSuggestions ( result , bucket , mMentionsEditText ) ; } // Make sure the list is scrolled to the top once you receive the first query result
if ( mWaitingForFirstResult && mSuggestionsList != null ) { mSuggestionsList . setSelection ( 0 ) ; mWaitingForFirstResult = false ; } } } ) ;


signature:
public class RichEditorView { /** * { @ inheritDoc } */
public void displaySuggestions ( boolean display ) { } }

implementation:
// If nothing to change , return early
if ( display == isDisplayingSuggestions ( ) || mMentionsEditText == null ) { return ; } // Change view depending on whether suggestions are being shown or not
if ( display ) { disableSpellingSuggestions ( true ) ; mTextCounterView . setVisibility ( View . GONE ) ; mSuggestionsList . setVisibility ( View . VISIBLE ) ; mPrevEditTextParams = mMentionsEditText . getLayoutParams ( ) ; mPrevEditTextBottomPadding = mMentionsEditText . getPaddingBottom ( ) ; mMentionsEditText . setPadding ( mMentionsEditText . getPaddingLeft ( ) , mMentionsEditText . getPaddingTop ( ) , mMentionsEditText . getPaddingRight ( ) , mMentionsEditText . getPaddingTop ( ) ) ; int height = mMentionsEditText . getPaddingTop ( ) + mMentionsEditText . getLineHeight ( ) + mMentionsEditText . getPaddingBottom ( ) ; mMentionsEditText . setLayoutParams ( new LayoutParams ( LayoutParams . MATCH_PARENT , height ) ) ; mMentionsEditText . setVerticalScrollBarEnabled ( false ) ; int cursorLine = getCurrentCursorLine ( ) ; Layout layout = mMentionsEditText . getLayout ( ) ; if ( layout != null ) { int lineTop = layout . getLineTop ( cursorLine ) ; mMentionsEditText . scrollTo ( 0 , lineTop ) ; } // Notify action listener that list was shown
if ( mActionListener != null ) { mActionListener . onSuggestionsDisplayed ( ) ; } } else { disableSpellingSuggestions ( false ) ; mTextCounterView . setVisibility ( View . VISIBLE ) ; mSuggestionsList . setVisibility ( View . GONE ) ; mMentionsEditText . setPadding ( mMentionsEditText . getPaddingLeft ( ) , mMentionsEditText . getPaddingTop ( ) , mMentionsEditText . getPaddingRight ( ) , mPrevEditTextBottomPadding ) ; if ( mPrevEditTextParams == null ) { mPrevEditTextParams = new LayoutParams ( LayoutParams . MATCH_PARENT , LayoutParams . MATCH_PARENT ) ; } mMentionsEditText . setLayoutParams ( mPrevEditTextParams ) ; mMentionsEditText . setVerticalScrollBarEnabled ( true ) ; // Notify action listener that list was hidden
if ( mActionListener != null ) { mActionListener . onSuggestionsHidden ( ) ; } } requestLayout ( ) ; invalidate ( ) ;


signature:
public class RichEditorView { /** * Disables spelling suggestions from the user ' s keyboard .
 * This is necessary because some keyboards will replace the input text with
 * spelling suggestions automatically , which changes the suggestion results .
 * This results in a confusing user experience .
 * @ param disable { @ code true } if spelling suggestions should be disabled , otherwise { @ code false } */
private void disableSpellingSuggestions ( boolean disable ) { } }

implementation:
// toggling suggestions often resets the cursor location , but we don ' t want that to happen
int start = mMentionsEditText . getSelectionStart ( ) ; int end = mMentionsEditText . getSelectionEnd ( ) ; // -1 means there is no selection or cursor .
if ( start == - 1 || end == - 1 ) { return ; } if ( disable ) { // store the previous input type
mOriginalInputType = mMentionsEditText . getInputType ( ) ; } mMentionsEditText . setRawInputType ( disable ? InputType . TYPE_TEXT_FLAG_NO_SUGGESTIONS : mOriginalInputType ) ; mMentionsEditText . setSelection ( start , end ) ;


signature:
public class RichEditorView { /** * Updates the TextView counting the number of characters in the editor . Sets not only the content
 * of the TextView , but also the color of the text depending if the limit has been reached . */
private void updateEditorTextCount ( ) { } }

implementation: if ( mMentionsEditText != null && mTextCounterView != null ) { int textCount = mMentionsEditText . getMentionsText ( ) . length ( ) ; mTextCounterView . setText ( String . valueOf ( textCount ) ) ; if ( mTextCountLimit > 0 && textCount > mTextCountLimit ) { mTextCounterView . setTextColor ( mBeyondCountLimitTextColor ) ; } else { mTextCounterView . setTextColor ( mWithinCountLimitTextColor ) ; } }


signature:
public class RichEditorView { /** * Sets the factory used to create MentionSpans within this class .
 * @ param factory the { @ link MentionsEditText . MentionSpanFactory } to use */
public void setMentionSpanFactory ( @ NonNull final MentionsEditText . MentionSpanFactory factory ) { } }

implementation: if ( mMentionsEditText != null ) { mMentionsEditText . setMentionSpanFactory ( factory ) ; }


signature:
public class RichEditorView { /** * Sets the { @ link com . linkedin . android . spyglass . suggestions . interfaces . SuggestionsVisibilityManager } to use ( determines which and how the suggestions are displayed ) .
 * @ param suggestionsVisibilityManager the { @ link com . linkedin . android . spyglass . suggestions . interfaces . SuggestionsVisibilityManager } to use */
public void setSuggestionsManager ( final @ NonNull SuggestionsVisibilityManager suggestionsVisibilityManager ) { } }

implementation: if ( mMentionsEditText != null && mSuggestionsAdapter != null ) { mMentionsEditText . setSuggestionsVisibilityManager ( suggestionsVisibilityManager ) ; mSuggestionsAdapter . setSuggestionsManager ( suggestionsVisibilityManager ) ; }


signature: public class GridMentions { @ Override public List < String > onQueryReceived ( final @ NonNull QueryToken queryToken ) { } }

implementation:
List < String > buckets = Arrays . asList ( BUCKET ) ; List < Person > suggestions = people . getSuggestions ( queryToken ) ; SuggestionsResult result = new SuggestionsResult ( queryToken , suggestions ) ; // Have suggestions , now call the listener ( which is this activity )
onReceiveSuggestionsResult ( result , BUCKET ) ; return buckets ;


signature: public class GridMentions { @ Override public void onReceiveSuggestionsResult ( @ NonNull SuggestionsResult result , @ NonNull String bucket ) { } }

implementation: List < ? extends Suggestible > suggestions = result . getSuggestions ( ) ; adapter = new PersonMentionAdapter ( result . getSuggestions ( ) ) ; recyclerView . swapAdapter ( adapter , true ) ; boolean display = suggestions != null && suggestions . size ( ) > 0 ; displaySuggestions ( display ) ;


signature: public class GridMentions { @ Override public void displaySuggestions ( boolean display ) { } }

implementation: if ( display ) { recyclerView . setVisibility ( RecyclerView . VISIBLE ) ; } else { recyclerView . setVisibility ( RecyclerView . GONE ) ; }


signature:
public class BasicSuggestionsListBuilder { /** * { @ inheritDoc } */
@ Override @ NonNull public List < Suggestible > buildSuggestions ( final @ NonNull Map < String , SuggestionsResult > latestResults , final @ NonNull String currentTokenString ) { } }

implementation: List < Suggestible > results = new ArrayList < Suggestible > ( ) ; for ( Map . Entry < String , SuggestionsResult > entry : latestResults . entrySet ( ) ) { SuggestionsResult result = entry . getValue ( ) ; if ( currentTokenString . equalsIgnoreCase ( result . getQueryToken ( ) . getTokenString ( ) ) ) { results . addAll ( result . getSuggestions ( ) ) ; } } return results ;


signature:
public class BasicSuggestionsListBuilder { /** * { @ inheritDoc } */
@ Override public View getView ( final @ NonNull Suggestible suggestion , @ Nullable View convertView , ViewGroup parent , final @ NonNull Context context , final @ NonNull LayoutInflater inflater , final @ NonNull Resources resources ) { } }

implementation: View view ; if ( convertView == null ) { view = inflater . inflate ( android . R . layout . simple_list_item_1 , parent , false ) ; } else { view = convertView ; } if ( view instanceof TextView ) { TextView text = ( TextView ) view ; text . setText ( suggestion . getSuggestiblePrimaryText ( ) ) ; text . setTextColor ( Color . BLACK ) ; text . setBackgroundColor ( Color . WHITE ) ; } return view ;


signature:
public class MentionsEditText { /** * Initialization method called by all constructors . */
private void init ( @ Nullable AttributeSet attrs , int defStyleAttr ) { } }

implementation:
// Get the mention span config from custom attributes
mentionSpanConfig = parseMentionSpanConfigFromAttributes ( attrs , defStyleAttr ) ; // Must set movement method in order for MentionSpans to be clickable
setMovementMethod ( MentionsMovementMethod . getInstance ( ) ) ; // Use MentionsEditable instead of default Editable
setEditableFactory ( MentionsEditableFactory . getInstance ( ) ) ; // Start watching itself for text changes
addTextChangedListener ( mInternalTextWatcher ) ; // Use default MentionSpanFactory initially
mentionSpanFactory = new MentionSpanFactory ( ) ;


signature:
public class MentionsEditText { /** * { @ inheritDoc } */
@ Override @ NonNull public String getCurrentTokenString ( ) { } }

implementation:
// Get the text and ensure a valid tokenizer is set
Editable text = getText ( ) ; if ( mTokenizer == null || text == null ) { return "" ; } // Use current text to determine token string
int cursor = Math . max ( getSelectionStart ( ) , 0 ) ; int start = mTokenizer . findTokenStart ( text , cursor ) ; int end = mTokenizer . findTokenEnd ( text , cursor ) ; String contentString = text . toString ( ) ; return TextUtils . isEmpty ( contentString ) ? "" : contentString . substring ( start , end ) ;


signature:
public class MentionsEditText { /** * { @ inheritDoc } */
@ Override @ Nullable public QueryToken getQueryTokenIfValid ( ) { } }

implementation:
if ( mTokenizer == null ) { return null ; } // Use current text to determine the start and end index of the token
MentionsEditable text = getMentionsText ( ) ; int cursor = Math . max ( getSelectionStart ( ) , 0 ) ; int start = mTokenizer . findTokenStart ( text , cursor ) ; int end = mTokenizer . findTokenEnd ( text , cursor ) ; if ( ! mTokenizer . isValidMention ( text , start , end ) ) { return null ; } String tokenString = text . subSequence ( start , end ) . toString ( ) ; char firstChar = tokenString . charAt ( 0 ) ; boolean isExplicit = mTokenizer . isExplicitChar ( tokenString . charAt ( 0 ) ) ; return ( isExplicit ? new QueryToken ( tokenString , firstChar ) : new QueryToken ( tokenString ) ) ;


signature:
public class MentionsEditText { /** * Called whenever the user touches this { @ link EditText } . This was one of the primary reasons for overriding
 * EditText in this library . This method ensures that when a user taps on a { @ link MentionSpan } in this EditText ,
 * { @ link MentionSpan # onClick ( View ) } is called before the onClick method of this { @ link EditText } .
 * @ param event the given { @ link MotionEvent }
 * @ return true if the { @ link MotionEvent } has been handled */
@ Override public boolean onTouchEvent ( @ NonNull MotionEvent event ) { } }

implementation:
final MentionSpan touchedSpan = getTouchedSpan ( event ) ; // Android 6 occasionally throws a NullPointerException inside Editor . onTouchEvent ( )
// for ACTION _ UP when attempting to display ( uninitialised ) text handles .
boolean superResult ; if ( android . os . Build . VERSION . SDK_INT == Build . VERSION_CODES . M && event . getActionMasked ( ) == MotionEvent . ACTION_UP ) { try { superResult = super . onTouchEvent ( event ) ; } catch ( NullPointerException ignored ) { // Ignore this ( see above ) - since we ' re now in an unknown state let ' s clear all
// selection ( which is still better than an arbitrary crash that we can ' t control ) :
clearFocus ( ) ; superResult = true ; } } else { superResult = super . onTouchEvent ( event ) ; } if ( event . getAction ( ) == MotionEvent . ACTION_UP ) { // Don ' t call the onclick on mention if MotionEvent . ACTION _ UP is for long click action ,
if ( ! isLongPressed && touchedSpan != null ) { // Manually click span and show soft keyboard
touchedSpan . onClick ( this ) ; Context context = getContext ( ) ; if ( context != null ) { InputMethodManager imm = ( InputMethodManager ) context . getSystemService ( Context . INPUT_METHOD_SERVICE ) ; imm . showSoftInput ( this , 0 ) ; } return true ; } } else if ( event . getAction ( ) == MotionEvent . ACTION_DOWN ) { isLongPressed = false ; if ( isLongClickable ( ) && touchedSpan != null ) { if ( longClickRunnable == null ) { longClickRunnable = new CheckLongClickRunnable ( ) ; } longClickRunnable . touchedSpan = touchedSpan ; removeCallbacks ( longClickRunnable ) ; postDelayed ( longClickRunnable , ViewConfiguration . getLongPressTimeout ( ) ) ; } } else if ( event . getAction ( ) == MotionEvent . ACTION_CANCEL ) { isLongPressed = false ; } // Check if user clicked on the EditText while showing the suggestions list
// If so , avoid the current prefix
if ( mAvoidPrefixOnTap && mSuggestionsVisibilityManager != null && mSuggestionsVisibilityManager . isDisplayingSuggestions ( ) ) { mSuggestionsVisibilityManager . displaySuggestions ( false ) ; String keywords = getCurrentKeywordsString ( ) ; String [ ] words = keywords . split ( " " ) ; if ( words . length > 0 ) { String prefix = words [ words . length - 1 ] ; // Note that prefix = = " " when user types an explicit character and taps the EditText
// We must not allow the user to avoid suggestions for the empty string prefix
// Otherwise , explicit mentions would be broken , see MOB - 38080
if ( prefix . length ( ) > 0 ) { setAvoidedPrefix ( prefix ) ; } } } return superResult ;


signature:
public class MentionsEditText { /** * Copy the text between start and end in clipboard .
 * If no span is present , text is saved as plain text but if span is present
 * save it in Clipboard using intent . */
private void copy ( @ IntRange ( from = 0 ) int start , @ IntRange ( from = 0 ) int end ) { } }

implementation:
MentionsEditable text = getMentionsText ( ) ; SpannableStringBuilder copiedText = ( SpannableStringBuilder ) text . subSequence ( start , end ) ; MentionSpan [ ] spans = text . getSpans ( start , end , MentionSpan . class ) ; Intent intent = null ; if ( spans . length > 0 ) { // Save MentionSpan and it ' s start offset .
intent = new Intent ( ) ; intent . putExtra ( KEY_MENTION_SPANS , spans ) ; int [ ] spanStart = new int [ spans . length ] ; for ( int i = 0 ; i < spans . length ; i ++ ) { spanStart [ i ] = copiedText . getSpanStart ( spans [ i ] ) ; } intent . putExtra ( KEY_MENTION_SPAN_STARTS , spanStart ) ; } saveToClipboard ( copiedText , intent ) ;


signature:
public class MentionsEditText { /** * Paste clipboard content between min and max positions . */
private void paste ( @ IntRange ( from = 0 ) int min , @ IntRange ( from = 0 ) int max ) { } }

implementation: if ( android . os . Build . VERSION . SDK_INT < android . os . Build . VERSION_CODES . HONEYCOMB ) { android . text . ClipboardManager clipboard = ( android . text . ClipboardManager ) getContext ( ) . getSystemService ( Context . CLIPBOARD_SERVICE ) ; MentionsEditable text = getMentionsText ( ) ; text . replace ( text . length ( ) , text . length ( ) , clipboard . getText ( ) ) ; } else { pasteHoneycombImpl ( min , max ) ; }


signature:
public class MentionsEditText { /** * Paste clipboard content between min and max positions . This method is supported for all the api above the 10.
 * If clipboard content contain the MentionSpan , set the span in copied text . */
@ TargetApi ( Build . VERSION_CODES . HONEYCOMB ) private void pasteHoneycombImpl ( @ IntRange ( from = 0 ) int min , @ IntRange ( from = 0 ) int max ) { } }

implementation:
ClipboardManager clipboard = ( ClipboardManager ) getContext ( ) . getSystemService ( Context . CLIPBOARD_SERVICE ) ; ClipData clip = clipboard . getPrimaryClip ( ) ; if ( clip != null ) { for ( int i = 0 ; i < clip . getItemCount ( ) ; i ++ ) { ClipData . Item item = clip . getItemAt ( i ) ; String selectedText = item . coerceToText ( getContext ( ) ) . toString ( ) ; MentionsEditable text = getMentionsText ( ) ; MentionSpan [ ] spans = text . getSpans ( min , max , MentionSpan . class ) ; /* * We need to remove the span between min and max . This is required because in
 * { @ link SpannableStringBuilder # replace ( int , int , CharSequence ) } existing spans within
 * the Editable that entirely cover the replaced range are retained , but any that
 * were strictly within the range that was replaced are removed . In our case the existing
 * spans are retained if the selection entirely covers the span . So , we just remove
 * the existing span and replace the new text with that span . */
for ( MentionSpan span : spans ) { if ( text . getSpanEnd ( span ) == min ) { // We do not want to remove the span , when we want to paste anything just next
// to the existing span . In this case " text . getSpanEnd ( span ) " will be equal
// to min .
continue ; } text . removeSpan ( span ) ; } Intent intent = item . getIntent ( ) ; // Just set the plain text if we do not have mentions data in the intent / bundle
if ( intent == null ) { text . replace ( min , max , selectedText ) ; continue ; } Bundle bundle = intent . getExtras ( ) ; if ( bundle == null ) { text . replace ( min , max , selectedText ) ; continue ; } bundle . setClassLoader ( getContext ( ) . getClassLoader ( ) ) ; int [ ] spanStart = bundle . getIntArray ( KEY_MENTION_SPAN_STARTS ) ; Parcelable [ ] parcelables = bundle . getParcelableArray ( KEY_MENTION_SPANS ) ; if ( parcelables == null || parcelables . length <= 0 || spanStart == null || spanStart . length <= 0 ) { text . replace ( min , max , selectedText ) ; continue ; } // Set the MentionSpan in text .
SpannableStringBuilder s = new SpannableStringBuilder ( selectedText ) ; for ( int j = 0 ; j < parcelables . length ; j ++ ) { MentionSpan mentionSpan = ( MentionSpan ) parcelables [ j ] ; s . setSpan ( mentionSpan , spanStart [ j ] , spanStart [ j ] + mentionSpan . getDisplayString ( ) . length ( ) , Spanned . SPAN_EXCLUSIVE_EXCLUSIVE ) ; } text . replace ( min , max , s ) ; } }


signature:
public class MentionsEditText { /** * Save the selected text and intent in ClipboardManager */
private void saveToClipboard ( @ NonNull CharSequence selectedText , @ Nullable Intent intent ) { } }

implementation: if ( android . os . Build . VERSION . SDK_INT < android . os . Build . VERSION_CODES . HONEYCOMB ) { android . text . ClipboardManager clipboard = ( android . text . ClipboardManager ) getContext ( ) . getSystemService ( Context . CLIPBOARD_SERVICE ) ; clipboard . setText ( selectedText ) ; } else { android . content . ClipboardManager clipboard = ( android . content . ClipboardManager ) getContext ( ) . getSystemService ( Context . CLIPBOARD_SERVICE ) ; ClipData . Item item = new ClipData . Item ( selectedText , intent , null ) ; android . content . ClipData clip = new ClipData ( null , new String [ ] { ClipDescription . MIMETYPE_TEXT_PLAIN } , item ) ; clipboard . setPrimaryClip ( clip ) ; }


signature:
public class MentionsEditText { /** * Gets the { @ link MentionSpan } from the { @ link MentionsEditText } that was tapped .
 * Note : Almost all of this code is taken directly from the Android source code , see :
 * { @ link LinkMovementMethod # onTouchEvent ( TextView , Spannable , MotionEvent ) }
 * @ param event the given ( @ link MotionEvent }
 * @ return the tapped { @ link MentionSpan } , or null if one was not tapped */
@ Nullable protected MentionSpan getTouchedSpan ( MotionEvent event ) { } }

implementation:
Layout layout = getLayout ( ) ; // Note : Layout can be null if text or width has recently changed , see MOB - 38193
if ( event == null || layout == null ) { return null ; } int x = ( int ) event . getX ( ) ; int y = ( int ) event . getY ( ) ; x -= getTotalPaddingLeft ( ) ; y -= getTotalPaddingTop ( ) ; x += getScrollX ( ) ; y += getScrollY ( ) ; int line = layout . getLineForVertical ( y ) ; int off = layout . getOffsetForHorizontal ( line , x ) ; Editable text = getText ( ) ; if ( text != null && off >= getText ( ) . length ( ) ) { return null ; } // Get the MentionSpans in the area that the user tapped
// If one exists , call the onClick method manually
MentionSpan [ ] spans = getText ( ) . getSpans ( off , off , MentionSpan . class ) ; if ( spans . length > 0 ) { return spans [ 0 ] ; } return null ;


signature:
public class MentionsEditText { /** * Called whenever the selection within the { @ link EditText } has changed .
 * @ param selStart starting position of the selection
 * @ param selEnd ending position of the selection */
@ Override protected void onSelectionChanged ( final int selStart , final int selEnd ) { } }

implementation:
// Handle case where there is only one cursor ( i . e . not selecting a range , just moving cursor )
if ( selStart == selEnd ) { if ( ! onCursorChanged ( selStart ) ) { super . onSelectionChanged ( selStart , selEnd ) ; } return ; } else { updateSelectionIfRequired ( selStart , selEnd ) ; } super . onSelectionChanged ( selStart , selEnd ) ;


signature:
public class MentionsEditText { /** * Don ' t allow user to set starting position or ending position of selection within the mention . */
private void updateSelectionIfRequired ( final int selStart , final int selEnd ) { } }

implementation: MentionsEditable text = getMentionsText ( ) ; MentionSpan startMentionSpan = text . getMentionSpanAtOffset ( selStart ) ; MentionSpan endMentionSpan = text . getMentionSpanAtOffset ( selEnd ) ; boolean selChanged = false ; int start = selStart ; int end = selEnd ; if ( text . getSpanStart ( startMentionSpan ) < selStart && selStart < text . getSpanEnd ( startMentionSpan ) ) { start = text . getSpanStart ( startMentionSpan ) ; selChanged = true ; } if ( text . getSpanStart ( endMentionSpan ) < selEnd && selEnd < text . getSpanEnd ( endMentionSpan ) ) { end = text . getSpanEnd ( endMentionSpan ) ; selChanged = true ; } if ( selChanged ) { setSelection ( start , end ) ; }


signature:
public class MentionsEditText { /** * Method to handle the cursor changing positions . Returns true if handled , false if it should
 * be passed to the super method .
 * @ param index int position of cursor within the text
 * @ return true if handled */
private boolean onCursorChanged ( final int index ) { } }

implementation:
Editable text = getText ( ) ; if ( text == null ) { return false ; } MentionSpan [ ] allSpans = text . getSpans ( 0 , text . length ( ) , MentionSpan . class ) ; for ( MentionSpan span : allSpans ) { // Deselect span if the cursor is not on the span .
if ( span . isSelected ( ) && ( index < text . getSpanStart ( span ) || index > text . getSpanEnd ( span ) ) ) { span . setSelected ( false ) ; updateSpan ( span ) ; } } // Do not allow the user to set the cursor within a span . If the user tries to do so , select
// move the cursor to the end of it .
MentionSpan [ ] currentSpans = text . getSpans ( index , index , MentionSpan . class ) ; if ( currentSpans . length != 0 ) { MentionSpan span = currentSpans [ 0 ] ; int start = text . getSpanStart ( span ) ; int end = text . getSpanEnd ( span ) ; if ( index > start && index < end ) { super . setSelection ( end ) ; return true ; } } return false ;


signature:
public class MentionsEditText { /** * Marks a span for deletion later if necessary by checking if the last character in a MentionSpan
 * is deleted by this change . If so , mark the span to be deleted later when
 * { @ link # ensureMentionSpanIntegrity ( Editable ) } is called in { @ link # handleTextChanged ( ) } .
 * @ param count length of affected text before change starting at start in text
 * @ param after length of affected text after change
 * @ return true if there is a span before the cursor that is going to change state */
private boolean markSpans ( int count , int after ) { } }

implementation:
int cursor = getSelectionStart ( ) ; MentionsEditable text = getMentionsText ( ) ; MentionSpan prevSpan = text . getMentionSpanEndingAt ( cursor ) ; if ( count == ( after + 1 ) && prevSpan != null ) { // Cursor was directly behind a span and was moved back one , so delete it if selected ,
// or select it if not already selected
if ( prevSpan . isSelected ( ) ) { Mentionable mention = prevSpan . getMention ( ) ; Mentionable . MentionDeleteStyle deleteStyle = mention . getDeleteStyle ( ) ; Mentionable . MentionDisplayMode displayMode = prevSpan . getDisplayMode ( ) ; // Determine new DisplayMode given previous DisplayMode and MentionDeleteStyle
if ( deleteStyle == Mentionable . MentionDeleteStyle . PARTIAL_NAME_DELETE && displayMode == Mentionable . MentionDisplayMode . FULL ) { prevSpan . setDisplayMode ( Mentionable . MentionDisplayMode . PARTIAL ) ; } else { prevSpan . setDisplayMode ( Mentionable . MentionDisplayMode . NONE ) ; } } else { // Span was not selected , so select it
prevSpan . setSelected ( true ) ; } return true ; } return false ;


signature:
public class MentionsEditText { /** * Temporarily remove MentionSpans that may interfere with composing text . Note that software keyboards are allowed
 * to place arbitrary spans over the text . This was resulting in several bugs in edge cases while handling the
 * MentionSpans while composing text ( with different issues for different keyboards ) . The easiest solution for this
 * is to remove any MentionSpans that could cause issues while the user is changing text .
 * Note : The MentionSpans are added again in { @ link # replacePlaceholdersWithCorrespondingMentionSpans ( Editable ) }
 * @ param text the current text before it changes */
private void replaceMentionSpansWithPlaceholdersAsNecessary ( @ NonNull CharSequence text ) { } }

implementation: int index = getSelectionStart ( ) ; int wordStart = findStartOfWord ( text , index ) ; Editable editable = getText ( ) ; MentionSpan [ ] mentionSpansInCurrentWord = editable . getSpans ( wordStart , index , MentionSpan . class ) ; for ( MentionSpan span : mentionSpansInCurrentWord ) { if ( span . getDisplayMode ( ) != Mentionable . MentionDisplayMode . NONE ) { int spanStart = editable . getSpanStart ( span ) ; int spanEnd = editable . getSpanEnd ( span ) ; editable . setSpan ( new PlaceholderSpan ( span , spanStart , spanEnd ) , spanStart , spanEnd , Spanned . SPAN_EXCLUSIVE_INCLUSIVE ) ; editable . removeSpan ( span ) ; } }


signature:
public class MentionsEditText { /** * Helper utility to determine the beginning of a word using the current tokenizer .
 * @ param text the text to examine
 * @ param index index of the cursor in the text
 * @ return index of the beginning of the word in text ( will be less than or equal to index ) */
private int findStartOfWord ( @ NonNull CharSequence text , int index ) { } }

implementation: int wordStart = index ; while ( wordStart > 0 && mTokenizer != null && ! mTokenizer . isWordBreakingChar ( text . charAt ( wordStart - 1 ) ) ) { wordStart -- ; } return wordStart ;


signature:
public class MentionsEditText { /** * Mark text that was duplicated during text composition to delete it later .
 * @ param text the given text
 * @ param cursor the index of the cursor in text
 * @ param tokenizer the { @ link Tokenizer } to use */
private void markDuplicatedTextForDeletionLater ( @ NonNull Editable text , int cursor , @ NonNull Tokenizer tokenizer ) { } }

implementation:
while ( cursor > 0 && tokenizer . isWordBreakingChar ( text . charAt ( cursor - 1 ) ) ) { cursor -- ; } int wordStart = findStartOfWord ( text , cursor ) ; PlaceholderSpan [ ] placeholderSpans = text . getSpans ( wordStart , wordStart + 1 , PlaceholderSpan . class ) ; for ( PlaceholderSpan span : placeholderSpans ) { int spanEnd = span . originalEnd ; int copyEnd = spanEnd + ( spanEnd - wordStart ) ; if ( copyEnd > spanEnd && copyEnd <= text . length ( ) ) { CharSequence endOfMention = text . subSequence ( wordStart , spanEnd ) ; CharSequence copyOfEndOfMentionText = text . subSequence ( spanEnd , copyEnd ) ; // Note : Comparing strings since we do not want to compare any other aspects of spanned strings
if ( endOfMention . toString ( ) . equals ( copyOfEndOfMentionText . toString ( ) ) ) { text . setSpan ( new DeleteSpan ( ) , spanEnd , copyEnd , Spanned . SPAN_EXCLUSIVE_EXCLUSIVE ) ; } } }


signature:
public class MentionsEditText { /** * Removes any { @ link com . linkedin . android . spyglass . ui . MentionsEditText . DeleteSpan } s and the text within them from
 * the given text .
 * @ param text the editable containing DeleteSpans to remove */
private void removeTextWithinDeleteSpans ( @ NonNull Editable text ) { } }

implementation: DeleteSpan [ ] deleteSpans = text . getSpans ( 0 , text . length ( ) , DeleteSpan . class ) ; for ( DeleteSpan span : deleteSpans ) { int spanStart = text . getSpanStart ( span ) ; int spanEnd = text . getSpanEnd ( span ) ; text . replace ( spanStart , spanEnd , "" ) ; text . removeSpan ( span ) ; }


signature:
public class MentionsEditText { /** * Replaces any { @ link com . linkedin . android . spyglass . ui . MentionsEditText . PlaceholderSpan } within the given text with
 * the { @ link MentionSpan } it contains .
 * Note : These PlaceholderSpans are added in { @ link # replaceMentionSpansWithPlaceholdersAsNecessary ( CharSequence ) }
 * @ param text the final version of the text after it was changed */
private void replacePlaceholdersWithCorrespondingMentionSpans ( @ NonNull Editable text ) { } }

implementation: PlaceholderSpan [ ] tempSpans = text . getSpans ( 0 , text . length ( ) , PlaceholderSpan . class ) ; for ( PlaceholderSpan span : tempSpans ) { int spanStart = text . getSpanStart ( span ) ; String mentionDisplayString = span . holder . getDisplayString ( ) ; int end = Math . min ( spanStart + mentionDisplayString . length ( ) , text . length ( ) ) ; text . replace ( spanStart , end , mentionDisplayString ) ; text . setSpan ( span . holder , spanStart , spanStart + mentionDisplayString . length ( ) , Spanned . SPAN_EXCLUSIVE_EXCLUSIVE ) ; text . removeSpan ( span ) ; }


signature:
public class MentionsEditText { /** * Ensures that the text within each { @ link MentionSpan } in the { @ link Editable } correctly
 * matches what it should be outputting . If not , replace it with the correct value .
 * @ param text the { @ link Editable } to examine */
private void ensureMentionSpanIntegrity ( Editable text ) { } }

implementation:
if ( text == null ) { return ; } MentionSpan [ ] spans = text . getSpans ( 0 , text . length ( ) , MentionSpan . class ) ; boolean spanAltered = false ; for ( MentionSpan span : spans ) { int start = text . getSpanStart ( span ) ; int end = text . getSpanEnd ( span ) ; CharSequence spanText = text . subSequence ( start , end ) . toString ( ) ; Mentionable . MentionDisplayMode displayMode = span . getDisplayMode ( ) ; switch ( displayMode ) { case PARTIAL : case FULL : String name = span . getDisplayString ( ) ; if ( ! name . equals ( spanText ) && start >= 0 && start < end && end <= text . length ( ) ) { // Mention display name does not match what is being shown ,
// replace text in span with proper display name
int cursor = getSelectionStart ( ) ; int diff = cursor - end ; text . removeSpan ( span ) ; text . replace ( start , end , name ) ; if ( diff > 0 && start + end + diff < text . length ( ) ) { text . replace ( start + end , start + end + diff , "" ) ; } if ( name . length ( ) > 0 ) { text . setSpan ( span , start , start + name . length ( ) , Spanned . SPAN_EXCLUSIVE_EXCLUSIVE ) ; } // Notify for partially deleted mentions .
if ( mMentionWatchers . size ( ) > 0 && displayMode == Mentionable . MentionDisplayMode . PARTIAL ) { notifyMentionPartiallyDeletedWatchers ( span . getMention ( ) , name , start , end ) ; } spanAltered = true ; } break ; case NONE : default : // Mention with DisplayMode = = NONE should be deleted from the text
boolean hasListeners = mMentionWatchers . size ( ) > 0 ; final String textBeforeDelete = hasListeners ? text . toString ( ) : null ; text . delete ( start , end ) ; setSelection ( start ) ; if ( hasListeners ) { notifyMentionDeletedWatchers ( span . getMention ( ) , textBeforeDelete , start , end ) ; } spanAltered = true ; break ; } } // Reset input method if spans have been changed ( updates suggestions )
if ( spanAltered ) { restartInput ( ) ; }


signature:
public class MentionsEditText { /** * Called after the { @ link Editable } text within the { @ link EditText } has been changed . Note that
 * editing text in this function is guaranteed to be safe and not cause an infinite loop . */
private void handleTextChanged ( ) { } }

implementation:
// Ignore requests if the last word in keywords is prefixed by the currently avoided prefix
if ( mAvoidedPrefix != null ) { String [ ] keywords = getCurrentKeywordsString ( ) . split ( " " ) ; // Add null and length check to avoid the ArrayIndexOutOfBoundsException
if ( keywords . length == 0 ) { return ; } String lastKeyword = keywords [ keywords . length - 1 ] ; if ( lastKeyword . startsWith ( mAvoidedPrefix ) ) { return ; } else { setAvoidedPrefix ( null ) ; } } // Request suggestions from the QueryClient
QueryToken queryToken = getQueryTokenIfValid ( ) ; if ( queryToken != null && mQueryTokenReceiver != null ) { // Valid token , so send query to the app for processing
mQueryTokenReceiver . onQueryReceived ( queryToken ) ; } else { // Ensure that the suggestions are hidden
if ( mSuggestionsVisibilityManager != null ) { mSuggestionsVisibilityManager . displaySuggestions ( false ) ; } }


signature:
public class MentionsEditText { /** * Gets the keywords that the { @ link Tokenizer } is currently considering for mention suggestions . Note that this is
 * the keywords string and will not include any explicit character , if present .
 * @ return a String representing current keywords in the { @ link EditText } */
@ NonNull public String getCurrentKeywordsString ( ) { } }

implementation: String keywordsString = getCurrentTokenString ( ) ; if ( keywordsString . length ( ) > 0 && mTokenizer . isExplicitChar ( keywordsString . charAt ( 0 ) ) ) { keywordsString = keywordsString . substring ( 1 ) ; } return keywordsString ;


signature:
public class MentionsEditText { /** * Resets the given { @ link MentionSpan } in the editor , forcing it to redraw with its latest drawable state .
 * @ param span the { @ link MentionSpan } to update */
public void updateSpan ( MentionSpan span ) { } }

implementation: mBlockCompletion = true ; Editable text = getText ( ) ; int start = text . getSpanStart ( span ) ; int end = text . getSpanEnd ( span ) ; if ( start >= 0 && end > start && end <= text . length ( ) ) { text . removeSpan ( span ) ; text . setSpan ( span , start , end , Spanned . SPAN_EXCLUSIVE_EXCLUSIVE ) ; } mBlockCompletion = false ;


signature:
public class MentionsEditText { /** * Deselects any spans in the editor that are currently selected . */
public void deselectAllSpans ( ) { } }

implementation: mBlockCompletion = true ; Editable text = getText ( ) ; MentionSpan [ ] spans = text . getSpans ( 0 , text . length ( ) , MentionSpan . class ) ; for ( MentionSpan span : spans ) { if ( span . isSelected ( ) ) { span . setSelected ( false ) ; updateSpan ( span ) ; } } mBlockCompletion = false ;


signature:
public class MentionsEditText { /** * Inserts a mention into the token being considered currently .
 * @ param mention { @ link Mentionable } to insert a span for */
public void insertMention ( @ NonNull Mentionable mention ) { } }

implementation:
if ( mTokenizer == null ) { return ; } // Setup variables and ensure they are valid
Editable text = getEditableText ( ) ; int cursor = getSelectionStart ( ) ; int start = mTokenizer . findTokenStart ( text , cursor ) ; int end = mTokenizer . findTokenEnd ( text , cursor ) ; if ( start < 0 || start >= end || end > text . length ( ) ) { return ; } insertMentionInternal ( mention , text , start , end ) ;


signature:
public class MentionsEditText { /** * Inserts a mention . This will not take any token into consideration . This method is useful
 * when you want to insert a mention which doesn ' t have a token .
 * @ param mention { @ link Mentionable } to insert a span for */
public void insertMentionWithoutToken ( @ NonNull Mentionable mention ) { } }

implementation:
// Setup variables and ensure they are valid
Editable text = getEditableText ( ) ; int index = getSelectionStart ( ) ; index = index > 0 ? index : 0 ; insertMentionInternal ( mention , text , index , index ) ;


signature:
public class MentionsEditText { /** * Determines if the { @ link Tokenizer } is looking at an explicit token right now .
 * @ return true if the { @ link Tokenizer } is currently considering an explicit query */
public boolean isCurrentlyExplicit ( ) { } }

implementation: String tokenString = getCurrentTokenString ( ) ; return tokenString . length ( ) > 0 && mTokenizer != null && mTokenizer . isExplicitChar ( tokenString . charAt ( 0 ) ) ;


signature:
public class MentionsEditText { /** * Populate an { @ link AccessibilityEvent } with information about this text view . Note that this implementation uses
 * a copy of the text that is explicitly not an instance of { @ link MentionsEditable } . This is due to the fact that
 * AccessibilityEvent will use the default system classloader when unparcelling the data within the event . This
 * results in a ClassNotFoundException . For more details , see : https : / / github . com / linkedin / Spyglass / issues / 10
 * @ param event the populated AccessibilityEvent */
@ Override public void onPopulateAccessibilityEvent ( @ NonNull AccessibilityEvent event ) { } }

implementation: super . onPopulateAccessibilityEvent ( event ) ; List < CharSequence > textList = event . getText ( ) ; CharSequence mentionLessText = getTextWithoutMentions ( ) ; for ( int i = 0 ; i < textList . size ( ) ; i ++ ) { CharSequence text = textList . get ( i ) ; if ( text instanceof MentionsEditable ) { textList . set ( i , mentionLessText ) ; } }


signature:
public class MentionsEditText { /** * Allows a class to watch for text changes . Note that adding this class to itself will add it
 * to the super class . Other instances of { @ link TextWatcher } will be notified by this class
 * as appropriate ( helps prevent infinite loops when text keeps changing ) .
 * @ param watcher the { @ link TextWatcher } to add */
@ Override public void addTextChangedListener ( TextWatcher watcher ) { } }

implementation: if ( watcher == mInternalTextWatcher ) { if ( ! mIsWatchingText ) { super . addTextChangedListener ( mInternalTextWatcher ) ; mIsWatchingText = true ; } } else { mExternalTextWatchers . add ( watcher ) ; }


signature:
public class MentionsEditText { /** * Removes a { @ link TextWatcher } from this class . Note that this function servers as the
 * counterpart to { @ link # addTextChangedListener ( TextWatcher ) } ) .
 * @ param watcher the { @ link TextWatcher } to remove */
@ Override public void removeTextChangedListener ( TextWatcher watcher ) { } }

implementation:
if ( watcher == mInternalTextWatcher ) { if ( mIsWatchingText ) { super . removeTextChangedListener ( mInternalTextWatcher ) ; mIsWatchingText = false ; } } else { // Other watchers are added
mExternalTextWatchers . remove ( watcher ) ; }


signature:
public class MentionsEditText { /** * Register a { @ link com . linkedin . android . spyglass . ui . MentionsEditText . MentionWatcher } in order to receive callbacks
 * when mentions are changed .
 * @ param watcher the { @ link com . linkedin . android . spyglass . ui . MentionsEditText . MentionWatcher } to add */
@ SuppressWarnings ( "unused" ) public void addMentionWatcher ( @ NonNull MentionWatcher watcher ) { } }

implementation: if ( ! mMentionWatchers . contains ( watcher ) ) { mMentionWatchers . add ( watcher ) ; }


signature: public class MentionsEditText { private void restartInput ( ) { } }

implementation: InputMethodManager imm = ( InputMethodManager ) getContext ( ) . getSystemService ( Context . INPUT_METHOD_SERVICE ) ; if ( imm != null ) { imm . restartInput ( this ) ; }


signature:
public class MentionsEditText { /** * Notify external text watchers that the text is about to change .
 * See { @ link TextWatcher # beforeTextChanged ( CharSequence , int , int , int ) } . */
private void sendBeforeTextChanged ( CharSequence text , int start , int before , int after ) { } }

implementation: final List < TextWatcher > list = mExternalTextWatchers ; final int count = list . size ( ) ; for ( int i = 0 ; i < count ; i ++ ) { TextWatcher watcher = list . get ( i ) ; if ( watcher != this ) { watcher . beforeTextChanged ( text , start , before , after ) ; } }


signature:
public class MentionsEditText { /** * Notify external text watchers that the text is changing .
 * See { @ link TextWatcher # onTextChanged ( CharSequence , int , int , int ) } . */
private void sendOnTextChanged ( CharSequence text , int start , int before , int after ) { } }

implementation: final List < TextWatcher > list = mExternalTextWatchers ; final int count = list . size ( ) ; for ( int i = 0 ; i < count ; i ++ ) { TextWatcher watcher = list . get ( i ) ; if ( watcher != this ) { watcher . onTextChanged ( text , start , before , after ) ; } }


signature:
public class MentionsEditText { /** * Notify external text watchers that the text has changed .
 * See { @ link TextWatcher # afterTextChanged ( Editable ) } . */
private void sendAfterTextChanged ( Editable text ) { } }

implementation: final List < TextWatcher > list = mExternalTextWatchers ; final int count = list . size ( ) ; for ( int i = 0 ; i < count ; i ++ ) { TextWatcher watcher = list . get ( i ) ; if ( watcher != this ) { watcher . afterTextChanged ( text ) ; } }


signature: public class MultiSourceMentions { @ Override public List < String > onQueryReceived ( final @ NonNull QueryToken queryToken ) { } }

implementation:
final boolean hasPeople = peopleCheckBox . isChecked ( ) ; final boolean hasCities = citiesCheckBox . isChecked ( ) ; final List < String > buckets = new ArrayList < > ( ) ; final SuggestionsResultListener listener = editor ; final Handler handler = new Handler ( Looper . getMainLooper ( ) ) ; // Fetch people if necessary
if ( hasPeople ) { buckets . add ( PERSON_BUCKET ) ; handler . postDelayed ( new Runnable ( ) { @ Override public void run ( ) { List < Person > suggestions = people . getSuggestions ( queryToken ) ; lastPersonSuggestions = new SuggestionsResult ( queryToken , suggestions ) ; listener . onReceiveSuggestionsResult ( lastPersonSuggestions , PERSON_BUCKET ) ; } } , PERSON_DELAY ) ; } // Fetch cities if necessary
if ( hasCities ) { buckets . add ( CITY_BUCKET ) ; handler . postDelayed ( new Runnable ( ) { @ Override public void run ( ) { List < City > suggestions = cities . getSuggestions ( queryToken ) ; lastCitySuggestions = new SuggestionsResult ( queryToken , suggestions ) ; listener . onReceiveSuggestionsResult ( lastCitySuggestions , CITY_BUCKET ) ; } } , CITY_DELAY ) ; } // Return buckets , one for each source ( serves as promise to editor that we will call
// onReceiveSuggestionsResult at a later time )
return buckets ;


signature: public class MentionsEditable { @ Override public void setSpan ( Object what , int start , int end , int flags ) { } }

implementation:
// Do not add any spans that affect the character appearance of a mention ( i . e . they overlap
// with a MentionSpan ) . This helps prevent mentions from having a red underline due to the spell
// checker . Note : SuggestionSpan was added in ICS , and different keyboards may use other kinds
// of spans ( i . e . the Motorola SpellCheckerMarkupSpan ) . Therefore , we cannot just filter out
// SuggestionSpans , but rather , any span that would change the appearance of our MentionSpans .
if ( what instanceof CharacterStyle ) { MentionSpan [ ] mentionSpans = getSpans ( start , end , MentionSpan . class ) ; if ( mentionSpans != null && mentionSpans . length > 0 ) { return ; } } // Ensure that the start and end points are set at zero initially
// Note : This issue was seen on a Gingerbread device ( start and end were both - 1 ) and
// prevents the device from crashing .
if ( ( what == Selection . SELECTION_START || what == Selection . SELECTION_END ) && length ( ) == 0 ) { start = 0 ; end = 0 ; } super . setSpan ( what , start , end , flags ) ;


signature:
public class MentionsEditable { /** * Implementation of { @ link String # trim ( ) } for an { @ link Editable } .
 * @ return a new { @ link MentionsEditable } with whitespace characters removed from the beginning and the end */
public MentionsEditable trim ( ) { } }

implementation:
// Delete beginning spaces
while ( length ( ) > 0 && Character . isWhitespace ( charAt ( 0 ) ) ) { delete ( 0 , 1 ) ; } // Delete ending spaces
int len = length ( ) ; while ( len > 0 && Character . isWhitespace ( charAt ( len - 1 ) ) ) { delete ( len - 1 , len ) ; len -- ; } return new MentionsEditable ( this , 0 , length ( ) ) ;


signature:
public class MentionsEditable { /** * Given an integer offset , return the { @ link MentionSpan } located at the offset in the text of the
 * { @ link android . widget . EditText } , if it exists . Otherwise , return null .
 * @ param index integer offset in text
 * @ return a { @ link MentionSpan } located at index in text , or null */
@ Nullable public MentionSpan getMentionSpanAtOffset ( int index ) { } }

implementation: MentionSpan [ ] spans = getSpans ( index , index , MentionSpan . class ) ; return ( spans != null && spans . length > 0 ) ? spans [ 0 ] : null ;


signature:
public class MentionsEditable { /** * Get the { @ link MentionSpan } starting at the given index in the text , or null if there is no { @ link MentionSpan }
 * starting at that index .
 * @ param index integer offset in text
 * @ return a { @ link MentionSpan } starting at index in text , or null */
@ Nullable public MentionSpan getMentionSpanStartingAt ( int index ) { } }

implementation: MentionSpan [ ] spans = getSpans ( 0 , length ( ) , MentionSpan . class ) ; if ( spans != null ) { for ( MentionSpan span : spans ) { if ( getSpanStart ( span ) == index ) { return span ; } } } return null ;


signature:
public class MentionsEditable { /** * Get the { @ link MentionSpan } ending at the given index in the text , or null if there is no { @ link MentionSpan }
 * ending at that index .
 * @ param index integer offset in text
 * @ return a { @ link MentionSpan } ending at index in text , or null */
@ Nullable public MentionSpan getMentionSpanEndingAt ( int index ) { } }

implementation: MentionSpan [ ] spans = getSpans ( 0 , length ( ) , MentionSpan . class ) ; if ( spans != null ) { for ( MentionSpan span : spans ) { if ( getSpanEnd ( span ) == index ) { return span ; } } } return null ;


signature: public class City { @ NonNull @ Override public String getTextForDisplayMode ( MentionDisplayMode mode ) { } }

implementation: switch ( mode ) { case FULL : return mName ; case PARTIAL : case NONE : default : return "" ; }


signature:
public class TimeParserUtil { /** * Parse a duration
 * @ param duration
 * 1d , 3h , 2mn , 7s , 50ms
 * @ return The number of milliseconds */
public static long parseDuration ( String duration ) { } }

implementation: if ( duration == null || duration . isEmpty ( ) ) { throw new IllegalArgumentException ( "duration may not be null" ) ; } long toAdd = - 1 ; if ( days . matcher ( duration ) . matches ( ) ) { Matcher matcher = days . matcher ( duration ) ; matcher . matches ( ) ; toAdd = Long . parseLong ( matcher . group ( 1 ) ) * 60 * 60 * 24 * 1000 ; } else if ( hours . matcher ( duration ) . matches ( ) ) { Matcher matcher = hours . matcher ( duration ) ; matcher . matches ( ) ; toAdd = Long . parseLong ( matcher . group ( 1 ) ) * 60 * 60 * 1000 ; } else if ( minutes . matcher ( duration ) . matches ( ) ) { Matcher matcher = minutes . matcher ( duration ) ; matcher . matches ( ) ; toAdd = Long . parseLong ( matcher . group ( 1 ) ) * 60 * 1000 ; } else if ( seconds . matcher ( duration ) . matches ( ) ) { Matcher matcher = seconds . matcher ( duration ) ; matcher . matches ( ) ; toAdd = Long . parseLong ( matcher . group ( 1 ) ) * 1000 ; } else if ( milliseconds . matcher ( duration ) . matches ( ) ) { Matcher matcher = milliseconds . matcher ( duration ) ; matcher . matches ( ) ; toAdd = Long . parseLong ( matcher . group ( 1 ) ) ; } if ( toAdd == - 1 ) { throw new IllegalArgumentException ( "Invalid duration pattern : " + duration ) ; } return toAdd ;


signature:
public class JobManager { /** * Allow timezone to be configured on a per - cron basis with [ timezoneName ] appended to the cron format
 * @ param cronExpr the modified cron format
 * @ return the cron schedule with the timezone applied to it if needed */
protected CronScheduleBuilder createCronScheduleBuilder ( String cronExpr ) { } }

implementation: int i = cronExpr . indexOf ( "[" ) ; int j = cronExpr . indexOf ( "]" ) ; TimeZone timezone = defaultTimezone ; if ( i > - 1 && j > - 1 ) { timezone = TimeZone . getTimeZone ( cronExpr . substring ( i + 1 , j ) ) ; cronExpr = cronExpr . substring ( 0 , i ) . trim ( ) ; } return CronScheduleBuilder . cronSchedule ( cronExpr ) . inTimeZone ( timezone ) ;


signature:
public class SVGHints { /** * Returns { @ code true } if this key is equivalent to
 * { @ link # KEY _ BEGIN _ GROUP } , and { @ code false } otherwise . The purpose
 * of this method is to allow certain keys from external packages ( such as
 * JFreeChart and Orson Charts ) to use their own keys to drive the
 * behaviour of { @ code SVGHints . KEY _ BEGIN _ GROUP } . This has two benefits :
 * ( 1 ) it avoids the necessity to make JFreeSVG a direct dependency , and
 * ( 2 ) it makes the grouping behaviour generic from the point of view of
 * the external package , rather than SVG - specific .
 * @ param key the key ( { @ code null } not permitted )
 * @ return A boolean .
 * @ since 1.8 */
public static boolean isBeginGroupKey ( RenderingHints . Key key ) { } }

implementation: return SVGHints . KEY_BEGIN_GROUP . equals ( key ) || beginGroupKeys . contains ( key ) ;


signature:
public class SVGHints { /** * Returns { @ code true } if this key is equivalent to
 * { @ link # KEY _ END _ GROUP } , and { @ code false } otherwise . The purpose
 * of this method is to allow certain keys from external packages ( such as
 * JFreeChart and Orson Charts ) to use their own keys to drive the
 * behaviour of { @ code SVGHints . KEY _ END _ GROUP } . This has two benefits :
 * ( 1 ) it avoids the necessity to make JFreeSVG a direct dependency , and
 * ( 2 ) it makes the grouping behaviour generic from the point of view of
 * the external package , rather than SVG - specific .
 * @ param key the key ( { @ code null } not permitted ) .
 * @ return A boolean .
 * @ since 1.8 */
public static boolean isEndGroupKey ( RenderingHints . Key key ) { } }

implementation: return SVGHints . KEY_END_GROUP . equals ( key ) || endGroupKeys . contains ( key ) ;


signature:
public class SVGHints { /** * Returns { @ code true } if this key is equivalent to
 * { @ link # KEY _ ELEMENT _ TITLE } , and { @ code false } otherwise . The
 * purpose of this method is to allow certain keys from external packages
 * ( such as JFreeChart and Orson Charts ) to use their own keys to drive the
 * behaviour of { @ code SVGHints . KEY _ ELEMENT _ TITLE } . This has two benefits :
 * ( 1 ) it avoids the necessity to make JFreeSVG a direct dependency , and
 * ( 2 ) it makes the element title behaviour generic from the point of view
 * of the external package , rather than SVG - specific .
 * @ param key the key ( { @ code null } not permitted )
 * @ return A boolean .
 * @ since 1.9 */
public static boolean isElementTitleKey ( RenderingHints . Key key ) { } }

implementation: return SVGHints . KEY_ELEMENT_TITLE . equals ( key ) || elementTitleKeys . contains ( key ) ;


signature:
public class SVGUtils { /** * Returns a new string where any special characters in the source string
 * have been encoded .
 * @ param source the source string ( { @ code null } not permitted ) .
 * @ return A new string with special characters escaped for XML .
 * @ since 1.5 */
public static String escapeForXML ( String source ) { } }

implementation: Args . nullNotPermitted ( source , "source" ) ; StringBuilder sb = new StringBuilder ( ) ; for ( int i = 0 ; i < source . length ( ) ; i ++ ) { char c = source . charAt ( i ) ; switch ( c ) { case '<' : { sb . append ( "<" ) ; break ; } case '>' : { sb . append ( ">" ) ; break ; } case '&' : { String next = source . substring ( i , Math . min ( i + 6 , source . length ( ) ) ) ; if ( next . startsWith ( "<" ) || next . startsWith ( ">" ) || next . startsWith ( "&" ) || next . startsWith ( "'" ) || next . startsWith ( """ ) ) { sb . append ( c ) ; } else { sb . append ( "&" ) ; } break ; } case '\'' : { sb . append ( "'" ) ; break ; } case '\"' : { sb . append ( """ ) ; break ; } default : sb . append ( c ) ; } } return sb . toString ( ) ;


signature:
public class SVGUtils { /** * Writes a file containing the SVG element .
 * @ param file the file ( { @ code null } not permitted ) .
 * @ param svgElement the SVG element ( { @ code null } not permitted ) .
 * @ throws IOException if there is an I / O problem .
 * @ since 1.2 */
public static void writeToSVG ( File file , String svgElement ) throws IOException { } }

implementation: writeToSVG ( file , svgElement , false ) ;


signature:
public class SVGUtils { /** * Writes a file containing the SVG element .
 * @ param file the file ( { @ code null } not permitted ) .
 * @ param svgElement the SVG element ( { @ code null } not permitted ) .
 * @ param zip compress the output .
 * @ throws IOException if there is an I / O problem .
 * @ since 3.0 */
public static void writeToSVG ( File file , String svgElement , boolean zip ) throws IOException { } }

implementation: BufferedWriter writer = null ; try { OutputStream os = new FileOutputStream ( file ) ; if ( zip ) { os = new GZIPOutputStream ( os ) ; } OutputStreamWriter osw = new OutputStreamWriter ( os , "UTF-8" ) ; writer = new BufferedWriter ( osw ) ; writer . write ( "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n" ) ; writer . write ( svgElement + "\n" ) ; writer . flush ( ) ; } finally { try { if ( writer != null ) { writer . close ( ) ; } } catch ( IOException ex ) { throw new RuntimeException ( ex ) ; } }


signature:
public class SVGUtils { /** * Writes an HTML file containing an SVG element .
 * @ param file the file .
 * @ param title the title .
 * @ param svgElement the SVG element .
 * @ throws IOException if there is an I / O problem . */
public static void writeToHTML ( File file , String title , String svgElement ) throws IOException { } }

implementation: BufferedWriter writer = null ; try { FileOutputStream fos = new FileOutputStream ( file ) ; OutputStreamWriter osw = new OutputStreamWriter ( fos , "UTF-8" ) ; writer = new BufferedWriter ( osw ) ; writer . write ( "<!DOCTYPE html>\n" ) ; writer . write ( "\n" ) ; writer . write ( "\n" ) ; writer . write ( "<title>" + title + "</title>\n" ) ; writer . write ( "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n" ) ; writer . write ( "\n" ) ; writer . write ( "\n" ) ; writer . write ( svgElement + "\n" ) ; writer . write ( "\n" ) ; writer . write ( "\n" ) ; writer . flush ( ) ; } finally { try { if ( writer != null ) { writer . close ( ) ; } } catch ( IOException ex ) { Logger . getLogger ( SVGUtils . class . getName ( ) ) . log ( Level . SEVERE , null , ex ) ; } }


signature:
public class GraphicsUtils { /** * Returns a shape that is ( more or less ) equivalent to the supplied shape .
 * For some known shape implementations ( { @ code Line2D } ,
 * { @ code Rectangle2D } , { @ code RoundRectangle2D } , { @ code Arc2D } ,
 * { @ code Ellipse2D } , and { @ code Polygon } ) the copy will be an instance of
 * that class . For other shapes , a { @ code Path2D } containing the outline
 * of the shape is returned .
 * @ param shape the shape ( { @ code null } not permitted ) .
 * @ return A copy of the shape or shape outline ( never { @ code null } ) . */
public static Shape copyOf ( Shape shape ) { } }

implementation: Args . nullNotPermitted ( shape , "shape" ) ; if ( shape instanceof Line2D ) { Line2D l = ( Line2D ) shape ; return new Line2D . Double ( l . getX1 ( ) , l . getY1 ( ) , l . getX2 ( ) , l . getY2 ( ) ) ; } if ( shape instanceof Rectangle2D ) { Rectangle2D r = ( Rectangle2D ) shape ; return new Rectangle2D . Double ( r . getX ( ) , r . getY ( ) , r . getWidth ( ) , r . getHeight ( ) ) ; } if ( shape instanceof RoundRectangle2D ) { RoundRectangle2D rr = ( RoundRectangle2D ) shape ; return new RoundRectangle2D . Double ( rr . getX ( ) , rr . getY ( ) , rr . getWidth ( ) , rr . getHeight ( ) , rr . getArcWidth ( ) , rr . getArcHeight ( ) ) ; } if ( shape instanceof Arc2D ) { Arc2D arc = ( Arc2D ) shape ; return new Arc2D . Double ( arc . getX ( ) , arc . getY ( ) , arc . getWidth ( ) , arc . getHeight ( ) , arc . getAngleStart ( ) , arc . getAngleExtent ( ) , arc . getArcType ( ) ) ; } if ( shape instanceof Ellipse2D ) { Ellipse2D ell = ( Ellipse2D ) shape ; return new Ellipse2D . Double ( ell . getX ( ) , ell . getY ( ) , ell . getWidth ( ) , ell . getHeight ( ) ) ; } if ( shape instanceof Polygon ) { Polygon p = ( Polygon ) shape ; return new Polygon ( p . xpoints , p . ypoints , p . npoints ) ; } return new Path2D . Double ( shape ) ;


signature:
public class GraphicsUtils { /** * Creates a polygon from the specified { @ code x } and { @ code y } coordinate
 * arrays .
 * @ param xPoints the x - points .
 * @ param yPoints the y - points .
 * @ param nPoints the number of points to use for the polyline .
 * @ param close closed ?
 * @ return A polygon . */
public static GeneralPath createPolygon ( int [ ] xPoints , int [ ] yPoints , int nPoints , boolean close ) { } }

implementation: GeneralPath p = new GeneralPath ( ) ; p . moveTo ( xPoints [ 0 ] , yPoints [ 0 ] ) ; for ( int i = 1 ; i < nPoints ; i ++ ) { p . lineTo ( xPoints [ i ] , yPoints [ i ] ) ; } if ( close ) { p . closePath ( ) ; } return p ;


signature:
public class SVGGraphicsConfiguration { /** * Returns the color model for the specified transparency type , or
 * { @ code null } .
 * @ param transparency the transparency type .
 * @ return A color model ( possibly { @ code null } ) . */
@ Override public ColorModel getColorModel ( int transparency ) { } }

implementation: if ( transparency == Transparency . TRANSLUCENT ) { return ColorModel . getRGBdefault ( ) ; } else if ( transparency == Transparency . OPAQUE ) { return new DirectColorModel ( 32 , 0x00ff0000 , 0x0000ff00 , 0x000000ff ) ; } else { return null ; }


signature:
public class SVGGraphicsConfiguration { /** * Creates a compatible image . This override is only here to provide
 * support for Java 6 because from Java 7 onwards the super class has a
 * non - abstract implementation for this method .
 * @ param width the width .
 * @ param height the height .
 * @ return A compatible image . */
@ Override public BufferedImage createCompatibleImage ( int width , int height ) { } }

implementation: ColorModel model = getColorModel ( ) ; WritableRaster raster = model . createCompatibleWritableRaster ( width , height ) ; return new BufferedImage ( model , raster , model . isAlphaPremultiplied ( ) , null ) ;


signature:
public class SVGGraphicsConfiguration { /** * Returns a volatile image . This method is a workaround for a
 * ClassCastException that occurs on MacOSX when exporting a Swing UI
 * that uses the Nimbus Look and Feel to SVG .
 * @ param width the image width .
 * @ param height the image height .
 * @ param caps the image capabilities .
 * @ param transparency the transparency .
 * @ return The volatile image .
 * @ throws AWTException if there is a problem creating the image . */
@ Override public VolatileImage createCompatibleVolatileImage ( int width , int height , ImageCapabilities caps , int transparency ) throws AWTException { } }

implementation: if ( img == null ) { img = new BufferedImage ( 1 , 1 , BufferedImage . TYPE_INT_ARGB ) ; gc = img . createGraphics ( ) . getDeviceConfiguration ( ) ; } return gc . createCompatibleVolatileImage ( width , height , caps , transparency ) ;


signature:
public class Args { /** * Checks an array to ensure it has the correct length and throws an
 * { @ code IllegalArgumentException } if it does not .
 * @ param length the required length .
 * @ param array the array to check .
 * @ param ref the text name of the array parameter ( to include in the
 * exception message ) . */
public static void arrayMustHaveLength ( int length , boolean [ ] array , String ref ) { } }

implementation: nullNotPermitted ( array , "array" ) ; if ( array . length != length ) { throw new IllegalArgumentException ( "Array '" + ref + "' requires length " + length ) ; }


signature:
public class ViewBox { /** * Returns a string containing the view box coordinates and dimensions .
 * @ return A string containing the view box coordinates and dimensions . */
public String valueStr ( ) { } }

implementation: return new StringBuilder ( ) . append ( this . minX ) . append ( " " ) . append ( this . minY ) . append ( " " ) . append ( this . width ) . append ( " " ) . append ( this . height ) . toString ( ) ;


signature:
public class StandardFontMapper { /** * Returns the mapped ( alternate ) font family name .
 * @ param family the font family ( { @ code null } not permitted ) .
 * @ return The alternate font family name ( possibly { @ code null } ) . */
public String get ( String family ) { } }

implementation: Args . nullNotPermitted ( family , "family" ) ; return this . alternates . get ( family ) ;


signature:
public class StandardFontMapper { /** * Adds a font family mapping ( if the specified alternate is
 * { @ code null } it has the effect of clearing any existing mapping ) .
 * @ param family the font family name ( { @ code null } not permitted ) .
 * @ param alternate the alternate ( { @ code null } permitted ) . */
public void put ( String family , String alternate ) { } }

implementation: Args . nullNotPermitted ( family , "family" ) ; this . alternates . put ( family , alternate ) ;


signature:
public class StandardFontMapper { /** * Maps the specified font family name to an alternative , or else returns
 * the same family name .
 * @ param family the font family name ( { @ code null } not permitted ) .
 * @ return The same font family name or an alternative ( never { @ code null } ) . */
@ Override public String mapFont ( String family ) { } }

implementation: Args . nullNotPermitted ( family , "family" ) ; String alternate = this . alternates . get ( family ) ; if ( alternate != null ) { return alternate ; } return family ;


signature:
public class SVGGraphics2D { /** * Sets the value of the ' shape - rendering ' property that will be written to
 * the SVG element . Permitted values are " auto " , " crispEdges " ,
 * " geometricPrecision " , " inherit " and " optimizeSpeed " .
 * @ param value the new value .
 * @ since 2.0 */
public void setShapeRendering ( String value ) { } }

implementation: if ( ! value . equals ( "auto" ) && ! value . equals ( "crispEdges" ) && ! value . equals ( "geometricPrecision" ) && ! value . equals ( "optimizeSpeed" ) ) { throw new IllegalArgumentException ( "Unrecognised value: " + value ) ; } this . shapeRendering = value ;


signature:
public class SVGGraphics2D { /** * Sets the value of the ' text - rendering ' property that will be written to
 * the SVG element . Permitted values are " auto " , " optimizeSpeed " ,
 * " optimizeLegibility " and " geometricPrecision " .
 * @ param value the new value .
 * @ since 2.0 */
public void setTextRendering ( String value ) { } }

implementation: if ( ! value . equals ( "auto" ) && ! value . equals ( "optimizeSpeed" ) && ! value . equals ( "optimizeLegibility" ) && ! value . equals ( "geometricPrecision" ) ) { throw new IllegalArgumentException ( "Unrecognised value: " + value ) ; } this . textRendering = value ;


signature:
public class SVGGraphics2D { /** * Sets the number of decimal places used to write the transformation
 * matrices in the SVG output . Values in the range 1 to 10 will be used
 * to configure a formatter to that number of decimal places , for all other
 * values we revert to the normal { @ code String } conversion of
 * { @ code double } primitives ( approximately 16 decimals places ) .
 * Note that there is a separate attribute to control the number of decimal
 * places for geometrical elements in the output ( see
 * { @ link # setGeometryDP ( int ) } ) .
 * @ param dp the number of decimal places ( normally 1 to 10 ) .
 * @ see # getTransformDP ( ) */
public void setTransformDP ( int dp ) { } }

implementation: this . transformDP = dp ; if ( dp < 1 || dp > 10 ) { this . transformFormat = null ; return ; } DecimalFormatSymbols dfs = new DecimalFormatSymbols ( ) ; dfs . setDecimalSeparator ( '.' ) ; this . transformFormat = new DecimalFormat ( "0." + "##########" . substring ( 0 , dp ) , dfs ) ;


signature:
public class SVGGraphics2D { /** * Sets the number of decimal places used to write the coordinates of
 * geometrical shapes in the SVG output . Values in the range 1 to 10 will
 * be used to configure a formatter to that number of decimal places , for
 * all other values we revert to the normal String conversion of double
 * primitives ( approximately 16 decimals places ) .
 * Note that there is a separate attribute to control the number of decimal
 * places for transform matrices in the output ( see
 * { @ link # setTransformDP ( int ) } ) .
 * @ param dp the number of decimal places ( normally 1 to 10 ) . */
public void setGeometryDP ( int dp ) { } }

implementation: this . geometryDP = dp ; if ( dp < 1 || dp > 10 ) { this . geometryFormat = null ; return ; } DecimalFormatSymbols dfs = new DecimalFormatSymbols ( ) ; dfs . setDecimalSeparator ( '.' ) ; this . geometryFormat = new DecimalFormat ( "0." + "##########" . substring ( 0 , dp ) , dfs ) ;


signature:
public class SVGGraphics2D { /** * Returns the device configuration associated with this
 * { @ code Graphics2D } .
 * @ return The graphics configuration . */
@ Override public GraphicsConfiguration getDeviceConfiguration ( ) { } }

implementation: if ( this . deviceConfiguration == null ) { this . deviceConfiguration = new SVGGraphicsConfiguration ( this . width , this . height ) ; } return this . deviceConfiguration ;


signature:
public class SVGGraphics2D { /** * Creates a new graphics object that is a copy of this graphics object
 * ( except that it has not accumulated the drawing operations ) . Not sure
 * yet when or why this would be useful when creating SVG output . Note
 * that the { @ code fontMapper } object ( { @ link # getFontMapper ( ) } ) is shared
 * between the existing instance and the new one .
 * @ return A new graphics object . */
@ Override public Graphics create ( ) { } }

implementation: SVGGraphics2D copy = new SVGGraphics2D ( this ) ; copy . setRenderingHints ( getRenderingHints ( ) ) ; copy . setTransform ( getTransform ( ) ) ; copy . setClip ( getClip ( ) ) ; copy . setPaint ( getPaint ( ) ) ; copy . setColor ( getColor ( ) ) ; copy . setComposite ( getComposite ( ) ) ; copy . setStroke ( getStroke ( ) ) ; copy . setFont ( getFont ( ) ) ; copy . setBackground ( getBackground ( ) ) ; copy . setFilePrefix ( getFilePrefix ( ) ) ; copy . setFileSuffix ( getFileSuffix ( ) ) ; return copy ;


signature:
public class SVGGraphics2D { /** * Sets the paint used to draw or fill shapes ( or text ) . If
 * { @ code paint } is an instance of { @ code Color } , this method will
 * also update the current color attribute ( see { @ link # getColor ( ) } ) . If
 * you pass { @ code null } to this method , it does nothing ( in
 * accordance with the JDK specification ) .
 * @ param paint the paint ( { @ code null } is permitted but ignored ) .
 * @ see # getPaint ( ) */
@ Override public void setPaint ( Paint paint ) { } }

implementation: if ( paint == null ) { return ; } this . paint = paint ; this . gradientPaintRef = null ; if ( paint instanceof Color ) { setColor ( ( Color ) paint ) ; } else if ( paint instanceof GradientPaint ) { GradientPaint gp = ( GradientPaint ) paint ; GradientPaintKey key = new GradientPaintKey ( gp ) ; String ref = this . gradientPaints . get ( key ) ; if ( ref == null ) { int count = this . gradientPaints . keySet ( ) . size ( ) ; String id = this . defsKeyPrefix + "gp" + count ; this . elementIDs . add ( id ) ; this . gradientPaints . put ( key , id ) ; this . gradientPaintRef = id ; } else { this . gradientPaintRef = ref ; } } else if ( paint instanceof LinearGradientPaint ) { LinearGradientPaint lgp = ( LinearGradientPaint ) paint ; LinearGradientPaintKey key = new LinearGradientPaintKey ( lgp ) ; String ref = this . linearGradientPaints . get ( key ) ; if ( ref == null ) { int count = this . linearGradientPaints . keySet ( ) . size ( ) ; String id = this . defsKeyPrefix + "lgp" + count ; this . elementIDs . add ( id ) ; this . linearGradientPaints . put ( key , id ) ; this . gradientPaintRef = id ; } } else if ( paint instanceof RadialGradientPaint ) { RadialGradientPaint rgp = ( RadialGradientPaint ) paint ; RadialGradientPaintKey key = new RadialGradientPaintKey ( rgp ) ; String ref = this . radialGradientPaints . get ( key ) ; if ( ref == null ) { int count = this . radialGradientPaints . keySet ( ) . size ( ) ; String id = this . defsKeyPrefix + "rgp" + count ; this . elementIDs . add ( id ) ; this . radialGradientPaints . put ( key , id ) ; this . gradientPaintRef = id ; } }


signature:
public class SVGGraphics2D { /** * Sets the foreground color . This method exists for backwards
 * compatibility in AWT , you should use the
 * { @ link # setPaint ( java . awt . Paint ) } method .
 * @ param c the color ( { @ code null } permitted but ignored ) .
 * @ see # setPaint ( java . awt . Paint ) */
@ Override public void setColor ( Color c ) { } }

implementation: if ( c == null ) { return ; } this . color = c ; this . paint = c ;


signature:
public class SVGGraphics2D { /** * Sets the value for a hint . See the { @ link SVGHints } class for
 * information about the hints that can be used with this implementation .
 * @ param hintKey the hint key ( { @ code null } not permitted ) .
 * @ param hintValue the hint value .
 * @ see # getRenderingHint ( java . awt . RenderingHints . Key ) */
@ Override public void setRenderingHint ( RenderingHints . Key hintKey , Object hintValue ) { } }

implementation:
if ( hintKey == null ) { throw new NullPointerException ( "Null 'hintKey' not permitted." ) ; } // KEY _ BEGIN _ GROUP and KEY _ END _ GROUP are handled as special cases that
// never get stored in the hints map . . .
if ( SVGHints . isBeginGroupKey ( hintKey ) ) { String groupId = null ; String ref = null ; List < Entry > otherKeysAndValues = null ; if ( hintValue instanceof String ) { groupId = ( String ) hintValue ; } else if ( hintValue instanceof Map ) { Map hintValueMap = ( Map ) hintValue ; groupId = ( String ) hintValueMap . get ( "id" ) ; ref = ( String ) hintValueMap . get ( "ref" ) ; for ( final Object obj : hintValueMap . entrySet ( ) ) { final Entry e = ( Entry ) obj ; final Object key = e . getKey ( ) ; if ( "id" . equals ( key ) || "ref" . equals ( key ) ) { continue ; } if ( otherKeysAndValues == null ) { otherKeysAndValues = new ArrayList < Entry > ( ) ; } otherKeysAndValues . add ( e ) ; } } this . sb . append ( "<g" ) ; if ( groupId != null ) { if ( this . elementIDs . contains ( groupId ) ) { throw new IllegalArgumentException ( "The group id (" + groupId + ") is not unique." ) ; } else { this . sb . append ( " id=\"" ) . append ( groupId ) . append ( "\"" ) ; this . elementIDs . add ( groupId ) ; } } if ( ref != null ) { this . sb . append ( " jfreesvg:ref=\"" ) ; this . sb . append ( SVGUtils . escapeForXML ( ref ) ) . append ( "\"" ) ; } if ( otherKeysAndValues != null ) { for ( final Entry e : otherKeysAndValues ) { this . sb . append ( " " ) . append ( e . getKey ( ) ) . append ( "=\"" ) ; this . sb . append ( SVGUtils . escapeForXML ( String . valueOf ( e . getValue ( ) ) ) ) . append ( "\"" ) ; } } this . sb . append ( ">" ) ; } else if ( SVGHints . isEndGroupKey ( hintKey ) ) { this . sb . append ( "</g>\n" ) ; } else if ( SVGHints . isElementTitleKey ( hintKey ) && ( hintValue != null ) ) { this . sb . append ( "<title>" ) ; this . sb . append ( SVGUtils . escapeForXML ( String . valueOf ( hintValue ) ) ) ; this . sb . append ( "</title>" ) ; } else { this . hints . put ( hintKey , hintValue ) ; }


signature:
public class SVGGraphics2D { /** * A utility method that appends an optional element id if one is
 * specified via the rendering hints .
 * @ param sb the string builder ( { @ code null } not permitted ) . */
private void appendOptionalElementIDFromHint ( StringBuilder sb ) { } }

implementation:
String elementID = ( String ) this . hints . get ( SVGHints . KEY_ELEMENT_ID ) ; if ( elementID != null ) { this . hints . put ( SVGHints . KEY_ELEMENT_ID , null ) ; // clear it
if ( this . elementIDs . contains ( elementID ) ) { throw new IllegalStateException ( "The element id " + elementID + " is already used." ) ; } else { this . elementIDs . add ( elementID ) ; } this . sb . append ( "id=\"" ) . append ( elementID ) . append ( "\" " ) ; }


signature:
public class SVGGraphics2D { /** * Draws the specified shape with the current { @ code paint } and
 * { @ code stroke } . There is direct handling for { @ code Line2D } ,
 * { @ code Rectangle2D } , { @ code Ellipse2D } and { @ code Path2D } . All other
 * shapes are mapped to a { @ code GeneralPath } and then drawn ( effectively
 * as { @ code Path2D } objects ) .
 * @ param s the shape ( { @ code null } not permitted ) .
 * @ see # fill ( java . awt . Shape ) */
@ Override public void draw ( Shape s ) { } }

implementation:
// if the current stroke is not a BasicStroke then it is handled as
// a special case
if ( ! ( this . stroke instanceof BasicStroke ) ) { fill ( this . stroke . createStrokedShape ( s ) ) ; return ; } if ( s instanceof Line2D ) { Line2D l = ( Line2D ) s ; this . sb . append ( "<line " ) ; appendOptionalElementIDFromHint ( this . sb ) ; this . sb . append ( "x1=\"" ) . append ( geomDP ( l . getX1 ( ) ) ) . append ( "\" y1=\"" ) . append ( geomDP ( l . getY1 ( ) ) ) . append ( "\" x2=\"" ) . append ( geomDP ( l . getX2 ( ) ) ) . append ( "\" y2=\"" ) . append ( geomDP ( l . getY2 ( ) ) ) . append ( "\" " ) ; this . sb . append ( "style=\"" ) . append ( strokeStyle ( ) ) . append ( "\" " ) ; if ( ! this . transform . isIdentity ( ) ) { this . sb . append ( "transform=\"" ) . append ( getSVGTransform ( this . transform ) ) . append ( "\" " ) ; } this . sb . append ( getClipPathRef ( ) ) ; this . sb . append ( "/>" ) ; } else if ( s instanceof Rectangle2D ) { Rectangle2D r = ( Rectangle2D ) s ; this . sb . append ( "<rect " ) ; appendOptionalElementIDFromHint ( this . sb ) ; this . sb . append ( "x=\"" ) . append ( geomDP ( r . getX ( ) ) ) . append ( "\" y=\"" ) . append ( geomDP ( r . getY ( ) ) ) . append ( "\" width=\"" ) . append ( geomDP ( r . getWidth ( ) ) ) . append ( "\" height=\"" ) . append ( geomDP ( r . getHeight ( ) ) ) . append ( "\" " ) ; this . sb . append ( "style=\"" ) . append ( strokeStyle ( ) ) . append ( "; fill: none" ) . append ( "\" " ) ; if ( ! this . transform . isIdentity ( ) ) { this . sb . append ( "transform=\"" ) . append ( getSVGTransform ( this . transform ) ) . append ( "\" " ) ; } this . sb . append ( getClipPathRef ( ) ) ; this . sb . append ( "/>" ) ; } else if ( s instanceof Ellipse2D ) { Ellipse2D e = ( Ellipse2D ) s ; this . sb . append ( "<ellipse " ) ; appendOptionalElementIDFromHint ( this . sb ) ; this . sb . append ( "cx=\"" ) . append ( geomDP ( e . getCenterX ( ) ) ) . append ( "\" cy=\"" ) . append ( geomDP ( e . getCenterY ( ) ) ) . append ( "\" rx=\"" ) . append ( geomDP ( e . getWidth ( ) / 2.0 ) ) . append ( "\" ry=\"" ) . append ( geomDP ( e . getHeight ( ) / 2.0 ) ) . append ( "\" " ) ; this . sb . append ( "style=\"" ) . append ( strokeStyle ( ) ) . append ( "; fill: none" ) . append ( "\" " ) ; if ( ! this . transform . isIdentity ( ) ) { this . sb . append ( "transform=\"" ) . append ( getSVGTransform ( this . transform ) ) . append ( "\" " ) ; } this . sb . append ( getClipPathRef ( ) ) ; this . sb . append ( "/>" ) ; } else if ( s instanceof Path2D ) { Path2D path = ( Path2D ) s ; this . sb . append ( "<g " ) ; appendOptionalElementIDFromHint ( this . sb ) ; this . sb . append ( "style=\"" ) . append ( strokeStyle ( ) ) . append ( "; fill: none" ) . append ( "\" " ) ; if ( ! this . transform . isIdentity ( ) ) { this . sb . append ( "transform=\"" ) . append ( getSVGTransform ( this . transform ) ) . append ( "\" " ) ; } this . sb . append ( getClipPathRef ( ) ) ; this . sb . append ( ">" ) ; this . sb . append ( "<path " ) . append ( getSVGPathData ( path ) ) . append ( "/>" ) ; this . sb . append ( "</g>" ) ; } else { draw ( new GeneralPath ( s ) ) ; // handled as a Path2D next time through
}


signature:
public class SVGGraphics2D { /** * Fills the specified shape with the current { @ code paint } . There is
 * direct handling for { @ code Rectangle2D } , { @ code Ellipse2D } and
 * { @ code Path2D } . All other shapes are mapped to a { @ code GeneralPath }
 * and then filled .
 * @ param s the shape ( { @ code null } not permitted ) .
 * @ see # draw ( java . awt . Shape ) */
@ Override public void fill ( Shape s ) { } }

implementation:
if ( s instanceof Rectangle2D ) { Rectangle2D r = ( Rectangle2D ) s ; if ( r . isEmpty ( ) ) { return ; } this . sb . append ( "<rect " ) ; appendOptionalElementIDFromHint ( this . sb ) ; this . sb . append ( "x=\"" ) . append ( geomDP ( r . getX ( ) ) ) . append ( "\" y=\"" ) . append ( geomDP ( r . getY ( ) ) ) . append ( "\" width=\"" ) . append ( geomDP ( r . getWidth ( ) ) ) . append ( "\" height=\"" ) . append ( geomDP ( r . getHeight ( ) ) ) . append ( "\" " ) ; this . sb . append ( "style=\"" ) . append ( getSVGFillStyle ( ) ) . append ( "\" " ) ; if ( ! this . transform . isIdentity ( ) ) { this . sb . append ( "transform=\"" ) . append ( getSVGTransform ( this . transform ) ) . append ( "\" " ) ; } this . sb . append ( getClipPathRef ( ) ) ; this . sb . append ( "/>" ) ; } else if ( s instanceof Ellipse2D ) { Ellipse2D e = ( Ellipse2D ) s ; this . sb . append ( "<ellipse " ) ; appendOptionalElementIDFromHint ( this . sb ) ; this . sb . append ( "cx=\"" ) . append ( geomDP ( e . getCenterX ( ) ) ) . append ( "\" cy=\"" ) . append ( geomDP ( e . getCenterY ( ) ) ) . append ( "\" rx=\"" ) . append ( geomDP ( e . getWidth ( ) / 2.0 ) ) . append ( "\" ry=\"" ) . append ( geomDP ( e . getHeight ( ) / 2.0 ) ) . append ( "\" " ) ; this . sb . append ( "style=\"" ) . append ( getSVGFillStyle ( ) ) . append ( "\" " ) ; if ( ! this . transform . isIdentity ( ) ) { this . sb . append ( "transform=\"" ) . append ( getSVGTransform ( this . transform ) ) . append ( "\" " ) ; } this . sb . append ( getClipPathRef ( ) ) ; this . sb . append ( "/>" ) ; } else if ( s instanceof Path2D ) { Path2D path = ( Path2D ) s ; this . sb . append ( "<g " ) ; appendOptionalElementIDFromHint ( this . sb ) ; this . sb . append ( "style=\"" ) . append ( getSVGFillStyle ( ) ) ; this . sb . append ( "; stroke: none" ) . append ( "\" " ) ; if ( ! this . transform . isIdentity ( ) ) { this . sb . append ( "transform=\"" ) . append ( getSVGTransform ( this . transform ) ) . append ( "\" " ) ; } this . sb . append ( getClipPathRef ( ) ) ; this . sb . append ( ">" ) ; this . sb . append ( "<path " ) . append ( getSVGPathData ( path ) ) . append ( "/>" ) ; this . sb . append ( "</g>" ) ; } else { fill ( new GeneralPath ( s ) ) ; // handled as a Path2D next time through
}


signature:
public class SVGGraphics2D { /** * Creates an SVG path string for the supplied Java2D path .
 * @ param path the path ( { @ code null } not permitted ) .
 * @ return An SVG path string . */
private String getSVGPathData ( Path2D path ) { } }

implementation: StringBuilder b = new StringBuilder ( "d=\"" ) ; float [ ] coords = new float [ 6 ] ; boolean first = true ; PathIterator iterator = path . getPathIterator ( null ) ; while ( ! iterator . isDone ( ) ) { int type = iterator . currentSegment ( coords ) ; if ( ! first ) { b . append ( " " ) ; } first = false ; switch ( type ) { case ( PathIterator . SEG_MOVETO ) : b . append ( "M " ) . append ( geomDP ( coords [ 0 ] ) ) . append ( " " ) . append ( geomDP ( coords [ 1 ] ) ) ; break ; case ( PathIterator . SEG_LINETO ) : b . append ( "L " ) . append ( geomDP ( coords [ 0 ] ) ) . append ( " " ) . append ( geomDP ( coords [ 1 ] ) ) ; break ; case ( PathIterator . SEG_QUADTO ) : b . append ( "Q " ) . append ( geomDP ( coords [ 0 ] ) ) . append ( " " ) . append ( geomDP ( coords [ 1 ] ) ) . append ( " " ) . append ( geomDP ( coords [ 2 ] ) ) . append ( " " ) . append ( geomDP ( coords [ 3 ] ) ) ; break ; case ( PathIterator . SEG_CUBICTO ) : b . append ( "C " ) . append ( geomDP ( coords [ 0 ] ) ) . append ( " " ) . append ( geomDP ( coords [ 1 ] ) ) . append ( " " ) . append ( geomDP ( coords [ 2 ] ) ) . append ( " " ) . append ( geomDP ( coords [ 3 ] ) ) . append ( " " ) . append ( geomDP ( coords [ 4 ] ) ) . append ( " " ) . append ( geomDP ( coords [ 5 ] ) ) ; break ; case ( PathIterator . SEG_CLOSE ) : b . append ( "Z " ) ; break ; default : break ; } iterator . next ( ) ; } return b . append ( "\"" ) . toString ( ) ;


signature:
public class SVGGraphics2D { /** * Returns the current alpha ( transparency ) in the range 0.0 to 1.0.
 * If the current composite is an { @ link AlphaComposite } we read the alpha
 * value from there , otherwise this method returns 1.0.
 * @ return The current alpha ( transparency ) in the range 0.0 to 1.0. */
private float getAlpha ( ) { } }

implementation: float alpha = 1.0f ; if ( this . composite instanceof AlphaComposite ) { AlphaComposite ac = ( AlphaComposite ) this . composite ; alpha = ac . getAlpha ( ) ; } return alpha ;


signature:
public class SVGGraphics2D { /** * Returns an SVG color string based on the current paint . To handle
 * { @ code GradientPaint } we rely on the { @ code setPaint ( ) } method
 * having set the { @ code gradientPaintRef } attribute .
 * @ return An SVG color string . */
private String svgColorStr ( ) { } }

implementation: String result = "black;" ; if ( this . paint instanceof Color ) { return rgbColorStr ( ( Color ) this . paint ) ; } else if ( this . paint instanceof GradientPaint || this . paint instanceof LinearGradientPaint || this . paint instanceof RadialGradientPaint ) { return "url(#" + this . gradientPaintRef + ")" ; } return result ;


signature:
public class SVGGraphics2D { /** * Returns the SVG RGB color string for the specified color .
 * @ param c the color ( { @ code null } not permitted ) .
 * @ return The SVG RGB color string . */
private String rgbColorStr ( Color c ) { } }

implementation: StringBuilder b = new StringBuilder ( "rgb(" ) ; b . append ( c . getRed ( ) ) . append ( "," ) . append ( c . getGreen ( ) ) . append ( "," ) . append ( c . getBlue ( ) ) . append ( ")" ) ; return b . toString ( ) ;


signature:
public class SVGGraphics2D { /** * Returns a string representing the specified color in RGBA format .
 * @ param c the color ( { @ code null } not permitted ) .
 * @ return The SVG RGBA color string . */
private String rgbaColorStr ( Color c ) { } }

implementation: StringBuilder b = new StringBuilder ( "rgba(" ) ; double alphaPercent = c . getAlpha ( ) / 255.0 ; b . append ( c . getRed ( ) ) . append ( "," ) . append ( c . getGreen ( ) ) . append ( "," ) . append ( c . getBlue ( ) ) ; b . append ( "," ) . append ( transformDP ( alphaPercent ) ) ; b . append ( ")" ) ; return b . toString ( ) ;


signature:
public class SVGGraphics2D { /** * Returns a stroke style string based on the current stroke and
 * alpha settings .
 * @ return A stroke style string . */
private String strokeStyle ( ) { } }

implementation:
double strokeWidth = 1.0f ; String strokeCap = DEFAULT_STROKE_CAP ; String strokeJoin = DEFAULT_STROKE_JOIN ; float miterLimit = DEFAULT_MITER_LIMIT ; float [ ] dashArray = new float [ 0 ] ; if ( this . stroke instanceof BasicStroke ) { BasicStroke bs = ( BasicStroke ) this . stroke ; strokeWidth = bs . getLineWidth ( ) > 0.0 ? bs . getLineWidth ( ) : this . zeroStrokeWidth ; switch ( bs . getEndCap ( ) ) { case BasicStroke . CAP_ROUND : strokeCap = "round" ; break ; case BasicStroke . CAP_SQUARE : strokeCap = "square" ; break ; case BasicStroke . CAP_BUTT : default : // already set to " butt "
} switch ( bs . getLineJoin ( ) ) { case BasicStroke . JOIN_BEVEL : strokeJoin = "bevel" ; break ; case BasicStroke . JOIN_ROUND : strokeJoin = "round" ; break ; case BasicStroke . JOIN_MITER : default : // already set to " miter "
} miterLimit = bs . getMiterLimit ( ) ; dashArray = bs . getDashArray ( ) ; } StringBuilder b = new StringBuilder ( ) ; b . append ( "stroke-width: " ) . append ( strokeWidth ) . append ( ";" ) ; b . append ( "stroke: " ) . append ( svgColorStr ( ) ) . append ( ";" ) ; b . append ( "stroke-opacity: " ) . append ( getColorAlpha ( ) * getAlpha ( ) ) . append ( ";" ) ; if ( ! strokeCap . equals ( DEFAULT_STROKE_CAP ) ) { b . append ( "stroke-linecap: " ) . append ( strokeCap ) . append ( ";" ) ; } if ( ! strokeJoin . equals ( DEFAULT_STROKE_JOIN ) ) { b . append ( "stroke-linejoin: " ) . append ( strokeJoin ) . append ( ";" ) ; } if ( Math . abs ( DEFAULT_MITER_LIMIT - miterLimit ) < 0.001 ) { b . append ( "stroke-miterlimit: " ) . append ( geomDP ( miterLimit ) ) ; } if ( dashArray != null && dashArray . length != 0 ) { b . append ( "stroke-dasharray: " ) ; for ( int i = 0 ; i < dashArray . length ; i ++ ) { if ( i != 0 ) b . append ( ", " ) ; b . append ( dashArray [ i ] ) ; } b . append ( ";" ) ; } if ( this . checkStrokeControlHint ) { Object hint = getRenderingHint ( RenderingHints . KEY_STROKE_CONTROL ) ; if ( RenderingHints . VALUE_STROKE_NORMALIZE . equals ( hint ) && ! this . shapeRendering . equals ( "crispEdges" ) ) { b . append ( "shape-rendering:crispEdges;" ) ; } if ( RenderingHints . VALUE_STROKE_PURE . equals ( hint ) && ! this . shapeRendering . equals ( "geometricPrecision" ) ) { b . append ( "shape-rendering:geometricPrecision;" ) ; } } return b . toString ( ) ;


signature:
public class SVGGraphics2D { /** * Returns a fill style string based on the current paint and
 * alpha settings .
 * @ return A fill style string . */
private String getSVGFillStyle ( ) { } }

implementation: StringBuilder b = new StringBuilder ( ) ; b . append ( "fill: " ) . append ( svgColorStr ( ) ) . append ( "; " ) ; b . append ( "fill-opacity: " ) . append ( getColorAlpha ( ) * getAlpha ( ) ) ; return b . toString ( ) ;


signature:
public class SVGGraphics2D { /** * Returns a string containing font style info .
 * @ return A string containing font style info . */
private String getSVGFontStyle ( ) { } }

implementation: StringBuilder b = new StringBuilder ( ) ; b . append ( "fill: " ) . append ( svgColorStr ( ) ) . append ( "; " ) ; b . append ( "fill-opacity: " ) . append ( getColorAlpha ( ) * getAlpha ( ) ) . append ( "; " ) ; String fontFamily = this . fontMapper . mapFont ( this . font . getFamily ( ) ) ; b . append ( "font-family: " ) . append ( fontFamily ) . append ( "; " ) ; b . append ( "font-size: " ) . append ( this . font . getSize ( ) ) . append ( this . fontSizeUnits ) . append ( ";" ) ; if ( this . font . isBold ( ) ) { b . append ( " font-weight: bold;" ) ; } if ( this . font . isItalic ( ) ) { b . append ( " font-style: italic;" ) ; } return b . toString ( ) ;


signature:
public class SVGGraphics2D { /** * Returns the font metrics for the specified font .
 * @ param f the font .
 * @ return The font metrics . */
@ Override public FontMetrics getFontMetrics ( Font f ) { } }

implementation: if ( this . fmImage == null ) { this . fmImage = new BufferedImage ( 10 , 10 , BufferedImage . TYPE_INT_RGB ) ; this . fmImageG2D = this . fmImage . createGraphics ( ) ; this . fmImageG2D . setRenderingHint ( RenderingHints . KEY_FRACTIONALMETRICS , RenderingHints . VALUE_FRACTIONALMETRICS_ON ) ; } return this . fmImageG2D . getFontMetrics ( f ) ;


signature:
public class SVGGraphics2D { /** * Draws a string at { @ code ( x , y ) } . The start of the text at the
 * baseline level will be aligned with the { @ code ( x , y ) } point .
 * < br > < br >
 * Note that you can make use of the { @ link SVGHints # KEY _ TEXT _ RENDERING }
 * hint when drawing strings ( this is completely optional though ) .
 * @ param str the string ( { @ code null } not permitted ) .
 * @ param x the x - coordinate .
 * @ param y the y - coordinate . */
@ Override public void drawString ( String str , float x , float y ) { } }

implementation: if ( str == null ) { throw new NullPointerException ( "Null 'str' argument." ) ; } if ( str . isEmpty ( ) ) { return ; } if ( ! SVGHints . VALUE_DRAW_STRING_TYPE_VECTOR . equals ( this . hints . get ( SVGHints . KEY_DRAW_STRING_TYPE ) ) ) { this . sb . append ( "<g " ) ; appendOptionalElementIDFromHint ( this . sb ) ; if ( ! this . transform . isIdentity ( ) ) { this . sb . append ( "transform=\"" ) . append ( getSVGTransform ( this . transform ) ) . append ( "\"" ) ; } this . sb . append ( ">" ) ; this . sb . append ( "<text x=\"" ) . append ( geomDP ( x ) ) . append ( "\" y=\"" ) . append ( geomDP ( y ) ) . append ( "\"" ) ; this . sb . append ( " style=\"" ) . append ( getSVGFontStyle ( ) ) . append ( "\"" ) ; Object hintValue = getRenderingHint ( SVGHints . KEY_TEXT_RENDERING ) ; if ( hintValue != null ) { String textRenderValue = hintValue . toString ( ) ; this . sb . append ( " text-rendering=\"" ) . append ( textRenderValue ) . append ( "\"" ) ; } this . sb . append ( " " ) . append ( getClipPathRef ( ) ) ; this . sb . append ( ">" ) ; this . sb . append ( SVGUtils . escapeForXML ( str ) ) . append ( "</text>" ) ; this . sb . append ( "</g>" ) ; } else { AttributedString as = new AttributedString ( str , this . font . getAttributes ( ) ) ; drawString ( as . getIterator ( ) , x , y ) ; }


signature:
public class SVGGraphics2D { /** * Draws a string of attributed characters at { @ code ( x , y ) } . The
 * call is delegated to
 * { @ link # drawString ( AttributedCharacterIterator , float , float ) } .
 * @ param iterator an iterator for the characters .
 * @ param x the x - coordinate .
 * @ param y the x - coordinate . */
@ Override public void drawString ( AttributedCharacterIterator iterator , int x , int y ) { } }

implementation: drawString ( iterator , ( float ) x , ( float ) y ) ;


signature:
public class SVGGraphics2D { /** * Draws a string of attributed characters at { @ code ( x , y ) } .
 * @ param iterator an iterator over the characters ( { @ code null } not
 * permitted ) .
 * @ param x the x - coordinate .
 * @ param y the y - coordinate . */
@ Override public void drawString ( AttributedCharacterIterator iterator , float x , float y ) { } }

implementation: Set < Attribute > s = iterator . getAllAttributeKeys ( ) ; if ( ! s . isEmpty ( ) ) { TextLayout layout = new TextLayout ( iterator , getFontRenderContext ( ) ) ; layout . draw ( this , x , y ) ; } else { StringBuilder strb = new StringBuilder ( ) ; iterator . first ( ) ; for ( int i = iterator . getBeginIndex ( ) ; i < iterator . getEndIndex ( ) ; i ++ ) { strb . append ( iterator . current ( ) ) ; iterator . next ( ) ; } drawString ( strb . toString ( ) , x , y ) ; }