| /* |
| * 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); |
| } |
| } |