com.google.appinventor.client.widgets.properties.TextPropertyEditorBase.java Source code

Java tutorial

Introduction

Here is the source code for com.google.appinventor.client.widgets.properties.TextPropertyEditorBase.java

Source

// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0

package com.google.appinventor.client.widgets.properties;

import static com.google.appinventor.client.Ode.MESSAGES;

import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.FocusEvent;
import com.google.gwt.event.dom.client.FocusHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.TextBoxBase;

/**
 * Property editor base for text box editors.
 *
 */
public class TextPropertyEditorBase extends PropertyEditor {

    /**
     * Thrown to indicate that text input is invalid.
     */
    public static class InvalidTextException extends Exception {
        public InvalidTextException(String message) {
            super(message);
        }
    }

    // This is the GWT object that supports the property editor
    // It can be TextBoxBase object, currently in App Inventor only
    // TextBox and TextArea
    protected TextBoxBase textEdit;

    private boolean hasFocus;

    /**
     * Creates a new instance of the property editor.
     */
    public TextPropertyEditorBase(final TextBoxBase widget) {

        textEdit = widget;

        textEdit.addKeyPressHandler(new KeyPressHandler() {
            @Override
            public void onKeyPress(KeyPressEvent event) {
                handleKeyPress(event.getCharCode());
            }
        });
        textEdit.addKeyUpHandler(new KeyUpHandler() {
            @Override
            public void onKeyUp(KeyUpEvent event) {
                handleKeyUp(event.getNativeKeyCode());
            }
        });
        textEdit.addValueChangeHandler(new ValueChangeHandler() {
            @Override
            public void onValueChange(ValueChangeEvent event) {
                validateText();
            }
        });

        // NOTE(lizlooney) - The following handlers for focus, blur, and click are needed to workaround
        // a bug with WebKit browsers (chrome and safari) where clicking in the TextBox causes it to
        // gain focus, but then immediately lose focus (blur). To work around the problem, we keep
        // track of whether the TextBox has focus using a FocusHandler and a BlurHandler. Then, we use
        // a ClickHandler and if we get a ClickEvent and the TextBox does not have focus, we explicitly
        // call setFocus.
        textEdit.addFocusHandler(new FocusHandler() {
            @Override
            public void onFocus(FocusEvent event) {
                hasFocus = true;
            }
        });
        textEdit.addBlurHandler(new BlurHandler() {
            @Override
            public void onBlur(BlurEvent event) {
                hasFocus = false;
                // Calling validateText here means that we will save the changed property value (if it is
                // valid) when this property editor loses focus (for example, when the user clicks on
                // another property editor).
                validateText();
            }
        });
        textEdit.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                if (!hasFocus) {
                    textEdit.setFocus(true);
                }
            }
        });

        initWidget(textEdit); //kludge for now fix this with instanceOf?

        setHeight("2em");
    }

    @Override
    protected void onUnload() {
        // onUnload is called immediately before a widget becomes detached from the browser's document.
        // Calling validateText here means that we will save the changed property value (if it is
        // valid) when the user clicks on another component.
        validateText();
        super.onUnload();
    }

    @Override
    protected void updateValue() {
        textEdit.setText(property.getValue());
    }

    private void handleKeyPress(char keyCode) {
        if (keyCode == KeyCodes.KEY_ENTER || keyCode == KeyCodes.KEY_TAB) {
            // Pressing <tab>, <enter> or <return> will surrender focus.
            textEdit.cancelKey();
            textEdit.setFocus(false);
        } else if (!validateKeyCode(keyCode)) {
            textEdit.cancelKey();
        }
    }

    private void handleKeyUp(int keyCode) {
        if (keyCode == KeyCodes.KEY_ESCAPE) {
            // Pressing <esc> will reset the content of the editor to the previous property value as well
            // as surrender focus.
            updateValue(); // Restore previous property value.
            textEdit.cancelKey();
            textEdit.setFocus(false);
        }
    }

    /*
     * Validates the text in the textEdit and if it is valid, sets the property
     * value to the text.
     */
    private void validateText() {
        String text = textEdit.getText();
        try {
            validate(text);
            property.setValue(text);
        } catch (InvalidTextException e) {
            String error = e.getMessage();
            if (error == null || error.isEmpty()) {
                error = MESSAGES.malformedInputError();
            }
            Window.alert(error);
            updateValue(); // Restore previous property value.
        }
    }

    /**
     * Validates the given key code.
     *
     * <p/>The implementation here does no validation. Subclasses may override
     * this method to provide actual validation.
     *
     * @param keyCode  key code to validate
     * @return true if the keycode is allowed, false if it is not allowed.
     */
    protected boolean validateKeyCode(char keyCode) {
        return true;
    }

    /**
     * Validates the given text. Throw an InvalidTextException if the text is
     * invalid.
     *
     * <p/>The implementation here does no validation. Subclasses may override
     * this method to provide actual validation.
     *
     * @param text  input string to validate
     * @throws InvalidTextException if the text is invalid
     */
    protected void validate(String text) throws InvalidTextException {
    }

}