com.google.gwt.sample.showcase.client.content.cell.CwCellValidation.java Source code

Java tutorial

Introduction

Here is the source code for com.google.gwt.sample.showcase.client.content.cell.CwCellValidation.java

Source

/*
 * Copyright 2010 Google Inc.
 *
 * 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.
 */
package com.google.gwt.sample.showcase.client.content.cell;

import com.google.gwt.cell.client.AbstractInputCell;
import com.google.gwt.cell.client.FieldUpdater;
import com.google.gwt.cell.client.TextCell;
import com.google.gwt.cell.client.ValueUpdater;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.InputElement;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.i18n.client.Constants;
import com.google.gwt.safecss.shared.SafeStyles;
import com.google.gwt.safecss.shared.SafeStylesUtils;
import com.google.gwt.safehtml.client.SafeHtmlTemplates;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.safehtml.shared.SimpleHtmlSanitizer;
import com.google.gwt.sample.showcase.client.ContentWidget;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseData;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseRaw;
import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseSource;
import com.google.gwt.sample.showcase.client.content.cell.ContactDatabase.ContactInfo;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Widget;

/**
 * Example file.
 */
@ShowcaseRaw({ "ContactDatabase.java" })
public class CwCellValidation extends ContentWidget {

    /**
     * The constants used in this Content Widget.
     */
    @ShowcaseSource
    public static interface CwConstants extends Constants {
        String cwCellValidationColumnAddress();

        String cwCellValidationColumnName();

        String cwCellValidationDescription();

        String cwCellValidationError();

        String cwCellValidationName();
    }

    interface Template extends SafeHtmlTemplates {
        @Template("<input type=\"text\" value=\"{0}\" style=\"{1}\" tabindex=\"-1\"/>")
        SafeHtml input(String value, SafeStyles color);
    }

    /**
     * An input cell that changes color based on the validation status.
     */
    @ShowcaseSource
    private static class ValidatableInputCell extends AbstractInputCell<String, ValidationData> {

        private SafeHtml errorMessage;

        public ValidatableInputCell(String errorMessage) {
            super("change");
            if (template == null) {
                template = GWT.create(Template.class);
            }
            this.errorMessage = SimpleHtmlSanitizer.sanitizeHtml(errorMessage);
        }

        @Override
        public void onBrowserEvent(Context context, Element parent, String value, NativeEvent event,
                ValueUpdater<String> valueUpdater) {
            super.onBrowserEvent(context, parent, value, event, valueUpdater);

            // Ignore events that don't target the input.
            Element target = event.getEventTarget().cast();
            if (!parent.getFirstChildElement().isOrHasChild(target)) {
                return;
            }

            Object key = context.getKey();
            ValidationData viewData = getViewData(key);
            String eventType = event.getType();
            if ("change".equals(eventType)) {
                InputElement input = parent.getFirstChild().cast();

                // Mark cell as containing a pending change
                input.getStyle().setColor("blue");

                // Save the new value in the view data.
                if (viewData == null) {
                    viewData = new ValidationData();
                    setViewData(key, viewData);
                }
                String newValue = input.getValue();
                viewData.setValue(newValue);
                finishEditing(parent, newValue, key, valueUpdater);

                // Update the value updater, which updates the field updater.
                if (valueUpdater != null) {
                    valueUpdater.update(newValue);
                }
            }
        }

        @Override
        public void render(Context context, String value, SafeHtmlBuilder sb) {
            // Get the view data.
            Object key = context.getKey();
            ValidationData viewData = getViewData(key);
            if (viewData != null && viewData.getValue().equals(value)) {
                // Clear the view data if the value is the same as the current value.
                clearViewData(key);
                viewData = null;
            }

            /*
             * If viewData is null, just paint the contents black. If it is non-null,
             * show the pending value and paint the contents red if they are known to
             * be invalid.
             */
            String pendingValue = (viewData == null) ? null : viewData.getValue();
            boolean invalid = (viewData == null) ? false : viewData.isInvalid();

            String color = pendingValue != null ? (invalid ? "red" : "blue") : "black";
            SafeStyles safeColor = SafeStylesUtils.fromTrustedString("color: " + color + ";");
            sb.append(template.input(pendingValue != null ? pendingValue : value, safeColor));

            if (invalid) {
                sb.appendHtmlConstant("&nbsp;<span style='color:red;'>");
                sb.append(errorMessage);
                sb.appendHtmlConstant("</span>");
            }
        }

        @Override
        protected void onEnterKeyDown(Context context, Element parent, String value, NativeEvent event,
                ValueUpdater<String> valueUpdater) {
            Element target = event.getEventTarget().cast();
            if (getInputElement(parent).isOrHasChild(target)) {
                finishEditing(parent, value, context.getKey(), valueUpdater);
            } else {
                super.onEnterKeyDown(context, parent, value, event, valueUpdater);
            }
        }
    }

    /**
     * The ViewData used by {@link ValidatableInputCell}.
     */
    @ShowcaseSource
    private static class ValidationData {
        private boolean invalid;
        private String value;

        public String getValue() {
            return value;
        }

        public boolean isInvalid() {
            return invalid;
        }

        public void setInvalid(boolean invalid) {
            this.invalid = invalid;
        }

        public void setValue(String value) {
            this.value = value;
        }
    }

    // Used by ValidatableInputCell
    private static Template template;

    /**
     * Checks if an address is valid. A valid address consists of a number
     * followed by a street name, which may be composed of multiple words.
     *
     * @param address the address
     * @return true if valid, false if invalid
     */
    @ShowcaseSource
    public static boolean isAddressValid(String address) {
        // Cannot be null.
        if (address == null) {
            return false;
        }

        // Must have two or more parts.
        String[] parts = address.split(" ");
        if (parts.length < 2) {
            return false;
        }

        // First part is a number.
        try {
            Integer.parseInt(parts[0]);
        } catch (NumberFormatException e) {
            return false;
        }

        // The remaining parts form the street name.
        return true;
    }

    /**
     * An instance of the constants.
     */
    @ShowcaseData
    private final CwConstants constants;

    /**
     * Constructor.
     *
     * @param constants the constants
     */
    public CwCellValidation(CwConstants constants) {
        super(constants.cwCellValidationName(), constants.cwCellValidationDescription(), false,
                "ContactDatabase.java");
        this.constants = constants;
    }

    /**
     * Initialize this example.
     */
    @ShowcaseSource
    @Override
    public Widget onInitialize() {
        // Create a table.
        final CellTable<ContactInfo> table = new CellTable<ContactInfo>(10, ContactInfo.KEY_PROVIDER);

        // Add the Name column.
        table.addColumn(new Column<ContactInfo, String>(new TextCell()) {
            @Override
            public String getValue(ContactInfo object) {
                return object.getFullName();
            }
        }, constants.cwCellValidationColumnName());

        // Add an editable address column.
        final ValidatableInputCell addressCell = new ValidatableInputCell(constants.cwCellValidationError());
        Column<ContactInfo, String> addressColumn = new Column<ContactInfo, String>(addressCell) {
            @Override
            public String getValue(ContactInfo object) {
                return object.getAddress();
            }
        };
        table.addColumn(addressColumn, constants.cwCellValidationColumnAddress());
        addressColumn.setFieldUpdater(new FieldUpdater<ContactInfo, String>() {
            public void update(int index, final ContactInfo object, final String value) {
                // Perform validation after 2 seconds to simulate network delay.
                new Timer() {
                    @Override
                    public void run() {
                        if (isAddressValid(value)) {
                            // The cell will clear the view data when it sees the updated
                            // value.
                            object.setAddress(value);

                            // Push the change to the views.
                            ContactDatabase.get().refreshDisplays();
                        } else {
                            // Update the view data to mark the pending value as invalid.
                            ValidationData viewData = addressCell
                                    .getViewData(ContactInfo.KEY_PROVIDER.getKey(object));
                            viewData.setInvalid(true);

                            // We only modified the cell, so do a local redraw.
                            table.redraw();
                        }
                    }
                }.schedule(1000);
            }
        });

        // Add the table to the database.
        ContactDatabase.get().addDataDisplay(table);

        return table;
    }

    @Override
    protected void asyncOnInitialize(final AsyncCallback<Widget> callback) {
        GWT.runAsync(CwCellValidation.class, new RunAsyncCallback() {

            public void onFailure(Throwable caught) {
                callback.onFailure(caught);
            }

            public void onSuccess() {
                callback.onSuccess(onInitialize());
            }
        });
    }
}