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