1 package org.kuali.student.lum.lu.ui.tools.client.configuration;
2
3 import java.util.Date;
4 import java.util.List;
5
6 import org.kuali.student.common.ui.client.application.Application;
7 import org.kuali.student.common.ui.client.application.KSAsyncCallback;
8 import org.kuali.student.common.ui.client.configurable.mvc.FieldDescriptor;
9 import org.kuali.student.common.ui.client.configurable.mvc.FieldDescriptorReadOnly;
10 import org.kuali.student.common.ui.client.configurable.mvc.SectionTitle;
11 import org.kuali.student.common.ui.client.configurable.mvc.binding.ModelWidgetBinding;
12 import org.kuali.student.common.ui.client.configurable.mvc.binding.ModelWidgetBindingSupport;
13 import org.kuali.student.common.ui.client.configurable.mvc.sections.Section;
14 import org.kuali.student.common.ui.client.configurable.mvc.sections.VerticalSection;
15 import org.kuali.student.common.ui.client.configurable.mvc.views.VerticalSectionView;
16 import org.kuali.student.common.ui.client.mvc.Callback;
17 import org.kuali.student.common.ui.client.mvc.Controller;
18 import org.kuali.student.common.ui.client.mvc.DataModel;
19 import org.kuali.student.common.ui.client.mvc.DataModelDefinition;
20 import org.kuali.student.common.ui.client.mvc.history.HistoryManager;
21 import org.kuali.student.common.ui.client.widgets.KSDatePicker;
22 import org.kuali.student.common.ui.client.widgets.KSLabel;
23 import org.kuali.student.common.ui.client.widgets.KSTextArea;
24 import org.kuali.student.common.ui.client.widgets.field.layout.element.MessageKeyInfo;
25 import org.kuali.student.common.ui.client.widgets.headers.KSDocumentHeader;
26 import org.kuali.student.common.ui.client.widgets.search.KSPicker;
27 import org.kuali.student.common.ui.client.widgets.search.SelectedResults;
28 import org.kuali.student.common.ui.client.widgets.table.summary.SummaryTableFieldBlock;
29 import org.kuali.student.common.ui.client.widgets.table.summary.SummaryTableFieldRow;
30 import org.kuali.student.common.ui.client.widgets.table.summary.SummaryTableSection;
31 import org.kuali.student.lum.common.client.lu.LUUIConstants;
32 import org.kuali.student.lum.common.client.widgets.CluSetDetailsWidget;
33 import org.kuali.student.lum.common.client.widgets.CluSetEditorWidget;
34 import org.kuali.student.lum.common.client.widgets.CluSetManagementRpcService;
35 import org.kuali.student.lum.common.client.widgets.CluSetManagementRpcServiceAsync;
36 import org.kuali.student.lum.common.client.widgets.CluSetRetriever;
37 import org.kuali.student.lum.common.client.widgets.CluSetRetrieverImpl;
38 import org.kuali.student.r1.common.assembly.data.LookupMetadata;
39 import org.kuali.student.r1.common.assembly.data.Metadata;
40 import org.kuali.student.r1.common.assembly.data.QueryPath;
41
42 import com.google.gwt.core.client.GWT;
43 import com.google.gwt.dom.client.Style;
44 import com.google.gwt.event.dom.client.ClickEvent;
45 import com.google.gwt.event.dom.client.ClickHandler;
46 import com.google.gwt.i18n.client.DateTimeFormat;
47 import com.google.gwt.user.client.Window;
48 import com.google.gwt.user.client.rpc.AsyncCallback;
49 import com.google.gwt.user.client.ui.Anchor;
50 import com.google.gwt.user.client.ui.HasText;
51 import com.google.gwt.user.client.ui.SimplePanel;
52 import com.google.gwt.user.client.ui.Widget;
53
54 public class ClusetView extends VerticalSectionView {
55
56 protected CluSetManagementRpcServiceAsync cluSetManagementRpcServiceAsync = GWT.create(CluSetManagementRpcService.class);
57 protected CluSetRetriever cluSetRetriever = new CluSetRetrieverImpl();
58 protected DataModelDefinition modelDefinition;
59 protected DataModelDefinition searchDefinition;
60 protected String selectedCluSetId;
61 protected CluSetsManagementViews viewEnum;
62 protected SimplePanel cluSetDisplay = new SimplePanel();
63 protected CluSetEditorWidget cluSetEditor;
64 protected String cluSetType;
65
66 protected KSLabel titleLabel = new KSLabel();
67
68 public void afterModelIsLoaded(DataModel cluSetModel) {
69 titleLabel.setText(cluSetModel.<String>get("name"));
70 }
71
72 public enum CluSetsManagementViews {
73 MAIN,
74 CREATE,
75 EDIT,
76 VIEW
77 }
78
79 public ClusetView() {
80 super();
81 }
82
83 public ClusetView(Enum<?> viewEnum, String name, String modelId,
84 boolean showTitle) {
85 super(viewEnum, name, modelId, showTitle);
86 }
87
88 public ClusetView(Enum<?> viewEnum, String name, String modelId,
89 Widget titleWidget) {
90 super(viewEnum, name, modelId, titleWidget);
91 }
92
93 public ClusetView(Enum<?> viewEnum, String name, String modelId) {
94 super(viewEnum, name, modelId);
95 }
96
97 public void init(CluSetsManagementViews clusetViewEnum, String name, String modelId, final Callback<Boolean> onReady) {
98 init(clusetViewEnum, name, modelId, false, onReady);
99 }
100
101 public void init(final CluSetsManagementViews clusetViewEnum, String name,
102 String clusetMgtModel, boolean showTitle, final Callback<Boolean> onReady) {
103 super.init(clusetViewEnum, name, modelId, showTitle);
104 cluSetType = "kuali.cluSet.type.CreditCourse";
105 if (clusetViewEnum == CluSetsManagementViews.CREATE ||
106 clusetViewEnum == CluSetsManagementViews.EDIT) {
107 cluSetEditor = new CluSetEditorWidget(
108 new CluSetRetrieverImpl(),
109 clusetViewEnum, name, modelId, true, null,
110 cluSetType, false);
111 }
112 viewEnum = clusetViewEnum;
113 cluSetManagementRpcServiceAsync.getMetadata("courseSet", null, new KSAsyncCallback<Metadata>() {
114 @Override
115 public void handleFailure(Throwable caught) {
116 Window.alert("Failed to retrieve cluset definition");
117 }
118
119 @Override
120 public void onSuccess(Metadata result) {
121 DataModelDefinition def = new DataModelDefinition(result);
122 setModelDefinition(def);
123 cluSetManagementRpcServiceAsync.getMetadata("search", null, new AsyncCallback<Metadata>() {
124 @Override
125 public void onFailure(Throwable caught) {
126 Window.alert("Failed to retrieve searchDefinition");
127 }
128
129 @Override
130 public void onSuccess(Metadata result) {
131 setSearchDefinition(new DataModelDefinition(result));
132 setupView(clusetViewEnum);
133 if (onReady != null) {
134 onReady.exec(new Boolean(true));
135 }
136 }
137 });
138 }
139 });
140 setStyles();
141 }
142
143 private void setStyles() {
144 titleLabel.addStyleName("cluSetTitle");
145 }
146
147 private void setModelDefinition(DataModelDefinition modelDefinition) {
148 this.modelDefinition = modelDefinition;
149 }
150
151 private void setSearchDefinition(DataModelDefinition searchDefinition) {
152 this.searchDefinition = searchDefinition;
153 }
154
155 @Override
156 public void beforeShow(Callback<Boolean> onReadyCallback) {
157 super.beforeShow(onReadyCallback);
158 if (viewEnum == CluSetsManagementViews.VIEW) {
159 refreshCluSetDisplay();
160 }
161 }
162
163 private void refreshCluSetDisplay() {
164 if (this.selectedCluSetId != null) {
165 CluSetDetailsWidget clusetDetailsWidget =
166 new CluSetDetailsWidget(selectedCluSetId, cluSetRetriever);
167 cluSetDisplay.clear();
168 cluSetDisplay.setWidget(clusetDetailsWidget);
169 }
170 }
171
172 private void setupView(CluSetsManagementViews clusetViewEnum) {
173 if (clusetViewEnum == CluSetsManagementViews.CREATE ||
174 clusetViewEnum == CluSetsManagementViews.EDIT) {
175 setupCreateEditClusetView();
176 } else if (clusetViewEnum == CluSetsManagementViews.MAIN) {
177 setupMainView();
178 } else if (clusetViewEnum == CluSetsManagementViews.VIEW) {
179 setupViewClusetView();
180 }
181 }
182
183 @Override
184 public void onHistoryEvent(String historyStack) {
185 super.onHistoryEvent(historyStack);
186 CluSetsManagementController cluSetsManagementController =
187 (CluSetsManagementController) getController();
188 selectedCluSetId = HistoryManager.getTokenMap(historyStack).get("docId");
189 cluSetsManagementController.getMainView().setSelectedCluSetId(selectedCluSetId);
190 cluSetsManagementController.showView(CluSetsManagementViews.VIEW);
191 }
192
193 protected void setupViewClusetView() {
194 Anchor editCluSet = new Anchor("Edit Course Set");
195 editCluSet.addClickHandler(new ClickHandler() {
196 @Override
197 public void onClick(ClickEvent event) {
198 Controller parentController = getController();
199 parentController.showView(CluSetsManagementViews.EDIT);
200 }
201 });
202 addWidget(titleLabel);
203 this.addWidget(editCluSet);
204 Section generalClusInfoSection = new VerticalSection();
205 KSLabel cluSetTitle = new KSLabel();
206 cluSetTitle.getElement().getStyle().setProperty("fontWeight", "bold");
207 cluSetTitle.getElement().getStyle().setProperty("fontSize", "16px");
208 cluSetTitle.getElement().getStyle().setProperty("borderBotton", "1px solid #D8D8D8");
209
210 addField(generalClusInfoSection,
211 ToolsConstants.CLU_SET_NAME_FIELD,
212 null,
213 cluSetTitle,
214 null);
215
216
217
218
219
220
221
222
223
224
225 this.addSection(setupGeneralClusInfoSection());
226
227 this.addWidget(new KSLabel("Items in this Course Set"));
228 this.addWidget(cluSetDisplay);
229 this.setStyleName("standard-content-padding");
230 }
231
232 protected SummaryTableSection setupGeneralClusInfoSection() {
233 SummaryTableSection result = GWT.create(SummaryTableSection.class);
234 result.init(getController());
235 result.setEditable(false);
236
237 SummaryTableFieldBlock block = new SummaryTableFieldBlock();
238
239
240 block.addSummaryTableFieldRow(getFieldRow(ToolsConstants.CLU_SET_DESCRIPTION_FIELD, generateMessageInfo(ToolsConstants.DESCRIPTION)));
241 SummaryTableFieldRow expDateRow = getFieldRow(ToolsConstants.CLU_SET_EXP_DATE_FIELD,
242 generateMessageInfo(ToolsConstants.EXPIRATION_DATE), null, null, null,
243 new ModelWidgetBindingSupport<HasText>() {
244 public String dateToString(Date date) {
245 String result = null;
246 DateTimeFormat format = DateTimeFormat.getFormat("MM/dd/yyyy");
247 result = format.format(date);
248
249 return result;
250 }
251
252 @Override
253 public void setModelValue(HasText widget, DataModel model, String path) {
254
255 }
256
257 @Override
258 public void setWidgetValue(HasText widget, DataModel model, String path) {
259 try {
260 QueryPath qPath = QueryPath.parse(path);
261
262 Object value = null;
263 if (model != null) {
264 value = model.get(qPath);
265 }
266
267 if (value != null && widget != null) {
268 if (value instanceof Date) {
269 widget.setText(dateToString((Date) value));
270 } else {
271 widget.setText(value.toString());
272 }
273 } else if (value == null && widget != null) {
274 widget.setText("");
275 }
276 } catch (Exception e) {
277 GWT.log("Error setting widget value for: " + path, e);
278 }
279 }
280
281 }
282 , false);
283 block.addSummaryTableFieldRow(expDateRow);
284
285 result.addSummaryTableFieldBlock(block);
286 return result;
287 }
288
289 protected SummaryTableFieldRow getFieldRow(String fieldKey, MessageKeyInfo messageKey) {
290 return getFieldRow(fieldKey, messageKey, null, null, null, null, false);
291 }
292
293 protected SummaryTableFieldRow getFieldRow(String fieldKey, MessageKeyInfo messageKey, boolean optional) {
294 return getFieldRow(fieldKey, messageKey, null, null, null, null, optional);
295 }
296
297 protected SummaryTableFieldRow getFieldRow(String fieldKey, MessageKeyInfo messageKey, Widget widget, Widget widget2, String parentPath, ModelWidgetBinding<?> binding, boolean optional) {
298 QueryPath path = QueryPath.concat(parentPath, fieldKey);
299 Metadata meta = modelDefinition.getMetadata(path);
300
301 FieldDescriptorReadOnly fd = new FieldDescriptorReadOnly(path.toString(), messageKey, meta);
302 if (widget != null) {
303 fd.setFieldWidget(widget);
304 }
305 if (binding != null) {
306 fd.setWidgetBinding(binding);
307 }
308 fd.setOptional(optional);
309
310 FieldDescriptorReadOnly fd2 = new FieldDescriptorReadOnly(path.toString(), messageKey, meta);
311 if (widget2 != null) {
312 fd2.setFieldWidget(widget2);
313 }
314 if (binding != null) {
315 fd2.setWidgetBinding(binding);
316 }
317 fd2.setOptional(optional);
318
319 SummaryTableFieldRow fieldRow = new SummaryTableFieldRow(fd, fd2);
320
321 return fieldRow;
322 }
323
324 private void setupMainView() {
325 this.addStyleName("blockLayout");
326 KSDocumentHeader header = new KSDocumentHeader();
327 header.setTitle("Course Set Management");
328 this.addWidget(header);
329
330 Anchor createCluSet = new Anchor("<h2 class=\"contentBlock-title\">Create Course Set</h2>", true);
331 createCluSet.addClickHandler(new ClickHandler() {
332 @Override
333 public void onClick(ClickEvent event) {
334 getController().showView(CluSetsManagementViews.CREATE);
335 }
336 });
337 this.addWidget(createCluSet);
338 this.addWidget(new KSLabel("Build a new Course set from courses, Course Sets, " +
339 "or specific criteria."));
340
341 Picker cluSetPicker = configureSearch(ToolsConstants.SEARCH_COURSE_SET);
342 cluSetPicker.addBasicSelectionCompletedCallback(new Callback<SelectedResults>() {
343 @Override
344 public void exec(SelectedResults result) {
345 if (result != null && result.getReturnKey() != null && result.getReturnKey().trim().length() > 0) {
346 selectedCluSetId = result.getReturnKey();
347 Controller parentController = getController();
348 parentController.showView(CluSetsManagementViews.VIEW);
349 }
350 }
351 });
352 SectionTitle modifyCluSetTitle = SectionTitle.generateH2Title("View or Modify Course Sets");
353 modifyCluSetTitle.addStyleName("contentBlock-title");
354 modifyCluSetTitle.getElement().getStyle().setPaddingTop(40, Style.Unit.PX);
355 this.addWidget(modifyCluSetTitle);
356 this.addWidget(cluSetPicker);
357 }
358
359 public String getSelectedCluSetId() {
360 return selectedCluSetId;
361 }
362
363 public void setSelectedCluSetId(String selectedCluSetId) {
364 this.selectedCluSetId = selectedCluSetId;
365 }
366
367 protected void setupCreateEditClusetView() {
368 String contextName = (cluSetType != null && cluSetType.equals("kuali.cluSet.type.Program")) ?
369 "Program" : "Course";
370 VerticalSection defineCluSet = initSection(getH3Title(ToolsConstants.DEFINE_CLUSET + contextName), true);
371
372 addFields(defineCluSet,contextName);
373
374 KSLabel spacer = new KSLabel();
375 spacer.setHeight("20px");
376 this.addSection(cluSetEditor);
377 this.addWidget(spacer);
378 this.addSection(defineCluSet);
379 this.setStyleName("standard-content-padding");
380 }
381
382 protected void addFields(VerticalSection defineCluSet, String contextName) {
383 addField(defineCluSet, ToolsConstants.CLU_SET_ORGANIZATION_FIELD, generateMessageInfo(ToolsConstants.ORGANIZATION), null, null);
384 addField(defineCluSet, ToolsConstants.CLU_SET_NAME_FIELD, generateMessageInfo(ToolsConstants.TITLE + contextName), null, null);
385 addField(defineCluSet, ToolsConstants.CLU_SET_DESCRIPTION_FIELD, generateMessageInfo(ToolsConstants.DESCRIPTION), new KSTextArea(), null);
386 addField(defineCluSet, ToolsConstants.CLU_SET_EFF_DATE_FIELD, generateMessageInfo(ToolsConstants.EFFECTIVE_DATE), new KSDatePicker(), null);
387 addField(defineCluSet, ToolsConstants.CLU_SET_EXP_DATE_FIELD, generateMessageInfo(ToolsConstants.EXPIRATION_DATE), new KSDatePicker(), null);
388 }
389
390 protected static VerticalSection initSection(SectionTitle title, boolean withDivider) {
391 VerticalSection section = new VerticalSection(title);
392 section.addStyleName(LUUIConstants.STYLE_SECTION);
393 if (withDivider)
394 section.addStyleName(LUUIConstants.STYLE_SECTION_DIVIDER);
395 return section;
396 }
397
398 private String getLabel(String labelKey) {
399 return Application.getApplicationContext().getUILabel("clusetmanagement", "clusetmanagement", "draft", labelKey);
400 }
401
402 protected SectionTitle getH3Title(String labelKey) {
403 return SectionTitle.generateH3Title(getLabel(labelKey));
404 }
405
406 protected MessageKeyInfo generateMessageInfo(String labelKey) {
407 return new MessageKeyInfo("clusetmanagement", "clusetmanagement", "draft", labelKey);
408 }
409
410 private FieldDescriptor getFieldDescriptor(
411 String fieldKey,
412 MessageKeyInfo messageKey,
413 Widget widget,
414 String parentPath) {
415 QueryPath path = QueryPath.concat(parentPath, fieldKey);
416 Metadata meta = modelDefinition.getMetadata(path);
417 FieldDescriptor fd;
418 if (widget != null) {
419 fd = new FieldDescriptor(path.toString(), messageKey, meta, widget);
420 } else {
421 fd = new FieldDescriptor(path.toString(), messageKey, meta);
422 }
423 return fd;
424 }
425
426 protected FieldDescriptor addField(Section section,
427 String fieldKey,
428 MessageKeyInfo messageKey,
429 Widget widget,
430 String parentPath) {
431 FieldDescriptor fd = getFieldDescriptor(fieldKey, messageKey, widget, parentPath);
432 section.addField(fd);
433 return fd;
434 }
435
436 private Picker configureSearch(String fieldKey) {
437 QueryPath path = QueryPath.concat(null, fieldKey);
438 Metadata metaData = searchDefinition.getMetadata(path);
439 Picker picker = new Picker(metaData.getInitialLookup(), metaData.getAdditionalLookups());
440 return picker;
441 }
442
443 public static class Picker extends KSPicker {
444
445 private String name;
446 private LookupMetadata initLookupMetadata;
447 private List<LookupMetadata> additionalLookupMetadata;
448
449 public Picker(LookupMetadata inLookupMetadata, List<LookupMetadata> additionalLookupMetadata) {
450 super.init(inLookupMetadata, additionalLookupMetadata);
451 this.initLookupMetadata = inLookupMetadata;
452 this.additionalLookupMetadata = additionalLookupMetadata;
453 }
454
455 public String getName() {
456 return name;
457 }
458
459 public void setName(String name) {
460 this.name = name;
461 }
462
463 public LookupMetadata getInitLookupMetadata() {
464 return initLookupMetadata;
465 }
466
467 public void setInitLookupMetadata(LookupMetadata initLookupMetadata) {
468 this.initLookupMetadata = initLookupMetadata;
469 }
470
471 public List<LookupMetadata> getAdditionalLookupMetadata() {
472 return additionalLookupMetadata;
473 }
474
475 public void setAdditionalLookupMetadata(List<LookupMetadata> additionalLookupMetadata) {
476 this.additionalLookupMetadata = additionalLookupMetadata;
477 }
478
479 }
480
481 @Override
482 public void setController(Controller controller) {
483 super.setController(controller);
484 if (cluSetEditor != null) {
485 cluSetEditor.setController(controller);
486 }
487 }
488
489 }