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.Label;
104 import com.google.gwt.user.client.ui.VerticalPanel;
105 import com.google.gwt.user.client.ui.Widget;
106
107
108
109
110
111
112
113 public class CourseConfigurer extends AbstractCourseConfigurer {
114 protected String groupName;
115
116 protected String type = "course";
117 protected String state = "draft";
118
119 protected boolean WITH_DIVIDER = true;
120 protected boolean NO_DIVIDER = false;
121
122
123 public static final String PROPOSAL_PATH = "proposal";
124 public static final String PROPOSAL_TITLE_PATH = "proposal/name";
125 public static final String COURSE_TITLE_PATH = "/courseTitle";
126 public static final String CLU_PROPOSAL_MODEL = "cluProposalModel";
127 protected DocumentTool documentTool;
128
129
130 public static final String PROPOSAL = "";
131 public static final String COURSE = "";
132
133 public enum CourseSections {
134 CLU_BEGIN, PEOPLE_PERMISSONS, SUMMARY, AUTHORS_RATIONALE, GOVERNANCE, COURSE_LOGISTICS, COURSE_INFO, LEARNING_OBJECTIVES,
135 COURSE_REQUISITES, ACTIVE_DATES, FINANCIALS, ATTACHMENTS, COMMENTS,DECISIONS, DOCUMENTS,
136 PROGRAM_INFO, ASSEMBLER_TEST
137 }
138
139 protected DataModelDefinition modelDefinition;
140 protected List<StatementTypeInfo> stmtTypes;
141
142 public void setModelDefinition(DataModelDefinition modelDefinition) {
143 this.modelDefinition = modelDefinition;
144 }
145
146 public void setStatementTypes(List<StatementTypeInfo> stmtTypes) {
147 this.stmtTypes = stmtTypes;
148 }
149
150 public void configure(final CourseProposalController layout) {
151 groupName = LUUIConstants.COURSE_GROUP_NAME;
152
153 groupName = LUUIConstants.COURSE_GROUP_NAME;
154
155 if (modelDefinition.getMetadata().isCanEdit()) {
156 addCluStartSection(layout);
157 String sections = getLabel(LUUIConstants.COURSE_SECTIONS);
158
159
160
161
162 layout.addMenu(sections);
163
164
165 layout.addMenuItem(sections, generateCourseInfoSection());
166 layout.addMenuItem(sections, generateGovernanceSection());
167 layout.addMenuItem(sections, generateCourseLogisticsSection());
168 layout.addMenuItem(sections, generateLearningObjectivesSection());
169
170
171 layout.addMenuItem(sections, generateCourseRequisitesSection(layout));
172
173
174 layout.addMenuItem(sections, generateActiveDatesSection());
175 layout.addMenuItem(sections, generateFinancialsSection());
176
177
178 layout.addMenuItem(sections, new CollaboratorSectionView(CourseSections.PEOPLE_PERMISSONS, LUUIConstants.SECTION_AUTHORS_AND_COLLABORATORS,CLU_PROPOSAL_MODEL));
179
180
181 documentTool = new DocumentTool(LUUIConstants.REF_DOC_RELATION_PROPOSAL_TYPE,CourseSections.DOCUMENTS, getLabel(LUUIConstants.TOOL_DOCUMENTS_LABEL_KEY));
182 documentTool.setModelDefinition(modelDefinition);
183 layout.addMenuItem(sections, documentTool);
184
185
186 CourseSummaryConfigurer summaryConfigurer = new CourseSummaryConfigurer(type, state, groupName, modelDefinition, stmtTypes, (Controller)layout, CLU_PROPOSAL_MODEL);
187 layout.addSpecialMenuItem(summaryConfigurer.generateProposalSummarySection(true), "Review and Submit");
188
189
190 List<Enum<?>> excludedViews = new ArrayList<Enum<?>>();
191 excludedViews.add(CourseSections.DOCUMENTS);
192 excludedViews.add(CourseSections.COURSE_REQUISITES);
193 layout.addCommonButton(LUUIConstants.COURSE_SECTIONS, layout.getSaveButton(), excludedViews);
194 layout.addCommonButton(LUUIConstants.COURSE_SECTIONS, layout.getCancelButton(CourseSections.SUMMARY), excludedViews);
195
196
197
198 layout.addButtonForView(CourseSections.DOCUMENTS, getContinueButton(layout));
199 }
200 else{
201 CourseSummaryConfigurer summaryConfigurer = new CourseSummaryConfigurer(type, state, groupName, modelDefinition, stmtTypes, (Controller)layout, CLU_PROPOSAL_MODEL);
202 layout.removeMenuNavigation();
203 layout.addView(summaryConfigurer.generateProposalSummarySection(false));
204 }
205 layout.showPrint(true);
206 layout.setDefaultView(CourseSections.SUMMARY);
207 layout.addContentWidget(layout.getWfUtilities().getWorkflowStatusLabel());
208 final CommentTool commentTool = new CommentTool(CourseSections.COMMENTS, getLabel(LUUIConstants.TOOL_COMMENTS_LABEL_KEY), "kuali.comment.type.generalRemarks", "Proposal Comments");
209 commentTool.setController((Controller)layout);
210
211 layout.addContentWidget(new KSButton("Comments", ButtonStyle.DEFAULT_ANCHOR, new ClickHandler() {
212
213 @Override
214 public void onClick(ClickEvent event) {
215 commentTool.show();
216 }
217 }));
218
219
220 final DecisionPanel decisionPanel = new DecisionPanel(CourseSections.DECISIONS, getLabel(LUUIConstants.TOOL_DECISION_LABEL_KEY), "kuali.comment.type.generalRemarks");
221 layout.addView(decisionPanel);
222 layout.addContentWidget(new KSButton("Decisions", ButtonStyle.DEFAULT_ANCHOR, new ClickHandler() {
223
224 @Override
225 public void onClick(ClickEvent event) {
226 decisionPanel.show();
227 }
228 }));
229
230 }
231
232 protected KSButton getContinueButton(final CourseProposalController layout){
233 return new KSButton("Continue", new ClickHandler(){
234 public void onClick(ClickEvent event) {
235 layout.showNextViewOnMenu();
236 }
237 });
238 }
239
240 public void addCluStartSection(CourseProposalController layout) {
241 VerticalSectionView section = initSectionView(CourseSections.CLU_BEGIN, LUUIConstants.START_LABEL_KEY);
242 section.setController(layout);
243 addField(section, PROPOSAL_TITLE_PATH, generateMessageInfo(LUUIConstants.PROPOSAL_TITLE_LABEL_KEY));
244 addField(section, COURSE + "/" + COURSE_TITLE, generateMessageInfo(LUUIConstants.COURSE_TITLE_LABEL_KEY));
245
246
247 layout.addStartViewPopup(section);
248 layout.getStartPopup().setMaxHeight(600);
249 }
250
251 protected View generateCourseRequisitesSection(Controller layout) {
252 return new CourseRequirementsViewController(layout, getLabel(LUUIConstants.REQUISITES_LABEL_KEY), CourseSections.COURSE_REQUISITES, false);
253 }
254
255 protected SectionView generateActiveDatesSection() {
256 VerticalSectionView section = initSectionView(CourseSections.ACTIVE_DATES, LUUIConstants.ACTIVE_DATES_LABEL_KEY);
257
258 addField(section, COURSE + "/" + START_TERM, generateMessageInfo(LUUIConstants.START_TERM_LABEL_KEY));
259 addField(section, COURSE + "/" + END_TERM, generateMessageInfo(LUUIConstants.END_TERM_LABEL_KEY));
260 addField(section, COURSE + "/" + PILOT_COURSE, generateMessageInfo(LUUIConstants.PILOT_COURSE_LABEL_KEY), new KSCheckBox(getLabel(LUUIConstants.PILOT_COURSE_TEXT_LABEL_KEY)));
261
262 return section;
263 }
264
265 protected VerticalSection generateActiveDateEndSection() {
266 VerticalSection endDate = initSection(getH3Title(LUUIConstants.END_DATE_LABEL_KEY), WITH_DIVIDER);
267 addField(endDate, COURSE + "/" + EXPIRATION_DATE, generateMessageInfo(LUUIConstants.EXPIRATION_DATE_LABEL_KEY));
268 return endDate;
269 }
270
271 protected VerticalSection generateActiveDateStartSection() {
272 VerticalSection startDate = initSection(getH3Title(LUUIConstants.START_DATE_LABEL_KEY), WITH_DIVIDER);
273 addField(startDate, COURSE + "/" + CreditCourseConstants.EFFECTIVE_DATE, generateMessageInfo(LUUIConstants.EFFECTIVE_DATE_LABEL_KEY));
274 return startDate;
275 }
276
277 protected SectionView generateGovernanceSection() {
278 VerticalSectionView section = initSectionView(CourseSections.GOVERNANCE, LUUIConstants.GOVERNANCE_LABEL_KEY);
279 addField(section, COURSE + "/" + CAMPUS_LOCATIONS, generateMessageInfo(LUUIConstants.CAMPUS_LOCATION_LABEL_KEY));
280 addField(section, COURSE + "/" + CURRICULUM_OVERSIGHT_ORGS_, generateMessageInfo(LUUIConstants.ACADEMIC_SUBJECT_ORGS_KEY));
281 addField(section, COURSE + "/" + ADMIN_ORGS, generateMessageInfo(LUUIConstants.ADMIN_ORG_LABEL_KEY));
282
283 return section;
284 }
285
286 public SectionView generateCourseInfoSection() {
287 VerticalSectionView section = initSectionView(CourseSections.COURSE_INFO, LUUIConstants.INFORMATION_LABEL_KEY);
288 addField(section, PROPOSAL_TITLE_PATH, generateMessageInfo(LUUIConstants.PROPOSAL_TITLE_LABEL_KEY));
289 addField(section, COURSE + "/" + COURSE_TITLE, generateMessageInfo(LUUIConstants.COURSE_TITLE_LABEL_KEY));
290 addField(section, COURSE + "/" + TRANSCRIPT_TITLE, generateMessageInfo(LUUIConstants.SHORT_TITLE_LABEL_KEY));
291 section.addSection(generateCourseNumberSection());
292 FieldDescriptor instructorsFd = addField(section, COURSE + "/" + INSTRUCTORS, generateMessageInfo(LUUIConstants.INSTRUCTORS_LABEL_KEY));
293 instructorsFd.setWidgetBinding(new KeyListModelWigetBinding("personId"));
294 section.addSection(generateDescriptionRationaleSection());
295
296 return section;
297 }
298
299 protected GroupSection generateCourseNumberSection() {
300
301
302 GroupSection courseNumber = new GroupSection(getH4Title(""));
303 courseNumber.addStyleName(LUUIConstants.STYLE_SECTION);
304 courseNumber.addStyleName(LUUIConstants.STYLE_SECTION_DIVIDER);
305 addField(courseNumber, COURSE + "/" + SUBJECT_AREA, generateMessageInfo(LUUIConstants.SUBJECT_CODE_LABEL_KEY));
306 addField(courseNumber, COURSE + "/" + COURSE_NUMBER_SUFFIX, generateMessageInfo(LUUIConstants.COURSE_NUMBER_LABEL_KEY));
307
308
309
310 courseNumber.addSection(generateCrossListed_Ver_Joint_Section());
311
312 return courseNumber;
313 }
314
315 protected CollapsableSection generateCrossListed_Ver_Joint_Section() {
316 CollapsableSection result = new CollapsableSection(getLabel(LUUIConstants.CL_V_J_LABEL_KEY));
317
318
319
320
321 SpanPanel crslabelpan = new SpanPanel();
322 crslabelpan.setStyleName("ks-multiplicity-section-label");
323 crslabelpan.setHTML("Cross Listed Courses");
324 crslabelpan.setVisible(true);
325 result.addWidget(crslabelpan);
326 addMultiplicityFields(result, COURSE + QueryPath.getPathSeparator() + CROSS_LISTINGS,
327 LUUIConstants.ADD_CROSS_LISTED_LABEL_KEY,
328 LUUIConstants.CROSS_LISTED_ITEM_LABEL_KEY,
329 Arrays.asList(
330 new MultiplicityFieldConfig(
331 SUBJECT_AREA,
332 LUUIConstants.SUBJECT_CODE_LABEL_KEY, null, null, true),
333 new MultiplicityFieldConfig(
334 COURSE_NUMBER_SUFFIX,
335 LUUIConstants.COURSE_NUMBER_LABEL_KEY, null, null, true)),
336 null,
337 null);
338 SpanPanel jntlabelpan = new SpanPanel();
339 jntlabelpan.setStyleName("ks-multiplicity-section-label");
340 jntlabelpan.setHTML("Jointly Offered Courses");
341 jntlabelpan.setVisible(true);
342 result.addWidget(jntlabelpan);
343 addMultiplicityFields(result, COURSE + QueryPath.getPathSeparator() + JOINTS,
344 LUUIConstants.ADD_EXISTING_LABEL_KEY,
345 LUUIConstants.JOINT_OFFER_ITEM_LABEL_KEY,
346 Arrays.asList(
347 new MultiplicityFieldConfig(
348 CreditCourseJointsConstants.COURSE_ID,
349 LUUIConstants.COURSE_NUMBER_OR_TITLE_LABEL_KEY, null, null, true)),
350 null,
351 null);
352 SpanPanel vsnlabelpan = new SpanPanel();
353 vsnlabelpan.setStyleName("ks-multiplicity-section-label");
354 vsnlabelpan.setHTML("Version Codes");
355 vsnlabelpan.setVisible(true);
356 result.addWidget(vsnlabelpan);
357 addMultiplicityFields(result, COURSE + QueryPath.getPathSeparator() + VERSIONS,
358 LUUIConstants.ADD_VERSION_CODE_LABEL_KEY,
359 LUUIConstants.VERSION_CODE_LABEL_KEY,
360 Arrays.asList(
361 new MultiplicityFieldConfig(
362 "variationCode",
363 LUUIConstants.VERSION_CODE_LABEL_KEY, null, null, true),
364 new MultiplicityFieldConfig(
365 "variationTitle",
366 LUUIConstants.TITLE_LABEL_KEY, null, null, true)
367 ),
368 null,
369 null);
370 return result;
371 }
372
373 protected void addFeeMultiplicityFields(Section section,
374 String path, String addItemlabelMessageKey,
375 String itemLabelMessageKey, List<MultiplicityFieldConfig> fieldConfigs,
376 Map<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>> swappableFieldsDefinition,
377 List<String> deletionParentKeys) {
378 MultiplicityConfiguration config = setupMultiplicityConfig(
379 MultiplicityConfiguration.MultiplicityType.GROUP,
380 MultiplicityConfiguration.StyleType.TOP_LEVEL_GROUP,
381 path, addItemlabelMessageKey, itemLabelMessageKey,
382 fieldConfigs, swappableFieldsDefinition, deletionParentKeys);
383 MultiplicitySection ms = null;
384 ms = new MultiplicitySection(config, swappableFieldsDefinition, deletionParentKeys);
385 section.addSection(ms);
386
387 }
388
389 protected MultiplicityConfiguration setupMultiplicityConfig(
390 MultiplicityConfiguration.MultiplicityType multiplicityType,
391 MultiplicityConfiguration.StyleType styleType,
392 String path, String addItemlabelMessageKey,
393 String itemLabelMessageKey, List<MultiplicityFieldConfig> fieldConfigs,
394 Map<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>> swappableFieldsDefinition,
395 List<String> deletionParentKeys) {
396 QueryPath parentPath = QueryPath.concat(path);
397 MultiplicityConfiguration config = new MultiplicityConfiguration(multiplicityType,
398 styleType, getMetaData(parentPath.toString()));
399 config.setAddItemLabel(getLabel(addItemlabelMessageKey));
400 config.setItemLabel(getLabel(itemLabelMessageKey));
401 config.setUpdateable(true);
402
403 FieldDescriptor parentFd = buildMultiplicityParentFieldDescriptor(path, getLabel(itemLabelMessageKey), null);
404 config.setParent(parentFd);
405
406 if (fieldConfigs != null) {
407 for (MultiplicityFieldConfig fieldConfig : fieldConfigs) {
408 MultiplicityFieldConfiguration fc = buildMultiplicityFD(fieldConfig.getFieldKey(),
409 fieldConfig.getLabelKey(), parentPath.toString());
410 config.addFieldConfiguration(fc);
411 if (fieldConfig.isNextLine()) {
412 config.nextLine();
413 }
414 }
415 }
416 return config;
417 }
418
419 protected void addMultiplicityFields(Section section,
420 String path, String addItemlabelMessageKey,
421 String itemLabelMessageKey, List<MultiplicityFieldConfig> fieldConfigs,
422 Map<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>> swappableFieldsDefinition,
423 List<String> deletionParentKeys) {
424 MultiplicityConfiguration config = setupMultiplicityConfig(
425 MultiplicityConfiguration.MultiplicityType.GROUP,
426 MultiplicityConfiguration.StyleType.TOP_LEVEL_GROUP,
427 path, addItemlabelMessageKey, itemLabelMessageKey,
428 fieldConfigs, swappableFieldsDefinition, deletionParentKeys);
429 MultiplicitySection ms = null;
430 ms = new MultiplicitySection(config, swappableFieldsDefinition, deletionParentKeys);
431 section.addSection(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 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);
607
608 return courseOutcomes;
609
610 }
611
612 protected Section generateStudentRegistrationOptionsSection() {
613 VerticalSection studentRegistrationOptionsSection = initSection(getH3Title(LUUIConstants.LEARNING_RESULTS_STUDENT_REGISTRATION_LABEL_KEY), WITH_DIVIDER);
614
615 addField(studentRegistrationOptionsSection, COURSE + "/" + AUDIT, generateMessageInfo(LUUIConstants.LEARNING_RESULT_AUDIT_LABEL_KEY), new KSCheckBox(getLabel(LUUIConstants.LEARNING_RESULT_AUDIT_TEXT_LABEL_KEY)));
616 addField(studentRegistrationOptionsSection, COURSE + "/" + PASS_FAIL, generateMessageInfo(LUUIConstants.LEARNING_RESULT_PASS_FAIL_LABEL_KEY), new KSCheckBox(getLabel(LUUIConstants.LEARNING_RESULT_PASS_FAIL_TEXT_LABEL_KEY)));
617
618 return studentRegistrationOptionsSection;
619 }
620
621 protected Section generateGradesAssessmentsSection() {
622 VerticalSection gradesAssessments = initSection(getH3Title(LUUIConstants.LEARNING_RESULTS_GRADES_ASSESSMENTS_LABEL_KEY), WITH_DIVIDER);
623
624 addField(gradesAssessments, COURSE + "/" + GRADING_OPTIONS, generateMessageInfo(LUUIConstants.LEARNING_RESULT_ASSESSMENT_SCALE_LABEL_KEY));
625
626 return gradesAssessments;
627 }
628
629 protected VerticalSection generateCourseFormatsSection() {
630
631 VerticalSection courseFormats = initSection(getH3Title(LUUIConstants.FORMATS_LABEL_KEY), WITH_DIVIDER);
632 courseFormats.setHelp(getLabel(LUUIConstants.FORMATS_LABEL_KEY + "-help"));
633 courseFormats.setInstructions(getLabel(LUUIConstants.FORMATS_LABEL_KEY + "-instruct"));
634
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 MultiplicityConfiguration activitiesConfig = setupMultiplicityConfig(
642 MultiplicityConfiguration.MultiplicityType.GROUP,
643 MultiplicityConfiguration.StyleType.SUB_LEVEL_GROUP,
644 COURSE + "/" + FORMATS + "/*/" + ACTIVITIES,
645 LUUIConstants.ADD_ACTIVITY_LABEL_KEY,
646 LUUIConstants.ACTIVITY_LITERAL_LABEL_KEY,
647 Arrays.asList(
648 new MultiplicityFieldConfig(
649 ACTIVITY_TYPE,
650 LUUIConstants.ACTIVITY_TYPE_LABEL_KEY,
651 null,
652 null,
653 true),
654 new MultiplicityFieldConfig(
655 CONTACT_HOURS + "/" + "unitQuantity",
656 LUUIConstants.CONTACT_HOURS_LABEL_KEY,
657 null,
658 null,
659 false),
660 new MultiplicityFieldConfig(
661 CONTACT_HOURS + "/" + "unitType",
662 LUUIConstants.CONTACT_HOURS_FREQUENCY_LABEL_KEY,
663 null,
664 null,
665 true),
666 new MultiplicityFieldConfig(
667 CreditCourseActivityConstants.DURATION + "/" + "atpDurationTypeKey",
668 LUUIConstants.DURATION_TYPE_LABEL_KEY,
669 null,
670 null,
671 false),
672 new MultiplicityFieldConfig(
673 CreditCourseActivityConstants.DURATION + "/" + "timeQuantity",
674 LUUIConstants.DURATION_LITERAL_LABEL_KEY,
675 null,
676 null,
677 true),
678 new MultiplicityFieldConfig(
679 DEFAULT_ENROLLMENT_ESTIMATE,
680 LUUIConstants.CLASS_SIZE_LABEL_KEY,
681 null,
682 null,
683 true)
684 ), null, null);
685 courseFormatConfig.setNestedConfig(activitiesConfig);
686
687 MultiplicitySection ms = null;
688 ms = new MultiplicitySection(courseFormatConfig,
689 null, null);
690 courseFormats.addSection(ms);
691
692 return courseFormats;
693 }
694
695 protected VerticalSection generateSchedulingSection() {
696 VerticalSection scheduling = initSection(getH3Title(LUUIConstants.SCHEDULING_LABEL_KEY), WITH_DIVIDER);
697 addField(scheduling, COURSE + "/" + TERMS_OFFERED, generateMessageInfo(LUUIConstants.TERMS_OFFERED_LABEL_KEY));
698 return scheduling;
699 }
700
701 protected VerticalSection generateDurationSection() {
702 VerticalSection duration = initSection(getH3Title(LUUIConstants.DURATION_LITERAL_LABEL_KEY), WITH_DIVIDER);
703 duration.setInstructions(getLabel(LUUIConstants.DURATION_LITERAL_LABEL_KEY + "-instruct"));
704 GroupSection duration_group = new GroupSection();
705 addField(duration_group, COURSE + "/" + CreditCourseConstants.DURATION + "/" + "atpDurationTypeKey", generateMessageInfo(LUUIConstants.DURATION_TYPE_LABEL_KEY));
706 addField(duration_group, COURSE + "/" + CreditCourseConstants.DURATION + "/" + "timeQuantity", generateMessageInfo(LUUIConstants.DURATION_QUANTITY_LABEL_KEY));
707
708 duration.addSection(duration_group);
709 return duration;
710 }
711
712 protected VerticalSection generateFinalExamSection() {
713 VerticalSection finalExam = initSection(getH3Title(LUUIConstants.FINAL_EXAM_LABEL_KEY), WITH_DIVIDER);
714 GroupSection finalExam_group = new GroupSection();
715 GroupSection finalExamRationale_group = new GroupSection();
716 GroupSection finalExamRationale_group2 = new GroupSection();
717
718 FieldDescriptor field = addField(finalExam_group, COURSE + "/" + CreditCourseConstants.FINAL_EXAM, generateMessageInfo(LUUIConstants.FINAL_EXAM_STATUS_LABEL_KEY));
719
720 if (field.isVisible()){
721 KSSelectItemWidgetAbstract picker = (KSSelectItemWidgetAbstract) (((KSPicker) field.getFieldWidget()).getInputWidget());
722 addField(finalExamRationale_group, COURSE + "/" + CreditCourseConstants.FINAL_EXAM_RATIONALE, generateMessageInfo(LUUIConstants.FINAL_EXAM_RATIONALE_LABEL_KEY));
723 addField(finalExamRationale_group2, COURSE + "/" + CreditCourseConstants.FINAL_EXAM_RATIONALE, generateMessageInfo(LUUIConstants.FINAL_EXAM_RATIONALE_LABEL_KEY));
724 SwapSection swapSection = new SwapSection(picker);
725 swapSection.addSection(finalExamRationale_group, "ALT");
726 swapSection.addSection(finalExamRationale_group2, "None");
727 finalExam.addSection(finalExam_group);
728
729 finalExam.addSection(swapSection);
730 return finalExam;
731 } else {
732 return new VerticalSection();
733 }
734
735 }
736
737 protected VerticalSection generateInstructorsSection() {
738 VerticalSection instructors = initSection(getH3Title(LUUIConstants.INSTRUCTOR_LABEL_KEY), WITH_DIVIDER);
739 addField(instructors, COURSE + "/" + PRIMARY_INSTRUCTOR + "/personId");
740 return instructors;
741 }
742
743 protected SectionView generateLearningObjectivesSection() {
744 VerticalSectionView section = initSectionView(CourseSections.LEARNING_OBJECTIVES, LUUIConstants.LEARNING_OBJECTIVES_LABEL_KEY);
745 section.addSection(generateLearningObjectivesNestedSection());
746 return section;
747 }
748
749 protected VerticalSection generateLearningObjectivesNestedSection() {
750 final VerticalSection los = initSection(null, NO_DIVIDER);
751
752 QueryPath path = QueryPath.concat(COURSE, COURSE_SPECIFIC_LOS, "*", "loInfo", "desc");
753 Metadata meta = modelDefinition.getMetadata(path);
754
755 LOBuilder loBuilder = new LOBuilder(type, state, groupName, "kuali.loRepository.key.singleUse", meta);
756 final FieldDescriptor fd = addField(los, CreditCourseConstants.COURSE_SPECIFIC_LOS, null,loBuilder, COURSE);
757
758 loBuilder.addValueChangeHandler(new ValueChangeHandler<List<OutlineNode<LOPicker>>>(){
759 @Override
760 public void onValueChange(ValueChangeEvent<List<OutlineNode<LOPicker>>> event) {
761 los.setIsDirty(true);
762 fd.setDirty(true);
763 }
764 });
765
766
767
768 fd.setWidgetBinding(LOBuilderBinding.INSTANCE);
769
770 los.addStyleName("KS-LUM-Section-Divider");
771 return los;
772 }
773
774 public class PersonList extends KSDropDown {
775 final SimpleListItems people = new SimpleListItems();
776
777 public PersonList() {
778 final PersonList us = this;
779 final String userId = Application.getApplicationContext().getUserId();
780
781
782 people.addItem(userId, userId);
783 us.setListItems(people);
784 us.selectItem(userId);
785 us.setBlankFirstItem(false);
786 this.setEnabled(false);
787
788
789
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 public boolean isMultipleSelect() {
817 return true;
818 }
819 }
820
821 public class ProposerPersonList extends KSLabelList {
822 public ProposerPersonList() {
823 SimpleListItems list = new SimpleListItems();
824
825 super.setListItems(list);
826 }
827 }
828
829 protected VerticalSection generateShortTitleSection() {
830 VerticalSection shortTitle = initSection(getH3Title(LUUIConstants.SHORT_TITLE_LABEL_KEY), WITH_DIVIDER);
831 addField(shortTitle, "cluInfo/officialIdentifier/shortName", null);
832 return shortTitle;
833 }
834
835 protected VerticalSectionView initSectionView(Enum<?> viewEnum, String labelKey) {
836 VerticalSectionView section = new VerticalSectionView(viewEnum, getLabel(labelKey), CLU_PROPOSAL_MODEL);
837 section.addStyleName(LUUIConstants.STYLE_SECTION);
838 return section;
839 }
840
841
842 protected VerticalSection initSection(SectionTitle title, boolean withDivider) {
843 VerticalSection section;
844 if (title != null) {
845 section = new VerticalSection(title);
846 } else {
847 section = new VerticalSection();
848 }
849 section.addStyleName(LUUIConstants.STYLE_SECTION);
850 if (withDivider)
851 section.addStyleName(LUUIConstants.STYLE_SECTION_DIVIDER);
852 return section;
853 }
854
855 protected MessageKeyInfo generateMessageInfo(String labelKey) {
856 return new MessageKeyInfo(groupName, type, state, labelKey);
857 }
858
859 protected String getLabel(String labelKey) {
860 return Application.getApplicationContext().getUILabel(groupName, type, state, labelKey);
861 }
862
863 protected SectionTitle getH1Title(String labelKey) {
864 return SectionTitle.generateH1Title(getLabel(labelKey));
865 }
866
867 protected SectionTitle getH2Title(String labelKey) {
868 return SectionTitle.generateH2Title(getLabel(labelKey));
869 }
870
871 protected SectionTitle getH3Title(String labelKey) {
872 return SectionTitle.generateH3Title(getLabel(labelKey));
873 }
874
875 protected SectionTitle getH4Title(String labelKey) {
876 return SectionTitle.generateH4Title(getLabel(labelKey));
877 }
878
879 protected SectionTitle getH5Title(String labelKey) {
880 return SectionTitle.generateH5Title(getLabel(labelKey));
881 }
882
883
884
885
886 public FieldDescriptor addField(Section section, String fieldKey) {
887 return addField(section, fieldKey, null, null, null);
888 }
889
890 public FieldDescriptor addField(Section section, String fieldKey, MessageKeyInfo messageKey) {
891 return addField(section, fieldKey, messageKey, null, null);
892 }
893
894 public FieldDescriptor addField(Section section, String fieldKey, MessageKeyInfo messageKey, Widget widget) {
895 return addField(section, fieldKey, messageKey, widget, null);
896 }
897
898 public FieldDescriptor addField(Section section, String fieldKey, MessageKeyInfo messageKey, String parentPath) {
899 return addField(section, fieldKey, messageKey, null, parentPath);
900 }
901
902 public FieldDescriptor addField(Section section, String fieldKey, MessageKeyInfo messageKey, Widget widget, String parentPath) {
903 QueryPath path = QueryPath.concat(parentPath, fieldKey);
904 Metadata meta = modelDefinition.getMetadata(path);
905
906 FieldDescriptor fd = new FieldDescriptor(path.toString(), messageKey, meta);
907 if (widget != null) {
908 fd.setFieldWidget(widget);
909 }
910 section.addField(fd);
911 return fd;
912 }
913
914 protected SectionView generateFinancialsSection() {
915 VerticalSectionView section = initSectionView(CourseSections.FINANCIALS, LUUIConstants.FINANCIALS_LABEL_KEY);
916
917 VerticalSection justiFee = initSection(getH3Title(LUUIConstants.COURSE_FEE_TITLE), WITH_DIVIDER);
918 SpanPanel courseFeeInstruction = new SpanPanel();
919 courseFeeInstruction.setStyleName("ks-form-module-elements-instruction");
920 courseFeeInstruction.setHTML(getLabel(LUUIConstants.COURSE_FEE_TITLE + FieldLayoutComponent.INSTRUCT_MESSAGE_KEY));
921 courseFeeInstruction.setVisible(true);
922 justiFee.addWidget(courseFeeInstruction);
923
924
925
926 addField(justiFee, COURSE + "/" + "feeJustification" + "/" + RichTextInfoConstants.PLAIN, generateMessageInfo(LUUIConstants.JUSTIFICATION_FEE));
927 section.addSection(justiFee);
928 Map<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>> swappableFieldsDefinition =
929 new HashMap<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>>();
930
931
932
933
934
935
936
937 QueryPath feesPath = QueryPath.concat(COURSE, FEES);
938 QueryPath rateTypeFieldPath = QueryPath.concat(feesPath.toString(), QueryPath.getWildCard(), "rateType");
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
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307