com.google.gwt.sample.expenses.client.place.AbstractProxyEditActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.google.gwt.sample.expenses.client.place.AbstractProxyEditActivity.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.expenses.client.place;

import com.google.gwt.activity.shared.Activity;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.place.shared.PlaceController;
import com.google.gwt.requestfactory.client.RequestFactoryEditorDriver;
import com.google.gwt.requestfactory.shared.EntityProxy;
import com.google.gwt.requestfactory.shared.EntityProxyId;
import com.google.gwt.requestfactory.shared.Receiver;
import com.google.gwt.requestfactory.shared.RequestContext;
import com.google.gwt.requestfactory.shared.ServerFailure;
import com.google.gwt.requestfactory.shared.Violation;
import com.google.gwt.sample.expenses.client.place.ProxyPlace.Operation;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.AcceptsOneWidget;

import java.util.Set;

/**
 * Abstract activity for editing a record. Subclasses must provide access to the
 * request that will be fired when Save is clicked.
 * <p>
 * Instances are not reusable. Once an activity is stoped, it cannot be
 * restarted.
 * 
 * @param <P> the type of Proxy being edited
 */
public abstract class AbstractProxyEditActivity<P extends EntityProxy> implements Activity, ProxyEditView.Delegate {

    private final ProxyEditView<P, ?> view;
    private final PlaceController placeController;

    private RequestFactoryEditorDriver<P, ?> editorDriver;
    private boolean waiting;

    public AbstractProxyEditActivity(ProxyEditView<P, ?> view, PlaceController placeController) {
        this.view = view;
        this.placeController = placeController;
    }

    public void cancelClicked() {
        String unsavedChangesWarning = mayStop();
        if ((unsavedChangesWarning == null) || Window.confirm(unsavedChangesWarning)) {
            editorDriver = null;
            exit(false);
        }
    }

    public String mayStop() {
        if (isWaiting() || changed()) {
            return "Are you sure you want to abandon your changes?";
        }

        return null;
    }

    public void onCancel() {
        onStop();
    }

    public void onStop() {
        view.setDelegate(null);
        editorDriver = null;
    }

    public void saveClicked() {
        if (!changed()) {
            return;
        }

        setWaiting(true);
        editorDriver.flush().fire(new Receiver<Void>() {
            /*
             * Callbacks do nothing if editorDriver is null, we were stopped in
             * midflight
             */
            @Override
            public void onFailure(ServerFailure error) {
                if (editorDriver != null) {
                    setWaiting(false);
                    super.onFailure(error);
                }
            }

            @Override
            public void onSuccess(Void ignore) {
                if (editorDriver != null) {
                    // We want no warnings from mayStop, so:

                    // Defeat isChanged check
                    editorDriver = null;

                    // Defeat call-in-flight check
                    setWaiting(false);

                    exit(true);
                }
            }

            @Override
            public void onViolation(Set<Violation> errors) {
                if (editorDriver != null) {
                    setWaiting(false);
                    editorDriver.setViolations(errors);
                }
            }
        });
    }

    public void start(AcceptsOneWidget display, EventBus eventBus) {
        editorDriver = view.createEditorDriver();
        view.setDelegate(this);
        editorDriver.edit(getProxy(), createSaveRequest(getProxy()));
        display.setWidget(view);
    }

    /**
     * Called once to create the appropriate request to save
     * changes.
     * 
     * @return the request context to fire when the save button is clicked
     */
    protected abstract RequestContext createSaveRequest(P proxy);

    /**
     * Called when the user cancels or has successfully saved. This default
     * implementation tells the {@link PlaceController} to show the details of the
     * edited record.
     * 
     * @param saved true if changes were comitted, false if user canceled
     */
    protected void exit(@SuppressWarnings("unused") boolean saved) {
        placeController.goTo(new ProxyPlace(getProxyId(), Operation.DETAILS));
    }

    /**
     * Get the proxy to be edited. Must be mutable, typically via a call to
     * {@link RequestContext#edit(EntityProxy)}, or
     * {@link RequestContext#create(Class)}.
     */
    protected abstract P getProxy();

    @SuppressWarnings("unchecked")
    // id type always matches proxy type
    protected EntityProxyId<P> getProxyId() {
        return (EntityProxyId<P>) getProxy().stableId();
    }

    private boolean changed() {
        return editorDriver != null && editorDriver.flush().isChanged();
    }

    /**
     * @return true if we're waiting for an rpc response.
     */
    private boolean isWaiting() {
        return waiting;
    }

    /**
     * While we are waiting for a response, we cannot poke setters on the proxy
     * (that is, we cannot call editorDriver.flush). So we set the waiting flag to
     * warn ourselves not to, and to disable the view.
     */
    private void setWaiting(boolean wait) {
        this.waiting = wait;
        view.setEnabled(!wait);
    }
}