• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * 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, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */
16 
17 package com.android.inputmethod.latin;
18 
19 import com.android.inputmethod.latin.StringUtils;
20 
21 import java.util.Locale;
22 
23 /**
24  * The status of the current recapitalize process.
25  */
26 public class RecapitalizeStatus {
27     public static final int NOT_A_RECAPITALIZE_MODE = -1;
28     public static final int CAPS_MODE_ORIGINAL_MIXED_CASE = 0;
29     public static final int CAPS_MODE_ALL_LOWER = 1;
30     public static final int CAPS_MODE_FIRST_WORD_UPPER = 2;
31     public static final int CAPS_MODE_ALL_UPPER = 3;
32     // When adding a new mode, don't forget to update the CAPS_MODE_LAST constant.
33     public static final int CAPS_MODE_LAST = CAPS_MODE_ALL_UPPER;
34 
35     private static final int[] ROTATION_STYLE = {
36         CAPS_MODE_ORIGINAL_MIXED_CASE,
37         CAPS_MODE_ALL_LOWER,
38         CAPS_MODE_FIRST_WORD_UPPER,
39         CAPS_MODE_ALL_UPPER
40     };
41 
getStringMode(final String string, final String separators)42     private static final int getStringMode(final String string, final String separators) {
43         if (StringUtils.isIdenticalAfterUpcase(string)) {
44             return CAPS_MODE_ALL_UPPER;
45         } else if (StringUtils.isIdenticalAfterDowncase(string)) {
46             return CAPS_MODE_ALL_LOWER;
47         } else if (StringUtils.isIdenticalAfterCapitalizeEachWord(string, separators)) {
48             return CAPS_MODE_FIRST_WORD_UPPER;
49         } else {
50             return CAPS_MODE_ORIGINAL_MIXED_CASE;
51         }
52     }
53 
54     /**
55      * We store the location of the cursor and the string that was there before the recapitalize
56      * action was done, and the location of the cursor and the string that was there after.
57      */
58     private int mCursorStartBefore;
59     private String mStringBefore;
60     private int mCursorStartAfter;
61     private int mCursorEndAfter;
62     private int mRotationStyleCurrentIndex;
63     private boolean mSkipOriginalMixedCaseMode;
64     private Locale mLocale;
65     private String mSeparators;
66     private String mStringAfter;
67     private boolean mIsActive;
68 
RecapitalizeStatus()69     public RecapitalizeStatus() {
70         // By default, initialize with dummy values that won't match any real recapitalize.
71         initialize(-1, -1, "", Locale.getDefault(), "");
72         deactivate();
73     }
74 
initialize(final int cursorStart, final int cursorEnd, final String string, final Locale locale, final String separators)75     public void initialize(final int cursorStart, final int cursorEnd, final String string,
76             final Locale locale, final String separators) {
77         mCursorStartBefore = cursorStart;
78         mStringBefore = string;
79         mCursorStartAfter = cursorStart;
80         mCursorEndAfter = cursorEnd;
81         mStringAfter = string;
82         final int initialMode = getStringMode(mStringBefore, separators);
83         mLocale = locale;
84         mSeparators = separators;
85         if (CAPS_MODE_ORIGINAL_MIXED_CASE == initialMode) {
86             mRotationStyleCurrentIndex = 0;
87             mSkipOriginalMixedCaseMode = false;
88         } else {
89             // Find the current mode in the array.
90             int currentMode;
91             for (currentMode = ROTATION_STYLE.length - 1; currentMode > 0; --currentMode) {
92                 if (ROTATION_STYLE[currentMode] == initialMode) {
93                     break;
94                 }
95             }
96             mRotationStyleCurrentIndex = currentMode;
97             mSkipOriginalMixedCaseMode = true;
98         }
99         mIsActive = true;
100     }
101 
deactivate()102     public void deactivate() {
103         mIsActive = false;
104     }
105 
isActive()106     public boolean isActive() {
107         return mIsActive;
108     }
109 
isSetAt(final int cursorStart, final int cursorEnd)110     public boolean isSetAt(final int cursorStart, final int cursorEnd) {
111         return cursorStart == mCursorStartAfter && cursorEnd == mCursorEndAfter;
112     }
113 
114     /**
115      * Rotate through the different possible capitalization modes.
116      */
rotate()117     public void rotate() {
118         final String oldResult = mStringAfter;
119         int count = 0; // Protection against infinite loop.
120         do {
121             mRotationStyleCurrentIndex = (mRotationStyleCurrentIndex + 1) % ROTATION_STYLE.length;
122             if (CAPS_MODE_ORIGINAL_MIXED_CASE == ROTATION_STYLE[mRotationStyleCurrentIndex]
123                     && mSkipOriginalMixedCaseMode) {
124                 mRotationStyleCurrentIndex =
125                         (mRotationStyleCurrentIndex + 1) % ROTATION_STYLE.length;
126             }
127             ++count;
128             switch (ROTATION_STYLE[mRotationStyleCurrentIndex]) {
129             case CAPS_MODE_ORIGINAL_MIXED_CASE:
130                 mStringAfter = mStringBefore;
131                 break;
132             case CAPS_MODE_ALL_LOWER:
133                 mStringAfter = mStringBefore.toLowerCase(mLocale);
134                 break;
135             case CAPS_MODE_FIRST_WORD_UPPER:
136                 mStringAfter = StringUtils.capitalizeEachWord(mStringBefore, mSeparators,
137                         mLocale);
138                 break;
139             case CAPS_MODE_ALL_UPPER:
140                 mStringAfter = mStringBefore.toUpperCase(mLocale);
141                 break;
142             default:
143                 mStringAfter = mStringBefore;
144             }
145         } while (mStringAfter.equals(oldResult) && count < ROTATION_STYLE.length + 1);
146         mCursorEndAfter = mCursorStartAfter + mStringAfter.length();
147     }
148 
149     /**
150      * Remove leading/trailing whitespace from the considered string.
151      */
trim()152     public void trim() {
153         final int len = mStringBefore.length();
154         int nonWhitespaceStart = 0;
155         for (; nonWhitespaceStart < len;
156                 nonWhitespaceStart = mStringBefore.offsetByCodePoints(nonWhitespaceStart, 1)) {
157             final int codePoint = mStringBefore.codePointAt(nonWhitespaceStart);
158             if (!Character.isWhitespace(codePoint)) break;
159         }
160         int nonWhitespaceEnd = len;
161         for (; nonWhitespaceEnd > 0;
162                 nonWhitespaceEnd = mStringBefore.offsetByCodePoints(nonWhitespaceEnd, -1)) {
163             final int codePoint = mStringBefore.codePointBefore(nonWhitespaceEnd);
164             if (!Character.isWhitespace(codePoint)) break;
165         }
166         if (0 != nonWhitespaceStart || len != nonWhitespaceEnd) {
167             mCursorEndAfter = mCursorStartBefore + nonWhitespaceEnd;
168             mCursorStartBefore = mCursorStartAfter = mCursorStartBefore + nonWhitespaceStart;
169             mStringAfter = mStringBefore =
170                     mStringBefore.substring(nonWhitespaceStart, nonWhitespaceEnd);
171         }
172     }
173 
getRecapitalizedString()174     public String getRecapitalizedString() {
175         return mStringAfter;
176     }
177 
getNewCursorStart()178     public int getNewCursorStart() {
179         return mCursorStartAfter;
180     }
181 
getNewCursorEnd()182     public int getNewCursorEnd() {
183         return mCursorEndAfter;
184     }
185 
getCurrentMode()186     public int getCurrentMode() {
187         return ROTATION_STYLE[mRotationStyleCurrentIndex];
188     }
189 }
190