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