1 package org.kuali.student.lum.lu.ui.course.client.controllers;
2
3 import java.util.ArrayList;
4 import java.util.List;
5
6 import org.kuali.student.common.assembly.data.Data;
7 import org.kuali.student.common.assembly.data.Metadata;
8 import org.kuali.student.common.dto.DtoConstants;
9 import org.kuali.student.common.ui.client.application.Application;
10 import org.kuali.student.common.ui.client.application.KSAsyncCallback;
11 import org.kuali.student.common.ui.client.configurable.mvc.layouts.BasicLayoutWithContentHeader;
12 import org.kuali.student.common.ui.client.configurable.mvc.sections.HorizontalSection;
13 import org.kuali.student.common.ui.client.configurable.mvc.views.VerticalSectionView;
14 import org.kuali.student.common.ui.client.mvc.Callback;
15 import org.kuali.student.common.ui.client.mvc.Controller;
16 import org.kuali.student.common.ui.client.mvc.DataModel;
17 import org.kuali.student.common.ui.client.mvc.DataModelDefinition;
18 import org.kuali.student.common.ui.client.mvc.ModelProvider;
19 import org.kuali.student.common.ui.client.mvc.ModelRequestCallback;
20 import org.kuali.student.common.ui.client.widgets.KSButton;
21 import org.kuali.student.common.ui.client.widgets.KSButtonAbstract.ButtonStyle;
22 import org.kuali.student.common.ui.client.widgets.KSLabel;
23 import org.kuali.student.common.ui.client.widgets.notification.KSNotification;
24 import org.kuali.student.common.ui.client.widgets.notification.KSNotifier;
25 import org.kuali.student.common.ui.client.widgets.progress.BlockingTask;
26 import org.kuali.student.common.ui.client.widgets.progress.KSBlockingProgressIndicator;
27 import org.kuali.student.core.statement.dto.StatementTypeInfo;
28 import org.kuali.student.lum.common.client.lu.LUUIConstants;
29 import org.kuali.student.lum.lu.ui.course.client.configuration.CourseSummaryConfigurer;
30 import org.kuali.student.lum.lu.ui.course.client.requirements.CourseRequirementsDataModel;
31 import org.kuali.student.lum.lu.ui.course.client.requirements.HasRequirements;
32 import org.kuali.student.lum.lu.ui.course.client.service.CourseRpcService;
33 import org.kuali.student.lum.lu.ui.course.client.service.CourseRpcServiceAsync;
34 import org.kuali.student.lum.lu.ui.course.client.views.SelectVersionsView;
35 import org.kuali.student.lum.lu.ui.course.client.views.ShowVersionView;
36 import org.kuali.student.lum.lu.ui.course.client.widgets.CourseWorkflowActionList;
37
38 import com.google.gwt.core.client.GWT;
39 import com.google.gwt.event.dom.client.ClickEvent;
40 import com.google.gwt.event.dom.client.ClickHandler;
41 import com.google.gwt.user.client.Window;
42 import com.google.gwt.user.client.ui.Widget;
43
44 public class VersionsController extends BasicLayoutWithContentHeader implements HasRequirements{
45
46 public static enum Views{VERSION_SELECT, VERSION_VIEW, VERSION_COMPARE}
47
48 private SelectVersionsView select = new SelectVersionsView(this, "", Views.VERSION_SELECT);
49 private ShowVersionView view;
50 private VerticalSectionView compare;
51 private static final String MSG_GROUP = "course";
52 private String type = "course";
53 private String state = DtoConstants.STATE_DRAFT;
54 private String groupName = LUUIConstants.COURSE_GROUP_NAME;
55 CourseSummaryConfigurer summaryConfigurer;
56 CourseRpcServiceAsync rpcServiceAsync = GWT.create(CourseRpcService.class);
57 DataModelDefinition definition;
58
59 private DataModel cluModel1;
60 private DataModel cluModel2;
61
62 private String lastId1 = "";
63 private String lastId2 = "";
64 private HorizontalSection workflowVersionInfoSection = new HorizontalSection();
65
66 private final CourseRequirementsDataModel reqDataModel1;
67 private final CourseRequirementsDataModel reqDataModel2;
68
69 private boolean initialized = false;
70 private String versionIndId = "";
71 private String currentVersionId = "";
72 private final BlockingTask loadDataTask = new BlockingTask("Retrieving Data....");
73
74 private List<CourseWorkflowActionList> actionDropDownWidgets = new ArrayList<CourseWorkflowActionList>();
75 private KSLabel statusLabel = new KSLabel("");
76
77 public VersionsController(Enum<?> viewType) {
78 super(VersionsController.class.toString());
79 this.addView(select);
80 this.setDefaultView(Views.VERSION_SELECT);
81 this.setName("Versions");
82 this.setViewEnum(viewType);
83 KSButton versionHistoryButton = new KSButton("Version History", ButtonStyle.DEFAULT_ANCHOR, new ClickHandler(){
84
85 @Override
86 public void onClick(ClickEvent event) {
87 VersionsController.this.showDefaultView(Controller.NO_OP_CALLBACK);
88 }
89 });
90 versionHistoryButton.addStyleName("versionHistoryLink");
91
92 reqDataModel1 = new CourseRequirementsDataModel(this);
93 reqDataModel2 = new CourseRequirementsDataModel(this);
94
95 workflowVersionInfoSection.addWidget(this.getStatusLabel());
96 workflowVersionInfoSection.addWidget(this.generateActionDropDown());
97 workflowVersionInfoSection.addWidget(versionHistoryButton);
98
99 this.getHeader().addWidget(workflowVersionInfoSection);
100 this.viewContainer.addStyleName("standard-content-padding");
101 initialize();
102 }
103
104 public void setVersionIndId(String versionIndId) {
105 this.versionIndId = versionIndId;
106 }
107
108 private void initialize() {
109 super.setDefaultModelId("Model");
110 super.registerModel("Model", new ModelProvider<DataModel>() {
111
112 @Override
113 public void requestModel(final ModelRequestCallback<DataModel> callback) {
114 if(getViewContext().getId() != null && !getViewContext().getId().isEmpty()){
115 getCourseFromCluId(getViewContext().getId(), 1, callback, true);
116 }
117 else{
118 callback.onModelReady(null);
119 }
120 }
121 });
122
123 super.registerModel("ComparisonModel", new ModelProvider<DataModel>() {
124 @Override
125 public void requestModel(final ModelRequestCallback<DataModel> callback) {
126 if(getViewContext().getAttribute("docId2") != null && !getViewContext().getAttribute("docId2").isEmpty()){
127 getCourseFromCluId(getViewContext().getAttribute("docId2"), 2, callback, false);
128 }
129 else{
130 callback.onModelReady(null);
131 }
132 }
133 });
134 }
135
136 @SuppressWarnings("unchecked")
137 private void getCourseFromCluId(final String courseId, final int modelNum, final ModelRequestCallback callback, final boolean id1Model){
138 KSBlockingProgressIndicator.addTask(loadDataTask);
139
140 rpcServiceAsync.getData(courseId, new KSAsyncCallback<Data>(){
141
142 @Override
143 public void handleFailure(Throwable caught) {
144 Window.alert("Error loading Course: "+caught.getMessage());
145 callback.onRequestFail(caught);
146 KSBlockingProgressIndicator.removeTask(loadDataTask);
147 }
148
149 @Override
150 public void onSuccess(Data result) {
151 if(modelNum == 1){
152 cluModel1 = new DataModel();
153 cluModel1.setDefinition(definition);
154 cluModel1.setRoot(result);
155 if(courseId.equals(currentVersionId)){
156 String name = "Version " + cluModel1.get("versionInfo/sequenceNumber") + " (current version)";
157 cluModel1.setModelName(name);
158 view.setName(name);
159 view.showWarningMessage(false);
160 }
161 else{
162 String name = "Version " + cluModel1.get("versionInfo/sequenceNumber");
163 cluModel1.setModelName(name);
164 view.setName(name);
165 view.showWarningMessage(true);
166 }
167 updateState(cluModel1);
168
169 reqDataModel1.retrieveStatementTypes(cluModel1.<String>get("id"), new Callback<Boolean>() {
170 @Override
171 public void exec(Boolean result) {
172 if (result) {
173 KSBlockingProgressIndicator.removeTask(loadDataTask);
174 callback.onModelReady(cluModel1);
175 }
176 }
177 });
178 }
179 else{
180 cluModel2 = new DataModel();
181 cluModel2.setDefinition(definition);
182 cluModel2.setRoot(result);
183 if(courseId.equals(currentVersionId)){
184 cluModel2.setModelName("Version " + cluModel2.get("versionInfo/sequenceNumber") + " (current version)");
185 }
186 else{
187 cluModel2.setModelName("Version " + cluModel2.get("versionInfo/sequenceNumber"));
188 }
189
190 reqDataModel2.retrieveStatementTypes(cluModel2.<String>get("id"), new Callback<Boolean>() {
191 @Override
192 public void exec(Boolean result) {
193 if (result) {
194 KSBlockingProgressIndicator.removeTask(loadDataTask);
195 callback.onModelReady(cluModel2);
196 }
197 }
198 });
199 }
200 }
201 });
202 }
203
204 @Override
205 public void showDefaultView(final Callback<Boolean> onReadyCallback) {
206 KSBlockingProgressIndicator.addTask(loadDataTask);
207
208 init(new Callback<Boolean>() {
209
210 @Override
211 public void exec(Boolean result) {
212 if (result) {
213 VersionsController.super.showDefaultView(new Callback<Boolean>() {
214
215 @Override
216 public void exec(Boolean result) {
217 onReadyCallback.exec(result);
218 KSBlockingProgressIndicator.removeTask(loadDataTask);
219 }
220 });
221 } else {
222 onReadyCallback.exec(false);
223 KSBlockingProgressIndicator.removeTask(loadDataTask);
224 }
225
226 }
227 });
228 }
229
230 @Override
231 public void beforeShow(Callback<Boolean> onReadyCallback) {
232 workflowVersionInfoSection.setVisible(false);
233 this.getHeader().showPrint(false);
234 this.getHeader().showExport(false);
235 showDefaultView(onReadyCallback);
236 }
237
238 private void init(final Callback<Boolean> onReadyCallback) {
239
240 if (initialized) {
241 onReadyCallback.exec(true);
242 } else {
243 KSBlockingProgressIndicator.addTask(loadDataTask);
244
245 rpcServiceAsync.getMetadata("", null, new KSAsyncCallback<Metadata>(){
246
247 public void handleFailure(Throwable caught) {
248 initialized = false;
249 onReadyCallback.exec(false);
250 KSBlockingProgressIndicator.removeTask(loadDataTask);
251 throw new RuntimeException("Failed to get model definition.", caught);
252 }
253
254 public void onSuccess(Metadata result) {
255 definition = new DataModelDefinition(result);
256 KSBlockingProgressIndicator.removeTask(loadDataTask);
257 configureScreens(onReadyCallback);
258 }
259 });
260
261 }
262 }
263
264 private void configureScreens(final Callback<Boolean> onReadyCallback) {
265 CourseRequirementsDataModel.getStatementTypes(new Callback<List<StatementTypeInfo>>() {
266
267 @Override
268 public void exec(List<StatementTypeInfo> stmtTypes) {
269 List<StatementTypeInfo> stmtTypesOut = new ArrayList<StatementTypeInfo>();
270 if (stmtTypes != null) {
271 for (StatementTypeInfo stmtType : stmtTypes) {
272 if (stmtType.getId().contains("kuali.statement.type.course.enrollmentEligibility") ||
273 stmtType.getId().contains("kuali.statement.type.course.creditConstraints")) {
274 continue;
275 }
276 stmtTypesOut.add(stmtType);
277 }
278 }
279
280 summaryConfigurer = GWT.create(CourseSummaryConfigurer.class);
281 summaryConfigurer.init(type, state, groupName, definition, stmtTypesOut, VersionsController.this, "Model");
282 view = new ShowVersionView(Views.VERSION_VIEW, "Version", "Model", VersionsController.this, stmtTypesOut);
283 compare = summaryConfigurer.generateCourseSummarySection();
284 compare.setLayoutController(VersionsController.this);
285 compare.setSectionTitle("Compare Versions");
286 compare.setName("Compare Versions");
287 compare.setViewEnum(Views.VERSION_COMPARE);
288 VersionsController.this.addView(view);
289 VersionsController.this.addView(compare);
290 initialized = true;
291 onReadyCallback.exec(true);
292 }
293 });
294 }
295
296 public Widget generateActionDropDown(){
297 CourseWorkflowActionList actionList = new CourseWorkflowActionList(this.getMessage("cluActionsLabel"));
298
299 actionDropDownWidgets.add(actionList);
300
301 return actionList;
302 }
303
304 private void updateState(final DataModel cluModel) {
305 if(cluModel.get("state") != null){
306 statusLabel.setText(getMessage("courseStatusLabel") + ": " + cluModel.get("state"));
307
308 for(CourseWorkflowActionList widget: actionDropDownWidgets){
309 widget.init(getViewContext(), "/HOME/CURRICULUM_HOME/COURSE_PROPOSAL", cluModel, new Callback<String>() {
310 @Override
311 public void exec(String newState) {
312 if (newState != null) {
313 KSNotifier.add(new KSNotification(getMessage("cluStateChangeNotification" + newState), false, 5000));
314
315 statusLabel.setText(getMessage("courseStatusLabel") + ": " + newState);
316 } else {
317 KSNotifier.add(new KSNotification(getMessage("cluStateChangeFailedNotification"), false, 5000));
318 }
319 }
320 });
321 widget.updateCourseActionItems(cluModel);
322
323 }
324 }
325 }
326
327 public Widget getStatusLabel() {
328 statusLabel.setStyleName("courseStatusLabel");
329 return statusLabel;
330 }
331
332 public DataModelDefinition getDefinition(){
333 return definition;
334 }
335
336 public void setCurrentVersionId(String id) {
337 this.currentVersionId = id;
338 }
339
340 public String getCurrentVersionId() {
341 return currentVersionId;
342 }
343
344 public String getVersionIndId() {
345 return versionIndId;
346 }
347
348 public String getMessage(String courseMessageKey) {
349 String msg = Application.getApplicationContext().getMessage(MSG_GROUP, courseMessageKey);
350 if (msg == null) {
351 msg = courseMessageKey;
352 }
353 return msg;
354 }
355
356
357 @Override
358 public <V extends Enum<?>> void showView(V viewType, Callback<Boolean> onReadyCallback) {
359 if(viewType != Views.VERSION_SELECT){
360 workflowVersionInfoSection.setVisible(true);
361 this.getHeader().showPrint(true);
362 this.getHeader().showExport(true);
363 }
364 else{
365 workflowVersionInfoSection.setVisible(false);
366 this.getHeader().showPrint(false);
367 this.getHeader().showExport(false);
368 }
369 super.showView(viewType, onReadyCallback);
370 }
371
372
373
374 public void setCurrentTitle(String currentTitle) {
375 this.getHeader().setTitle(currentTitle);
376 }
377
378
379 @Override
380 public CourseRequirementsDataModel getReqDataModel() {
381 return reqDataModel1;
382 }
383
384 public CourseRequirementsDataModel getReqDataModelComp() {
385 return reqDataModel2;
386 }
387 }