1 /* 2 * Copyright 2010 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 package com.google.gwt.sample.dynatablerf.client; 17 18 import com.google.gwt.core.client.GWT; 19 import com.google.gwt.event.dom.client.ClickEvent; 20 import com.google.gwt.event.dom.client.KeyCodes; 21 import com.google.gwt.event.dom.client.KeyUpEvent; 22 import com.google.gwt.event.dom.client.KeyUpHandler; 23 import com.google.gwt.event.logical.shared.ValueChangeEvent; 24 import com.google.gwt.event.shared.EventBus; 25 import com.google.gwt.sample.dynatablerf.client.events.EditPersonEvent; 26 import com.google.gwt.sample.dynatablerf.client.widgets.MentorSelector; 27 import com.google.gwt.sample.dynatablerf.client.widgets.PersonEditor; 28 import com.google.gwt.sample.dynatablerf.client.widgets.ScheduleEditor; 29 import com.google.gwt.sample.dynatablerf.client.widgets.TimeSlotListWidget; 30 import com.google.gwt.sample.dynatablerf.shared.DynaTableRequestFactory; 31 import com.google.gwt.sample.dynatablerf.shared.DynaTableRequestFactory.PersonRequest; 32 import com.google.gwt.sample.dynatablerf.shared.PersonProxy; 33 import com.google.gwt.uibinder.client.UiBinder; 34 import com.google.gwt.uibinder.client.UiField; 35 import com.google.gwt.uibinder.client.UiHandler; 36 import com.google.gwt.user.client.ui.CheckBox; 37 import com.google.gwt.user.client.ui.DialogBox; 38 import com.google.gwt.user.client.ui.HTMLPanel; 39 import com.google.web.bindery.requestfactory.gwt.client.RequestFactoryEditorDriver; 40 import com.google.web.bindery.requestfactory.shared.Receiver; 41 import com.google.web.bindery.requestfactory.shared.Request; 42 import com.google.web.bindery.requestfactory.shared.RequestContext; 43 44 import java.util.Set; 45 46 import javax.validation.ConstraintViolation; 47 48 /** 49 * This class shows how the UI for editing a person is wired up to the 50 * RequestFactoryEditorDelegate. It is also responsible for showing and 51 * dismissing the PersonEditor. The use of the FavoriteManager shows integration 52 * between a remote service and a local service. 53 */ 54 public class PersonEditorWorkflow { 55 interface Binder extends UiBinder<DialogBox, PersonEditorWorkflow> { 56 Binder BINDER = GWT.create(Binder.class); 57 } 58 59 interface Driver extends 60 RequestFactoryEditorDriver<PersonProxy, PersonEditor> { 61 } 62 register(EventBus eventBus, final DynaTableRequestFactory requestFactory, final FavoritesManager manager)63 static void register(EventBus eventBus, 64 final DynaTableRequestFactory requestFactory, 65 final FavoritesManager manager) { 66 eventBus.addHandler(EditPersonEvent.TYPE, new EditPersonEvent.Handler() { 67 public void startEdit(PersonProxy person, RequestContext requestContext) { 68 new PersonEditorWorkflow(requestFactory, manager, person).edit(requestContext); 69 } 70 }); 71 } 72 73 @UiField 74 HTMLPanel contents; 75 76 @UiField 77 DialogBox dialog; 78 79 @UiField 80 CheckBox favorite; 81 82 @UiField(provided = true) 83 PersonEditor personEditor; 84 85 private Driver editorDriver; 86 private final FavoritesManager manager; 87 private PersonProxy person; 88 private final DynaTableRequestFactory requestFactory; 89 PersonEditorWorkflow(DynaTableRequestFactory requestFactory, FavoritesManager manager, PersonProxy person)90 private PersonEditorWorkflow(DynaTableRequestFactory requestFactory, 91 FavoritesManager manager, PersonProxy person) { 92 this.requestFactory = requestFactory; 93 this.manager = manager; 94 this.person = person; 95 TimeSlotListWidget timeSlotEditor = new TimeSlotListWidget(requestFactory); 96 ScheduleEditor scheduleEditor = new ScheduleEditor(timeSlotEditor); 97 MentorSelector mentorEditor = new MentorSelector(requestFactory); 98 personEditor = new PersonEditor(mentorEditor, scheduleEditor); 99 Binder.BINDER.createAndBindUi(this); 100 contents.addDomHandler(new KeyUpHandler() { 101 public void onKeyUp(KeyUpEvent event) { 102 if (event.getNativeKeyCode() == KeyCodes.KEY_ESCAPE) { 103 onCancel(null); 104 } 105 } 106 }, KeyUpEvent.getType()); 107 this.favorite.setVisible(false); 108 } 109 110 /** 111 * Called by the cancel button when it is clicked. This method will just tear 112 * down the UI and clear the state of the workflow. 113 */ 114 @UiHandler("cancel") onCancel(ClickEvent event)115 void onCancel(ClickEvent event) { 116 dialog.hide(); 117 } 118 119 /** 120 * Called by the edit dialog's save button. This method will flush the 121 * contents of the UI into the PersonProxy that is being edited, check for 122 * errors, and send the request to the server. 123 */ 124 @UiHandler("save") onSave(ClickEvent event)125 void onSave(ClickEvent event) { 126 // Flush the contents of the UI 127 RequestContext context = editorDriver.flush(); 128 129 // Check for errors 130 if (editorDriver.hasErrors()) { 131 dialog.setText("Errors detected locally"); 132 return; 133 } 134 135 // Send the request 136 context.fire(new Receiver<Void>() { 137 @Override 138 public void onConstraintViolation(Set<ConstraintViolation<?>> errors) { 139 // Otherwise, show ConstraintViolations in the UI 140 dialog.setText("Errors detected on the server"); 141 editorDriver.setConstraintViolations(errors); 142 } 143 144 @Override 145 public void onSuccess(Void response) { 146 // If everything went as planned, just dismiss the dialog box 147 dialog.hide(); 148 } 149 }); 150 } 151 152 /** 153 * Called by the favorite checkbox when its value has been toggled. 154 */ 155 @UiHandler("favorite") onValueChanged(ValueChangeEvent<Boolean> event)156 void onValueChanged(ValueChangeEvent<Boolean> event) { 157 manager.setFavorite(person.stableId(), favorite.getValue()); 158 } 159 160 /** 161 * Construct and display the UI that will be used to edit the current 162 * PersonProxy, using the given RequestContext to accumulate the edits. 163 */ edit(RequestContext requestContext)164 private void edit(RequestContext requestContext) { 165 editorDriver = GWT.create(Driver.class); 166 editorDriver.initialize(requestFactory, personEditor); 167 168 if (requestContext == null) { 169 this.favorite.setVisible(true); 170 fetchAndEdit(); 171 return; 172 } 173 174 editorDriver.edit(person, requestContext); 175 personEditor.focus(); 176 favorite.setValue(manager.isFavorite(person), false); 177 dialog.center(); 178 } 179 fetchAndEdit()180 private void fetchAndEdit() { 181 // The request is configured arbitrarily 182 Request<PersonProxy> fetchRequest = requestFactory.find(person.stableId()); 183 184 // Add the paths that the EditorDrives computes 185 fetchRequest.with(editorDriver.getPaths()); 186 187 // We could do more with the request, but we just fire it 188 fetchRequest.to(new Receiver<PersonProxy>() { 189 @Override 190 public void onSuccess(PersonProxy person) { 191 PersonEditorWorkflow.this.person = person; 192 // Start the edit process 193 PersonRequest context = requestFactory.personRequest(); 194 // Display the UI 195 edit(context); 196 // Configure the method invocation to be sent in the context 197 context.persist().using(person); 198 // The context will be fire()'ed from the onSave() method 199 } 200 }).fire(); 201 } 202 } 203