Coverage Report - org.kuali.student.lum.lu.ui.course.client.controllers.CourseProposalController
 
Classes in this File Line Coverage Branch Coverage Complexity
CourseProposalController
0%
0/171
0%
0/58
1.985
CourseProposalController$1
0%
0/6
0%
0/2
1.985
CourseProposalController$1$1
0%
0/6
0%
0/4
1.985
CourseProposalController$10
0%
0/14
N/A
1.985
CourseProposalController$11
0%
0/9
0%
0/2
1.985
CourseProposalController$11$1
0%
0/9
0%
0/4
1.985
CourseProposalController$12
0%
0/5
N/A
1.985
CourseProposalController$13
0%
0/35
0%
0/14
1.985
CourseProposalController$14
0%
0/10
0%
0/2
1.985
CourseProposalController$15
0%
0/11
0%
0/6
1.985
CourseProposalController$15$1
0%
0/12
0%
0/4
1.985
CourseProposalController$15$1$1
0%
0/5
0%
0/2
1.985
CourseProposalController$15$1$2
0%
0/10
0%
0/2
1.985
CourseProposalController$16
0%
0/3
N/A
1.985
CourseProposalController$17
0%
0/3
N/A
1.985
CourseProposalController$18
0%
0/5
0%
0/2
1.985
CourseProposalController$19
0%
0/1
N/A
1.985
CourseProposalController$2
0%
0/5
0%
0/4
1.985
CourseProposalController$3
0%
0/3
N/A
1.985
CourseProposalController$4
0%
0/4
N/A
1.985
CourseProposalController$5
0%
0/19
0%
0/10
1.985
CourseProposalController$5$1
0%
0/14
N/A
1.985
CourseProposalController$6
0%
0/13
0%
0/8
1.985
CourseProposalController$7
0%
0/8
N/A
1.985
CourseProposalController$8
0%
0/10
N/A
1.985
CourseProposalController$9
0%
0/11
0%
0/2
1.985
 
 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.course.client.controllers;
 17  
 
 18  
 import java.text.DateFormat;
 19  
 import java.util.ArrayList;
 20  
 import java.util.Date;
 21  
 import java.util.HashMap;
 22  
 import java.util.List;
 23  
 import java.util.Map;
 24  
 
 25  
 import org.kuali.student.common.ui.client.application.Application;
 26  
 import org.kuali.student.common.ui.client.application.KSAsyncCallback;
 27  
 import org.kuali.student.common.ui.client.application.ViewContext;
 28  
 import org.kuali.student.common.ui.client.configurable.mvc.layouts.MenuEditableSectionController;
 29  
 import org.kuali.student.common.ui.client.configurable.mvc.sections.Section;
 30  
 import org.kuali.student.common.ui.client.configurable.mvc.views.SectionView;
 31  
 import org.kuali.student.common.ui.client.event.ActionEvent;
 32  
 import org.kuali.student.common.ui.client.event.ContentDirtyEvent;
 33  
 import org.kuali.student.common.ui.client.event.ContentDirtyEventHandler;
 34  
 import org.kuali.student.common.ui.client.event.SaveActionEvent;
 35  
 import org.kuali.student.common.ui.client.event.SaveActionHandler;
 36  
 import org.kuali.student.common.ui.client.mvc.ActionCompleteCallback;
 37  
 import org.kuali.student.common.ui.client.mvc.Callback;
 38  
 import org.kuali.student.common.ui.client.mvc.Controller;
 39  
 import org.kuali.student.common.ui.client.mvc.DataModel;
 40  
 import org.kuali.student.common.ui.client.mvc.DataModelDefinition;
 41  
 import org.kuali.student.common.ui.client.mvc.ModelProvider;
 42  
 import org.kuali.student.common.ui.client.mvc.ModelRequestCallback;
 43  
 import org.kuali.student.common.ui.client.mvc.View;
 44  
 import org.kuali.student.common.ui.client.mvc.WorkQueue;
 45  
 import org.kuali.student.common.ui.client.mvc.WorkQueue.WorkItem;
 46  
 import org.kuali.student.common.ui.client.mvc.dto.ReferenceModel;
 47  
 import org.kuali.student.common.ui.client.mvc.history.HistoryManager;
 48  
 import org.kuali.student.common.ui.client.security.AuthorizationCallback;
 49  
 import org.kuali.student.common.ui.client.security.RequiresAuthorization;
 50  
 import org.kuali.student.common.ui.client.service.DataSaveResult;
 51  
 import org.kuali.student.common.ui.client.util.WindowTitleUtils;
 52  
 import org.kuali.student.common.ui.client.widgets.KSButton;
 53  
 import org.kuali.student.common.ui.client.widgets.KSButtonAbstract.ButtonStyle;
 54  
 import org.kuali.student.common.ui.client.widgets.buttongroups.ButtonEnumerations.YesNoCancelEnum;
 55  
 import org.kuali.student.common.ui.client.widgets.dialog.ButtonMessageDialog;
 56  
 import org.kuali.student.common.ui.client.widgets.field.layout.button.ButtonGroup;
 57  
 import org.kuali.student.common.ui.client.widgets.field.layout.button.YesNoCancelGroup;
 58  
 import org.kuali.student.common.ui.client.widgets.notification.KSNotification;
 59  
 import org.kuali.student.common.ui.client.widgets.notification.KSNotifier;
 60  
 import org.kuali.student.common.ui.client.widgets.progress.BlockingTask;
 61  
 import org.kuali.student.common.ui.client.widgets.progress.KSBlockingProgressIndicator;
 62  
 import org.kuali.student.common.ui.shared.IdAttributes;
 63  
 import org.kuali.student.common.ui.shared.IdAttributes.IdType;
 64  
 import org.kuali.student.core.assembly.data.Data;
 65  
 import org.kuali.student.core.assembly.data.Metadata;
 66  
 import org.kuali.student.core.assembly.data.QueryPath;
 67  
 import org.kuali.student.core.rice.StudentIdentityConstants;
 68  
 import org.kuali.student.core.rice.authorization.PermissionType;
 69  
 import org.kuali.student.core.statement.dto.StatementTypeInfo;
 70  
 import org.kuali.student.core.validation.dto.ValidationResultInfo;
 71  
 import org.kuali.student.core.workflow.ui.client.widgets.WorkflowEnhancedNavController;
 72  
 import org.kuali.student.core.workflow.ui.client.widgets.WorkflowUtilities;
 73  
 import org.kuali.student.lum.common.client.helpers.RecentlyViewedHelper;
 74  
 import org.kuali.student.lum.common.client.widgets.AppLocations;
 75  
 import org.kuali.student.lum.lu.ui.course.client.configuration.CourseConfigurer;
 76  
 import org.kuali.student.lum.lu.ui.course.client.requirements.CourseRequirementsDataModel;
 77  
 import org.kuali.student.lum.lu.ui.course.client.service.CourseRpcService;
 78  
 import org.kuali.student.lum.lu.ui.course.client.service.CourseRpcServiceAsync;
 79  
 import org.kuali.student.lum.lu.ui.course.client.service.CreditCourseProposalRpcService;
 80  
 import org.kuali.student.lum.lu.ui.course.client.service.CreditCourseProposalRpcServiceAsync;
 81  
 
 82  
 import com.google.gwt.core.client.GWT;
 83  
 import com.google.gwt.event.dom.client.ClickEvent;
 84  
 import com.google.gwt.event.dom.client.ClickHandler;
 85  
 import com.google.gwt.user.client.Window;
 86  
 import com.google.gwt.user.client.rpc.AsyncCallback;
 87  
 
 88  
 /**
 89  
  * Controller for course proposal screens
 90  
  *
 91  
  * @author Kuali Student Team
 92  
  *
 93  
  */
 94  
 
 95  0
 public class CourseProposalController extends MenuEditableSectionController implements RequiresAuthorization, WorkflowEnhancedNavController{
 96  
 
 97  
         //RPC Services
 98  0
         CreditCourseProposalRpcServiceAsync cluProposalRpcServiceAsync = GWT.create(CreditCourseProposalRpcService.class);
 99  0
         CourseRpcServiceAsync courseServiceAsync = GWT.create(CourseRpcService.class);
 100  
         //Models
 101  0
         private final DataModel cluProposalModel = new DataModel("Proposal");
 102  0
         private final DataModel comparisonModel = new DataModel("Original Course");
 103  
 
 104  0
         CourseConfigurer cfg = GWT.create(CourseConfigurer.class);
 105  
         
 106  
         private WorkQueue modelRequestQueue;
 107  
 
 108  
     private WorkflowUtilities workflowUtil;
 109  
 
 110  0
         private boolean initialized = false;
 111  0
         private boolean isNew = false;
 112  
 
 113  
         private static final String UPDATED_KEY = "metaInfo/updateTime";
 114  
         private static final String VERSION_KEY  = "versionInfo/versionedFromId";
 115  
         private static final String MODIFY_TYPE = "kuali.proposal.type.course.modify";
 116  
         public static final String CREATE_TYPE = "kuali.proposal.type.course.create";
 117  
         public static final String INITIAL_SAVE_VERSION = "1";
 118  0
         private String currentDocType = CREATE_TYPE;
 119  0
         private String proposalPath = "";
 120  
         private String currentTitle;
 121  
 
 122  0
         private final DateFormat df = DateFormat.getInstance();
 123  
 
 124  0
         private final BlockingTask initializingTask = new BlockingTask("Loading");
 125  0
         private final BlockingTask loadDataTask = new BlockingTask("Retrieving Data");
 126  0
         private final BlockingTask saving = new BlockingTask("Saving");
 127  
 
 128  
     public CourseProposalController(){
 129  0
         super(CourseProposalController.class.getName());
 130  0
         initialize();
 131  0
         addStyleName("courseProposal");
 132  0
     }
 133  
 
 134  
     @Override
 135  
     public void setViewContext(ViewContext viewContext) {
 136  0
             super.setViewContext(viewContext);
 137  0
             if(viewContext.getId() != null && !viewContext.getId().isEmpty()){
 138  0
                     if(viewContext.getIdType() != IdType.COPY_OF_OBJECT_ID){
 139  0
                             viewContext.setPermissionType(PermissionType.OPEN);
 140  
                     }
 141  
                     else{
 142  
                             //they are trying to make a modification
 143  0
                             viewContext.setPermissionType(PermissionType.INITIATE);
 144  
                     }
 145  
             }
 146  
             else{
 147  0
                     viewContext.setPermissionType(PermissionType.INITIATE);
 148  
             }
 149  0
     }
 150  
 
 151  
     private void initialize() {
 152  
             //TODO get from messages
 153  
 
 154  0
                    proposalPath = cfg.getProposalPath();
 155  0
                    workflowUtil = new WorkflowUtilities(CourseProposalController.this ,proposalPath);
 156  
 
 157  0
         super.setDefaultModelId(cfg.getModelId());
 158  0
         super.registerModel(cfg.getModelId(), new ModelProvider<DataModel>() {
 159  
 
 160  
             @Override
 161  
             public void requestModel(final ModelRequestCallback<DataModel> callback) {
 162  0
                 if (modelRequestQueue == null){
 163  0
                     modelRequestQueue = new WorkQueue();
 164  
                 }
 165  
 
 166  0
                 WorkItem workItem = new WorkItem(){
 167  
                     @Override
 168  
                     public void exec(Callback<Boolean> workCompleteCallback) {
 169  0
                         if (cluProposalModel.getRoot() == null || initialized == false){
 170  0
                             initModel(callback, workCompleteCallback);
 171  
                         } else {
 172  0
                             callback.onModelReady(cluProposalModel);
 173  0
                             workCompleteCallback.exec(true);
 174  
                         }
 175  0
                     }
 176  
                 };
 177  0
                 modelRequestQueue.submit(workItem);
 178  
 
 179  0
             }
 180  
 
 181  
         });
 182  0
         super.registerModel("ComparisonModel", new ModelProvider<DataModel>() {
 183  
             @Override
 184  
             public void requestModel(final ModelRequestCallback<DataModel> callback) {
 185  0
                     if(comparisonModel.getRoot() != null && comparisonModel.getRoot().size() != 0){
 186  0
                             callback.onModelReady(comparisonModel);
 187  
                             
 188  
                     }
 189  
                     else{
 190  0
                             callback.onModelReady(null);
 191  
                     }
 192  
                 
 193  0
             }
 194  
         });
 195  0
         super.addApplicationEventHandler(ContentDirtyEvent.TYPE, new ContentDirtyEventHandler(){
 196  
                         public void onContentDirty(ContentDirtyEvent event) {
 197  0
                         setContentWarning("You have unsaved changes");                                
 198  0
                         }                
 199  
         });
 200  
 
 201  0
         addApplicationEventHandler(SaveActionEvent.TYPE, new SaveActionHandler(){
 202  
             public void doSave(SaveActionEvent saveAction) {
 203  0
                 GWT.log("CluProposalController received save action request.", null);
 204  0
                 doSaveAction(saveAction);
 205  0
             }
 206  
         });
 207  0
     }
 208  
 
 209  
     private void initModel(final ModelRequestCallback<DataModel> callback, Callback<Boolean> workCompleteCallback){
 210  0
             if(getViewContext().getIdType() == IdType.DOCUMENT_ID){
 211  0
             getCluProposalFromWorkflowId(callback, workCompleteCallback);
 212  0
         } else if (getViewContext().getIdType() == IdType.KS_KEW_OBJECT_ID){
 213  0
             getCluProposalFromProposalId(getViewContext().getId(), callback, workCompleteCallback);
 214  0
         } else if (getViewContext().getIdType() == IdType.COPY_OF_OBJECT_ID){
 215  0
             createModifyCluProposalModel("versionComment", callback, workCompleteCallback);
 216  
         } else{
 217  0
             createNewCluProposalModel(callback, workCompleteCallback);
 218  
         }
 219  0
     }
 220  
 
 221  
     private void getCurrentModel(final ModelRequestCallback<DataModel> callback, Callback<Boolean> workCompleteCallback){
 222  0
             if (cluProposalModel.getRoot() != null && cluProposalModel.getRoot().size() > 0){
 223  0
                 String id = cluProposalModel.get(cfg.getProposalPath()+"/id");
 224  0
                 if(id != null){
 225  0
                         getCluProposalFromProposalId(id, callback, workCompleteCallback);
 226  
                 }
 227  
                 else{
 228  0
                         initModel(callback, workCompleteCallback);
 229  
                 }
 230  0
             }
 231  
             else{
 232  0
                     initModel(callback, workCompleteCallback);
 233  
             }
 234  0
     }
 235  
 
 236  
     private void init(final Callback<Boolean> onReadyCallback) {
 237  0
             if (initialized) {
 238  0
                     onReadyCallback.exec(true);
 239  
             } else {
 240  0
                     initialized = true;
 241  0
                     KSBlockingProgressIndicator.addTask(initializingTask);
 242  0
                     setContentWarning("");
 243  0
             this.requestModel(new ModelRequestCallback<DataModel>(){
 244  
 
 245  
                                 @Override
 246  
                                 public void onModelReady(DataModel model) {
 247  
                                         //Setup View Context
 248  0
                                         String idType = null;
 249  0
                                     String viewContextId = "";
 250  0
                                     if(getViewContext().getIdType() != null){
 251  0
                                 idType = getViewContext().getIdType().toString();
 252  0
                                 viewContextId = getViewContext().getId();
 253  0
                                 if(getViewContext().getIdType()==IdAttributes.IdType.COPY_OF_OBJECT_ID){
 254  0
                                         viewContextId = null;
 255  
                                 }
 256  
 
 257  
                                     }
 258  0
                                         HashMap<String, String> idAttributes = new HashMap<String, String>();
 259  0
                                     if(idType != null){
 260  0
                                             idAttributes.put(IdAttributes.ID_TYPE, idType);
 261  
                                     }
 262  0
                                     if(cluProposalModel.get(VERSION_KEY) != null && !((String)cluProposalModel.get(VERSION_KEY)).equals("")){
 263  0
                                             currentDocType = MODIFY_TYPE;
 264  
                                     }
 265  0
                                     idAttributes.put(StudentIdentityConstants.DOCUMENT_TYPE_NAME, currentDocType);
 266  
 
 267  
                                     //Get metadata and complete initializing the screen
 268  0
                                     cluProposalRpcServiceAsync.getMetadata(viewContextId, idAttributes, new KSAsyncCallback<Metadata>(){
 269  
                                                 @Override
 270  
                         public void handleTimeout(Throwable caught) {
 271  0
                                         initializeFailed(); 
 272  0
                                                 }
 273  
 
 274  
                                                 @Override
 275  
                         public void handleFailure(Throwable caught) {
 276  0
                                                         initializeFailed();
 277  0
                                     throw new RuntimeException("Failed to get model definition.", caught);
 278  
                                 }
 279  
 
 280  
                                                 public void initializeFailed(){
 281  0
                                                 initialized = false;
 282  0
                                         onReadyCallback.exec(false);
 283  0
                                         KSBlockingProgressIndicator.removeTask(initializingTask);                                                        
 284  0
                                                 }
 285  
                                                 
 286  
                                 public void onSuccess(Metadata result) {
 287  0
                                         DataModelDefinition def = new DataModelDefinition(result);
 288  0
                                     cluProposalModel.setDefinition(def);
 289  0
                                     comparisonModel.setDefinition(def);
 290  
 
 291  0
                                     configureScreens(def, onReadyCallback);
 292  0
                                 }
 293  
                                   });
 294  
                                         
 295  0
                                 }
 296  
 
 297  
                                 @Override
 298  
                                 public void onRequestFail(Throwable cause) {
 299  0
                                         GWT.log("Failed to get modeld for proposal controller init");
 300  0
                                         onReadyCallback.exec(false);
 301  0
                                 }
 302  
                         });
 303  
                                 
 304  
             }
 305  0
     }
 306  
 
 307  
     private void configureScreens(final DataModelDefinition modelDefinition, final Callback<Boolean> onReadyCallback){
 308  0
         workflowUtil.requestAndSetupModel();
 309  
 
 310  0
         CourseRequirementsDataModel.getStatementTypes(new Callback<List<StatementTypeInfo>>() {
 311  
 
 312  
             @Override
 313  
             public void exec(List<StatementTypeInfo> stmtTypes) {
 314  0
                 List<StatementTypeInfo> stmtTypesOut = new ArrayList<StatementTypeInfo>();
 315  0
                 if (stmtTypes != null) {
 316  0
                     for (StatementTypeInfo stmtType : stmtTypes) {
 317  0
                         if (stmtType.getId().contains("kuali.statement.type.course.enrollmentEligibility") ||
 318  
                             stmtType.getId().contains("kuali.statement.type.course.creditConstraints")) {
 319  0
                             continue;
 320  
                         }
 321  0
                         stmtTypesOut.add(stmtType);
 322  
                     }
 323  
                 }
 324  
 
 325  0
                 cfg.setStatementTypes(stmtTypesOut);
 326  0
                 cfg.setModelDefinition(modelDefinition);
 327  0
                 cfg.configure(CourseProposalController.this);
 328  
 
 329  0
                 onReadyCallback.exec(true);
 330  0
                 KSBlockingProgressIndicator.removeTask(initializingTask);
 331  0
             }
 332  
         });
 333  0
     }
 334  
 
 335  
         /**
 336  
      * @see org.kuali.student.common.ui.client.mvc.Controller#getViewsEnum()
 337  
      */
 338  
     @Override
 339  
     public Class<? extends Enum<?>> getViewsEnum() {
 340  0
         return cfg.getViewsEnum();
 341  
     }
 342  
 
 343  
     @Override
 344  
     @SuppressWarnings("unchecked")
 345  
     public void requestModel(Class modelType, final ModelRequestCallback callback) {
 346  0
         if(modelType == ReferenceModel.class){
 347  0
                 if (cluProposalModel != null){
 348  0
                         ReferenceModel ref = new ReferenceModel();
 349  
 
 350  0
                         if(cluProposalModel.get(cfg.getProposalPath()) != null){
 351  0
                             ref.setReferenceId((String)cluProposalModel.get(cfg.getProposalPath()+"/id"));
 352  
                         } else {
 353  0
                                 ref.setReferenceId(null);
 354  
                         }
 355  
                         
 356  
                         //Use the referenceAttribute to store misc data from the parent model like reference name, etc
 357  0
                         if(cluProposalModel.get(cfg.getProposalPath()) != null){
 358  0
                                 Map<String, String> attributes = new HashMap<String, String>();
 359  0
                                 attributes.put("name", (String)cluProposalModel.get(cfg.getProposalPath()+"/name"));
 360  0
                                 ref.setReferenceAttributes(attributes);
 361  0
                         } else {
 362  0
                                 ref.setReferenceAttributes(null);
 363  
                         }
 364  
 
 365  0
                         ref.setReferenceTypeKey(cfg.getProposalReferenceTypeKey());
 366  0
                         ref.setReferenceType(cfg.getProposalReferenceObjectType());
 367  0
                         ref.setReferenceState(getViewContext().getState());
 368  
 
 369  0
                         callback.onModelReady(ref);
 370  0
                 }
 371  0
         } else if (modelType == Data.class){
 372  0
                 requestModel(cfg.getModelId(), callback);
 373  
         } else {
 374  0
             super.requestModel(modelType, callback);
 375  
         }
 376  
 
 377  0
     }
 378  
 
 379  
     @SuppressWarnings("unchecked")
 380  
     private void getCluProposalFromWorkflowId(final ModelRequestCallback callback, final Callback<Boolean> workCompleteCallback){
 381  0
         KSBlockingProgressIndicator.addTask(loadDataTask);
 382  0
         workflowUtil.getDataIdFromWorkflowId(getViewContext().getId(), new KSAsyncCallback<String>(){
 383  
                         @Override
 384  
                         public void handleFailure(Throwable caught) {
 385  0
                 Window.alert("Error loading Proposal from Workflow Document: "+caught.getMessage());
 386  0
                 createNewCluProposalModel(callback, workCompleteCallback);
 387  0
                 KSBlockingProgressIndicator.removeTask(loadDataTask);
 388  0
                         }
 389  
 
 390  
                         @Override
 391  
                         public void onSuccess(String proposalId) {
 392  0
                                 KSBlockingProgressIndicator.removeTask(loadDataTask);
 393  0
                                 getCluProposalFromProposalId(proposalId, callback, workCompleteCallback);
 394  0
                         }
 395  
         });
 396  0
     }
 397  
 
 398  
     @SuppressWarnings("unchecked")
 399  
     private void getCluProposalFromProposalId(String id, final ModelRequestCallback callback, final Callback<Boolean> workCompleteCallback){
 400  0
             KSBlockingProgressIndicator.addTask(loadDataTask);
 401  0
             cluProposalRpcServiceAsync.getData(id, new KSAsyncCallback<Data>(){
 402  
 
 403  
                         @Override
 404  
                         public void handleFailure(Throwable caught) {
 405  0
                 Window.alert("Error loading Proposal: "+caught.getMessage());
 406  0
                 createNewCluProposalModel(callback, workCompleteCallback);
 407  0
                 KSBlockingProgressIndicator.removeTask(loadDataTask);
 408  0
                         }
 409  
 
 410  
                         @Override
 411  
                         public void onSuccess(Data result) {
 412  0
                                 cluProposalModel.setRoot(result);
 413  0
                         setProposalHeaderTitle();
 414  0
                         setLastUpdated();
 415  0
                         getCourseComparisonModel(callback, workCompleteCallback);
 416  0
                         }
 417  
 
 418  
             });
 419  0
     }
 420  
 
 421  
         @SuppressWarnings("unchecked")
 422  
         private void getCourseComparisonModel(final ModelRequestCallback proposalModelRequestCallback, final Callback<Boolean> workCompleteCallback){
 423  0
                 if(cluProposalModel.get(VERSION_KEY) != null && !((String)cluProposalModel.get(VERSION_KEY)).equals("")){
 424  0
                         courseServiceAsync.getData((String)cluProposalModel.get(VERSION_KEY), new KSAsyncCallback<Data>(){
 425  
         
 426  
                             @Override
 427  
                     public void handleFailure(Throwable caught) {
 428  0
                         Window.alert("Error loading Proposal: "+caught.getMessage());
 429  0
                         createNewCluProposalModel(proposalModelRequestCallback, workCompleteCallback);
 430  0
                         KSBlockingProgressIndicator.removeTask(loadDataTask);
 431  0
                     }
 432  
                             
 433  
                                 @Override
 434  
                                 public void onSuccess(Data result) {
 435  0
                                         if(result != null){
 436  0
                                                 comparisonModel.setRoot(result);
 437  
                                         }
 438  0
                                         proposalModelRequestCallback.onModelReady(cluProposalModel);
 439  0
                                         workCompleteCallback.exec(true);
 440  0
                                         KSBlockingProgressIndicator.removeTask(loadDataTask);
 441  0
                                 }
 442  
                         });
 443  
                 }
 444  
                 else{
 445  0
                         proposalModelRequestCallback.onModelReady(cluProposalModel);
 446  0
                         workCompleteCallback.exec(true);
 447  0
                         KSBlockingProgressIndicator.removeTask(loadDataTask);
 448  
                 }
 449  0
         }
 450  
 
 451  
     @SuppressWarnings("unchecked")
 452  
     private void createNewCluProposalModel(final ModelRequestCallback callback, final Callback<Boolean> workCompleteCallback){
 453  0
         cluProposalModel.setRoot(new Data());
 454  0
         isNew = true;
 455  0
         setProposalHeaderTitle();
 456  0
         setLastUpdated();
 457  0
         callback.onModelReady(cluProposalModel);
 458  0
         workCompleteCallback.exec(true);
 459  0
     }
 460  
 
 461  
     @SuppressWarnings("unchecked")
 462  
     private void createModifyCluProposalModel(String versionComment, final ModelRequestCallback callback, final Callback<Boolean> workCompleteCallback){
 463  0
         Data data = new Data();
 464  
         
 465  0
         Data proposalData = new Data();
 466  0
         proposalData.set(new Data.StringKey("type"), MODIFY_TYPE);
 467  0
         data.set(new Data.StringKey("proposal"), proposalData);
 468  
         
 469  0
         Data versionData = new Data();
 470  0
         versionData.set(new Data.StringKey("versionIndId"), getViewContext().getId());
 471  0
         versionData.set(new Data.StringKey("versionComment"), versionComment);
 472  0
         data.set(new Data.StringKey("versionInfo"), versionData);
 473  
         
 474  0
         cluProposalModel.setRoot(data);
 475  0
         cluProposalRpcServiceAsync.saveData(cluProposalModel.getRoot(), new AsyncCallback<DataSaveResult>() {
 476  
                         public void onSuccess(DataSaveResult result) {
 477  0
                                 cluProposalModel.setRoot(result.getValue());
 478  0
                                 setProposalHeaderTitle();
 479  0
                         setLastUpdated();
 480  
                         //add to recently viewed now that we know the id of proposal
 481  0
                         ViewContext docContext = new ViewContext();
 482  0
                         docContext.setId((String) cluProposalModel.get(cfg.getProposalPath()+"/id"));
 483  0
                         docContext.setIdType(IdType.KS_KEW_OBJECT_ID);
 484  0
                         RecentlyViewedHelper.addDocument(getProposalTitle(), 
 485  
                                         HistoryManager.appendContext(AppLocations.Locations.COURSE_PROPOSAL.getLocation(), docContext)
 486  
                                         + "/SUMMARY");
 487  0
                         getCourseComparisonModel(callback, workCompleteCallback);
 488  0
                         }
 489  
                         
 490  
                         public void onFailure(Throwable caught) {
 491  0
                 Window.alert("Error loading Proposal: "+caught.getMessage());
 492  0
                 createNewCluProposalModel(callback, workCompleteCallback);
 493  0
                 KSBlockingProgressIndicator.removeTask(loadDataTask);
 494  0
                         }
 495  
                 });
 496  0
     }
 497  
 
 498  
     public void doSaveAction(final SaveActionEvent saveActionEvent){
 499  0
         requestModel(new ModelRequestCallback<DataModel>() {
 500  
             @Override
 501  
             public void onModelReady(DataModel model) {
 502  0
                 CourseProposalController.this.updateModelFromCurrentView();
 503  
 
 504  0
                 if (isStartViewShowing()){
 505  
                         //This call required so fields in start section, which also appear in
 506  
                         //other sections don't get overridden from updateModel call above.
 507  0
                         getStartPopupView().updateModel();
 508  
                 }
 509  
 
 510  0
                     model.validate(new Callback<List<ValidationResultInfo>>() {
 511  
                     @Override
 512  
                     public void exec(List<ValidationResultInfo> result) {
 513  
 
 514  0
                             boolean isSectionValid = isValid(result, true);
 515  
 
 516  0
                             if(isSectionValid){
 517  0
                             if (startSectionRequired()){
 518  0
                                 showStartPopup(NO_OP_CALLBACK);
 519  0
                                 saveActionEvent.doActionComplete();
 520  
                             }
 521  
                             else{
 522  0
                                     saveProposalClu(saveActionEvent);
 523  
                             }
 524  
                             }
 525  
                             else{
 526  
                                     //saveActionEvent.doActionComplete();
 527  0
                                     Window.alert("Save failed.  Please check fields for errors.");
 528  
                             }
 529  
 
 530  0
                     }
 531  
                 });
 532  0
             }
 533  
 
 534  
             @Override
 535  
             public void onRequestFail(Throwable cause) {
 536  0
                     saveActionEvent.doActionComplete();
 537  0
                 GWT.log("Unable to retrieve model for validation and save", cause);
 538  0
             }
 539  
 
 540  
         });
 541  
 
 542  0
     }
 543  
 
 544  
     public boolean startSectionRequired(){
 545  0
         String proposalId = cluProposalModel.get(cfg.getProposalPath()+"/id");
 546  
 
 547  
         //Defaulting the proposalTitle to courseTitle, this way course data gets set and assembler doesn't
 548  
         //complain. This may not be the correct approach.
 549  0
         String proposalTitle = cluProposalModel.get(cfg.getProposalTitlePath());
 550  0
         if (proposalTitle == null || proposalTitle.isEmpty()){
 551  0
             String courseTitle = cluProposalModel.get(cfg.getCourseTitlePath());
 552  0
             cluProposalModel.set(QueryPath.parse(cfg.getProposalTitlePath()), courseTitle);
 553  
         }
 554  
 
 555  0
             return proposalId==null && !CourseProposalController.this.isStartViewShowing();
 556  
     }
 557  
 
 558  
     public void saveProposalClu(final SaveActionEvent saveActionEvent){
 559  0
             KSBlockingProgressIndicator.addTask(saving);
 560  0
         final Callback<Throwable> saveFailedCallback = new Callback<Throwable>() {
 561  
 
 562  
                         @Override
 563  
                         public void exec(Throwable caught) {
 564  0
                                  GWT.log("Save Failed.", caught);
 565  0
                                  KSBlockingProgressIndicator.removeTask(saving);
 566  0
                  KSNotifier.add(new KSNotification("Save Failed on server. Please try again.", false, 5000));
 567  0
                         }
 568  
 
 569  
         };
 570  
         try {
 571  0
             cluProposalRpcServiceAsync.saveData(cluProposalModel.getRoot(), new KSAsyncCallback<DataSaveResult>(){
 572  
                 @Override
 573  
                 public void handleFailure(Throwable caught) {
 574  0
                    saveFailedCallback.exec(caught);
 575  0
                 }
 576  
 
 577  
                 public void onSuccess(DataSaveResult result) {
 578  0
                         KSBlockingProgressIndicator.removeTask(saving);
 579  
 
 580  0
                         if(result.getValidationResults()!=null && !result.getValidationResults().isEmpty()){
 581  0
                                 isValid(result.getValidationResults(), false, true);
 582  0
                             saveActionEvent.setGotoNextView(false);
 583  0
                         saveActionEvent.doActionComplete();
 584  0
                         KSNotifier.add(new KSNotification("Save Failed. There were validation errors.", false, 5000));
 585  
                         }else{
 586  
                                 
 587  0
                                 saveActionEvent.setSaveSuccessful(true);
 588  0
                                 cluProposalModel.setRoot(result.getValue());
 589  0
                                 String title = getProposalTitle();
 590  
 
 591  0
                                 View currentView = getCurrentView();
 592  0
                                             if (currentView instanceof SectionView){
 593  0
                                                     ((SectionView)currentView).updateView(cluProposalModel);
 594  0
                                                     ((SectionView) currentView).resetDirtyFlags();
 595  
                                 }
 596  0
                             saveActionEvent.doActionComplete();
 597  
                             
 598  0
                                             ViewContext context = CourseProposalController.this.getViewContext();
 599  0
                                             context.setId((String)cluProposalModel.get(proposalPath+"/id"));
 600  0
                                             context.setIdType(IdType.KS_KEW_OBJECT_ID);
 601  
                                             
 602  
                                             //Ensure workflow doc status gets updated from draft, only done on intial save
 603  
                                             //to reduce workflow rpc calls.
 604  0
                                             String proposalVersion = cluProposalModel.get(proposalPath+"/metaInfo/versionInd");
 605  0
                                             if (INITIAL_SAVE_VERSION.equals(proposalVersion)){
 606  0
                                                     workflowUtil.refresh();
 607  
                                             }
 608  
                                             
 609  0
                                             setProposalHeaderTitle();
 610  0
                                             setLastUpdated();
 611  0
                                             HistoryManager.logHistoryChange();
 612  0
                                 if(isNew){
 613  0
                                         RecentlyViewedHelper.addCurrentDocument(title);
 614  
                                 }
 615  0
                                 else if(!currentTitle.equals(title)){
 616  0
                                         RecentlyViewedHelper.updateTitle(currentTitle, title, (String)cluProposalModel.get(proposalPath+"/id"));
 617  
                                 }
 618  0
                                 isNew = false;
 619  
                                             
 620  0
                                             if(saveActionEvent.gotoNextView()){
 621  0
                                                     CourseProposalController.this.showNextViewOnMenu();
 622  
                                             }
 623  0
                                             KSNotifier.add(new KSNotification("Save Successful", false, 4000));
 624  
                         }
 625  0
                 }
 626  
             });
 627  0
         } catch (Exception e) {
 628  0
                 saveFailedCallback.exec(e);
 629  0
         }
 630  
 
 631  0
     }
 632  
 
 633  
     public void setLastUpdated(){
 634  0
             Date lastUpdated = (Date)cluProposalModel.get(UPDATED_KEY);
 635  0
             if(lastUpdated != null){
 636  0
                     setContentInfo("Last Updated: " + df.format(lastUpdated));
 637  
             }
 638  
             else{
 639  0
                     setContentInfo("");
 640  
             }
 641  0
     }
 642  
 
 643  
     @Override
 644  
         public void beforeShow(final Callback<Boolean> onReadyCallback){
 645  0
                 init(onReadyCallback);
 646  0
         }
 647  
     
 648  
    @Override
 649  
    public void showDefaultView(Callback<Boolean> onReadyCallback) {
 650  0
            if(isNew){
 651  0
                    super.showFirstView(onReadyCallback);
 652  
            }
 653  
            else{
 654  0
                    super.showDefaultView(onReadyCallback);
 655  
            }
 656  0
    }
 657  
 
 658  
         @Override
 659  
     public void setParentController(Controller controller) {
 660  0
         super.setParentController(controller);
 661  0
     }
 662  
 
 663  
         @Override
 664  
         public void checkAuthorization(final PermissionType permissionType, final AuthorizationCallback authCallback) {
 665  0
                 Map<String,String> attributes = new HashMap<String,String>();
 666  
 //                if (StringUtils.isNotBlank(getViewContext().getId())) {
 667  0
                 GWT.log("Attempting Auth Check.", null);
 668  0
                 if ( (getViewContext().getId() != null) && (!"".equals(getViewContext().getId())) ) {
 669  0
                         attributes.put(getViewContext().getIdType().toString(), getViewContext().getId());
 670  
                 }
 671  
 
 672  0
                 cluProposalRpcServiceAsync.isAuthorized(permissionType, attributes, new KSAsyncCallback<Boolean>(){
 673  
 
 674  
                         @Override
 675  
                         public void handleFailure(Throwable caught) {
 676  0
                                 authCallback.isNotAuthorized("Error checking authorization.");
 677  0
                                 GWT.log("Error checking proposal authorization.", caught);
 678  0
                 Window.alert("Error Checking Proposal Authorization: "+caught.getMessage());
 679  0
                         }
 680  
 
 681  
                         @Override
 682  
                         public void onSuccess(Boolean result) {
 683  0
                                 GWT.log("Succeeded checking auth for permission type '" + permissionType + "' with result: " + result, null);
 684  0
                                 if (Boolean.TRUE.equals(result)) {
 685  0
                                         authCallback.isAuthorized();
 686  
                                 }
 687  
                                 else {
 688  0
                                         authCallback.isNotAuthorized("User is not authorized: " + permissionType);
 689  
                                 }
 690  0
                         }
 691  
             });
 692  0
         }
 693  
 
 694  
         @Override
 695  
         public boolean isAuthorizationRequired() {
 696  0
                 return true;
 697  
         }
 698  
 
 699  
         @Override
 700  
         public void setAuthorizationRequired(boolean required) {
 701  0
                 throw new UnsupportedOperationException();
 702  
         }
 703  
 
 704  
     protected void setProposalHeaderTitle(){
 705  
             String title;
 706  0
             if (cluProposalModel.get(cfg.getProposalTitlePath()) != null){
 707  0
                     title = getProposalTitle();
 708  
             }
 709  
             else{
 710  0
                     title = "New Course (Proposal)";
 711  
             }
 712  0
             this.setContentTitle(title);
 713  0
             this.setName(title);
 714  0
             WindowTitleUtils.setContextTitle(title);
 715  0
                 currentTitle = title;
 716  0
     }
 717  
 
 718  
         @Override
 719  
         public WorkflowUtilities getWfUtilities() {
 720  0
                 return workflowUtil;
 721  
         }
 722  
 
 723  
         @Override
 724  
         public void beforeViewChange(Enum<?> viewChangingTo, final Callback<Boolean> okToChange) {
 725  
                 //We do this check here because theoretically the subcontroller views
 726  
                 //will display their own messages to the user to give them a reason why the view
 727  
                 //change has been cancelled, otherwise continue to check for reasons not to change
 728  
                 //with this controller
 729  0
                 super.beforeViewChange(viewChangingTo, new Callback<Boolean>(){
 730  
 
 731  
                         @Override
 732  
                         public void exec(Boolean result) {
 733  0
                                 if(result){
 734  0
                                         if(getCurrentView() instanceof SectionView && ((SectionView)getCurrentView()).isDirty()){
 735  0
                                                 ButtonGroup<YesNoCancelEnum> buttonGroup = new YesNoCancelGroup();
 736  0
                                                 final ButtonMessageDialog<YesNoCancelEnum> dialog = new ButtonMessageDialog<YesNoCancelEnum>("Warning", "You may have unsaved changes.  Save changes?", buttonGroup);
 737  0
                                                 buttonGroup.addCallback(new Callback<YesNoCancelEnum>(){
 738  
 
 739  
                                                         @Override
 740  
                                                         public void exec(YesNoCancelEnum result) {
 741  0
                                                                 switch(result){
 742  
                                                                         case YES:
 743  0
                                                                                 dialog.hide();
 744  0
                                                                                 final SaveActionEvent e = new SaveActionEvent();
 745  0
                                                                                 e.setActionCompleteCallback(new ActionCompleteCallback(){
 746  
 
 747  
                                                                                         @Override
 748  
                                                                                         public void onActionComplete(ActionEvent action) {
 749  0
                                                                                                 if(e.isSaveSuccessful()){
 750  0
                                                                                                         okToChange.exec(true);
 751  
                                                                                                 }
 752  
                                                                                                 else{
 753  0
                                                                                                         okToChange.exec(false);
 754  
                                                                                                 }
 755  0
                                                                                         }
 756  
                                                                                         
 757  
                                                                                 });
 758  0
                                                                                 fireApplicationEvent(e);
 759  0
                                                                                 break;
 760  
                                                                         case NO:
 761  
                                                                                 //Force a model request from server
 762  0
                                                                                 getCurrentModel(new ModelRequestCallback<DataModel>(){
 763  
 
 764  
                                                                                         @Override
 765  
                                                                                         public void onModelReady(DataModel model) {
 766  0
                                                                                                 if (getCurrentView()instanceof Section){
 767  0
                                                                                                     ((Section) getCurrentView()).resetFieldInteractionFlags();
 768  
                                                                                                 }
 769  0
                                                                                                 okToChange.exec(true);
 770  0
                                                                                                 dialog.hide();
 771  0
                                                                                         }
 772  
 
 773  
                                                                                         @Override
 774  
                                                                                         public void onRequestFail(Throwable cause) {
 775  
                                                                                                 //TODO Is this correct... do we want to stop view change if we can't restore the data?  Possibly traps the user
 776  
                                                                                                 //if we don't it messes up saves, possibly warn the user that it failed and continue?
 777  0
                                                                                                 okToChange.exec(false);
 778  0
                                                                                                 dialog.hide();
 779  0
                                                                                                 GWT.log("Unable to retrieve model for data restore on view change with no save", cause);
 780  0
                                                                                         }},
 781  
                                                                                         NO_OP_CALLBACK);
 782  
 
 783  0
                                                                                 break;
 784  
                                                                         case CANCEL:
 785  0
                                                                                 okToChange.exec(false);
 786  0
                                                                                 dialog.hide();
 787  
                                                                                 break;
 788  
                                                                 }
 789  0
                                                         }
 790  
                                                 });
 791  0
                                                 dialog.show();
 792  0
                                         }
 793  
                                         else{
 794  0
                                                 okToChange.exec(true);
 795  
                                         }
 796  
                                 }
 797  
                                 else{
 798  0
                                         okToChange.exec(false);
 799  
                                 }
 800  0
                         }
 801  
                 });
 802  0
         }
 803  
         
 804  
     public KSButton getSaveButton(){
 805  0
             if(currentDocType != MODIFY_TYPE){
 806  0
                 return new KSButton("Save and Continue", new ClickHandler(){
 807  
                             public void onClick(ClickEvent event) {
 808  0
                                     CourseProposalController.this.fireApplicationEvent(new SaveActionEvent(true));
 809  0
                             }
 810  
                         });
 811  
             }
 812  
             else{
 813  0
                     return new KSButton("Save", new ClickHandler(){
 814  
                 public void onClick(ClickEvent event) {
 815  0
                     CourseProposalController.this.fireApplicationEvent(new SaveActionEvent(false));
 816  0
                 }
 817  
             });
 818  
             }
 819  
     }
 820  
     
 821  
     public KSButton getCancelButton(final Enum<?> summaryView){
 822  
             
 823  0
         return new KSButton("Cancel", ButtonStyle.ANCHOR_LARGE_CENTERED, new ClickHandler(){
 824  
                     public void onClick(ClickEvent event) {
 825  0
                             if(!isNew){
 826  0
                                     CourseProposalController.this.showView(summaryView);
 827  
                             }
 828  
                             else{
 829  0
                                     Application.navigate(AppLocations.Locations.CURRICULUM_MANAGEMENT.getLocation());
 830  
                             }
 831  0
                     }
 832  
                 });
 833  
 
 834  
     }
 835  
         
 836  
         @Override
 837  
         public void onHistoryEvent(String historyStack) {
 838  0
                 super.onHistoryEvent(historyStack);
 839  
                 //we dont want to add proposals that are brand new before saving, or copy addresses (as they will initiate
 840  
                 //the modify/copy logic again if called)
 841  0
                 if(cluProposalModel.get(cfg.getProposalTitlePath()) != null && 
 842  
                                 this.getViewContext().getIdType() != IdType.COPY_OF_OBJECT_ID){
 843  0
                         RecentlyViewedHelper.addCurrentDocument(getProposalTitle());
 844  
                 }
 845  0
         }
 846  
         
 847  
         private String getProposalTitle(){
 848  0
                 StringBuffer sb = new StringBuffer();
 849  0
                 sb.append(cluProposalModel.get(cfg.getProposalTitlePath()));
 850  0
                 sb.append(" (Proposal)");
 851  0
                 return sb.toString();
 852  
         }
 853  
 
 854  
     public boolean isNew() {
 855  0
         return isNew;
 856  
     }
 857  
 }