Skip to content
Snippets Groups Projects
RecapitalizeStatus.java 8.02 KiB
Newer Older
/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

abb128's avatar
abb128 committed
package org.futo.inputmethod.latin.utils;
abb128's avatar
abb128 committed
import org.futo.inputmethod.latin.common.StringUtils;
import java.util.Locale;

/**
 * The status of the current recapitalize process.
 */
public class RecapitalizeStatus {
    public static final int NOT_A_RECAPITALIZE_MODE = -1;
    public static final int CAPS_MODE_ORIGINAL_MIXED_CASE = 0;
    public static final int CAPS_MODE_ALL_LOWER = 1;
    public static final int CAPS_MODE_FIRST_WORD_UPPER = 2;
    public static final int CAPS_MODE_ALL_UPPER = 3;
    // When adding a new mode, don't forget to update the CAPS_MODE_LAST constant.
    public static final int CAPS_MODE_LAST = CAPS_MODE_ALL_UPPER;

    private static final int[] ROTATION_STYLE = {
        CAPS_MODE_ORIGINAL_MIXED_CASE,
        CAPS_MODE_ALL_LOWER,
        CAPS_MODE_FIRST_WORD_UPPER,
        CAPS_MODE_ALL_UPPER
    };
    private static final int getStringMode(final String string, final int[] sortedSeparators) {
        if (StringUtils.isIdenticalAfterUpcase(string)) {
            return CAPS_MODE_ALL_UPPER;
        } else if (StringUtils.isIdenticalAfterDowncase(string)) {
            return CAPS_MODE_ALL_LOWER;
        } else if (StringUtils.isIdenticalAfterCapitalizeEachWord(string, sortedSeparators)) {
            return CAPS_MODE_FIRST_WORD_UPPER;
        } else {
            return CAPS_MODE_ORIGINAL_MIXED_CASE;
        }
    }

    public static String modeToString(final int recapitalizeMode) {
        switch (recapitalizeMode) {
        case NOT_A_RECAPITALIZE_MODE: return "undefined";
        case CAPS_MODE_ORIGINAL_MIXED_CASE: return "mixedCase";
        case CAPS_MODE_ALL_LOWER: return "allLower";
        case CAPS_MODE_FIRST_WORD_UPPER: return "firstWordUpper";
        case CAPS_MODE_ALL_UPPER: return "allUpper";
        default: return "unknown<" + recapitalizeMode + ">";
        }
    }

     * We store the location of the cursor and the string that was there before the recapitalize
     * action was done, and the location of the cursor and the string that was there after.
     */
    private int mCursorStartBefore;
    private String mStringBefore;
    private int mCursorStartAfter;
    private int mCursorEndAfter;
    private int mRotationStyleCurrentIndex;
    private boolean mSkipOriginalMixedCaseMode;
    private Locale mLocale;
    private int[] mSortedSeparators;
    private String mStringAfter;
Jean Chalard's avatar
Jean Chalard committed
    private boolean mIsStarted;
    private boolean mIsEnabled = true;
    private static final int[] EMPTY_STORTED_SEPARATORS = {};

    public RecapitalizeStatus() {
        // By default, initialize with fake values that won't match any real recapitalize.
Jean Chalard's avatar
Jean Chalard committed
        start(-1, -1, "", Locale.getDefault(), EMPTY_STORTED_SEPARATORS);
        stop();
Jean Chalard's avatar
Jean Chalard committed
    public void start(final int cursorStart, final int cursorEnd, final String string,
            final Locale locale, final int[] sortedSeparators) {
        if (!mIsEnabled) {
            return;
        }
        mCursorStartBefore = cursorStart;
        mStringBefore = string;
        mCursorStartAfter = cursorStart;
        mCursorEndAfter = cursorEnd;
        mStringAfter = string;
        final int initialMode = getStringMode(mStringBefore, sortedSeparators);
        mLocale = locale;
        mSortedSeparators = sortedSeparators;
        if (CAPS_MODE_ORIGINAL_MIXED_CASE == initialMode) {
            mRotationStyleCurrentIndex = 0;
            mSkipOriginalMixedCaseMode = false;
        } else {
            // Find the current mode in the array.
            int currentMode;
            for (currentMode = ROTATION_STYLE.length - 1; currentMode > 0; --currentMode) {
                if (ROTATION_STYLE[currentMode] == initialMode) {
                    break;
                }
            }
            mRotationStyleCurrentIndex = currentMode;
            mSkipOriginalMixedCaseMode = true;
        }
Jean Chalard's avatar
Jean Chalard committed
        mIsStarted = true;
Jean Chalard's avatar
Jean Chalard committed
    public void stop() {
        mIsStarted = false;
Jean Chalard's avatar
Jean Chalard committed
    public boolean isStarted() {
        return mIsStarted;
    public void enable() {
        mIsEnabled = true;
    }

    public void disable() {
        mIsEnabled = false;
    }

    public boolean mIsEnabled() {
        return mIsEnabled;
    }

    public boolean isSetAt(final int cursorStart, final int cursorEnd) {
        return cursorStart == mCursorStartAfter && cursorEnd == mCursorEndAfter;
    }

    /**
     * Rotate through the different possible capitalization modes.
     */
    public void rotate() {
        final String oldResult = mStringAfter;
        int count = 0; // Protection against infinite loop.
        do {
            mRotationStyleCurrentIndex = (mRotationStyleCurrentIndex + 1) % ROTATION_STYLE.length;
            if (CAPS_MODE_ORIGINAL_MIXED_CASE == ROTATION_STYLE[mRotationStyleCurrentIndex]
                    && mSkipOriginalMixedCaseMode) {
                mRotationStyleCurrentIndex =
                        (mRotationStyleCurrentIndex + 1) % ROTATION_STYLE.length;
            }
            ++count;
            switch (ROTATION_STYLE[mRotationStyleCurrentIndex]) {
            case CAPS_MODE_ORIGINAL_MIXED_CASE:
                mStringAfter = mStringBefore;
                break;
            case CAPS_MODE_ALL_LOWER:
                mStringAfter = mStringBefore.toLowerCase(mLocale);
                break;
            case CAPS_MODE_FIRST_WORD_UPPER:
                mStringAfter = StringUtils.capitalizeEachWord(mStringBefore, mSortedSeparators,
                        mLocale);
                break;
            case CAPS_MODE_ALL_UPPER:
                mStringAfter = mStringBefore.toUpperCase(mLocale);
                break;
            default:
                mStringAfter = mStringBefore;
        } while (mStringAfter.equals(oldResult) && count < ROTATION_STYLE.length + 1);
        mCursorEndAfter = mCursorStartAfter + mStringAfter.length();
    }

    /**
     * Remove leading/trailing whitespace from the considered string.
     */
    public void trim() {
        final int len = mStringBefore.length();
        int nonWhitespaceStart = 0;
        for (; nonWhitespaceStart < len;
                nonWhitespaceStart = mStringBefore.offsetByCodePoints(nonWhitespaceStart, 1)) {
            final int codePoint = mStringBefore.codePointAt(nonWhitespaceStart);
            if (!Character.isWhitespace(codePoint)) break;
        }
        int nonWhitespaceEnd = len;
        for (; nonWhitespaceEnd > 0;
                nonWhitespaceEnd = mStringBefore.offsetByCodePoints(nonWhitespaceEnd, -1)) {
            final int codePoint = mStringBefore.codePointBefore(nonWhitespaceEnd);
            if (!Character.isWhitespace(codePoint)) break;
        }
        // If nonWhitespaceStart >= nonWhitespaceEnd, that means the selection contained only
        // whitespace, so we leave it as is.
        if ((0 != nonWhitespaceStart || len != nonWhitespaceEnd)
                && nonWhitespaceStart < nonWhitespaceEnd) {
            mCursorEndAfter = mCursorStartBefore + nonWhitespaceEnd;
            mCursorStartBefore = mCursorStartAfter = mCursorStartBefore + nonWhitespaceStart;
            mStringAfter = mStringBefore =
                    mStringBefore.substring(nonWhitespaceStart, nonWhitespaceEnd);
        }
    }

    public String getRecapitalizedString() {
        return mStringAfter;
    }

    public int getNewCursorStart() {
        return mCursorStartAfter;
    }

    public int getNewCursorEnd() {
        return mCursorEndAfter;
    }

    public int getCurrentMode() {
        return ROTATION_STYLE[mRotationStyleCurrentIndex];
    }