package __TOP_LEVEL_PACKAGE__.client.scaffold.place; import javax.validation.ConstraintViolation; import com.google.gwt.activity.shared.Activity; import com.google.gwt.event.shared.EventBus; import com.google.gwt.place.shared.PlaceController; import com.google.web.bindery.requestfactory.gwt.client.RequestFactoryEditorDriver; import com.google.web.bindery.requestfactory.shared.*; 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 stopped, it cannot be * restarted. * * @param <P> the type of Proxy being edited */ public abstract class AbstractProxyEditActivity<P extends EntityProxy> implements Activity, ProxyEditView.Delegate { protected 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; } RequestContext request = editorDriver.flush(); if (editorDriver.hasErrors()) { return; } setWaiting(true); request.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 onConstraintViolation(Set<ConstraintViolation<?>> violations) { if (editorDriver != null) { setWaiting(false); editorDriver.setConstraintViolations(violations); } } }); } public void start(AcceptsOneWidget display, EventBus eventBus) { editorDriver = view.createEditorDriver(); view.setDelegate(this); editorDriver.edit(getProxy(), createSaveRequest(getProxy())); editorDriver.flush(); 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(), ProxyPlace.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); } }