package org.activityinfo.ui.client.page.app; import com.extjs.gxt.ui.client.binding.FieldBinding; import com.extjs.gxt.ui.client.binding.FormBinding; import com.extjs.gxt.ui.client.event.Events; import com.extjs.gxt.ui.client.event.FieldEvent; import com.extjs.gxt.ui.client.event.Listener; import com.extjs.gxt.ui.client.widget.Info; import com.extjs.gxt.ui.client.widget.MessageBox; import com.extjs.gxt.ui.client.widget.form.CheckBox; import com.extjs.gxt.ui.client.widget.form.FormPanel; import com.extjs.gxt.ui.client.widget.form.TextField; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.inject.Inject; import org.activityinfo.i18n.shared.I18N; import org.activityinfo.legacy.client.Dispatcher; import org.activityinfo.legacy.shared.Log; import org.activityinfo.legacy.shared.command.GetUserProfile; import org.activityinfo.legacy.shared.command.UpdateUserProfile; import org.activityinfo.legacy.shared.command.result.VoidResult; import org.activityinfo.legacy.shared.model.UserProfileDTO; import org.activityinfo.model.auth.AuthenticatedUser; import org.activityinfo.ui.client.inject.ClientSideAuthProvider; import org.activityinfo.ui.client.page.*; import java.util.Arrays; import java.util.List; import java.util.Objects; public class UserProfilePage extends FormPanel implements Page { public static final PageId PAGE_ID = new PageId("userprofile"); private final Dispatcher dispatcher; private FormBinding binding; private UserProfileDTO userProfile; @Inject public UserProfilePage(final Dispatcher dispatcher) { super(); this.dispatcher = dispatcher; this.setHeadingText(I18N.CONSTANTS.userProfile()); this.hide(); // avoid showing an unbound form, will be shown when bound binding = new FormBinding(this); TextField<String> nameField = new TextField<String>(); nameField.setAllowBlank(false); nameField.setFieldLabel(I18N.CONSTANTS.name()); nameField.setMaxLength(50); nameField.addListener(Events.Change, new ProfileChangeListener("name")); binding.addFieldBinding(new FieldBinding(nameField, "name")); this.add(nameField); TextField<String> organizationField = new TextField<String>(); organizationField.setFieldLabel(I18N.CONSTANTS.organization()); organizationField.setMaxLength(100); organizationField.addListener(Events.Change, new ProfileChangeListener("organization")); binding.addFieldBinding(new FieldBinding(organizationField, "organization")); this.add(organizationField); TextField<String> jobtitleField = new TextField<String>(); jobtitleField.setFieldLabel(I18N.CONSTANTS.jobtitle()); jobtitleField.setMaxLength(100); jobtitleField.addListener(Events.Change, new ProfileChangeListener("jobtitle")); binding.addFieldBinding(new FieldBinding(jobtitleField, "jobtitle")); this.add(jobtitleField); CheckBox emailNotification = new CheckBox(); emailNotification.setFieldLabel(I18N.CONSTANTS.emailNotification()); emailNotification.addListener(Events.Change, new ProfileChangeListener("emailNotification")); binding.addFieldBinding(new FieldBinding(emailNotification, "emailNotification")); this.add(emailNotification); bindProfile(); } private void bindProfile() { userProfile = new UserProfileDTO(); AuthenticatedUser user = new ClientSideAuthProvider().get(); dispatcher.execute(new GetUserProfile(user.getUserId()), new AsyncCallback<UserProfileDTO>() { @Override public void onFailure(Throwable caught) { Log.error("error binding profile", caught); MessageBox.alert(I18N.CONSTANTS.serverError(), caught.getMessage(), null); } @Override public void onSuccess(UserProfileDTO userProfileDTO) { userProfile = userProfileDTO; binding.bind(userProfile); UserProfilePage.this.show(); } }); } private void saveProfile() { AuthenticatedUser user = new ClientSideAuthProvider().get(); if (user != null && user.getUserId() == userProfile.getUserId()) { dispatcher.execute(new UpdateUserProfile(userProfile), new AsyncCallback<VoidResult>() { @Override public void onSuccess(final VoidResult result) { Info.display(I18N.CONSTANTS.saved(), I18N.CONSTANTS.savedChanges()); } @Override public final void onFailure(final Throwable caught) { Log.error("error saving profile", caught); MessageBox.alert(I18N.CONSTANTS.serverError(), caught.getMessage(), null); } }); } } @Override public void shutdown() { } @Override public PageId getPageId() { return PAGE_ID; } @Override public Object getWidget() { return this; } @Override public void requestToNavigateAway(PageState place, NavigationCallback callback) { callback.onDecided(true); } @Override public String beforeWindowCloses() { return null; } @Override public boolean navigate(PageState place) { return true; } private class ProfileChangeListener implements Listener<FieldEvent> { private String fieldname; public ProfileChangeListener(String fieldname) { this.fieldname = fieldname; } @Override public void handleEvent(FieldEvent fe) { // check if we need to save (change-event is also called on init) Object modelValue = userProfile.get(fieldname); Object fieldValue = fe.getField().getValue(); if (!Objects.equals(modelValue, fieldValue)) { // this eventtype fires before the form->model binding occurs, so we need to // set the model-value manually before save.. userProfile.set(fieldname, fieldValue); saveProfile(); } } } public static class State implements PageState { @Override public PageId getPageId() { return UserProfilePage.PAGE_ID; } @Override public String serializeAsHistoryToken() { return null; } @Override public List<PageId> getEnclosingFrames() { return Arrays.asList(UserProfilePage.PAGE_ID); } @Override public Section getSection() { return null; } } public static class StateParser implements PageStateParser { @Override public PageState parse(String token) { return new State(); } } }