package com.andreabaccega.widget; import android.content.Context; import android.content.res.TypedArray; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; import android.util.AttributeSet; import android.widget.EditText; import com.andreabaccega.formedittextvalidator.AlphaNumericValidator; import com.andreabaccega.formedittextvalidator.AlphaValidator; import com.andreabaccega.formedittextvalidator.AndValidator; import com.andreabaccega.formedittextvalidator.CreditCardValidator; import com.andreabaccega.formedittextvalidator.DateValidator; import com.andreabaccega.formedittextvalidator.DomainValidator; import com.andreabaccega.formedittextvalidator.DummyValidator; import com.andreabaccega.formedittextvalidator.EmailValidator; import com.andreabaccega.formedittextvalidator.EmptyValidator; import com.andreabaccega.formedittextvalidator.IpAddressValidator; import com.andreabaccega.formedittextvalidator.MultiValidator; import com.andreabaccega.formedittextvalidator.NotValidator; import com.andreabaccega.formedittextvalidator.NumericRangeValidator; import com.andreabaccega.formedittextvalidator.NumericValidator; import com.andreabaccega.formedittextvalidator.OrValidator; import com.andreabaccega.formedittextvalidator.PhoneValidator; import com.andreabaccega.formedittextvalidator.RegexpValidator; import com.andreabaccega.formedittextvalidator.Validator; import com.andreabaccega.formedittextvalidator.WebUrlValidator; import com.andreabaccega.formedittextvalidator.PersonNameValidator; import com.andreabaccega.formedittextvalidator.PersonFullNameValidator; import com.hoollyzhang.hlib.R; /** * Default implementation of an {@link com.andreabaccega.widget.EditTextValidator} */ public class DefaultEditTextValidator implements EditTextValidator { /** * support dynamic new DefaultEditTextValidator() ,used for Java call * @param editText * @param context */ public DefaultEditTextValidator( EditText editText, Context context ) { testType = EditTextValidator.TEST_NOCHECK; setEditText( editText ); resetValidators( context ); } public DefaultEditTextValidator( EditText editText, AttributeSet attrs, Context context ) { TypedArray typedArray = context.obtainStyledAttributes( attrs, R.styleable.FormEditText ); emptyAllowed = typedArray.getBoolean( R.styleable.FormEditText_emptyAllowed, false ); testType = typedArray.getInt( R.styleable.FormEditText_testType, EditTextValidator.TEST_NOCHECK ); testErrorString = typedArray.getString( R.styleable.FormEditText_testErrorString ); classType = typedArray.getString( R.styleable.FormEditText_classType ); customRegexp = typedArray.getString( R.styleable.FormEditText_customRegexp ); emptyErrorString = typedArray.getString( R.styleable.FormEditText_emptyErrorString ); customFormat = typedArray.getString(R.styleable.FormEditText_customFormat); if(testType == TEST_NUMERIC_RANGE) { minNumber = typedArray.getInt(R.styleable.FormEditText_minNumber, Integer.MIN_VALUE); maxNumber = typedArray.getInt(R.styleable.FormEditText_maxNumber, Integer.MAX_VALUE); } typedArray.recycle(); setEditText( editText ); resetValidators( context ); } @Override public void addValidator( Validator theValidator ) throws IllegalArgumentException { if ( theValidator == null ) { throw new IllegalArgumentException( "theValidator argument should not be null" ); } mValidator.enqueue( theValidator ); } public String getClassType() { return classType; } public String getCustomRegexp() { return customRegexp; } public EditText getEditText() { return editText; } public String getTestErrorString() { return testErrorString; } public int getTestType() { return testType; } @Override public TextWatcher getTextWatcher() { if ( tw == null ) { tw = new TextWatcher() { public void afterTextChanged( Editable s ) { } public void beforeTextChanged( CharSequence s, int start, int count, int after ) { } public void onTextChanged( CharSequence s, int start, int before, int count ) { if ( s != null && s.length() > 0 && editText.getError() != null ) { editText.setError( null ); } } }; } return tw; } @Override public boolean isEmptyAllowed() { return emptyAllowed; } @Override public void resetValidators( Context context ) { // its possible the context may have changed so re-get the defaultEmptyErrorString defaultEmptyErrorString = context.getString( R.string.error_field_must_not_be_empty ); setEmptyErrorString( emptyErrorString ); mValidator = new AndValidator(); Validator toAdd; switch ( testType ) { default: case TEST_NOCHECK: toAdd = new DummyValidator(); break; case TEST_ALPHA: toAdd = new AlphaValidator( TextUtils.isEmpty( testErrorString ) ? context.getString( R.string.error_only_standard_letters_are_allowed ) : testErrorString ); break; case TEST_ALPHANUMERIC: toAdd = new AlphaNumericValidator( TextUtils.isEmpty( testErrorString ) ? context.getString( R.string.error_this_field_cannot_contain_special_character ) : testErrorString ); break; case TEST_NUMERIC: toAdd = new NumericValidator( TextUtils.isEmpty( testErrorString ) ? context.getString( R.string.error_only_numeric_digits_allowed ) : testErrorString ); break; case TEST_NUMERIC_RANGE: toAdd = new NumericRangeValidator( TextUtils.isEmpty( testErrorString ) ? context.getString( R.string.error_only_numeric_digits_range_allowed, minNumber, maxNumber ) : testErrorString, minNumber, maxNumber); break; case TEST_REGEXP: toAdd = new RegexpValidator( testErrorString, customRegexp ); break; case TEST_CREDITCARD: toAdd = new CreditCardValidator( TextUtils.isEmpty( testErrorString ) ? context.getString( R.string.error_creditcard_number_not_valid ) : testErrorString ); break; case TEST_EMAIL: toAdd = new EmailValidator( TextUtils.isEmpty( testErrorString ) ? context.getString( R.string.error_email_address_not_valid ) : testErrorString ); break; case TEST_PHONE: toAdd = new PhoneValidator( TextUtils.isEmpty( testErrorString ) ? context.getString( R.string.error_phone_not_valid ) : testErrorString ); break; case TEST_DOMAINNAME: toAdd = new DomainValidator( TextUtils.isEmpty( testErrorString ) ? context.getString( R.string.error_domain_not_valid ) : testErrorString ); break; case TEST_IPADDRESS: toAdd = new IpAddressValidator( TextUtils.isEmpty( testErrorString ) ? context.getString( R.string.error_ip_not_valid ) : testErrorString ); break; case TEST_WEBURL: toAdd = new WebUrlValidator( TextUtils.isEmpty( testErrorString ) ? context.getString( R.string.error_url_not_valid ) : testErrorString ); break; case TEST_PERSONNAME: toAdd = new PersonNameValidator( TextUtils.isEmpty( testErrorString ) ? context.getString( R.string.error_notvalid_personname ) : testErrorString ); break; case TEST_PERSONFULLNAME: toAdd = new PersonFullNameValidator( TextUtils.isEmpty( testErrorString ) ? context.getString( R.string.error_notvalid_personfullname ) : testErrorString ); break; case TEST_CUSTOM: // must specify the fully qualified class name & an error message if ( classType == null ) { throw new RuntimeException( "Trying to create a custom validator but no classType has been specified." ); } if ( TextUtils.isEmpty( testErrorString ) ) { throw new RuntimeException( String.format( "Trying to create a custom validator (%s) but no error string specified.", classType ) ); } Class<? extends Validator> customValidatorClass; try { Class<?> loadedClass = this.getClass().getClassLoader().loadClass( classType ); if ( !Validator.class.isAssignableFrom( loadedClass ) ) { throw new RuntimeException( String.format( "Custom validator (%s) does not extend %s", classType, Validator.class.getName() ) ); } customValidatorClass = (Class<? extends Validator>) loadedClass; } catch ( ClassNotFoundException e ) { throw new RuntimeException( String.format( "Unable to load class for custom validator (%s).", classType ) ); } try { toAdd = customValidatorClass.getConstructor( String.class ).newInstance( testErrorString ); } catch ( Exception e ) { throw new RuntimeException( String.format( "Unable to construct custom validator (%s) with argument: %s", classType, testErrorString ) ); } break; case TEST_DATE: toAdd = new DateValidator( TextUtils.isEmpty( testErrorString ) ? context.getString( R.string.error_date_not_valid ) : testErrorString, customFormat); break; } MultiValidator tmpValidator; if ( !emptyAllowed ) { // If the xml tells us that this is a required field, we will add the EmptyValidator. tmpValidator = new AndValidator(); tmpValidator.enqueue( new EmptyValidator( emptyErrorStringActual ) ); tmpValidator.enqueue( toAdd ); } else { tmpValidator = new OrValidator( toAdd.getErrorMessage(), new NotValidator( null, new EmptyValidator( null ) ), toAdd ); } addValidator( tmpValidator ); } public void setClassType( String classType, String testErrorString, Context context ) { testType = EditTextValidator.TEST_CUSTOM; this.classType = classType; this.testErrorString = testErrorString; resetValidators( context ); } public void setCustomRegexp( String customRegexp, Context context ) { testType = EditTextValidator.TEST_REGEXP; this.customRegexp = customRegexp; resetValidators( context ); } public void setEditText( EditText editText ) { if (this.editText != null) { this.editText.removeTextChangedListener( getTextWatcher() ); } this.editText = editText; editText.addTextChangedListener( getTextWatcher() ); } public void setEmptyAllowed( boolean emptyAllowed, Context context ) { this.emptyAllowed = emptyAllowed; resetValidators( context ); } public void setEmptyErrorString( String emptyErrorString ) { if ( !TextUtils.isEmpty( emptyErrorString ) ) { emptyErrorStringActual = emptyErrorString; } else { emptyErrorStringActual = defaultEmptyErrorString; } } public void setTestErrorString( String testErrorString, Context context ) { this.testErrorString = testErrorString; resetValidators( context ); } public void setTestType( int testType, Context context ) { this.testType = testType; resetValidators( context ); } @Override public boolean testValidity() { return testValidity(true); } @Override public boolean testValidity(boolean showUIError) { boolean isValid = mValidator.isValid( editText ); if ( !isValid && showUIError) { showUIError(); } return isValid; } @Override public void showUIError() { if ( mValidator.hasErrorMessage() ) { editText.setError( mValidator.getErrorMessage() ); } } private TextWatcher tw; private String defaultEmptyErrorString; /** * The custom validators setted using */ protected MultiValidator mValidator; protected String testErrorString; protected boolean emptyAllowed; protected EditText editText; protected int testType; protected String classType; protected String customRegexp; protected String customFormat; protected String emptyErrorStringActual; protected String emptyErrorString; protected int minNumber; protected int maxNumber; }