View Javadoc

1   /**
2    * Copyright 2010 The Kuali Foundation Licensed under the
3    * Educational Community License, Version 2.0 (the "License"); you may
4    * not use this file except in compliance with the License. You may
5    * obtain a copy of the License at
6    *
7    * http://www.osedu.org/licenses/ECL-2.0
8    *
9    * Unless required by applicable law or agreed to in writing,
10   * software distributed under the License is distributed on an "AS IS"
11   * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
12   * or implied. See the License for the specific language governing
13   * permissions and limitations under the License.
14   */
15  
16  package org.kuali.student.lum.lu.ui.tools.client.configuration;
17  
18  import java.util.List;
19  
20  import org.kuali.student.common.assembly.data.Data;
21  import org.kuali.student.common.assembly.data.Metadata;
22  import org.kuali.student.common.rice.authorization.PermissionType;
23  import org.kuali.student.common.ui.client.application.Application;
24  import org.kuali.student.common.ui.client.application.KSAsyncCallback;
25  import org.kuali.student.common.ui.client.configurable.mvc.layouts.BasicLayout;
26  import org.kuali.student.common.ui.client.configurable.mvc.sections.Section;
27  import org.kuali.student.common.ui.client.event.SaveActionEvent;
28  import org.kuali.student.common.ui.client.event.SaveActionHandler;
29  import org.kuali.student.common.ui.client.mvc.Callback;
30  import org.kuali.student.common.ui.client.mvc.Controller;
31  import org.kuali.student.common.ui.client.mvc.DataModel;
32  import org.kuali.student.common.ui.client.mvc.DataModelDefinition;
33  import org.kuali.student.common.ui.client.mvc.ModelProvider;
34  import org.kuali.student.common.ui.client.mvc.ModelRequestCallback;
35  import org.kuali.student.common.ui.client.mvc.View;
36  import org.kuali.student.common.ui.client.mvc.WorkQueue;
37  import org.kuali.student.common.ui.client.mvc.WorkQueue.WorkItem;
38  import org.kuali.student.common.ui.client.security.AuthorizationCallback;
39  import org.kuali.student.common.ui.client.security.RequiresAuthorization;
40  import org.kuali.student.common.ui.client.service.DataSaveResult;
41  import org.kuali.student.common.ui.client.widgets.buttongroups.ButtonEnumerations;
42  import org.kuali.student.common.ui.client.widgets.buttongroups.ButtonEnumerations.ButtonEnum;
43  import org.kuali.student.common.ui.client.widgets.field.layout.button.ActionCancelGroup;
44  import org.kuali.student.common.ui.client.widgets.notification.KSNotification;
45  import org.kuali.student.common.ui.client.widgets.notification.KSNotifier;
46  import org.kuali.student.common.ui.client.widgets.progress.BlockingTask;
47  import org.kuali.student.common.ui.client.widgets.progress.KSBlockingProgressIndicator;
48  import org.kuali.student.common.validation.dto.ValidationResultInfo;
49  import org.kuali.student.common.validation.dto.ValidationResultInfo.ErrorLevel;
50  import org.kuali.student.lum.common.client.lu.LUUIPermissions;
51  import org.kuali.student.lum.common.client.widgets.CluSetHelper;
52  import org.kuali.student.lum.common.client.widgets.CluSetManagementRpcService;
53  import org.kuali.student.lum.common.client.widgets.CluSetManagementRpcServiceAsync;
54  
55  import com.google.gwt.core.client.GWT;
56  import com.google.gwt.dom.client.Style;
57  import com.google.gwt.user.client.Window;
58  import com.google.gwt.user.client.ui.Widget;
59  
60  public class CluSetsManagementController extends BasicLayout implements RequiresAuthorization{  
61  
62      private final DataModel cluSetModel = new DataModel();    
63      private WorkQueue cluSetModelRequestQueue;
64      
65      private ClusetView mainView;
66      private ClusetView createClusetView;
67      private ClusetView editClusetView;
68      private ClusetView viewClusetView;
69  
70      private boolean initialized = false;
71      CluSetManagementRpcServiceAsync cluSetManagementRpcServiceAsync = GWT.create(CluSetManagementRpcService.class);
72      public static final String CLUSET_MGT_MODEL = "cluSetManagementModel";
73      
74      private final BlockingTask initializingTask = new BlockingTask("Loading");
75      private final BlockingTask retrievingTask = new BlockingTask("Retrieving ...");
76  	private final BlockingTask saving = new BlockingTask("Saving");    
77  
78      public CluSetsManagementController(){
79          super(CluSetsManagementController.class.getName());
80          setName("Course Set Management");
81          initialize();
82      }
83      
84      public ClusetView getMainView() {
85          return mainView;
86      }
87      
88      @Override
89      public <V extends Enum<?>> void showView(final V viewType) {
90          if (viewType == ClusetView.CluSetsManagementViews.EDIT) {
91              final String cluSetId = mainView.getSelectedCluSetId();
92              editClusetView.setSelectedCluSetId(cluSetId);
93              viewClusetView.setSelectedCluSetId(cluSetId);
94              if (cluSetId != null) {
95                  KSBlockingProgressIndicator.addTask(retrievingTask);
96                  cluSetManagementRpcServiceAsync.getData(cluSetId,  new KSAsyncCallback<Data>() {
97                      @Override
98                      public void handleFailure(Throwable caught) {
99                          KSBlockingProgressIndicator.removeTask(retrievingTask);
100                         Window.alert("Failed to retrieve cluset with id" + cluSetId);
101                     }
102                     @Override
103                     public void onSuccess(Data result) {
104                         try {
105                             cluSetModel.setRoot(result);
106                             editClusetView.updateView(cluSetModel);
107                             CluSetsManagementController.super.showView(viewType);
108                         } finally {
109                             KSBlockingProgressIndicator.removeTask(retrievingTask);
110                         }
111                     }
112                 });
113             }
114         } else if (viewType == ClusetView.CluSetsManagementViews.VIEW) {
115             final String cluSetId = mainView.getSelectedCluSetId();
116             editClusetView.setSelectedCluSetId(cluSetId);
117             viewClusetView.setSelectedCluSetId(cluSetId);
118             if (cluSetId != null) {
119                 KSBlockingProgressIndicator.addTask(retrievingTask);
120                 cluSetManagementRpcServiceAsync.getData(cluSetId,  new KSAsyncCallback<Data>() {
121                     @Override
122                     public void handleFailure(Throwable caught) {
123                         KSBlockingProgressIndicator.removeTask(retrievingTask);
124                         Window.alert("Failed to retrieve cluset with id" + cluSetId);
125                     }
126                     @Override
127                     public void onSuccess(Data result) {
128                         try {
129                             cluSetModel.setRoot(result);
130                             viewClusetView.updateView(cluSetModel);
131                             afterModelLoaded();
132                             CluSetsManagementController.super.showView(viewType);
133                         } finally {
134                             KSBlockingProgressIndicator.removeTask(retrievingTask);
135                         }
136                     }
137                 });
138             }
139         } else {
140             cluSetModel.setRoot(new Data());
141             super.showView(viewType);
142         }
143     }
144 
145     private void afterModelLoaded() {
146       viewClusetView.afterModelIsLoaded(cluSetModel);
147     }
148 
149     private Widget getButtonPanel() {
150         ActionCancelGroup actionCancel =  new ActionCancelGroup(
151                 ButtonEnumerations.SaveCancelEnum.SAVE,
152                 ButtonEnumerations.SaveCancelEnum.CANCEL);
153         actionCancel.addCallback(new Callback<ButtonEnumerations.ButtonEnum>() {
154             @Override
155             public void exec(ButtonEnum result) {
156                 if (result == ButtonEnumerations.SaveCancelEnum.SAVE) {
157                     fireApplicationEvent(new SaveActionEvent());
158                 } else if (result == ButtonEnumerations.SaveCancelEnum.CANCEL) {
159                     showView(ClusetView.CluSetsManagementViews.MAIN);
160                 }
161             }
162         });
163         return actionCancel;
164     }
165 
166     private void initialize() {
167         super.setDefaultModelId(CLUSET_MGT_MODEL);
168         
169         // the callback is used here to append widgets at the end of the view.
170         // callback is needed here because there is an asynchronous call to retrieve
171         // metadata during the construction of ClusetView
172         createClusetView = new ClusetView(ClusetView.CluSetsManagementViews.CREATE,
173                 "Build Course Set", CLUSET_MGT_MODEL, new Callback<Boolean>() {
174                     @Override
175                     public void exec(Boolean result) {
176                         if (result == true) {
177                             Widget buttonPanel = getButtonPanel();
178                             buttonPanel.getElement().getStyle().setPaddingTop(50, Style.Unit.PX);
179                             createClusetView.addWidget(buttonPanel);
180                         }
181                     }
182         });
183         editClusetView = new ClusetView(ClusetView.CluSetsManagementViews.EDIT,
184                 "Edit Course Set", CLUSET_MGT_MODEL, new Callback<Boolean>() {
185                     @Override
186                     public void exec(Boolean result) {
187                         if (result == true) {
188                             Widget buttonPanel = getButtonPanel();
189                             buttonPanel.getElement().getStyle().setPaddingTop(50, Style.Unit.PX);
190                             editClusetView.addWidget(buttonPanel);
191                         }
192                     }
193         });
194         viewClusetView = new ClusetView(ClusetView.CluSetsManagementViews.VIEW,
195                 "View Course Set", CLUSET_MGT_MODEL, null);
196         
197         mainView = new ClusetView(ClusetView.CluSetsManagementViews.MAIN,
198                 "", CLUSET_MGT_MODEL, null);
199         
200         setDefaultView(ClusetView.CluSetsManagementViews.MAIN);
201         addView(createClusetView);
202         addView(editClusetView);
203         addView(viewClusetView);
204         addView(mainView);
205         
206         super.registerModel(CLUSET_MGT_MODEL, new ModelProvider<DataModel>() {
207 
208             @Override
209             public void requestModel(final ModelRequestCallback<DataModel> callback) {
210                 if (cluSetModelRequestQueue == null){
211                     cluSetModelRequestQueue = new WorkQueue();
212                 }
213 
214                 WorkItem workItem = new WorkItem(){
215                     @Override
216                     public void exec(Callback<Boolean> workCompleteCallback) {
217                         if (cluSetModel.getRoot() == null || cluSetModel.getRoot().size() == 0){
218                             cluSetModel.setRoot(new Data());
219                         }
220                         callback.onModelReady(cluSetModel);
221                         workCompleteCallback.exec(true);
222 
223                     }               
224                 };
225                 cluSetModelRequestQueue.submit(workItem);                
226             }
227 
228         });
229 
230     }
231     
232     private void init(final Callback<Boolean> onReadyCallback) {
233 		
234         if (initialized) {
235             onReadyCallback.exec(true);
236         } else {
237     		KSBlockingProgressIndicator.addTask(initializingTask);
238             cluSetManagementRpcServiceAsync.getMetadata("courseSet", null, new KSAsyncCallback<Metadata>(){
239 
240                 @Override
241                 public void handleFailure(Throwable caught) {
242                     onReadyCallback.exec(false);
243                     KSBlockingProgressIndicator.removeTask(initializingTask);
244                     throw new RuntimeException("Failed to get model definition.", caught);                        
245                 }
246 
247                 @Override
248                 public void onSuccess(Metadata result) {
249                     DataModelDefinition def = new DataModelDefinition(result);
250                     cluSetModel.setDefinition(def);
251                     init(def);
252                     initialized = true;
253                     onReadyCallback.exec(true);
254                     KSBlockingProgressIndicator.removeTask(initializingTask);
255                 }                
256             });	        
257         }
258     }
259     
260     private void init(DataModelDefinition modelDefinition){
261 
262         if (!initialized){
263 //            cfg.configureCluSetManager(this);
264 //            addButton("Manage CLU Sets", getSaveButton());
265 //            addButton("Manage CLU Sets", getQuitButton());
266 //            addButton("View CLU Sets", getSaveButton());
267 //            addButton("View CLU Sets", getQuitButton());
268 
269             addApplicationEventHandler(SaveActionEvent.TYPE, new SaveActionHandler(){
270                 @Override
271                 public void doSave(SaveActionEvent saveAction) {
272                     GWT.log("CluSetManagementController received save action request.", null);
273                     doSaveAction(saveAction);
274                 }
275             });
276         }
277 
278         initialized = true;
279     }
280 
281     @Override
282     protected void renderView(View view) {
283         super.renderView(view);
284 //        getNextButton("Manage CLU Sets").setVisible(false);
285 //        getNextButton("View CLU Sets").setVisible(false);
286     }
287 
288     @SuppressWarnings("unchecked")
289     @Override
290     public void requestModel(Class modelType, final ModelRequestCallback callback) {
291         super.requestModel(modelType, callback);
292     }
293 
294     public void doSaveAction(final SaveActionEvent saveActionEvent){
295 //        Enum clusetSectionEnum = getCurrentViewEnum();
296 
297         getCurrentView().updateModel();
298 
299         if(cluSetModel!=null){
300             cluSetModel.validate(new Callback<List<ValidationResultInfo>>() {
301 	            @Override
302 	            public void exec(List<ValidationResultInfo> result) {
303 	
304 	                boolean save = true;
305 	                View v = getCurrentView();
306 	                if(v instanceof Section){
307 	                    ((Section) v).setFieldHasHadFocusFlags(true);
308 	                    ErrorLevel status = ((Section) v).processValidationResults(result);
309 	                    if(status == ErrorLevel.ERROR){
310 	                        save = false;
311 	                    }
312 	                }
313 	
314 	                if(save){
315 	                    getCurrentView().updateModel();
316 	                    CluSetsManagementController.this.updateModel();
317 	                    // set reusable flag here for CluSetManagement.
318 //	                    CluSetHelper.wrap((Data)cluSetModel.getRoot().get("cluset")).setReusable(new Boolean(true));
319 	                    CluSetHelper.wrap((Data)cluSetModel.getRoot()).setReusable(new Boolean(true));
320 	                    saveModel(cluSetModel, saveActionEvent);
321 	                }
322 	                else{
323 	                    Window.alert("Save failed.  Please check fields for errors.");
324 	                }
325 	
326 	            }
327 	        });
328         }
329     }
330 
331     private void saveModel(final DataModel dataModel, final SaveActionEvent saveActionEvent) {
332     	KSBlockingProgressIndicator.addTask(saving);    	
333         
334     	cluSetManagementRpcServiceAsync.saveData(dataModel.getRoot(), new KSAsyncCallback<DataSaveResult>() {
335     	    @Override
336             public void handleFailure(Throwable caught) {
337                 GWT.log("Save Failed.", caught);
338                 KSBlockingProgressIndicator.removeTask(saving);                
339                 KSNotifier.add(new KSNotification("Save Failed on server. Please try again.", false, true, 5000));
340             }
341                 
342             @Override
343             public void handleVersionMismatch(Throwable caught) {
344                 super.handleVersionMismatch(caught);
345                 KSBlockingProgressIndicator.removeTask(saving);
346             }
347 
348             @Override
349             public void onSuccess(DataSaveResult result) {
350               	KSBlockingProgressIndicator.removeTask(saving);
351                	if (result.getValidationResults() != null &&
352                	        !result.getValidationResults().isEmpty()) {
353                	    StringBuilder errorMessage = new StringBuilder();
354                     errorMessage.append("Validation error: ");
355                     for (ValidationResultInfo validationError : result.getValidationResults()) {
356                         errorMessage.append(validationError.getMessage()).append(" ");
357                     }
358                     KSNotifier.add(new KSNotification("Save Failed. " + errorMessage, false, 5000));                        
359                	} else {
360                     dataModel.setRoot(result.getValue());
361                     KSNotifier.add(new KSNotification("Save Successful", false, 4000));
362                 }
363             }
364         });
365     	
366     }
367 
368     @Override
369     public void showDefaultView(final Callback<Boolean> onReadyCallback) {
370         init(new Callback<Boolean>() {
371             @Override
372             public void exec(Boolean result) {
373                 if (result) {
374                     doShowDefaultView(onReadyCallback);
375                 } else {
376                     onReadyCallback.exec(false);
377                 }
378             }
379         });
380     }
381     
382     @Override
383     public void beforeShow(Callback<Boolean> onReadyCallback) {
384     	showDefaultView(onReadyCallback);
385     }
386 
387     private void doShowDefaultView(final Callback<Boolean> onReadyCallback) {
388         super.showDefaultView(onReadyCallback);
389     }
390 
391     @Override
392     public void setParentController(Controller controller) {
393         super.setParentController(controller);    
394     }
395     
396     @Override
397 	public boolean isAuthorizationRequired() {
398 		return true;
399 	}
400 
401 	@Override
402 	public void setAuthorizationRequired(boolean required) {
403 		throw new UnsupportedOperationException();
404 	}
405 	
406 	@Override
407 	public void checkAuthorization(final AuthorizationCallback authCallback) {
408 		Application.getApplicationContext().getSecurityContext().checkScreenPermission(LUUIPermissions.USE_VIEW_COURSE_SET_MANAGEMENT_SCREENS, new Callback<Boolean>() {
409 			@Override
410 			public void exec(Boolean result) {
411 
412 				final boolean isAuthorized = result;
413 	        
414 				if(isAuthorized){
415 					authCallback.isAuthorized();
416 				}
417 				else
418 					authCallback.isNotAuthorized("User is not authorized: " + LUUIPermissions.USE_VIEW_COURSE_SET_MANAGEMENT_SCREENS);
419 			}	
420 		});
421 	}
422     
423 }