blob: d27a8c618aff40d547c8656fb10e8caf5ea3ba23 [file] [log] [blame]
/*
* 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.app.place;
import com.google.gwt.app.place.ProxyPlace.Operation;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.requestfactory.shared.Receiver;
import com.google.gwt.requestfactory.shared.RecordRequest;
import com.google.gwt.requestfactory.shared.RequestFactory;
import com.google.gwt.requestfactory.shared.RequestObject;
import com.google.gwt.user.client.Window;
import com.google.gwt.valuestore.shared.Record;
import com.google.gwt.valuestore.shared.SyncResult;
import com.google.gwt.valuestore.shared.Value;
import java.util.Set;
/**
* <p>
* <span style="color:red">Experimental API: This class is still under rapid
* development, and is very likely to be deleted. Use it at your own risk.
* </span>
* </p>
* Abstract activity for editing a record.
*
* @param <R> the type of Record being edited
*/
public abstract class AbstractRecordEditActivity<R extends Record> implements
Activity, RecordEditView.Delegate {
private RequestObject<Void> requestObject;
private final boolean creating;
private final RecordEditView<R> view;
private final Class<R> proxyType;
private final RequestFactory requests;
private final PlaceController placeController;
private R record;
private Long futureId;
private Display display;
public AbstractRecordEditActivity(RecordEditView<R> view, R record,
Class<R> proxyType, boolean creating, RequestFactory requests,
PlaceController placeController) {
this.view = view;
this.record = record;
this.proxyType = proxyType;
this.placeController = placeController;
this.creating = creating;
this.requests = requests;
}
public void cancelClicked() {
String unsavedChangesWarning = mayStop();
if ((unsavedChangesWarning == null)
|| Window.confirm(unsavedChangesWarning)) {
if (requestObject != null) {
// silence the next mayStop() call when place changes
requestObject.reset();
}
exit(false);
}
}
public R getRecord() {
return record;
}
public RecordEditView<R> getView() {
return view;
}
public String mayStop() {
if (requestObject != null && requestObject.isChanged()) {
return "Are you sure you want to abandon your changes?";
}
return null;
}
public void onCancel() {
onStop();
}
public void onStop() {
this.display = null;
}
public void saveClicked() {
assert requestObject != null;
if (!requestObject.isChanged()) {
return;
}
view.setEnabled(false);
final RequestObject<Void> toCommit = requestObject;
requestObject = null;
Receiver<Void> receiver = new Receiver<Void>() {
public void onSuccess(Void ignore, Set<SyncResult> response) {
if (display == null) {
return;
}
boolean hasViolations = false;
for (SyncResult syncResult : response) {
Record syncRecord = syncResult.getRecord();
if (creating) {
if (futureId == null || !futureId.equals(syncResult.getFutureId())) {
continue;
}
record = cast(syncRecord);
} else {
if (!syncRecord.getId().equals(record.getId())) {
continue;
}
}
if (syncResult.hasViolations()) {
hasViolations = true;
view.showErrors(syncResult.getViolations());
}
}
if (!hasViolations) {
exit(true);
} else {
requestObject = toCommit;
requestObject.clearUsed();
view.setEnabled(true);
}
}
};
toCommit.fire(receiver);
}
public void start(Display display, EventBus eventBus) {
this.display = display;
view.setDelegate(this);
view.setCreating(creating);
if (creating) {
R tempRecord = requests.create(proxyType);
futureId = tempRecord.getId();
doStart(display, tempRecord);
} else {
RecordRequest<R> findRequest = getFindRequest(Value.of(getRecord().getId()));
findRequest.with(getView().getPaths()).fire(new Receiver<R>() {
public void onSuccess(R record, Set<SyncResult> syncResults) {
if (AbstractRecordEditActivity.this.display != null) {
doStart(AbstractRecordEditActivity.this.display, record);
}
}
});
}
}
/**
* Called when the user cancels or has successfully saved. This default
* implementation tells the {@link PlaceController} to show the details of the
* edited record, or clears the display if a creation was canceled.
* <p>
* If we're creating, a call to getRecord() from here will return a record
* with the correct id. However, other properties may be stale or unset.
*
* @param saved true if changes were comitted
*/
protected void exit(boolean saved) {
if (!saved && creating) {
display.showActivityWidget(null);
} else {
placeController.goTo(new ProxyPlace(getRecord(), Operation.DETAILS));
}
}
/**
* Called to fetch the details of the edited record.
*/
protected abstract RecordRequest<R> getFindRequest(Value<Long> id);
protected abstract RequestObject<Void> getPersistRequest(R record);
@SuppressWarnings("unchecked")
private R cast(Record syncRecord) {
return (R) syncRecord;
}
private void doStart(final Display display, R record) {
requestObject = getPersistRequest(record);
R editableRecord = requestObject.edit(record);
view.setEnabled(true);
view.setValue(editableRecord);
view.showErrors(null);
display.showActivityWidget(view);
}
}