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.PermissionTypeGwt;
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.setPermissionTypeGwt(PermissionTypeGwt.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 = GWT.create(CourseWorkflowActionList.class);
155 actionList.initialise(this.getMessage("cluActionsLabel"), getViewContext(), "/HOME/CURRICULUM_HOME/COURSE_PROPOSAL", cluModel, new Callback<String>() {
156
157 @Override
158 public void exec(String newState) {
159 if (newState != null) {
160 KSNotifier.add(new KSNotification(getMessage("cluStateChangeNotification" + newState), false, 5000));
161
162 statusLabel.setText("Course Status: " + newState);
163 } else {
164 KSNotifier.add(new KSNotification(getMessage("cluStateChangeFailedNotification"), false, 5000));
165 }
166 }
167 });
168 actionDropDownWidgets.add(actionList);
169
170 return actionList;
171 }
172
173 private void init(final Callback<Boolean> onReadyCallback) {
174
175 if (initialized) {
176 onReadyCallback.exec(true);
177 } else {
178 KSBlockingProgressIndicator.addTask(initTask);
179 this.setContentTitle("View Course");
180 this.setName("Course");
181 String idType = null;
182 String viewContextId = null;
183
184
185 if(getViewContext().getIdType() != null){
186 idType = getViewContext().getIdType().toString();
187 viewContextId = getViewContext().getId();
188 if(getViewContext().getIdType()==IdType.COPY_OF_OBJECT_ID){
189 viewContextId = null;
190 }
191
192 }
193
194 rpcServiceAsync.getMetadata("", null, new KSAsyncCallback<Metadata>(){
195
196 @Override
197 public void handleFailure(Throwable caught) {
198 initialized = false;
199 onReadyCallback.exec(false);
200 KSBlockingProgressIndicator.removeTask(initTask);
201 throw new RuntimeException("Failed to get model definition.", caught);
202 }
203
204 public void onSuccess(Metadata result) {
205 DataModelDefinition def = new DataModelDefinition(result);
206 cluModel.setDefinition(def);
207 init(def, onReadyCallback);
208 }
209 });
210
211 }
212 }
213
214 private void updateCourseActionItems() {
215
216 for(CourseWorkflowActionList widget: actionDropDownWidgets){
217 widget.updateCourseActionItems(cluModel);
218 }
219 }
220
221 private void init(final DataModelDefinition modelDefinition, final Callback<Boolean> onReadyCallback){
222
223 CourseRequirementsDataModel.getStatementTypes(new Callback<List<StatementTypeInfo>>() {
224
225 @Override
226 public void exec(List<StatementTypeInfo> stmtTypes) {
227 List<StatementTypeInfo> stmtTypesOut = new ArrayList<StatementTypeInfo>();
228 if (stmtTypes != null) {
229 for (StatementTypeInfo stmtType : stmtTypes) {
230 if (stmtType.getId().contains("kuali.statement.type.course.enrollmentEligibility") ||
231 stmtType.getId().contains("kuali.statement.type.course.creditConstraints")) {
232 continue;
233 }
234 stmtTypesOut.add(stmtType);
235 }
236 }
237 if(!initialized){
238 initialized = true;
239 cfg.setStatementTypes(stmtTypesOut);
240 cfg.setModelDefinition(modelDefinition);
241 cfg.generateLayout(ViewCourseController.this);
242 }
243 onReadyCallback.exec(true);
244 KSBlockingProgressIndicator.removeTask(initTask);
245 }
246 });
247 }
248
249 @SuppressWarnings("unchecked")
250 @Override
251 public void requestModel(Class modelType, final ModelRequestCallback callback) {
252 if(modelType == ReferenceModel.class){
253 if (cluModel != null){
254 ReferenceModel ref = new ReferenceModel();
255
256 if(cluModel.get("course/id") != null){
257 ref.setReferenceId((String)cluModel.get("course/id"));
258 } else{
259 ref.setReferenceId(null);
260 }
261
262 ref.setReferenceTypeKey(REFERENCE_TYPE);
263 ref.setReferenceType(cluType);
264 ref.setReferenceState(CLU_STATE);
265
266 callback.onModelReady(ref);
267 }
268 }else if (modelType == Data.class){
269 requestModel(CourseProposalConfigurer.COURSE_PROPOSAL_MODEL, callback);
270 } else {
271 super.requestModel(modelType, callback);
272 }
273 }
274
275 @SuppressWarnings("unchecked")
276 private void getCourseFromCluId(final ModelRequestCallback callback, final Callback<Boolean> workCompleteCallback){
277 KSBlockingProgressIndicator.addTask(loadDataTask);
278
279 rpcServiceAsync.getData(courseId, new KSAsyncCallback<Data>(){
280
281 @Override
282 public void handleFailure(Throwable caught) {
283 Window.alert("Error loading Course: "+caught.getMessage());
284 createNewCluModel(callback, workCompleteCallback);
285 KSBlockingProgressIndicator.removeTask(loadDataTask);
286 }
287
288 @Override
289 public void onSuccess(Data result) {
290 cluModel.setRoot(result);
291
292 setHeaderTitle();
293 updateCourseActionItems();
294 callback.onModelReady(cluModel);
295 workCompleteCallback.exec(true);
296 reqDataModel.retrieveStatementTypes(cluModel.<String>get("id"), new Callback<Boolean>() {
297 @Override
298 public void exec(Boolean result) {
299 if (result) {
300 KSBlockingProgressIndicator.removeTask(loadDataTask);
301 }
302 }
303 });
304
305 }
306
307 });
308 }
309
310 @SuppressWarnings("unchecked")
311 private void getCurrentVersion(final ModelRequestCallback callback, final Callback<Boolean> workCompleteCallback) {
312 rpcServiceAsync.getData(courseId, new KSAsyncCallback<Data>(){
313
314 @Override
315 public void handleFailure(Throwable caught) {
316 Window.alert("Error loading Course: "+caught.getMessage());
317 createNewCluModel(callback, workCompleteCallback);
318 KSBlockingProgressIndicator.removeTask(loadDataTask);
319 }
320
321 @Override
322 public void onSuccess(Data result) {
323 cluModel.setRoot(result);
324
325 setHeaderTitle();
326 updateCourseActionItems();
327 callback.onModelReady(cluModel);
328 workCompleteCallback.exec(true);
329 KSBlockingProgressIndicator.removeTask(loadDataTask);
330 }
331
332 });
333 }
334
335 @SuppressWarnings("unchecked")
336 private void createNewCluModel(final ModelRequestCallback callback, final Callback<Boolean> workCompleteCallback){
337 cluModel.setRoot(new Data());
338 callback.onModelReady(cluModel);
339 workCompleteCallback.exec(true);
340 }
341
342 public String getCourseId() {
343 return courseId;
344 }
345
346 public String getVersionIndId() {
347 return (String)cluModel.get("version/versionIndId");
348 }
349
350 public void setCourseId(String courseId) {
351 this.courseId = courseId;
352 this.cluModel.setRoot(new Data());
353 }
354
355 public void clear(String cluType){
356 super.clear();
357 this.cluType = cluType;
358 if (cluModel != null){
359 this.cluModel.setRoot(new Data());
360 }
361 this.courseId = null;
362 }
363
364 @Override
365 public void showDefaultView(final Callback<Boolean> onReadyCallback) {
366 init(new Callback<Boolean>() {
367
368 @Override
369 public void exec(Boolean result) {
370 if (result) {
371 ViewCourseController.super.showDefaultView(onReadyCallback);
372 } else {
373 onReadyCallback.exec(false);
374 }
375 }
376 });
377 }
378
379 @Override
380 public void beforeShow(Callback<Boolean> onReadyCallback) {
381 showDefaultView(onReadyCallback);
382 }
383
384 private KSButton getQuitButton(){
385 return new KSButton("Quit", new ClickHandler(){
386 public void onClick(ClickEvent event) {
387 Application.navigate("/HOME/CURRICULUM_HOME");
388 }
389 });
390 }
391
392
393 protected void setHeaderTitle() {
394
395 String title;
396 if (cluModel.get("transcriptTitle") != null){
397 title = getCourseTitle();
398 }
399 else{
400 title = "Course";
401 }
402
403 updateStatus();
404
405 this.setContentTitle(title);
406 this.setName(title);
407 WindowTitleUtils.setContextTitle(title);
408 }
409
410 protected void updateStatus() {
411 if(cluModel.get("stateKey") != null){
412 statusLabel.setText(getMessage("courseStatusLabel") + ": " + cluModel.get("stateKey"));
413 }
414 }
415
416 private CloseHandler<KSLightBox> createActionSubmitSuccessHandler() {
417 CloseHandler<KSLightBox> handler = new CloseHandler<KSLightBox>(){
418 @Override
419 public void onClose(CloseEvent<KSLightBox> event) {
420
421 Window.Location.reload();
422 }
423 };
424 return handler;
425 }
426
427 public String getMessage(String courseMessageKey) {
428 String msg = Application.getApplicationContext().getMessage(MSG_GROUP, courseMessageKey);
429 if (msg == null) {
430 msg = courseMessageKey;
431 }
432 return msg;
433 }
434
435 public Widget getStatusLabel() {
436 statusLabel.setStyleName("courseStatusLabel");
437 return statusLabel;
438 }
439
440 public Widget getVersionHistoryWidget(){
441 KSButton button = new KSButton("Version History", ButtonStyle.DEFAULT_ANCHOR, new ClickHandler(){
442
443 @Override
444 public void onClick(ClickEvent event) {
445 parentController.showView(ViewCourseParentController.Views.VERSIONS);
446 }
447 });
448 button.addStyleName("versionHistoryLink");
449 return button;
450
451 }
452
453 @Override
454 public void onHistoryEvent(String historyStack) {
455 super.onHistoryEvent(historyStack);
456 if (cluModel.get("courseTitle") != null){
457 RecentlyViewedHelper.addCurrentDocument(getCourseTitle());
458 }
459 }
460
461 public String getCourseTitle(){
462 return cluModel.get("courseTitle");
463 }
464
465
466 public String getCurrentId() {
467 return cluModel.get("id");
468 }
469
470 @Override
471 public CourseRequirementsDataModel getReqDataModel() {
472 return reqDataModel;
473 }
474
475 @Override
476 public DataModel getExportDataModel() {
477 return cluModel;
478 }
479
480 @Override
481 public boolean isExportButtonActive() {
482 return true;
483 }
484
485 @Override
486 public List<ExportElement> getExportElementsFromView() {
487 List<ExportElement> exportElements = new ArrayList<ExportElement>();
488 ExportElement heading = GWT.create(ExportElement.class);
489 heading.setFieldLabel("");
490 heading.setFieldValue(this.tabPanel.getSelectedTabName());
491 exportElements.add(heading);
492 if (this.getCurrentViewEnum() != null) {
493 if (this.getCurrentViewEnum().equals(ViewCourseSections.DETAILED)) {
494 exportElements.addAll(ExportUtils.getDetailsForWidget(this.tabPanel.getSelectedTab(), "", "").get(0).getSubset());
495 } else if (this.getCurrentViewEnum().equals(ViewCourseSections.BRIEF)){
496 exportElements.addAll(ExportUtils.getDetailsForWidget(this.tabPanel.getSelectedTab(), "", "").get(0).getSubset());
497 } else if (this.getCurrentViewEnum().equals(ViewCourseSections.CATALOG)){
498 exportElements.addAll(ExportUtils.getDetailsForWidget(this.tabPanel.getSelectedTab(), "", ""));
499 }
500 }
501 return exportElements;
502 }
503
504 @Override
505 public boolean isAuthorizationRequired() {
506 return true;
507 }
508
509 @Override
510 public void setAuthorizationRequired(boolean required) {
511 throw new UnsupportedOperationException();
512 }
513
514 @Override
515 public void checkAuthorization(final AuthorizationCallback authCallback) {
516 Application.getApplicationContext().getSecurityContext().checkScreenPermission(LUUIPermissions.USE_FIND_COURSE_SCREEN, new Callback<Boolean>() {
517 @Override
518 public void exec(Boolean result) {
519
520 final boolean isAuthorized = result;
521
522 if(isAuthorized){
523 authCallback.isAuthorized();
524 }
525 else
526 authCallback.isNotAuthorized("User is not authorized: " + LUUIPermissions.USE_FIND_COURSE_SCREEN);
527 }
528 });
529 }
530 }