Home | History | Annotate | Download | only in method
      1 /*
      2  * Copyright (C) 2006 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.text.method;
     18 
     19 import android.graphics.Rect;
     20 import android.text.Editable;
     21 import android.text.GetChars;
     22 import android.text.Spannable;
     23 import android.text.Spanned;
     24 import android.text.SpannedString;
     25 import android.text.TextUtils;
     26 import android.view.View;
     27 
     28 /**
     29  * This transformation method causes the characters in the {@link #getOriginal}
     30  * array to be replaced by the corresponding characters in the
     31  * {@link #getReplacement} array.
     32  */
     33 public abstract class ReplacementTransformationMethod
     34 implements TransformationMethod
     35 {
     36     /**
     37      * Returns the list of characters that are to be replaced by other
     38      * characters when displayed.
     39      */
     40     protected abstract char[] getOriginal();
     41     /**
     42      * Returns a parallel array of replacement characters for the ones
     43      * that are to be replaced.
     44      */
     45     protected abstract char[] getReplacement();
     46 
     47     /**
     48      * Returns a CharSequence that will mirror the contents of the
     49      * source CharSequence but with the characters in {@link #getOriginal}
     50      * replaced by ones from {@link #getReplacement}.
     51      */
     52     public CharSequence getTransformation(CharSequence source, View v) {
     53         char[] original = getOriginal();
     54         char[] replacement = getReplacement();
     55 
     56         /*
     57          * Short circuit for faster display if the text will never change.
     58          */
     59         if (!(source instanceof Editable)) {
     60             /*
     61              * Check whether the text does not contain any of the
     62              * source characters so can be used unchanged.
     63              */
     64             boolean doNothing = true;
     65             int n = original.length;
     66             for (int i = 0; i < n; i++) {
     67                 if (TextUtils.indexOf(source, original[i]) >= 0) {
     68                     doNothing = false;
     69                     break;
     70                 }
     71             }
     72             if (doNothing) {
     73                 return source;
     74             }
     75 
     76             if (!(source instanceof Spannable)) {
     77                 /*
     78                  * The text contains some of the source characters,
     79                  * but they can be flattened out now instead of
     80                  * at display time.
     81                  */
     82                 if (source instanceof Spanned) {
     83                     return new SpannedString(new SpannedReplacementCharSequence(
     84                                                         (Spanned) source,
     85                                                         original, replacement));
     86                 } else {
     87                     return new ReplacementCharSequence(source,
     88                                                        original,
     89                                                        replacement).toString();
     90                 }
     91             }
     92         }
     93 
     94         if (source instanceof Spanned) {
     95             return new SpannedReplacementCharSequence((Spanned) source,
     96                                                       original, replacement);
     97         } else {
     98             return new ReplacementCharSequence(source, original, replacement);
     99         }
    100     }
    101 
    102     public void onFocusChanged(View view, CharSequence sourceText,
    103                                boolean focused, int direction,
    104                                Rect previouslyFocusedRect) {
    105         // This callback isn't used.
    106     }
    107 
    108     private static class ReplacementCharSequence
    109     implements CharSequence, GetChars {
    110         private char[] mOriginal, mReplacement;
    111 
    112         public ReplacementCharSequence(CharSequence source, char[] original,
    113                                        char[] replacement) {
    114             mSource = source;
    115             mOriginal = original;
    116             mReplacement = replacement;
    117         }
    118 
    119         public int length() {
    120             return mSource.length();
    121         }
    122 
    123         public char charAt(int i) {
    124             char c = mSource.charAt(i);
    125 
    126             int n = mOriginal.length;
    127             for (int j = 0; j < n; j++) {
    128                 if (c == mOriginal[j]) {
    129                     c = mReplacement[j];
    130                 }
    131             }
    132 
    133             return c;
    134         }
    135 
    136         public CharSequence subSequence(int start, int end) {
    137             char[] c = new char[end - start];
    138 
    139             getChars(start, end, c, 0);
    140             return new String(c);
    141         }
    142 
    143         public String toString() {
    144             char[] c = new char[length()];
    145 
    146             getChars(0, length(), c, 0);
    147             return new String(c);
    148         }
    149 
    150         public void getChars(int start, int end, char[] dest, int off) {
    151             TextUtils.getChars(mSource, start, end, dest, off);
    152             int offend = end - start + off;
    153             int n = mOriginal.length;
    154 
    155             for (int i = off; i < offend; i++) {
    156                 char c = dest[i];
    157 
    158                 for (int j = 0; j < n; j++) {
    159                     if (c == mOriginal[j]) {
    160                         dest[i] = mReplacement[j];
    161                     }
    162                 }
    163             }
    164         }
    165 
    166         private CharSequence mSource;
    167     }
    168 
    169     private static class SpannedReplacementCharSequence
    170     extends ReplacementCharSequence
    171     implements Spanned
    172     {
    173         public SpannedReplacementCharSequence(Spanned source, char[] original,
    174                                               char[] replacement) {
    175             super(source, original, replacement);
    176             mSpanned = source;
    177         }
    178 
    179         public CharSequence subSequence(int start, int end) {
    180             return new SpannedString(this).subSequence(start, end);
    181         }
    182 
    183         public <T> T[] getSpans(int start, int end, Class<T> type) {
    184             return mSpanned.getSpans(start, end, type);
    185         }
    186 
    187         public int getSpanStart(Object tag) {
    188             return mSpanned.getSpanStart(tag);
    189         }
    190 
    191         public int getSpanEnd(Object tag) {
    192             return mSpanned.getSpanEnd(tag);
    193         }
    194 
    195         public int getSpanFlags(Object tag) {
    196             return mSpanned.getSpanFlags(tag);
    197         }
    198 
    199         public int nextSpanTransition(int start, int end, Class type) {
    200             return mSpanned.nextSpanTransition(start, end, type);
    201         }
    202 
    203         private Spanned mSpanned;
    204     }
    205 }
    206