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