1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.student.lum.lu.ui.course.client.controllers;
17
18 import java.util.ArrayList;
19 import java.util.List;
20
21 import org.kuali.student.common.ui.client.application.Application;
22 import org.kuali.student.common.ui.client.application.KSAsyncCallback;
23 import org.kuali.student.common.ui.client.application.ViewContext;
24 import org.kuali.student.common.ui.client.configurable.mvc.layouts.DocumentLayoutController;
25 import org.kuali.student.common.ui.client.configurable.mvc.layouts.TabMenuController;
26 import org.kuali.student.common.ui.client.mvc.Callback;
27 import org.kuali.student.common.ui.client.mvc.DataModel;
28 import org.kuali.student.common.ui.client.mvc.DataModelDefinition;
29 import org.kuali.student.common.ui.client.mvc.ModelProvider;
30 import org.kuali.student.common.ui.client.mvc.ModelRequestCallback;
31 import org.kuali.student.common.ui.client.mvc.WorkQueue;
32 import org.kuali.student.common.ui.client.mvc.WorkQueue.WorkItem;
33 import org.kuali.student.common.ui.client.mvc.dto.ReferenceModel;
34 import org.kuali.student.common.ui.client.security.AuthorizationCallback;
35 import org.kuali.student.common.ui.client.security.RequiresAuthorization;
36 import org.kuali.student.common.ui.client.util.ExportElement;
37 import org.kuali.student.common.ui.client.util.ExportUtils;
38 import org.kuali.student.common.ui.client.util.WindowTitleUtils;
39 import org.kuali.student.common.ui.client.widgets.KSButton;
40 import org.kuali.student.common.ui.client.widgets.KSButtonAbstract.ButtonStyle;
41 import org.kuali.student.common.ui.client.widgets.KSLabel;
42 import org.kuali.student.common.ui.client.widgets.KSLightBox;
43 import org.kuali.student.common.ui.client.widgets.notification.KSNotification;
44 import org.kuali.student.common.ui.client.widgets.notification.KSNotifier;
45 import org.kuali.student.common.ui.client.widgets.progress.BlockingTask;
46 import org.kuali.student.common.ui.client.widgets.progress.KSBlockingProgressIndicator;
47 import org.kuali.student.common.ui.shared.IdAttributes.IdType;
48 import org.kuali.student.lum.common.client.helpers.RecentlyViewedHelper;
49 import org.kuali.student.lum.common.client.lu.LUUIPermissions;
50 import org.kuali.student.lum.lu.ui.course.client.configuration.CourseProposalConfigurer;
51 import org.kuali.student.lum.lu.ui.course.client.configuration.ViewCourseConfigurer;
52 import org.kuali.student.lum.lu.ui.course.client.configuration.ViewCourseConfigurer.ViewCourseSections;
53 import org.kuali.student.lum.lu.ui.course.client.requirements.CourseRequirementsDataModel;
54 import org.kuali.student.lum.lu.ui.course.client.requirements.HasRequirements;
55 import org.kuali.student.lum.lu.ui.course.client.service.CourseRpcService;
56 import org.kuali.student.lum.lu.ui.course.client.service.CourseRpcServiceAsync;
57 import org.kuali.student.lum.lu.ui.course.client.widgets.CourseWorkflowActionList;
58 import org.kuali.student.r1.common.assembly.data.Data;
59 import org.kuali.student.r1.common.assembly.data.Metadata;
60 import org.kuali.student.r1.common.rice.authorization.PermissionType;
61 import org.kuali.student.r1.core.statement.dto.StatementTypeInfo;
62 import org.kuali.student.r2.common.dto.DtoConstants;
63
64 import com.google.gwt.core.client.GWT;
65 import com.google.gwt.event.dom.client.ClickEvent;
66 import com.google.gwt.event.dom.client.ClickHandler;
67 import com.google.gwt.event.logical.shared.CloseEvent;
68 import com.google.gwt.event.logical.shared.CloseHandler;
69 import com.google.gwt.user.client.Window;
70 import com.google.gwt.user.client.ui.Widget;
71
72
73
74
75
76
77
78 public class ViewCourseController extends TabMenuController implements DocumentLayoutController, HasRequirements, RequiresAuthorization {
79 protected final DataModel cluModel = new DataModel();
80
81 private WorkQueue modelRequestQueue;
82
83 private String cluType = "kuali.lu.type.CreditCourse";
84 private String courseId = null;
85
86 private static final String CLU_STATE = DtoConstants.STATE_ACTIVE;
87 private static final String MSG_GROUP = "course";
88
89 private final String REFERENCE_TYPE = "referenceType.clu";
90 private boolean initialized = false;
91 CourseRpcServiceAsync rpcServiceAsync = GWT.create(CourseRpcService.class);
92
93 private final BlockingTask loadDataTask = new BlockingTask("Retrieving Data....");
94 private final BlockingTask initTask = new BlockingTask("Initializing....");
95 private final KSLabel statusLabel = new KSLabel("");
96
97 private final List<CourseWorkflowActionList> actionDropDownWidgets = new ArrayList<CourseWorkflowActionList>();
98
99 private CourseRequirementsDataModel reqDataModel;
100
101 final ViewCourseConfigurer cfg = GWT.create(ViewCourseConfigurer.class);
102
103 public ViewCourseController(){
104 super(CourseProposalController.class.getName());
105 }
106
107 @Override
108 public void setViewContext(ViewContext viewContext) {
109 super.setViewContext(viewContext);
110 if(viewContext.getId() != null && !viewContext.getId().isEmpty()){
111 viewContext.setPermissionType(PermissionType.OPEN);
112 this.setCourseId(viewContext.getId());
113 }
114 }
115
116 public void initialize(Enum<?> viewType) {
117 addStyleName("courseView");
118 reqDataModel = new CourseRequirementsDataModel(this);
119 this.tabPanel.addStyleName("standard-content-padding");
120 this.setViewEnum(viewType);
121 super.setDefaultModelId(CourseProposalConfigurer.COURSE_PROPOSAL_MODEL);
122 super.registerModel(CourseProposalConfigurer.COURSE_PROPOSAL_MODEL, new ModelProvider<DataModel>() {
123
124 @Override
125 public void requestModel(final ModelRequestCallback<DataModel> callback) {
126 if (modelRequestQueue == null){
127 modelRequestQueue = new WorkQueue();
128 }
129
130 WorkItem workItem = new WorkItem(){
131 @Override
132 public void exec(Callback<Boolean> workCompleteCallback) {
133 if (cluModel.getRoot() == null || cluModel.getRoot().size() == 0){
134 if (courseId != null){
135 getCourseFromCluId(callback, workCompleteCallback);
136 } else{
137 createNewCluModel(callback, workCompleteCallback);
138 }
139 } else {
140 callback.onModelReady(cluModel);
141 workCompleteCallback.exec(true);
142 }
143 }
144 };
145 modelRequestQueue.submit(workItem);
146
147 }
148
149 });
150 }
151
152
153 public Widget generateActionDropDown(){
154 CourseWorkflowActionList actionList = new CourseWorkflowActionList(this.getMessage("cluActionsLabel"), getViewContext(), "/HOME/CURRICULUM_HOME/COURSE_PROPOSAL", cluModel, new Callback<String>() {
155 @Override
156 public void exec(String newState) {
157 if (newState != null) {
158 KSNotifier.add(new KSNotification(getMessage("cluStateChangeNotification" + newState), false, 5000));
159
160 statusLabel.setText("Course Status: " + newState);
161 } else {
162 KSNotifier.add(new KSNotification(getMessage("cluStateChangeFailedNotification"), false, 5000));
163 }
164 }
165 });
166 actionDropDownWidgets.add(actionList);
167
168 return actionList;
169 }
170
171 private void init(final Callback<Boolean> onReadyCallback) {
172
173 if (initialized) {
174 onReadyCallback.exec(true);
175 } else {
176 KSBlockingProgressIndicator.addTask(initTask);
177 this.setContentTitle("View Course");
178 this.setName("Course");
179 String idType = null;
180 String viewContextId = null;
181
182
183 if(getViewContext().getIdType() != null){
184 idType = getViewContext().getIdType().toString();
185 viewContextId = getViewContext().getId();
186 if(getViewContext().getIdType()==IdType.COPY_OF_OBJECT_ID){
187 viewContextId = null;
188 }
189
190 }
191
192 rpcServiceAsync.getMetadata("", null, new KSAsyncCallback<Metadata>(){
193
194 @Override
195 public void handleFailure(Throwable caught) {
196 initialized = false;
197 onReadyCallback.exec(false);
198 KSBlockingProgressIndicator.removeTask(initTask);
199 throw new RuntimeException("Failed to get model definition.", caught);
200 }
201
202 public void onSuccess(Metadata result) {
203 DataModelDefinition def = new DataModelDefinition(result);
204 cluModel.setDefinition(def);
205 init(def, onReadyCallback);
206 }
207 });
208
209 }
210 }
211
212 private void updateCourseActionItems() {
213
214 for(CourseWorkflowActionList widget: actionDropDownWidgets){
215 widget.updateCourseActionItems(cluModel);
216 }
217 }
218
219 private void init(final DataModelDefinition modelDefinition, final Callback<Boolean> onReadyCallback){
220
221 CourseRequirementsDataModel.getStatementTypes(new Callback<List<StatementTypeInfo>>() {
222
223 @Override
224 public void exec(List<StatementTypeInfo> stmtTypes) {
225 List<StatementTypeInfo> stmtTypesOut = new ArrayList<StatementTypeInfo>();
226 if (stmtTypes != null) {
227 for (StatementTypeInfo stmtType : stmtTypes) {
228 if (stmtType.getId().contains("kuali.statement.type.course.enrollmentEligibility") ||
229 stmtType.getId().contains("kuali.statement.type.course.creditConstraints")) {
230 continue;
231 }
232 stmtTypesOut.add(stmtType);
233 }
234 }
235 if(!initialized){
236 initialized = true;
237 cfg.setStatementTypes(stmtTypesOut);
238 cfg.setModelDefinition(modelDefinition);
239 cfg.generateLayout(ViewCourseController.this);
240 }
241 onReadyCallback.exec(true);
242 KSBlockingProgressIndicator.removeTask(initTask);
243 }
244 });
245 }
246
247 @SuppressWarnings("unchecked")
248 @Override
249 public void requestModel(Class modelType, final ModelRequestCallback callback) {
250 if(modelType == ReferenceModel.class){
251 if (cluModel != null){
252 ReferenceModel ref = new ReferenceModel();
253
254 if(cluModel.get("course/id") != null){
255 ref.setReferenceId((String)cluModel.get("course/id"));
256 } else{
257 ref.setReferenceId(null);
258 }
259
260 ref.setReferenceTypeKey(REFERENCE_TYPE);
261 ref.setReferenceType(cluType);
262 ref.setReferenceState(CLU_STATE);
263
264 callback.onModelReady(ref);
265 }
266 }else if (modelType == Data.class){
267 requestModel(CourseProposalConfigurer.COURSE_PROPOSAL_MODEL, callback);
268 } else {
269 super.requestModel(modelType, callback);
270 }
271 }
272
273 @SuppressWarnings("unchecked")
274 private void getCourseFromCluId(final ModelRequestCallback callback, final Callback<Boolean> workCompleteCallback){
275 KSBlockingProgressIndicator.addTask(loadDataTask);
276
277 rpcServiceAsync.getData(courseId, new KSAsyncCallback<Data>(){
278
279 @Override
280 public void handleFailure(Throwable caught) {
281 Window.alert("Error loading Course: "+caught.getMessage());
282 createNewCluModel(callback, workCompleteCallback);
283 KSBlockingProgressIndicator.removeTask(loadDataTask);
284 }
285
286 @Override
287 public void onSuccess(Data result) {
288 cluModel.setRoot(result);
289
290 setHeaderTitle();
291 updateCourseActionItems();
292 callback.onModelReady(cluModel);
293 workCompleteCallback.exec(true);
294 reqDataModel.retrieveStatementTypes(cluModel.<String>get("id"), new Callback<Boolean>() {
295 @Override
296 public void exec(Boolean result) {
297 if (result) {
298 KSBlockingProgressIndicator.removeTask(loadDataTask);
299 }
300 }
301 });
302
303 }
304
305 });
306 }
307
308 @SuppressWarnings("unchecked")
309 private void getCurrentVersion(final ModelRequestCallback callback, final Callback<Boolean> workCompleteCallback) {
310 rpcServiceAsync.getData(courseId, new KSAsyncCallback<Data>(){
311
312 @Override
313 public void handleFailure(Throwable caught) {
314 Window.alert("Error loading Course: "+caught.getMessage());
315 createNewCluModel(callback, workCompleteCallback);
316 KSBlockingProgressIndicator.removeTask(loadDataTask);
317 }
318
319 @Override
320 public void onSuccess(Data result) {
321 cluModel.setRoot(result);
322
323 setHeaderTitle();
324 updateCourseActionItems();
325 callback.onModelReady(cluModel);
326 workCompleteCallback.exec(true);
327 KSBlockingProgressIndicator.removeTask(loadDataTask);
328 }
329
330 });
331 }
332
333 @SuppressWarnings("unchecked")
334 private void createNewCluModel(final ModelRequestCallback callback, final Callback<Boolean> workCompleteCallback){
335 cluModel.setRoot(new Data());
336 callback.onModelReady(cluModel);
337 workCompleteCallback.exec(true);
338 }
339
340 public String getCourseId() {
341 return courseId;
342 }
343
344 public String getVersionIndId() {
345 return (String)cluModel.get("version/versionIndId");
346 }
347
348 public void setCourseId(String courseId) {
349 this.courseId = courseId;
350 this.cluModel.setRoot(new Data());
351 }
352
353 public void clear(String cluType){
354 super.clear();
355 this.cluType = cluType;
356 if (cluModel != null){
357 this.cluModel.setRoot(new Data());
358 }
359 this.courseId = null;
360 }
361
362 @Override
363 public void showDefaultView(final Callback<Boolean> onReadyCallback) {
364 init(new Callback<Boolean>() {
365
366 @Override
367 public void exec(Boolean result) {
368 if (result) {
369 ViewCourseController.super.showDefaultView(onReadyCallback);
370 } else {
371 onReadyCallback.exec(false);
372 }
373 }
374 });
375 }
376
377 @Override
378 public void beforeShow(Callback<Boolean> onReadyCallback) {
379 showDefaultView(onReadyCallback);
380 }
381
382 private KSButton getQuitButton(){
383 return new KSButton("Quit", new ClickHandler(){
384 public void onClick(ClickEvent event) {
385 Application.navigate("/HOME/CURRICULUM_HOME");
386 }
387 });
388 }
389
390
391 protected void setHeaderTitle() {
392
393 String title;
394 if (cluModel.get("transcriptTitle") != null){
395 title = getCourseTitle();
396 }
397 else{
398 title = "Course";
399 }
400
401 updateStatus();
402
403 this.setContentTitle(title);
404 this.setName(title);
405 WindowTitleUtils.setContextTitle(title);
406 }
407
408 protected void updateStatus() {
409 if(cluModel.get("stateKey") != null){
410 statusLabel.setText(getMessage("courseStatusLabel") + ": " + cluModel.get("stateKey"));
411 }
412 }
413
414 private CloseHandler<KSLightBox> createActionSubmitSuccessHandler() {
415 CloseHandler<KSLightBox> handler = new CloseHandler<KSLightBox>(){
416 @Override
417 public void onClose(CloseEvent<KSLightBox> event) {
418
419 Window.Location.reload();
420 }
421 };
422 return handler;
423 }
424
425 public String getMessage(String courseMessageKey) {
426 String msg = Application.getApplicationContext().getMessage(MSG_GROUP, courseMessageKey);
427 if (msg == null) {
428 msg = courseMessageKey;
429 }
430 return msg;
431 }
432
433 public Widget getStatusLabel() {
434 statusLabel.setStyleName("courseStatusLabel");
435 return statusLabel;
436 }
437
438 public Widget getVersionHistoryWidget(){
439 KSButton button = new KSButton("Version History", ButtonStyle.DEFAULT_ANCHOR, new ClickHandler(){
440
441 @Override
442 public void onClick(ClickEvent event) {
443 parentController.showView(ViewCourseParentController.Views.VERSIONS);
444 }
445 });
446 button.addStyleName("versionHistoryLink");
447 return button;
448
449 }
450
451 @Override
452 public void onHistoryEvent(String historyStack) {
453 super.onHistoryEvent(historyStack);
454 if (cluModel.get("courseTitle") != null){
455 RecentlyViewedHelper.addCurrentDocument(getCourseTitle());
456 }
457 }
458
459 public String getCourseTitle(){
460 return cluModel.get("courseTitle");
461 }
462
463
464 public String getCurrentId() {
465 return cluModel.get("id");
466 }
467
468 @Override
469 public CourseRequirementsDataModel getReqDataModel() {
470 return reqDataModel;
471 }
472
473 @Override
474 public DataModel getExportDataModel() {
475 return cluModel;
476 }
477
478 @Override
479 public boolean isExportButtonActive() {
480 return true;
481 }
482
483 @Override
484 public List<ExportElement> getExportElementsFromView() {
485 List<ExportElement> exportElements = new ArrayList<ExportElement>();
486 ExportElement heading = GWT.create(ExportElement.class);
487 heading.setFieldLabel("");
488 heading.setFieldValue(this.tabPanel.getSelectedTabName());
489 exportElements.add(heading);
490 if (this.getCurrentViewEnum() != null) {
491 if (this.getCurrentViewEnum().equals(ViewCourseSections.DETAILED)) {
492 exportElements.addAll(ExportUtils.getDetailsForWidget(this.tabPanel.getSelectedTab(), "", "").get(0).getSubset());
493 } else if (this.getCurrentViewEnum().equals(ViewCourseSections.BRIEF)){
494 exportElements.addAll(ExportUtils.getDetailsForWidget(this.tabPanel.getSelectedTab(), "", "").get(0).getSubset());
495 } else if (this.getCurrentViewEnum().equals(ViewCourseSections.CATALOG)){
496 exportElements.addAll(ExportUtils.getDetailsForWidget(this.tabPanel.getSelectedTab(), "", ""));
497 }
498 }
499 return exportElements;
500 }
501
502 @Override
503 public boolean isAuthorizationRequired() {
504 return true;
505 }
506
507 @Override
508 public void setAuthorizationRequired(boolean required) {
509 throw new UnsupportedOperationException();
510 }
511
512 @Override
513 public void checkAuthorization(final AuthorizationCallback authCallback) {
514 Application.getApplicationContext().getSecurityContext().checkScreenPermission(LUUIPermissions.USE_FIND_COURSE_SCREEN, new Callback<Boolean>() {
515 @Override
516 public void exec(Boolean result) {
517
518 final boolean isAuthorized = result;
519
520 if(isAuthorized){
521 authCallback.isAuthorized();
522 }
523 else
524 authCallback.isNotAuthorized("User is not authorized: " + LUUIPermissions.USE_FIND_COURSE_SCREEN);
525 }
526 });
527 }
528 }