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.requirements;
17
18 import java.util.HashMap;
19 import java.util.List;
20 import java.util.Map;
21
22 import org.kuali.student.common.assembly.data.Metadata;
23 import org.kuali.student.common.ui.client.application.KSAsyncCallback;
24 import org.kuali.student.common.ui.client.configurable.mvc.SectionTitle;
25 import org.kuali.student.common.ui.client.configurable.mvc.views.VerticalSectionView;
26 import org.kuali.student.common.ui.client.mvc.Callback;
27 import org.kuali.student.common.ui.client.service.MetadataRpcService;
28 import org.kuali.student.common.ui.client.service.MetadataRpcServiceAsync;
29 import org.kuali.student.common.ui.client.widgets.KSProgressIndicator;
30 import org.kuali.student.common.ui.client.widgets.buttongroups.ButtonEnumerations;
31 import org.kuali.student.common.ui.client.widgets.field.layout.button.ActionCancelGroup;
32 import org.kuali.student.common.ui.client.widgets.progress.BlockingTask;
33 import org.kuali.student.common.ui.client.widgets.progress.KSBlockingProgressIndicator;
34 import org.kuali.student.common.versionmanagement.dto.VersionDisplayInfo;
35 import org.kuali.student.core.statement.dto.ReqCompFieldInfo;
36 import org.kuali.student.core.statement.dto.ReqCompFieldTypeInfo;
37 import org.kuali.student.core.statement.dto.ReqComponentInfo;
38 import org.kuali.student.core.statement.dto.ReqComponentTypeInfo;
39 import org.kuali.student.core.statement.dto.StatementOperatorTypeKey;
40 import org.kuali.student.core.statement.dto.StatementTreeViewInfo;
41 import org.kuali.student.core.statement.ui.client.widgets.rules.ReqCompEditWidget;
42 import org.kuali.student.core.statement.ui.client.widgets.rules.ReqComponentInfoUi;
43 import org.kuali.student.core.statement.ui.client.widgets.rules.RuleManageWidget;
44 import org.kuali.student.core.statement.ui.client.widgets.rules.RulesUtil;
45 import org.kuali.student.lum.common.client.widgets.BuildCluSetWidget;
46 import org.kuali.student.lum.common.client.widgets.CluSetRetrieverImpl;
47 import org.kuali.student.lum.common.client.widgets.CourseWidget;
48 import org.kuali.student.lum.common.client.widgets.GradeWidget;
49 import org.kuali.student.lum.common.client.widgets.ProgramWidget;
50 import org.kuali.student.lum.lu.dto.CluInfo;
51 import org.kuali.student.lum.lu.ui.course.client.service.LuRpcService;
52 import org.kuali.student.lum.lu.ui.course.client.service.LuRpcServiceAsync;
53 import org.kuali.student.lum.program.client.rpc.StatementRpcService;
54 import org.kuali.student.lum.program.client.rpc.StatementRpcServiceAsync;
55
56 import com.google.gwt.core.client.GWT;
57 import com.google.gwt.user.client.Window;
58 import com.google.gwt.user.client.rpc.AsyncCallback;
59 import com.google.gwt.user.client.ui.SimplePanel;
60 import com.google.gwt.user.client.ui.VerticalPanel;
61 import com.google.gwt.user.client.ui.Widget;
62
63 public class CourseRequirementsManageView extends VerticalSectionView {
64
65 private StatementRpcServiceAsync statementRpcServiceAsync = GWT.create(StatementRpcService.class);
66 private MetadataRpcServiceAsync metadataServiceAsync = GWT.create(MetadataRpcService.class);
67 private LuRpcServiceAsync luRpcServiceAsync = GWT.create(LuRpcService.class);
68
69 protected static final String TEMLATE_LANGUAGE = "en";
70 protected static final String RULEEDIT_TEMLATE = "KUALI.RULE";
71 protected static final String RULEPREVIEW_TEMLATE = "KUALI.RULE.PREVIEW";
72 protected static final String COMPOSITION_TEMLATE = "KUALI.RULE.COMPOSITION";
73 private static final String LU_NAMESPACE = "http://student.kuali.org/wsdl/lu";
74 private static final String CLU_NAMESPACE_URI = "{" + LU_NAMESPACE + "}cluInfo";
75
76 private CourseRequirementsViewController parentController;
77
78
79 protected VerticalPanel layout = new VerticalPanel();
80 protected ReqCompEditWidget editReqCompWidget;
81 protected RuleManageWidget ruleManageWidget;
82 protected SimplePanel twiddlerPanel = new SimplePanel();
83 private ActionCancelGroup actionCancelButtons = new ActionCancelGroup(ButtonEnumerations.SaveCancelEnum.SAVE, ButtonEnumerations.SaveCancelEnum.CANCEL);
84
85
86 private StatementTreeViewInfo rule = null;
87 private boolean isInitialized = false;
88 protected boolean isNewRule = false;
89 private ReqComponentInfo editedReqCompInfo = null;
90 private static int tempStmtTreeViewInfoID = 9999;
91 private Integer internalCourseReqID = null;
92 private String originalReqCompNL;
93 private String originalLogicExpression;
94
95
96 private boolean userClickedSaveButton = false;
97 private BlockingTask creatingRuleTask = new BlockingTask("Creating Rule");
98
99 public CourseRequirementsManageView() {
100 super();
101 }
102
103 public CourseRequirementsManageView(CourseRequirementsViewController parentController, Enum<?> viewEnum,
104 String name, String modelId) {
105 super(viewEnum, name, modelId);
106 this.parentController = parentController;
107 }
108
109 public void init(CourseRequirementsViewController parentController, Enum<?> viewEnum, String name, String modelId) {
110 super.init(viewEnum, name, modelId, true);
111 this.parentController = parentController;
112 }
113
114 @Override
115 public void beforeShow(final Callback<Boolean> onReadyCallback) {
116
117 retrieveAndSetupReqCompTypes();
118 if (!isInitialized) {
119 setupHandlers();
120 draw();
121 isInitialized = true;
122 }
123
124 onReadyCallback.exec(true);
125 }
126
127 private void setupHandlers() {
128 editReqCompWidget.setReqCompConfirmButtonClickCallback(actionButtonClickedReqCompCallback);
129 editReqCompWidget.setNewReqCompSelectedCallbackCallback(newReqCompSelectedCallbackCallback);
130 editReqCompWidget.setRetrieveCompositionTemplateCallback(retrieveCompositionTemplateCallback);
131 editReqCompWidget.setRetrieveFieldsMetadataCallback(retrieveFieldsMetadataCallback);
132 editReqCompWidget.setRetrieveCustomWidgetCallback(retrieveCustomWidgetCallback);
133 }
134
135 protected void draw() {
136
137 remove(layout);
138 layout.clear();
139
140
141 SectionTitle title = SectionTitle.generateH3Title("Step 1: Build and Add Rules");
142 title.setStyleName("KS-Course-Requisites-Manage-Step-header1");
143 layout.add(title);
144
145 layout.add(editReqCompWidget);
146
147
148 title = SectionTitle.generateH3Title("Step 2: Combine Rules with Logic");
149 title.setStyleName("KS-Course-Requisites-Manage-Step-header2");
150 layout.add(title);
151
152 layout.add(ruleManageWidget);
153
154
155 KSProgressIndicator twiddler = new KSProgressIndicator();
156 twiddler.setVisible(false);
157 twiddlerPanel.setWidget(twiddler);
158 layout.add(twiddlerPanel);
159
160 addWidget(layout);
161
162 displaySaveButton();
163 }
164
165 protected void displaySaveButton() {
166 actionCancelButtons.addStyleName("KS-Course-Requisites-Save-Button");
167 actionCancelButtons.addCallback(new Callback<ButtonEnumerations.ButtonEnum>(){
168 @Override
169 public void exec(ButtonEnumerations.ButtonEnum result) {
170 userClickedSaveButton = (result == ButtonEnumerations.SaveCancelEnum.SAVE);
171 parentController.showView(CourseRequirementsViewController.CourseRequirementsViews.PREVIEW);
172 }
173 });
174 addWidget(actionCancelButtons);
175 }
176
177
178 public void setRuleTree(StatementTreeViewInfo stmtTreeInfo, boolean newRuleFlag, Integer internalCourseReqID) {
179
180 if (!isInitialized) {
181 editReqCompWidget = new ReqCompEditWidget(CourseRequirementsSummaryView.NEW_REQ_COMP_ID);
182 ruleManageWidget = new RuleManageWidget();
183 ruleManageWidget.setReqCompEditButtonClickCallback(editReqCompCallback);
184 ruleManageWidget.setRuleChangedButtonClickCallback(ruleChangedCallback);
185 }
186
187 this.internalCourseReqID = internalCourseReqID;
188 editedReqCompInfo = null;
189 userClickedSaveButton = false;
190 rule = RulesUtil.clone(stmtTreeInfo);
191 isNewRule = newRuleFlag;
192 originalReqCompNL = getAllReqCompNLs();
193
194
195 editReqCompWidget.setupNewReqComp();
196 ruleManageWidget.redraw(rule, false);
197
198 }
199
200
201 public StatementTreeViewInfo getRuleTree() {
202 rule = ruleManageWidget.getStatementTreeViewInfo();
203 return rule;
204 }
205
206 public boolean isNewRule() {
207 return isNewRule;
208 }
209
210
211 protected Callback<ReqComponentInfo> editReqCompCallback = new Callback<ReqComponentInfo>(){
212 public void exec(ReqComponentInfo reqComp) {
213 setEnabled(false);
214 editReqCompWidget.setupExistingReqComp(reqComp);
215 editedReqCompInfo = reqComp;
216 }
217 };
218
219 protected Callback<Boolean> ruleChangedCallback = new Callback<Boolean>(){
220 public void exec(Boolean ruleChanged) {
221 actionCancelButtons.getButton(ButtonEnumerations.SaveCancelEnum.SAVE).setEnabled(ruleChanged);
222 }
223 };
224
225 protected void setEnabled(boolean enabled) {
226 ruleManageWidget.setEnabled(enabled);
227 actionCancelButtons.getButton(ButtonEnumerations.SaveCancelEnum.SAVE).setEnabled(enabled);
228 }
229
230 @Override
231 public boolean isDirty() {
232 if (!isInitialized) {
233 return false;
234 }
235
236
237 return true;
238
239
240
241
242
243
244
245
246
247
248
249
250 }
251
252 private String getAllReqCompNLs() {
253 StringBuilder NL = new StringBuilder();
254 for (StatementTreeViewInfo tree : rule.getStatements()) {
255 for (ReqComponentInfo reqComp : tree.getReqComponents()) {
256 NL.append(reqComp.getNaturalLanguageTranslation());
257 }
258 }
259 return NL.toString();
260 }
261
262
263 protected Callback<ReqComponentInfoUi> actionButtonClickedReqCompCallback = new Callback<ReqComponentInfoUi>(){
264 public void exec(final ReqComponentInfoUi reqComp) {
265
266 editReqCompWidget.setupNewReqComp();
267 setEnabled(true);
268
269
270 if (reqComp == null) {
271 return;
272 }
273
274 KSBlockingProgressIndicator.addTask(creatingRuleTask);
275
276
277 statementRpcServiceAsync.translateReqComponentToNLs(reqComp, new String[]{RULEEDIT_TEMLATE, RULEPREVIEW_TEMLATE}, TEMLATE_LANGUAGE, new KSAsyncCallback<List<String>>() {
278 public void handleFailure(Throwable caught) {
279 KSBlockingProgressIndicator.removeTask(creatingRuleTask);
280 Window.alert(caught.getMessage());
281 GWT.log("translateReqComponentToNL failed", caught);
282 }
283
284 public void onSuccess(final List<String> reqCompNL) {
285
286 reqComp.setNaturalLanguageTranslation(reqCompNL.get(0));
287 reqComp.setPreviewNaturalLanguageTranslation(reqCompNL.get(1));
288
289
290 rule = ruleManageWidget.getStatementTreeViewInfo();
291
292 if (editedReqCompInfo == null) {
293 if (rule.getStatements() != null && !rule.getStatements().isEmpty()) {
294 StatementTreeViewInfo newStatementTreeViewInfo = new StatementTreeViewInfo();
295 newStatementTreeViewInfo.setId(CourseRequirementsSummaryView.NEW_STMT_TREE_ID + Integer.toString(tempStmtTreeViewInfoID++));
296 newStatementTreeViewInfo.setOperator(rule.getOperator());
297 newStatementTreeViewInfo.getReqComponents().add(reqComp);
298 newStatementTreeViewInfo.setType(rule.getType());
299 rule.getStatements().add(newStatementTreeViewInfo);
300 } else {
301 rule.getReqComponents().add(reqComp);
302
303 if (rule.getOperator() == null) {
304 rule.setOperator(StatementOperatorTypeKey.AND);
305 }
306 }
307 } else {
308 editedReqCompInfo.setNaturalLanguageTranslation(reqComp.getNaturalLanguageTranslation());
309 editedReqCompInfo.setReqCompFields(reqComp.getReqCompFields());
310 editedReqCompInfo.setType(reqComp.getType());
311 editedReqCompInfo = null;
312 }
313
314 ruleManageWidget.redraw(rule, true);
315 KSBlockingProgressIndicator.removeTask(creatingRuleTask);
316 }
317 });
318 }
319 };
320
321
322 protected Callback<ReqComponentInfo> newReqCompSelectedCallbackCallback = new Callback<ReqComponentInfo>(){
323 public void exec(final ReqComponentInfo reqComp) {
324 setEnabled(false);
325 }
326 };
327
328 private void retrieveAndSetupReqCompTypes() {
329
330 statementRpcServiceAsync.getReqComponentTypesForStatementType(rule.getType(), new KSAsyncCallback<List<ReqComponentTypeInfo>>() {
331 public void handleFailure(Throwable cause) {
332 GWT.log("Failed to get req. component types for statement of type:" + rule.getType(), cause);
333 Window.alert("Failed to get req. component types for statement of type:" + rule.getType());
334 }
335
336 public void onSuccess(final List<ReqComponentTypeInfo> reqComponentTypeInfoList) {
337 if (reqComponentTypeInfoList == null || reqComponentTypeInfoList.size() == 0) {
338 GWT.log("Missing Requirement Component Types", null);
339 Window.alert("Missing Requirement Component Types");
340 return;
341 }
342 editReqCompWidget.setReqCompList(reqComponentTypeInfoList);
343 editReqCompWidget.setCustomWidgets(getCustomWidgets(reqComponentTypeInfoList));
344 }
345 });
346 }
347
348 private Map<String, Widget> getCustomWidgets(List<ReqComponentTypeInfo> reqComponentTypeInfoList) {
349 Map<String, Widget> customWidgets = new HashMap<String, Widget>();
350
351 for (ReqComponentTypeInfo reqCompTypeInfo : reqComponentTypeInfoList) {
352 for (ReqCompFieldTypeInfo fieldTypeInfo : reqCompTypeInfo.getReqCompFieldTypeInfos()) {
353 if (RulesUtil.isGradeWidget(fieldTypeInfo.getId())) {
354 customWidgets.put("kuali.reqComponent.field.type.grade.id", new GradeWidget());
355 } else if (RulesUtil.isCourseWidget(fieldTypeInfo.getId())) {
356
357 final CourseWidget courseWidget = GWT.create(CourseWidget.class);
358
359 courseWidget.addGetCluNameCallback(new Callback() {
360
361 @Override
362 public void exec(Object id) {
363
364 luRpcServiceAsync.getCurrentVersion(CLU_NAMESPACE_URI, (String)id, new AsyncCallback<VersionDisplayInfo>() {
365 @Override
366 public void onFailure(Throwable throwable) {
367 Window.alert(throwable.getMessage());
368 GWT.log("Failed to retrieve clu for id: '" + "'", throwable);
369 }
370
371 @Override
372 public void onSuccess(final VersionDisplayInfo versionInfo) {
373 luRpcServiceAsync.getClu(versionInfo.getId(), new AsyncCallback<CluInfo>() {
374 @Override
375 public void onFailure(Throwable throwable) {
376 Window.alert(throwable.getMessage());
377 GWT.log("Failed to retrieve clu", throwable);
378 }
379
380 @Override
381 public void onSuccess(CluInfo cluInfo) {
382 courseWidget.setLabelContent(cluInfo.getVersionInfo().getVersionIndId(), cluInfo.getOfficialIdentifier().getCode());
383 }
384 });
385 }
386 });
387
388
389 }
390 });
391
392 customWidgets.put("kuali.reqComponent.field.type.course.clu.id", courseWidget);
393 } else if (RulesUtil.isProgramWidget(fieldTypeInfo.getId())) {
394 final ProgramWidget programWidget = new ProgramWidget();
395
396 programWidget.addGetCluNameCallback(new Callback() {
397
398 @Override
399 public void exec(Object id) {
400
401 statementRpcServiceAsync.getCurrentVersion(CLU_NAMESPACE_URI, (String)id, new AsyncCallback<VersionDisplayInfo>() {
402 @Override
403 public void onFailure(Throwable throwable) {
404 Window.alert(throwable.getMessage());
405 GWT.log("Failed to retrieve clu for id: '" + "'", throwable);
406 }
407
408 @Override
409 public void onSuccess(final VersionDisplayInfo versionInfo) {
410 statementRpcServiceAsync.getClu(versionInfo.getId(), new AsyncCallback<CluInfo>() {
411 @Override
412 public void onFailure(Throwable throwable) {
413 Window.alert(throwable.getMessage());
414 GWT.log("Failed to retrieve clu", throwable);
415 }
416
417 @Override
418 public void onSuccess(CluInfo cluInfo) {
419 programWidget.setLabelContent(cluInfo.getVersionInfo().getVersionIndId(), cluInfo.getOfficialIdentifier().getCode());
420 }
421 });
422 }
423 });
424 }
425 });
426
427 customWidgets.put("kuali.reqComponent.field.type.program.clu.id", programWidget);
428 }
429 }
430 }
431 return customWidgets;
432 }
433
434
435 protected Callback<ReqComponentInfo> retrieveCompositionTemplateCallback = new Callback<ReqComponentInfo>(){
436 public void exec(final ReqComponentInfo reqComp) {
437 statementRpcServiceAsync.translateReqComponentToNL(reqComp, COMPOSITION_TEMLATE, TEMLATE_LANGUAGE, new KSAsyncCallback<String>() {
438 public void handleFailure(Throwable caught) {
439 Window.alert(caught.getMessage());
440 GWT.log("translateReqComponentToNL failed for req. comp. type: '" + reqComp.getType() + "'",caught);
441 }
442
443 public void onSuccess(final String compositionTemplate) {
444 editReqCompWidget.displayFieldsStart(compositionTemplate);
445 }
446 });
447 }
448 };
449
450 protected Callback<List<String>> retrieveFieldsMetadataCallback = new Callback<List<String>>(){
451 public void exec(final List<String> fieldTypes) {
452
453 if (fieldTypes.contains("kuali.reqComponent.field.type.grade.id")) {
454 fieldTypes.add("kuali.reqComponent.field.type.gradeType.id");
455 }
456
457 metadataServiceAsync.getMetadataList(ReqCompFieldInfo.class.getName(), fieldTypes, null, new KSAsyncCallback<List<Metadata>>() {
458 public void handleFailure(Throwable caught) {
459 Window.alert(caught.getMessage());
460 GWT.log("getMetadataList failed for req. comp. types: '" + fieldTypes.toString() + "'",caught);
461 }
462
463 public void onSuccess(final List<Metadata> metadataList) {
464 editReqCompWidget.displayFieldsEnd(metadataList);
465 }
466 });
467 }
468 };
469
470 protected Callback<String> retrieveCustomWidgetCallback = new Callback<String>(){
471 public void exec(final String fieldType) {
472 if (RulesUtil.isCluSetWidget(fieldType)) {
473 String clusetType = "kuali.cluSet.type.Course";
474 if (fieldType.toLowerCase().indexOf("program") > 0) {
475 clusetType = "kuali.cluSet.type.Program";
476 }
477 editReqCompWidget.displayCustomWidget(fieldType, new BuildCluSetWidget(new CluSetRetrieverImpl(), clusetType, false));
478 }
479 }
480 };
481
482 public boolean isUserClickedSaveButton() {
483 return userClickedSaveButton;
484 }
485
486 public void setUserClickedSaveButton(boolean userClickedSaveButton) {
487 this.userClickedSaveButton = userClickedSaveButton;
488 }
489
490 public Integer getInternalCourseReqID() {
491 return internalCourseReqID;
492 }
493
494 public RuleManageWidget getRuleManageWidget() {
495 return ruleManageWidget;
496 }
497 }