From af4c39784e62c52ae6db678a8fb0586968e9eb3a Mon Sep 17 00:00:00 2001 From: "jia.shao.peng" Date: Mon, 24 May 2010 08:47:31 +0000 Subject: [PATCH] Adding inputDigitAndRememberPosition and getRememberedPosition methods to AsYouTypeFormatter.java to provide better cursor control. git-svn-id: http://libphonenumber.googlecode.com/svn/trunk@25 ee073f10-1060-11df-b6a4-87a95322a99c --- .../i18n/phonenumbers/AsYouTypeFormatter.java | 80 ++++++++++++++++++++-- .../i18n/phonenumbers/AsYouTypeFormatterTest.java | 74 +++++++++++++++++--- 2 files changed, 137 insertions(+), 17 deletions(-) diff --git a/java/src/com/google/i18n/phonenumbers/AsYouTypeFormatter.java b/java/src/com/google/i18n/phonenumbers/AsYouTypeFormatter.java index e4e26d7..2099718 100644 --- a/java/src/com/google/i18n/phonenumbers/AsYouTypeFormatter.java +++ b/java/src/com/google/i18n/phonenumbers/AsYouTypeFormatter.java @@ -54,11 +54,16 @@ public class AsYouTypeFormatter { private String digitPlaceholder = "\u2008"; private Pattern digitPattern = Pattern.compile(digitPlaceholder); private int lastMatchPosition = 0; + private boolean rememberPosition = false; + private int positionRemembered = 0; + private int originalPosition = 0; private Pattern nationalPrefixForParsing; private Pattern internationalPrefix; private StringBuffer prefixBeforeNationalNumber; private StringBuffer nationalNumber; - private final Pattern UNSUPPORTED_SYNTAX = Pattern.compile("[*#;,a-zA-Z]"); + // No formatting will be applied when any of the character in the following character class is + // entered by users. + private final Pattern UNSUPPORTED_SYNTAX = Pattern.compile("[- *#;,.()/a-zA-Z]"); private final Pattern CHARACTER_CLASS_PATTERN = Pattern.compile("\\[([^\\[\\]])*\\]"); private final Pattern STANDALONE_DIGIT_PATTERN = Pattern.compile("\\d(?=[^,}][^,}])"); @@ -169,6 +174,8 @@ public class AsYouTypeFormatter { prefixBeforeNationalNumber.setLength(0); nationalNumber.setLength(0); ableToFormat = true; + positionRemembered = 0; + originalPosition = 0; isInternationalFormatting = false; if (!currentMetaData.equals(defaultMetaData)) { initializeCountrySpecificInfo(defaultCountry); @@ -185,11 +192,18 @@ public class AsYouTypeFormatter { */ public String inputDigit(char nextChar) { accruedInput.append(nextChar); - // * and # are normally used in mobile codes, which we do not format. if (UNSUPPORTED_SYNTAX.matcher(Character.toString(nextChar)).matches()) { ableToFormat = false; } if (!ableToFormat) { + if (positionRemembered > 0 && currentOutput.length() > 0) { + positionRemembered = originalPosition; + currentOutput.setLength(0); + } + if (rememberPosition) { + positionRemembered = accruedInput.length(); + originalPosition = positionRemembered; + } return accruedInput.toString(); } @@ -204,10 +218,18 @@ public class AsYouTypeFormatter { case 3: case 4: case 5: + if (rememberPosition) { + positionRemembered = accruedInput.length(); + originalPosition = positionRemembered; + } return accruedInput.toString(); case 6: if (!extractIddAndValidCountryCode()) { ableToFormat = false; + if (rememberPosition) { + positionRemembered = accruedInput.length(); + originalPosition = positionRemembered; + } return accruedInput.toString(); } removeNationalPrefixFromNationalNumber(); @@ -221,6 +243,26 @@ public class AsYouTypeFormatter { } } + /** + * Same as inputDigit, but remember the position where nextChar is inserted, so that it could be + * retrieved later using getRememberedPosition(). The remembered position will be automatically + * adjusted if additional formatting characters are later inserted/removed in front of it. + */ + public String inputDigitAndRememberPosition(char nextChar) { + rememberPosition = true; + String result = inputDigit(nextChar); + rememberPosition = false; + return result; + } + + /** + * Returns the current position in the partially formatted phone number of the character which was + * previously passed in as the parameter of inputDigitAndRememberPosition. + */ + public int getRememberedPosition() { + return positionRemembered; + } + // Attempts to set the formatting template and returns a string which contains the formatted // version of the digits entered so far. private String attemptToChooseFormattingPattern() { @@ -230,6 +272,9 @@ public class AsYouTypeFormatter { chooseFormatAndCreateTemplate(nationalNumber.substring(0, 4)); return inputAccruedNationalNumber(); } else { + if (rememberPosition) { + positionRemembered = prefixBeforeNationalNumber.length() + nationalNumber.length(); + } return prefixBeforeNationalNumber + nationalNumber.toString(); } } @@ -240,11 +285,17 @@ public class AsYouTypeFormatter { int lengthOfNationalNumber = nationalNumber.length(); if (lengthOfNationalNumber > 0) { for (int i = 0; i < lengthOfNationalNumber - 1; i++) { - inputDigitHelper(nationalNumber.charAt(i)); + String temp = inputDigitHelper(nationalNumber.charAt(i)); + if (positionRemembered == i + 1) { + positionRemembered = temp.length(); + } } - return prefixBeforeNationalNumber - + inputDigitHelper(nationalNumber.charAt(lengthOfNationalNumber - 1)); + return prefixBeforeNationalNumber + + inputDigitHelper(nationalNumber.charAt(lengthOfNationalNumber - 1)); } else { + if (rememberPosition) { + positionRemembered = prefixBeforeNationalNumber.length(); + } return prefixBeforeNationalNumber.toString(); } } @@ -291,9 +342,20 @@ public class AsYouTypeFormatter { prefixBeforeNationalNumber.append( accruedInputWithoutFormatting.substring(0, startOfCountryCode)); if (accruedInputWithoutFormatting.charAt(0) != PhoneNumberUtil.PLUS_SIGN ) { + if (positionRemembered > prefixBeforeNationalNumber.length()) { + // Since a space will be inserted in front of the country code in this case, we increase + // the remembered position by 1. + positionRemembered++; + } prefixBeforeNationalNumber.append(" "); } - prefixBeforeNationalNumber.append(countryCode).append(" "); + String countryCodeString = Integer.toString(countryCode); + if (positionRemembered > prefixBeforeNationalNumber.length() + countryCodeString.length()) { + // Since a space will be inserted after the country code in this case, we increase the + // remembered position by 1. + positionRemembered++; + } + prefixBeforeNationalNumber.append(countryCodeString).append(" "); } } else { nationalNumber.setLength(0); @@ -328,10 +390,16 @@ public class AsYouTypeFormatter { if (digitMatcher.find(lastMatchPosition)) { currentOutput = new StringBuffer(digitMatcher.replaceFirst(Character.toString(nextChar))); lastMatchPosition = digitMatcher.start(); + if (rememberPosition) { + positionRemembered = prefixBeforeNationalNumber.length() + lastMatchPosition + 1; + } return currentOutput.substring(0, lastMatchPosition + 1); } else { // More digits are entered than we could handle. currentOutput.append(nextChar); ableToFormat = false; + if (rememberPosition) { + positionRemembered = prefixBeforeNationalNumber.length() + currentOutput.length(); + } return currentOutput.toString(); } } diff --git a/java/test/com/google/i18n/phonenumbers/AsYouTypeFormatterTest.java b/java/test/com/google/i18n/phonenumbers/AsYouTypeFormatterTest.java index 076b4b4..fda9c79 100644 --- a/java/test/com/google/i18n/phonenumbers/AsYouTypeFormatterTest.java +++ b/java/test/com/google/i18n/phonenumbers/AsYouTypeFormatterTest.java @@ -67,43 +67,73 @@ public class AsYouTypeFormatterTest extends TestCase { assertEquals("1 650 253 2222", formatter.inputDigit('2')); formatter.clear(); + assertEquals("1", formatter.inputDigitAndRememberPosition('1')); + assertEquals(1, formatter.getRememberedPosition()); + assertEquals("16", formatter.inputDigit('6')); + assertEquals("165", formatter.inputDigit('5')); + assertEquals(1, formatter.getRememberedPosition()); + assertEquals("1650", formatter.inputDigitAndRememberPosition('0')); + assertEquals(4, formatter.getRememberedPosition()); + assertEquals("16502", formatter.inputDigit('2')); + assertEquals("1 650 25", formatter.inputDigit('5')); + assertEquals(5, formatter.getRememberedPosition()); + assertEquals("1 650 253", formatter.inputDigit('3')); + assertEquals("1 650 253 2", formatter.inputDigit('2')); + assertEquals("1 650 253 22", formatter.inputDigit('2')); + assertEquals(5, formatter.getRememberedPosition()); + assertEquals("1 650 253 222", formatter.inputDigitAndRememberPosition('2')); + assertEquals(13, formatter.getRememberedPosition()); + assertEquals("1 650 253 2222", formatter.inputDigit('2')); + assertEquals(13, formatter.getRememberedPosition()); + + formatter.clear(); assertEquals("6", formatter.inputDigit('6')); assertEquals("65", formatter.inputDigit('5')); assertEquals("650", formatter.inputDigit('0')); assertEquals("6502", formatter.inputDigit('2')); - assertEquals("65025", formatter.inputDigit('5')); + assertEquals("65025", formatter.inputDigitAndRememberPosition('5')); + assertEquals(5, formatter.getRememberedPosition()); assertEquals("650 253", formatter.inputDigit('3')); + assertEquals(6, formatter.getRememberedPosition()); assertEquals("650 253 2", formatter.inputDigit('2')); assertEquals("650 253 22", formatter.inputDigit('2')); assertEquals("650 253 222", formatter.inputDigit('2')); // No more formatting when semicolon is entered. assertEquals("650253222;", formatter.inputDigit(';')); + assertEquals(5, formatter.getRememberedPosition()); assertEquals("650253222;2", formatter.inputDigit('2')); formatter.clear(); assertEquals("6", formatter.inputDigit('6')); assertEquals("65", formatter.inputDigit('5')); assertEquals("650", formatter.inputDigit('0')); + // No more formatting when users choose to do their own formatting. assertEquals("650-", formatter.inputDigit('-')); - assertEquals("650-2", formatter.inputDigit('2')); + assertEquals("650-2", formatter.inputDigitAndRememberPosition('2')); + assertEquals(5, formatter.getRememberedPosition()); assertEquals("650-25", formatter.inputDigit('5')); - assertEquals("650 253", formatter.inputDigit('3')); - assertEquals("650 253", formatter.inputDigit('-')); - assertEquals("650 253 2", formatter.inputDigit('2')); - assertEquals("650 253 22", formatter.inputDigit('2')); - assertEquals("650 253 222", formatter.inputDigit('2')); - assertEquals("650 253 2222", formatter.inputDigit('2')); + assertEquals(5, formatter.getRememberedPosition()); + assertEquals("650-253", formatter.inputDigit('3')); + assertEquals(5, formatter.getRememberedPosition()); + assertEquals("650-253-", formatter.inputDigit('-')); + assertEquals("650-253-2", formatter.inputDigit('2')); + assertEquals("650-253-22", formatter.inputDigit('2')); + assertEquals("650-253-222", formatter.inputDigit('2')); + assertEquals("650-253-2222", formatter.inputDigit('2')); formatter.clear(); assertEquals("0", formatter.inputDigit('0')); assertEquals("01", formatter.inputDigit('1')); assertEquals("011", formatter.inputDigit('1')); - assertEquals("0114", formatter.inputDigit('4')); + assertEquals("0114", formatter.inputDigitAndRememberPosition('4')); assertEquals("01148", formatter.inputDigit('8')); + assertEquals(4, formatter.getRememberedPosition()); assertEquals("011 48 8", formatter.inputDigit('8')); + assertEquals(5, formatter.getRememberedPosition()); assertEquals("011 48 88", formatter.inputDigit('8')); assertEquals("011 48 881", formatter.inputDigit('1')); assertEquals("011 48 88 12", formatter.inputDigit('2')); + assertEquals(5, formatter.getRememberedPosition()); assertEquals("011 48 88 123", formatter.inputDigit('3')); assertEquals("011 48 88 123 1", formatter.inputDigit('1')); assertEquals("011 48 88 123 12", formatter.inputDigit('2')); @@ -148,15 +178,35 @@ public class AsYouTypeFormatterTest extends TestCase { formatter.clear(); assertEquals("+", formatter.inputDigit('+')); assertEquals("+1", formatter.inputDigit('1')); - assertEquals("+16", formatter.inputDigit('6')); + assertEquals("+16", formatter.inputDigitAndRememberPosition('6')); + assertEquals("+165", formatter.inputDigit('5')); + assertEquals("+1650", formatter.inputDigit('0')); + assertEquals(3, formatter.getRememberedPosition()); + assertEquals("+1 650 2", formatter.inputDigit('2')); + assertEquals(4, formatter.getRememberedPosition()); + assertEquals("+1 650 25", formatter.inputDigit('5')); + assertEquals("+1 650 253", formatter.inputDigitAndRememberPosition('3')); + assertEquals("+1 650 253 2", formatter.inputDigit('2')); + assertEquals("+1 650 253 22", formatter.inputDigit('2')); + assertEquals("+1 650 253 222", formatter.inputDigit('2')); + assertEquals(10, formatter.getRememberedPosition()); + + formatter.clear(); + assertEquals("+", formatter.inputDigit('+')); + assertEquals("+1", formatter.inputDigit('1')); + assertEquals("+16", formatter.inputDigitAndRememberPosition('6')); assertEquals("+165", formatter.inputDigit('5')); assertEquals("+1650", formatter.inputDigit('0')); + assertEquals(3, formatter.getRememberedPosition()); assertEquals("+1 650 2", formatter.inputDigit('2')); + assertEquals(4, formatter.getRememberedPosition()); assertEquals("+1 650 25", formatter.inputDigit('5')); assertEquals("+1 650 253", formatter.inputDigit('3')); assertEquals("+1 650 253 2", formatter.inputDigit('2')); assertEquals("+1 650 253 22", formatter.inputDigit('2')); assertEquals("+1 650 253 222", formatter.inputDigit('2')); + assertEquals("+1650253222;", formatter.inputDigit(';')); + assertEquals(3, formatter.getRememberedPosition()); formatter.clear(); assertEquals("+", formatter.inputDigit('+')); @@ -214,9 +264,11 @@ public class AsYouTypeFormatterTest extends TestCase { assertEquals("0", formatter.inputDigit('0')); assertEquals("02", formatter.inputDigit('2')); assertEquals("020", formatter.inputDigit('0')); - assertEquals("0207", formatter.inputDigit('7')); + assertEquals("0207", formatter.inputDigitAndRememberPosition('7')); + assertEquals(4, formatter.getRememberedPosition()); assertEquals("02070", formatter.inputDigit('0')); assertEquals("020 703", formatter.inputDigit('3')); + assertEquals(5, formatter.getRememberedPosition()); assertEquals("020 7031", formatter.inputDigit('1')); assertEquals("020 7031 3", formatter.inputDigit('3')); assertEquals("020 7031 30", formatter.inputDigit('0')); -- 2.7.4