1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 package org.kuali.student.lum.lu.ui.course.client.configuration;
31
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.HashMap;
35 import java.util.List;
36 import java.util.Map;
37
38 import org.kuali.student.common.ui.client.application.Application;
39 import org.kuali.student.common.ui.client.configurable.mvc.FieldDescriptor;
40 import org.kuali.student.common.ui.client.configurable.mvc.SectionTitle;
41 import org.kuali.student.common.ui.client.configurable.mvc.binding.HasDataValueBinding;
42 import org.kuali.student.common.ui.client.configurable.mvc.binding.ListOfStringBinding;
43 import org.kuali.student.common.ui.client.configurable.mvc.binding.ModelWidgetBinding;
44 import org.kuali.student.common.ui.client.configurable.mvc.binding.ModelWidgetBindingSupport;
45 import org.kuali.student.common.ui.client.configurable.mvc.multiplicity.CompositeConditionOperator;
46 import org.kuali.student.common.ui.client.configurable.mvc.multiplicity.MultiplicityConfiguration;
47 import org.kuali.student.common.ui.client.configurable.mvc.multiplicity.MultiplicityFieldConfiguration;
48 import org.kuali.student.common.ui.client.configurable.mvc.multiplicity.MultiplicityFieldWidgetInitializer;
49 import org.kuali.student.common.ui.client.configurable.mvc.multiplicity.SwapCompositeCondition;
50 import org.kuali.student.common.ui.client.configurable.mvc.multiplicity.SwapCompositeConditionFieldConfig;
51 import org.kuali.student.common.ui.client.configurable.mvc.multiplicity.SwapCondition;
52 import org.kuali.student.common.ui.client.configurable.mvc.sections.CollapsableSection;
53 import org.kuali.student.common.ui.client.configurable.mvc.sections.GroupSection;
54 import org.kuali.student.common.ui.client.configurable.mvc.sections.MultiplicitySection;
55 import org.kuali.student.common.ui.client.configurable.mvc.sections.Section;
56 import org.kuali.student.common.ui.client.configurable.mvc.sections.SwapSection;
57 import org.kuali.student.common.ui.client.configurable.mvc.sections.VerticalSection;
58 import org.kuali.student.common.ui.client.configurable.mvc.views.SectionView;
59 import org.kuali.student.common.ui.client.configurable.mvc.views.VerticalSectionView;
60 import org.kuali.student.common.ui.client.mvc.Controller;
61 import org.kuali.student.common.ui.client.mvc.DataModel;
62 import org.kuali.student.common.ui.client.mvc.DataModelDefinition;
63 import org.kuali.student.common.ui.client.mvc.HasDataValue;
64 import org.kuali.student.common.ui.client.mvc.View;
65 import org.kuali.student.common.ui.client.widgets.KSButton;
66 import org.kuali.student.common.ui.client.widgets.KSCheckBox;
67 import org.kuali.student.common.ui.client.widgets.KSDropDown;
68 import org.kuali.student.common.ui.client.widgets.ListOfStringWidget;
69 import org.kuali.student.common.ui.client.widgets.KSButtonAbstract.ButtonStyle;
70 import org.kuali.student.common.ui.client.widgets.commenttool.CommentTool;
71 import org.kuali.student.common.ui.client.widgets.documenttool.DocumentTool;
72 import org.kuali.student.common.ui.client.widgets.field.layout.element.MessageKeyInfo;
73 import org.kuali.student.common.ui.client.widgets.field.layout.element.SpanPanel;
74 import org.kuali.student.common.ui.client.widgets.field.layout.layouts.FieldLayoutComponent;
75 import org.kuali.student.common.ui.client.widgets.list.KSLabelList;
76 import org.kuali.student.common.ui.client.widgets.list.KSSelectItemWidgetAbstract;
77 import org.kuali.student.common.ui.client.widgets.list.KSSelectedList;
78 import org.kuali.student.common.ui.client.widgets.list.impl.SimpleListItems;
79 import org.kuali.student.common.ui.client.widgets.search.KSPicker;
80 import org.kuali.student.core.assembly.data.Data;
81 import org.kuali.student.core.assembly.data.Metadata;
82 import org.kuali.student.core.assembly.data.QueryPath;
83 import org.kuali.student.core.assembly.data.Data.Value;
84 import org.kuali.student.core.comments.ui.client.widgets.decisiontool.DecisionPanel;
85 import org.kuali.student.core.statement.dto.StatementTypeInfo;
86 import org.kuali.student.core.workflow.ui.client.views.CollaboratorSectionView;
87 import org.kuali.student.lum.common.client.lo.LOBuilder;
88 import org.kuali.student.lum.common.client.lo.LOBuilderBinding;
89 import org.kuali.student.lum.common.client.lo.LOPicker;
90 import org.kuali.student.lum.common.client.lo.OutlineNode;
91 import org.kuali.student.lum.common.client.lu.LUUIConstants;
92 import org.kuali.student.lum.lu.assembly.data.client.constants.base.RichTextInfoConstants;
93 import org.kuali.student.lum.lu.assembly.data.client.constants.orch.CreditCourseActivityConstants;
94 import org.kuali.student.lum.lu.assembly.data.client.constants.orch.CreditCourseConstants;
95 import org.kuali.student.lum.lu.assembly.data.client.constants.orch.CreditCourseJointsConstants;
96 import org.kuali.student.lum.lu.ui.course.client.controllers.CourseProposalController;
97 import org.kuali.student.lum.lu.ui.course.client.requirements.CourseRequirementsViewController;
98
99 import com.google.gwt.event.dom.client.ClickEvent;
100 import com.google.gwt.event.dom.client.ClickHandler;
101 import com.google.gwt.event.logical.shared.ValueChangeEvent;
102 import com.google.gwt.event.logical.shared.ValueChangeHandler;
103 import com.google.gwt.user.client.ui.Widget;
104
105
106
107
108
109
110
111 public class CourseConfigurer extends AbstractCourseConfigurer {
112
113 protected boolean WITH_DIVIDER = true;
114 protected boolean NO_DIVIDER = false;
115
116 public static final String PROPOSAL_PATH = "proposal";
117 public static final String PROPOSAL_TITLE_PATH = "proposal/name";
118 public static final String COURSE_TITLE_PATH = "/courseTitle";
119 public static final String CLU_PROPOSAL_MODEL = "cluProposalModel";
120 protected DocumentTool documentTool;
121
122
123 public static final String PROPOSAL = "";
124 public static final String COURSE = "";
125
126 public enum CourseSections {
127 CLU_BEGIN, PEOPLE_PERMISSONS, SUMMARY, AUTHORS_RATIONALE, GOVERNANCE, COURSE_LOGISTICS, COURSE_INFO, LEARNING_OBJECTIVES,
128 COURSE_REQUISITES, ACTIVE_DATES, FINANCIALS, ATTACHMENTS, COMMENTS,DECISIONS, DOCUMENTS,
129 PROGRAM_INFO, ASSEMBLER_TEST
130 }
131
132 protected List<StatementTypeInfo> stmtTypes;
133
134 public void setModelDefinition(DataModelDefinition modelDefinition) {
135 super.modelDefinition = modelDefinition;
136 }
137
138 public void setStatementTypes(List<StatementTypeInfo> stmtTypes) {
139 this.stmtTypes = stmtTypes;
140 }
141
142
143
144
145
146
147
148 public void configure(final CourseProposalController layout) {
149 type = "course";
150 state = "draft";
151 groupName = LUUIConstants.COURSE_GROUP_NAME;
152
153 if (modelDefinition.getMetadata().isCanEdit()) {
154 addCluStartSection(layout);
155 String sections = getLabel(LUUIConstants.COURSE_SECTIONS);
156
157
158
159
160 layout.addMenu(sections);
161
162
163 layout.addMenuItem(sections, generateCourseInfoSection());
164 layout.addMenuItem(sections, generateGovernanceSection());
165 layout.addMenuItem(sections, generateCourseLogisticsSection());
166 layout.addMenuItem(sections, generateLearningObjectivesSection());
167
168
169 layout.addMenuItem(sections, generateCourseRequisitesSection(layout));
170
171
172 layout.addMenuItem(sections, generateActiveDatesSection());
173 layout.addMenuItem(sections, generateFinancialsSection());
174
175
176 layout.addMenuItem(sections, new CollaboratorSectionView(CourseSections.PEOPLE_PERMISSONS, LUUIConstants.SECTION_AUTHORS_AND_COLLABORATORS,CLU_PROPOSAL_MODEL));
177
178
179 documentTool = new DocumentTool(LUUIConstants.REF_DOC_RELATION_PROPOSAL_TYPE,CourseSections.DOCUMENTS, getLabel(LUUIConstants.TOOL_DOCUMENTS_LABEL_KEY));
180 documentTool.setModelDefinition((DataModelDefinition)modelDefinition);
181 layout.addMenuItem(sections, documentTool);
182
183
184 CourseSummaryConfigurer summaryConfigurer = new CourseSummaryConfigurer(type, state, groupName,(DataModelDefinition)modelDefinition, stmtTypes, (Controller)layout, CLU_PROPOSAL_MODEL);
185 layout.addSpecialMenuItem(summaryConfigurer.generateProposalSummarySection(true), "Review and Submit");
186
187
188 List<Enum<?>> excludedViews = new ArrayList<Enum<?>>();
189 excludedViews.add(CourseSections.DOCUMENTS);
190 excludedViews.add(CourseSections.COURSE_REQUISITES);
191 layout.addCommonButton(LUUIConstants.COURSE_SECTIONS, layout.getSaveButton(), excludedViews);
192 layout.addCommonButton(LUUIConstants.COURSE_SECTIONS, layout.getCancelButton(CourseSections.SUMMARY), excludedViews);
193
194
195
196 layout.addButtonForView(CourseSections.DOCUMENTS, getContinueButton(layout));
197 }
198 else{
199 CourseSummaryConfigurer summaryConfigurer = new CourseSummaryConfigurer(type, state, groupName, (DataModelDefinition)modelDefinition, stmtTypes, (Controller)layout, CLU_PROPOSAL_MODEL);
200 layout.removeMenuNavigation();
201 layout.addView(summaryConfigurer.generateProposalSummarySection(false));
202 }
203 layout.showPrint(true);
204 layout.setDefaultView(CourseSections.SUMMARY);
205 layout.addContentWidget(layout.getWfUtilities().getWorkflowStatusLabel());
206 final CommentTool commentTool = new CommentTool(CourseSections.COMMENTS, getLabel(LUUIConstants.TOOL_COMMENTS_LABEL_KEY), "kuali.comment.type.generalRemarks", "Proposal Comments");
207 commentTool.setController(layout);
208
209 layout.addContentWidget(new KSButton("Comments", ButtonStyle.DEFAULT_ANCHOR, new ClickHandler() {
210
211 @Override
212 public void onClick(ClickEvent event) {
213 commentTool.show();
214 }
215 }));
216
217
218 final DecisionPanel decisionPanel = new DecisionPanel(CourseSections.DECISIONS, getLabel(LUUIConstants.TOOL_DECISION_LABEL_KEY), "kuali.comment.type.generalRemarks");
219 layout.addView(decisionPanel);
220 layout.addContentWidget(new KSButton("Decisions", ButtonStyle.DEFAULT_ANCHOR, new ClickHandler() {
221
222 @Override
223 public void onClick(ClickEvent event) {
224 decisionPanel.show();
225 }
226 }));
227
228 }
229
230 protected KSButton getContinueButton(final CourseProposalController layout){
231 return new KSButton("Continue", new ClickHandler(){
232 public void onClick(ClickEvent event) {
233 layout.showNextViewOnMenu();
234 }
235 });
236 }
237
238 public void addCluStartSection(CourseProposalController layout) {
239 VerticalSectionView section = initSectionView(CourseSections.CLU_BEGIN, LUUIConstants.START_LABEL_KEY);
240 section.setController(layout);
241 addField(section, PROPOSAL_TITLE_PATH, generateMessageInfo(LUUIConstants.PROPOSAL_TITLE_LABEL_KEY));
242 addField(section, COURSE + "/" + COURSE_TITLE, generateMessageInfo(LUUIConstants.COURSE_TITLE_LABEL_KEY));
243
244
245 layout.addStartViewPopup(section);
246 layout.getStartPopup().setMaxHeight(600);
247 }
248
249 protected View generateCourseRequisitesSection(Controller layout) {
250 return new CourseRequirementsViewController(layout, getLabel(LUUIConstants.REQUISITES_LABEL_KEY), CourseSections.COURSE_REQUISITES, false);
251 }
252
253 protected SectionView generateActiveDatesSection() {
254 VerticalSectionView section = initSectionView(CourseSections.ACTIVE_DATES, LUUIConstants.ACTIVE_DATES_LABEL_KEY);
255
256 addField(section, COURSE + "/" + START_TERM, generateMessageInfo(LUUIConstants.START_TERM_LABEL_KEY));
257 addField(section, COURSE + "/" + END_TERM, generateMessageInfo(LUUIConstants.END_TERM_LABEL_KEY));
258 addField(section, COURSE + "/" + PILOT_COURSE, generateMessageInfo(LUUIConstants.PILOT_COURSE_LABEL_KEY), new KSCheckBox(getLabel(LUUIConstants.PILOT_COURSE_TEXT_LABEL_KEY)));
259
260 return section;
261 }
262
263 protected VerticalSection generateActiveDateEndSection() {
264 VerticalSection endDate = initSection(getH3Title(LUUIConstants.END_DATE_LABEL_KEY), WITH_DIVIDER);
265 addField(endDate, COURSE + "/" + EXPIRATION_DATE, generateMessageInfo(LUUIConstants.EXPIRATION_DATE_LABEL_KEY));
266 return endDate;
267 }
268
269 protected VerticalSection generateActiveDateStartSection() {
270 VerticalSection startDate = initSection(getH3Title(LUUIConstants.START_DATE_LABEL_KEY), WITH_DIVIDER);
271 addField(startDate, COURSE + "/" + CreditCourseConstants.EFFECTIVE_DATE, generateMessageInfo(LUUIConstants.EFFECTIVE_DATE_LABEL_KEY));
272 return startDate;
273 }
274
275 protected SectionView generateGovernanceSection() {
276 VerticalSectionView section = initSectionView(CourseSections.GOVERNANCE, LUUIConstants.GOVERNANCE_LABEL_KEY);
277 addField(section, COURSE + "/" + CAMPUS_LOCATIONS, generateMessageInfo(LUUIConstants.CAMPUS_LOCATION_LABEL_KEY));
278 addField(section, COURSE + "/" + CURRICULUM_OVERSIGHT_ORGS_, generateMessageInfo(LUUIConstants.ACADEMIC_SUBJECT_ORGS_KEY));
279 addField(section, COURSE + "/" + ADMIN_ORGS, generateMessageInfo(LUUIConstants.ADMIN_ORG_LABEL_KEY));
280
281 return section;
282 }
283
284 public SectionView generateCourseInfoSection() {
285 VerticalSectionView section = initSectionView(CourseSections.COURSE_INFO, LUUIConstants.INFORMATION_LABEL_KEY);
286 addField(section, PROPOSAL_TITLE_PATH, generateMessageInfo(LUUIConstants.PROPOSAL_TITLE_LABEL_KEY));
287 addField(section, COURSE + "/" + COURSE_TITLE, generateMessageInfo(LUUIConstants.COURSE_TITLE_LABEL_KEY));
288 addField(section, COURSE + "/" + TRANSCRIPT_TITLE, generateMessageInfo(LUUIConstants.SHORT_TITLE_LABEL_KEY));
289 section.addSection(generateCourseNumberSection());
290 FieldDescriptor instructorsFd = addField(section, COURSE + "/" + INSTRUCTORS, generateMessageInfo(LUUIConstants.INSTRUCTORS_LABEL_KEY));
291 instructorsFd.setWidgetBinding(new KeyListModelWigetBinding("personId"));
292 section.addSection(generateDescriptionRationaleSection());
293
294 return section;
295 }
296
297 protected GroupSection generateCourseNumberSection() {
298
299
300 GroupSection courseNumber = new GroupSection(getH4Title(""));
301 courseNumber.addStyleName(LUUIConstants.STYLE_SECTION);
302 courseNumber.addStyleName(LUUIConstants.STYLE_SECTION_DIVIDER);
303 addField(courseNumber, COURSE + "/" + SUBJECT_AREA, generateMessageInfo(LUUIConstants.SUBJECT_CODE_LABEL_KEY));
304 addField(courseNumber, COURSE + "/" + COURSE_NUMBER_SUFFIX, generateMessageInfo(LUUIConstants.COURSE_NUMBER_LABEL_KEY));
305
306
307
308 courseNumber.addSection(generateCrossListed_Ver_Joint_Section());
309
310 return courseNumber;
311 }
312
313 protected CollapsableSection generateCrossListed_Ver_Joint_Section() {
314 CollapsableSection result = new CollapsableSection(getLabel(LUUIConstants.CL_V_J_LABEL_KEY));
315
316
317
318
319 SpanPanel crslabelpan = new SpanPanel();
320 crslabelpan.setStyleName("ks-multiplicity-section-label");
321 crslabelpan.setHTML("Cross Listed Courses");
322 crslabelpan.setVisible(true);
323 result.addWidget(crslabelpan);
324 addMultiplicityFields(result, COURSE + QueryPath.getPathSeparator() + CROSS_LISTINGS,
325 LUUIConstants.ADD_CROSS_LISTED_LABEL_KEY,
326 LUUIConstants.CROSS_LISTED_ITEM_LABEL_KEY,
327 Arrays.asList(
328 new MultiplicityFieldConfig(
329 SUBJECT_AREA,
330 LUUIConstants.SUBJECT_CODE_LABEL_KEY, null, null, true),
331 new MultiplicityFieldConfig(
332 COURSE_NUMBER_SUFFIX,
333 LUUIConstants.COURSE_NUMBER_LABEL_KEY, null, null, true)),
334 null,
335 null,0);
336 SpanPanel jntlabelpan = new SpanPanel();
337 jntlabelpan.setStyleName("ks-multiplicity-section-label");
338 jntlabelpan.setHTML("Jointly Offered Courses");
339 jntlabelpan.setVisible(true);
340 result.addWidget(jntlabelpan);
341 addMultiplicityFields(result, COURSE + QueryPath.getPathSeparator() + JOINTS,
342 LUUIConstants.ADD_EXISTING_LABEL_KEY,
343 LUUIConstants.JOINT_OFFER_ITEM_LABEL_KEY,
344 Arrays.asList(
345 new MultiplicityFieldConfig(
346 CreditCourseJointsConstants.COURSE_ID,
347 LUUIConstants.COURSE_NUMBER_OR_TITLE_LABEL_KEY, null, null, true)),
348 null,
349 null,0);
350 SpanPanel vsnlabelpan = new SpanPanel();
351 vsnlabelpan.setStyleName("ks-multiplicity-section-label");
352 vsnlabelpan.setHTML("Version Codes");
353 vsnlabelpan.setVisible(true);
354 result.addWidget(vsnlabelpan);
355 addMultiplicityFields(result, COURSE + QueryPath.getPathSeparator() + VERSIONS,
356 LUUIConstants.ADD_VERSION_CODE_LABEL_KEY,
357 LUUIConstants.VERSION_CODE_LABEL_KEY,
358 Arrays.asList(
359 new MultiplicityFieldConfig(
360 "variationCode",
361 LUUIConstants.VERSION_CODE_LABEL_KEY, null, null, true),
362 new MultiplicityFieldConfig(
363 "variationTitle",
364 LUUIConstants.TITLE_LABEL_KEY, null, null, true)
365 ),
366 null,
367 null,0);
368 return result;
369 }
370
371 protected void addFeeMultiplicityFields(Section section,
372 String path, String addItemlabelMessageKey,
373 String itemLabelMessageKey, List<MultiplicityFieldConfig> fieldConfigs,
374 Map<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>> swappableFieldsDefinition,
375 List<String> deletionParentKeys) {
376 MultiplicityConfiguration config = setupMultiplicityConfig(
377 MultiplicityConfiguration.MultiplicityType.GROUP,
378 MultiplicityConfiguration.StyleType.TOP_LEVEL_GROUP,
379 path, addItemlabelMessageKey, itemLabelMessageKey,
380 fieldConfigs, swappableFieldsDefinition, deletionParentKeys);
381 MultiplicitySection ms = null;
382 ms = new MultiplicitySection(config, swappableFieldsDefinition, deletionParentKeys);
383 section.addSection(ms);
384
385 }
386
387 protected MultiplicityConfiguration setupMultiplicityConfig(
388 MultiplicityConfiguration.MultiplicityType multiplicityType,
389 MultiplicityConfiguration.StyleType styleType,
390 String path, String addItemlabelMessageKey,
391 String itemLabelMessageKey, List<MultiplicityFieldConfig> fieldConfigs,
392 Map<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>> swappableFieldsDefinition,
393 List<String> deletionParentKeys) {
394 QueryPath parentPath = QueryPath.concat(path);
395 MultiplicityConfiguration config = new MultiplicityConfiguration(multiplicityType,
396 styleType, getMetaData(parentPath.toString()));
397 config.setAddItemLabel(getLabel(addItemlabelMessageKey));
398 config.setItemLabel(getLabel(itemLabelMessageKey));
399 config.setUpdateable(true);
400
401 FieldDescriptor parentFd = buildMultiplicityParentFieldDescriptor(path, getLabel(itemLabelMessageKey), null);
402 config.setParent(parentFd);
403
404 if (fieldConfigs != null) {
405 for (MultiplicityFieldConfig fieldConfig : fieldConfigs) {
406 MultiplicityFieldConfiguration fc = buildMultiplicityFD(fieldConfig.getFieldKey(),
407 fieldConfig.getLabelKey(), parentPath.toString());
408 config.addFieldConfiguration(fc);
409 if (fieldConfig.isNextLine()) {
410 config.nextLine();
411 }
412 }
413 }
414 return config;
415 }
416
417 protected MultiplicitySection addMultiplicityFields(Section section,
418 String path, String addItemlabelMessageKey,
419 String itemLabelMessageKey, List<MultiplicityFieldConfig> fieldConfigs,
420 Map<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>> swappableFieldsDefinition,
421 List<String> deletionParentKeys,int defaultItemsCreated) {
422 MultiplicityConfiguration config = setupMultiplicityConfig(
423 MultiplicityConfiguration.MultiplicityType.GROUP,
424 MultiplicityConfiguration.StyleType.TOP_LEVEL_GROUP,
425 path, addItemlabelMessageKey, itemLabelMessageKey,
426 fieldConfigs, swappableFieldsDefinition, deletionParentKeys);
427 config.setDefaultItemsCreated(defaultItemsCreated);
428 MultiplicitySection ms = null;
429 ms = new MultiplicitySection(config, swappableFieldsDefinition, deletionParentKeys);
430 section.addSection(ms);
431 return ms;
432 }
433
434 protected Metadata getMetaData(String fieldKey) {
435 return modelDefinition.getMetadata(QueryPath.concat(fieldKey));
436 }
437
438 protected MultiplicityFieldConfiguration buildMultiplicityFD(
439 String fieldKey, String labelKey, String parentPath) {
440
441 QueryPath fieldPath = QueryPath.concat(parentPath, QueryPath.getWildCard(), fieldKey);
442 Metadata meta = modelDefinition.getMetadata(fieldPath);
443
444 MultiplicityFieldConfiguration fd = new MultiplicityFieldConfiguration(
445 fieldPath.toString(), generateMessageInfo(labelKey), meta, null);
446
447
448 return fd;
449
450 }
451
452 protected FieldDescriptor buildMultiplicityParentFieldDescriptor(String fieldKey, String messageKey, String parentPath) {
453 QueryPath path = QueryPath.concat(parentPath, fieldKey);
454 Metadata meta = modelDefinition.getMetadata(path);
455
456 FieldDescriptor fd = new FieldDescriptor(path.toString(), generateMessageInfo(messageKey), meta);
457 fd.hideLabel();
458 return fd;
459 }
460
461 protected VerticalSection generateCourseInfoShortTitleSection() {
462 VerticalSection shortTitle = initSection(getH3Title(LUUIConstants.SHORT_TITLE_LABEL_KEY), WITH_DIVIDER);
463 addField(shortTitle, COURSE + "/" + TRANSCRIPT_TITLE, null);
464 return shortTitle;
465 }
466
467 protected VerticalSection generateLongTitleSection() {
468 VerticalSection longTitle = initSection(getH3Title(LUUIConstants.TITLE_LABEL_KEY), WITH_DIVIDER);
469 addField(longTitle, COURSE + "/" + COURSE_TITLE, null);
470 return longTitle;
471 }
472
473 protected VerticalSection generateDescriptionRationaleSection() {
474 SectionTitle title = getH4Title(LUUIConstants.PROPOSAL_TITLE_SECTION_LABEL_KEY);
475 VerticalSection description = initSection(title, !WITH_DIVIDER);
476 title.setStyleName("cluProposalTitleSection");
477
478
479 addField(description, COURSE + "/" + PROPOSAL_DESCRIPTION + "/" + RichTextInfoConstants.PLAIN, generateMessageInfo(LUUIConstants.DESCRIPTION_LABEL_KEY));
480 addField(description, "proposal/rationale", generateMessageInfo(LUUIConstants.PROPOSAL_RATIONALE_LABEL_KEY));
481 return description;
482 }
483
484 public SectionView generateCourseLogisticsSection() {
485 VerticalSectionView section = initSectionView(CourseSections.COURSE_LOGISTICS, LUUIConstants.LOGISTICS_LABEL_KEY);
486 section.setInstructions(getLabel(LUUIConstants.LOGISTICS_LABEL_KEY + "-instruct") + "<br><br>");
487
488 section.addSection(generateSchedulingSection());
489 section.addSection(generateDurationSection());
490 section.addSection(generateLearningResultsSection());
491 section.addSection(generateCourseFormatsSection());
492
493 return section;
494 }
495
496 protected Section generateLearningResultsSection() {
497 VerticalSection learningResults = initSection(getH3Title(LUUIConstants.LEARNING_RESULTS_LABEL_KEY), WITH_DIVIDER);
498 learningResults.setInstructions(getLabel(LUUIConstants.LEARNING_RESULTS_LABEL_KEY + "-instruct") + "<br><br><br>");
499
500 learningResults.addSection(generateGradesAssessmentsSection());
501 learningResults.addSection(generateStudentRegistrationOptionsSection());
502 learningResults.addSection(generateFinalExamSection());
503 learningResults.addSection(generateOutcomesSection());
504
505 return learningResults;
506 }
507
508 protected Section generateOutcomesSection() {
509
510 String path = COURSE + QueryPath.getPathSeparator() + CREDIT_OPTIONS;
511 QueryPath creditTypeFullPath = QueryPath.concat(path, QueryPath.getWildCard(), CreditCourseConstants.TYPE);
512 QueryPath creditOptionFixedFullPath = QueryPath.concat(path, QueryPath.getWildCard(), CREDIT_OPTION_FIXED_CREDITS);
513 QueryPath creditOptionMinFullPath = QueryPath.concat(path, QueryPath.getWildCard(), CREDIT_OPTION_MIN_CREDITS);
514 QueryPath creditOptionMaxFullPath = QueryPath.concat(path, QueryPath.getWildCard(), CREDIT_OPTION_MAX_CREDITS);
515 QueryPath creditResultValuesFullPath = QueryPath.concat(path, QueryPath.getWildCard(), "resultValues");
516
517 VerticalSection courseOutcomes = initSection(getH3Title(LUUIConstants.LEARNING_RESULT_OUTCOME_LABEL_KEY), WITH_DIVIDER);
518 Map<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>> swappableFieldsDefinition =
519 new HashMap<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>>();
520 SwapCompositeCondition fixedCreditCondition = new SwapCompositeCondition(
521 CompositeConditionOperator.AND);
522 fixedCreditCondition.getChildrenConditions().add(
523 makeCondition(creditTypeFullPath, LUUIConstants.LEARNING_RESULT_OUTCOME_TYPE_LABEL_KEY, "kuali.resultComponentType.credit.degree.fixed")
524 );
525 fixedCreditCondition.setConditionId("1");
526 SwapCompositeCondition multipleCreditCondition = new SwapCompositeCondition(
527 CompositeConditionOperator.AND);
528 multipleCreditCondition.getChildrenConditions().add(
529 makeCondition(creditTypeFullPath, LUUIConstants.LEARNING_RESULT_OUTCOME_TYPE_LABEL_KEY, "kuali.resultComponentType.credit.degree.multiple")
530 );
531 multipleCreditCondition.setConditionId("2");
532 SwapCompositeCondition variableCreditCondition = new SwapCompositeCondition(
533 CompositeConditionOperator.AND);
534 variableCreditCondition.getChildrenConditions().add(
535 makeCondition(creditTypeFullPath, LUUIConstants.LEARNING_RESULT_OUTCOME_TYPE_LABEL_KEY, "kuali.resultComponentType.credit.degree.range")
536 );
537 variableCreditCondition.setConditionId("3");
538
539 swappableFieldsDefinition.put(fixedCreditCondition,
540 Arrays.asList(
541 new SwapCompositeConditionFieldConfig(
542 new MultiplicityFieldConfiguration(
543 creditOptionFixedFullPath.toString(),
544 generateMessageInfo(LUUIConstants.CREDIT_OPTION_FIXED_CREDITS_LABEL_KEY),
545 modelDefinition.getMetadata(creditOptionFixedFullPath),
546 null),
547 null
548 )
549 )
550 );
551 MultiplicityFieldWidgetInitializer multipleCreditInitializer =
552 new MultiplicityFieldWidgetInitializer() {
553 @Override
554 public ModelWidgetBinding<?> getModelWidgetBindingInstance() {
555 return new ListOfStringBinding();
556 }
557 @Override
558 public Widget getNewWidget() {
559 return new ListOfStringWidget("Add Item");
560 }
561 };
562
563 swappableFieldsDefinition.put(multipleCreditCondition,
564 Arrays.asList(
565 new SwapCompositeConditionFieldConfig(
566 new MultiplicityFieldConfiguration(
567 creditResultValuesFullPath.toString(),
568 generateMessageInfo(LUUIConstants.CREDIT_OPTION_FIXED_CREDITS_LABEL_KEY),
569 modelDefinition.getMetadata(creditResultValuesFullPath),
570 multipleCreditInitializer),
571 null
572 )
573 )
574 );
575 swappableFieldsDefinition.put(variableCreditCondition,
576 Arrays.asList(
577 new SwapCompositeConditionFieldConfig(
578 new MultiplicityFieldConfiguration(
579 creditOptionMinFullPath.toString(),
580 generateMessageInfo(LUUIConstants.CREDIT_OPTION_MIN_CREDITS_LABEL_KEY),
581 modelDefinition.getMetadata(creditOptionMinFullPath),
582 null),
583 null
584 ),
585 new SwapCompositeConditionFieldConfig(
586 new MultiplicityFieldConfiguration(
587 creditOptionMaxFullPath.toString(),
588 generateMessageInfo(LUUIConstants.CREDIT_OPTION_MAX_CREDITS_LABEL_KEY),
589 modelDefinition.getMetadata(creditOptionMaxFullPath),
590 null),
591 null
592 )
593 )
594 );
595
596 MultiplicitySection ms = addMultiplicityFields(
597 courseOutcomes,
598 path,
599 LUUIConstants.LEARNING_RESULT_OUTCOME_LABEL_KEY,
600 LUUIConstants.LEARNING_RESULT_OUTCOME_LABEL_KEY,
601 Arrays.asList(
602 new MultiplicityFieldConfig(
603 CreditCourseConstants.TYPE,
604 LUUIConstants.LEARNING_RESULT_OUTCOME_TYPE_LABEL_KEY,
605 null, null, true)
606 ), swappableFieldsDefinition, null,1);
607
608 courseOutcomes.setRequired(ms.getConfig().getParentFd().getFieldElement().getRequiredPanel());
609 return courseOutcomes;
610
611 }
612
613 protected Section generateStudentRegistrationOptionsSection() {
614 VerticalSection studentRegistrationOptionsSection = initSection(getH3Title(LUUIConstants.LEARNING_RESULTS_STUDENT_REGISTRATION_LABEL_KEY), WITH_DIVIDER);
615
616 addField(studentRegistrationOptionsSection, COURSE + "/" + AUDIT, generateMessageInfo(LUUIConstants.LEARNING_RESULT_AUDIT_LABEL_KEY), new KSCheckBox(getLabel(LUUIConstants.LEARNING_RESULT_AUDIT_TEXT_LABEL_KEY)));
617 addField(studentRegistrationOptionsSection, COURSE + "/" + PASS_FAIL, generateMessageInfo(LUUIConstants.LEARNING_RESULT_PASS_FAIL_LABEL_KEY), new KSCheckBox(getLabel(LUUIConstants.LEARNING_RESULT_PASS_FAIL_TEXT_LABEL_KEY)));
618
619 return studentRegistrationOptionsSection;
620 }
621
622 protected Section generateGradesAssessmentsSection() {
623 VerticalSection gradesAssessments = initSection(getH3Title(LUUIConstants.LEARNING_RESULTS_GRADES_ASSESSMENTS_LABEL_KEY), WITH_DIVIDER);
624
625 addField(gradesAssessments, COURSE + "/" + GRADING_OPTIONS, generateMessageInfo(LUUIConstants.LEARNING_RESULT_ASSESSMENT_SCALE_LABEL_KEY));
626
627 return gradesAssessments;
628 }
629
630 protected VerticalSection generateCourseFormatsSection() {
631
632 VerticalSection courseFormats = initSection(getH3Title(LUUIConstants.FORMATS_LABEL_KEY), WITH_DIVIDER);
633 courseFormats.setHelp(getLabel(LUUIConstants.FORMATS_LABEL_KEY + "-help"));
634 courseFormats.setInstructions(getLabel(LUUIConstants.FORMATS_LABEL_KEY + "-instruct"));
635 MultiplicityConfiguration courseFormatConfig = setupMultiplicityConfig(
636 MultiplicityConfiguration.MultiplicityType.GROUP,
637 MultiplicityConfiguration.StyleType.TOP_LEVEL_GROUP,
638 COURSE + "/" + FORMATS, LUUIConstants.COURSE_ADD_FORMAT_LABEL_KEY,
639 LUUIConstants.FORMAT_LABEL_KEY,
640 null, null, null);
641 courseFormatConfig.setDefaultItemsCreated(1);
642 MultiplicityConfiguration activitiesConfig = setupMultiplicityConfig(
643 MultiplicityConfiguration.MultiplicityType.GROUP,
644 MultiplicityConfiguration.StyleType.SUB_LEVEL_GROUP,
645 COURSE + "/" + FORMATS + "/*/" + ACTIVITIES,
646 LUUIConstants.ADD_ACTIVITY_LABEL_KEY,
647 LUUIConstants.ACTIVITY_LITERAL_LABEL_KEY,
648 Arrays.asList(
649 new MultiplicityFieldConfig(
650 ACTIVITY_TYPE,
651 LUUIConstants.ACTIVITY_TYPE_LABEL_KEY,
652 null,
653 null,
654 true),
655 new MultiplicityFieldConfig(
656 CONTACT_HOURS + "/" + "unitQuantity",
657 LUUIConstants.CONTACT_HOURS_LABEL_KEY,
658 null,
659 null,
660 false),
661 new MultiplicityFieldConfig(
662 CONTACT_HOURS + "/" + "unitType",
663 LUUIConstants.CONTACT_HOURS_FREQUENCY_LABEL_KEY,
664 null,
665 null,
666 true),
667 new MultiplicityFieldConfig(
668 CreditCourseActivityConstants.DURATION + "/" + "atpDurationTypeKey",
669 LUUIConstants.DURATION_TYPE_LABEL_KEY,
670 null,
671 null,
672 false),
673 new MultiplicityFieldConfig(
674 CreditCourseActivityConstants.DURATION + "/" + "timeQuantity",
675 LUUIConstants.DURATION_LITERAL_LABEL_KEY,
676 null,
677 null,
678 true),
679 new MultiplicityFieldConfig(
680 DEFAULT_ENROLLMENT_ESTIMATE,
681 LUUIConstants.CLASS_SIZE_LABEL_KEY,
682 null,
683 null,
684 true)
685 ), null, null);
686 activitiesConfig.setDefaultItemsCreated(1);
687 courseFormatConfig.setNestedConfig(activitiesConfig);
688
689
690 MultiplicitySection ms = null;
691 ms = new MultiplicitySection(courseFormatConfig,
692 null, null);
693 courseFormats.addSection(ms);
694 courseFormats.setRequired(courseFormatConfig.getParentFd().getFieldElement().getRequiredPanel());
695 return courseFormats;
696 }
697
698 protected VerticalSection generateSchedulingSection() {
699 VerticalSection scheduling = initSection(getH3Title(LUUIConstants.SCHEDULING_LABEL_KEY), WITH_DIVIDER);
700 addField(scheduling, COURSE + "/" + TERMS_OFFERED, generateMessageInfo(LUUIConstants.TERMS_OFFERED_LABEL_KEY));
701 return scheduling;
702 }
703
704 protected VerticalSection generateDurationSection() {
705 VerticalSection duration = initSection(getH3Title(LUUIConstants.DURATION_LITERAL_LABEL_KEY), WITH_DIVIDER);
706 duration.setInstructions(getLabel(LUUIConstants.DURATION_LITERAL_LABEL_KEY + "-instruct"));
707 GroupSection duration_group = new GroupSection();
708 addField(duration_group, COURSE + "/" + CreditCourseConstants.DURATION + "/" + "atpDurationTypeKey", generateMessageInfo(LUUIConstants.DURATION_TYPE_LABEL_KEY));
709 addField(duration_group, COURSE + "/" + CreditCourseConstants.DURATION + "/" + "timeQuantity", generateMessageInfo(LUUIConstants.DURATION_QUANTITY_LABEL_KEY));
710
711 duration.addSection(duration_group);
712 return duration;
713 }
714
715 protected VerticalSection generateFinalExamSection() {
716 VerticalSection finalExam = initSection(getH3Title(LUUIConstants.FINAL_EXAM_LABEL_KEY), WITH_DIVIDER);
717 GroupSection finalExam_group = new GroupSection();
718 GroupSection finalExamRationale_group = new GroupSection();
719 GroupSection finalExamRationale_group2 = new GroupSection();
720
721 FieldDescriptor field = addField(finalExam_group, COURSE + "/" + CreditCourseConstants.FINAL_EXAM, generateMessageInfo(LUUIConstants.FINAL_EXAM_STATUS_LABEL_KEY));
722
723 if (field.isVisible()){
724 KSSelectItemWidgetAbstract picker = (KSSelectItemWidgetAbstract) (((KSPicker) field.getFieldWidget()).getInputWidget());
725 addField(finalExamRationale_group, COURSE + "/" + CreditCourseConstants.FINAL_EXAM_RATIONALE, generateMessageInfo(LUUIConstants.FINAL_EXAM_RATIONALE_LABEL_KEY));
726 addField(finalExamRationale_group2, COURSE + "/" + CreditCourseConstants.FINAL_EXAM_RATIONALE, generateMessageInfo(LUUIConstants.FINAL_EXAM_RATIONALE_LABEL_KEY));
727 SwapSection swapSection = new SwapSection(picker);
728 swapSection.addSection(finalExamRationale_group, "ALT");
729 swapSection.addSection(finalExamRationale_group2, "None");
730 finalExam.addSection(finalExam_group);
731
732 finalExam.addSection(swapSection);
733 return finalExam;
734 } else {
735 return new VerticalSection();
736 }
737
738 }
739
740 protected VerticalSection generateInstructorsSection() {
741 VerticalSection instructors = initSection(getH3Title(LUUIConstants.INSTRUCTOR_LABEL_KEY), WITH_DIVIDER);
742 addField(instructors, COURSE + "/" + PRIMARY_INSTRUCTOR + "/personId");
743 return instructors;
744 }
745
746 protected SectionView generateLearningObjectivesSection() {
747 VerticalSectionView section = initSectionView(CourseSections.LEARNING_OBJECTIVES, LUUIConstants.LEARNING_OBJECTIVES_LABEL_KEY);
748 section.addSection(generateLearningObjectivesNestedSection());
749 return section;
750 }
751
752 protected VerticalSection generateLearningObjectivesNestedSection() {
753 final VerticalSection los = initSection(null, NO_DIVIDER);
754
755 QueryPath path = QueryPath.concat(COURSE, COURSE_SPECIFIC_LOS, "*", "loInfo", "desc");
756 Metadata meta = modelDefinition.getMetadata(path);
757
758 LOBuilder loBuilder = new LOBuilder(type, state, groupName, "kuali.loRepository.key.singleUse", COURSE_SPECIFIC_LOS, meta);
759 final FieldDescriptor fd = addField(los, CreditCourseConstants.COURSE_SPECIFIC_LOS, null,loBuilder, COURSE);
760
761 loBuilder.addValueChangeHandler(new ValueChangeHandler<List<OutlineNode<LOPicker>>>(){
762 @Override
763 public void onValueChange(ValueChangeEvent<List<OutlineNode<LOPicker>>> event) {
764 los.setIsDirty(true);
765 fd.setDirty(true);
766 }
767 });
768
769
770
771 fd.setWidgetBinding(LOBuilderBinding.INSTANCE);
772
773 los.addStyleName("KS-LUM-Section-Divider");
774 return los;
775 }
776
777 public class PersonList extends KSDropDown {
778 final SimpleListItems people = new SimpleListItems();
779
780 public PersonList() {
781 final PersonList us = this;
782 final String userId = Application.getApplicationContext().getUserId();
783
784
785 people.addItem(userId, userId);
786 us.setListItems(people);
787 us.selectItem(userId);
788 us.setBlankFirstItem(false);
789 this.setEnabled(false);
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817 }
818
819 @Override
820 public boolean isMultipleSelect() {
821 return true;
822 }
823 }
824
825 public class ProposerPersonList extends KSLabelList {
826 public ProposerPersonList() {
827 SimpleListItems list = new SimpleListItems();
828
829 super.setListItems(list);
830 }
831 }
832
833 protected VerticalSection generateShortTitleSection() {
834 VerticalSection shortTitle = initSection(getH3Title(LUUIConstants.SHORT_TITLE_LABEL_KEY), WITH_DIVIDER);
835 addField(shortTitle, "cluInfo/officialIdentifier/shortName", null);
836 return shortTitle;
837 }
838
839 protected VerticalSectionView initSectionView(Enum<?> viewEnum, String labelKey) {
840 VerticalSectionView section = new VerticalSectionView(viewEnum, getLabel(labelKey), CLU_PROPOSAL_MODEL);
841 section.addStyleName(LUUIConstants.STYLE_SECTION);
842 return section;
843 }
844
845
846 protected VerticalSection initSection(SectionTitle title, boolean withDivider) {
847 VerticalSection section;
848 if (title != null) {
849 section = new VerticalSection(title);
850 } else {
851 section = new VerticalSection();
852 }
853 section.addStyleName(LUUIConstants.STYLE_SECTION);
854 if (withDivider)
855 section.addStyleName(LUUIConstants.STYLE_SECTION_DIVIDER);
856 return section;
857 }
858
859 @Override
860 protected MessageKeyInfo generateMessageInfo(String labelKey) {
861 return new MessageKeyInfo(groupName, type, state, labelKey);
862 }
863
864 protected SectionView generateFinancialsSection() {
865 VerticalSectionView section = initSectionView(CourseSections.FINANCIALS, LUUIConstants.FINANCIALS_LABEL_KEY);
866
867 VerticalSection justiFee = initSection(getH3Title(LUUIConstants.COURSE_FEE_TITLE), WITH_DIVIDER);
868 SpanPanel courseFeeInstruction = new SpanPanel();
869 courseFeeInstruction.setStyleName("ks-form-module-elements-instruction");
870 courseFeeInstruction.setHTML(getLabel(LUUIConstants.COURSE_FEE_TITLE + FieldLayoutComponent.INSTRUCT_MESSAGE_KEY));
871 courseFeeInstruction.setVisible(true);
872 justiFee.addWidget(courseFeeInstruction);
873
874
875
876 addField(justiFee, COURSE + "/" + "feeJustification" + "/" + RichTextInfoConstants.PLAIN, generateMessageInfo(LUUIConstants.JUSTIFICATION_FEE));
877 section.addSection(justiFee);
878 Map<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>> swappableFieldsDefinition =
879 new HashMap<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>>();
880
881
882
883
884
885
886
887 QueryPath feesPath = QueryPath.concat(COURSE, FEES);
888 QueryPath rateTypeFieldPath = QueryPath.concat(feesPath.toString(), QueryPath.getWildCard(), "rateType");
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258