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.BaseSection;
53 import org.kuali.student.common.ui.client.configurable.mvc.sections.CollapsableSection;
54 import org.kuali.student.common.ui.client.configurable.mvc.sections.GroupSection;
55 import org.kuali.student.common.ui.client.configurable.mvc.sections.MultiplicitySection;
56 import org.kuali.student.common.ui.client.configurable.mvc.sections.Section;
57 import org.kuali.student.common.ui.client.configurable.mvc.sections.SwapEventHandler;
58 import org.kuali.student.common.ui.client.configurable.mvc.sections.SwapSection;
59 import org.kuali.student.common.ui.client.configurable.mvc.sections.VerticalSection;
60 import org.kuali.student.common.ui.client.configurable.mvc.views.SectionView;
61 import org.kuali.student.common.ui.client.configurable.mvc.views.VerticalSectionView;
62 import org.kuali.student.common.ui.client.mvc.Controller;
63 import org.kuali.student.common.ui.client.mvc.DataModel;
64 import org.kuali.student.common.ui.client.mvc.DataModelDefinition;
65 import org.kuali.student.common.ui.client.mvc.HasDataValue;
66 import org.kuali.student.common.ui.client.mvc.View;
67 import org.kuali.student.common.ui.client.widgets.KSButton;
68 import org.kuali.student.common.ui.client.widgets.KSButtonAbstract.ButtonStyle;
69 import org.kuali.student.common.ui.client.widgets.KSCharCount;
70 import org.kuali.student.common.ui.client.widgets.KSCheckBox;
71 import org.kuali.student.common.ui.client.widgets.KSDropDown;
72 import org.kuali.student.common.ui.client.widgets.ListOfStringWidget;
73 import org.kuali.student.common.ui.client.widgets.field.layout.element.MessageKeyInfo;
74 import org.kuali.student.common.ui.client.widgets.field.layout.element.SpanPanel;
75 import org.kuali.student.common.ui.client.widgets.field.layout.layouts.FieldLayoutComponent;
76 import org.kuali.student.common.ui.client.widgets.list.KSLabelList;
77 import org.kuali.student.common.ui.client.widgets.list.KSSelectItemWidgetAbstract;
78 import org.kuali.student.common.ui.client.widgets.list.KSSelectedList;
79 import org.kuali.student.common.ui.client.widgets.list.impl.SimpleListItems;
80 import org.kuali.student.common.ui.client.widgets.search.KSPicker;
81 import org.kuali.student.core.comments.ui.client.widgets.commenttool.CommentTool;
82 import org.kuali.student.core.comments.ui.client.widgets.decisiontool.DecisionPanel;
83 import org.kuali.student.core.document.ui.client.widgets.documenttool.DocumentTool;
84 import org.kuali.student.core.workflow.ui.client.views.CollaboratorSectionView;
85 import org.kuali.student.lum.common.client.lo.LOBuilder;
86 import org.kuali.student.lum.common.client.lo.LOBuilderBinding;
87 import org.kuali.student.lum.common.client.lo.LOPicker;
88 import org.kuali.student.lum.common.client.lo.OutlineNode;
89 import org.kuali.student.lum.common.client.lu.LUUIConstants;
90 import org.kuali.student.lum.lu.assembly.data.client.constants.base.RichTextInfoConstants;
91 import org.kuali.student.lum.lu.assembly.data.client.constants.orch.CreditCourseActivityConstants;
92 import org.kuali.student.lum.lu.assembly.data.client.constants.orch.CreditCourseConstants;
93 import org.kuali.student.lum.lu.assembly.data.client.constants.orch.CreditCourseJointsConstants;
94 import org.kuali.student.lum.lu.ui.course.client.controllers.CourseProposalController;
95 import org.kuali.student.lum.lu.ui.course.client.requirements.CourseRequirementsViewController;
96 import org.kuali.student.r1.common.assembly.data.Data;
97 import org.kuali.student.r1.common.assembly.data.Data.Value;
98 import org.kuali.student.r1.common.assembly.data.Metadata;
99 import org.kuali.student.r1.common.assembly.data.QueryPath;
100 import org.kuali.student.r1.core.statement.dto.StatementTypeInfo;
101 import org.kuali.student.r2.common.dto.DtoConstants;
102
103 import com.google.gwt.core.client.GWT;
104 import com.google.gwt.event.dom.client.ClickEvent;
105 import com.google.gwt.event.dom.client.ClickHandler;
106 import com.google.gwt.event.logical.shared.ValueChangeEvent;
107 import com.google.gwt.event.logical.shared.ValueChangeHandler;
108 import com.google.gwt.user.client.ui.Widget;
109
110
111
112
113
114
115
116 public class CourseProposalConfigurer extends AbstractCourseConfigurer {
117
118 protected boolean WITH_DIVIDER = true;
119 protected boolean NO_DIVIDER = false;
120
121 public static final String PROPOSAL_PATH = "proposal";
122 public static final String PROPOSAL_TITLE_PATH = "proposal/name";
123 public static final String COURSE_TITLE_PATH = "/courseTitle";
124
125
126 protected DocumentTool documentTool;
127 protected CourseSummaryConfigurer summaryConfigurer;
128
129 protected List<StatementTypeInfo> stmtTypes;
130
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, WF_APPROVE_DIALOG
137 }
138
139 public void setStatementTypes(List<StatementTypeInfo> stmtTypes) {
140 this.stmtTypes = stmtTypes;
141 }
142
143
144
145
146
147
148
149 public void configure(final CourseProposalController layout) {
150 type = "course";
151 state = DtoConstants.STATE_DRAFT;
152 groupName = LUUIConstants.COURSE_GROUP_NAME;
153
154 if (modelDefinition.getMetadata().isCanEdit()) {
155 addCluStartSection(layout);
156 String sections = getLabel(LUUIConstants.COURSE_SECTIONS);
157
158
159
160
161 layout.addMenu(sections);
162
163
164
165 layout.addMenuItem(sections, (SectionView)generateCourseInfoSection(initSectionView(CourseSections.COURSE_INFO, LUUIConstants.INFORMATION_LABEL_KEY)));
166 layout.addMenuItem(sections, (SectionView)generateGovernanceSection(initSectionView(CourseSections.GOVERNANCE, LUUIConstants.GOVERNANCE_LABEL_KEY)));
167 layout.addMenuItem(sections, (SectionView)generateCourseLogisticsSection(initSectionView(CourseSections.COURSE_LOGISTICS, LUUIConstants.LOGISTICS_LABEL_KEY)));
168 layout.addMenuItem(sections, generateLearningObjectivesSection());
169
170
171 layout.addMenuItem(sections, generateCourseRequisitesSection(layout,true));
172
173
174 layout.addMenuItem(sections, (SectionView)generateActiveDatesSection(initSectionView(CourseSections.ACTIVE_DATES, LUUIConstants.ACTIVE_DATES_LABEL_KEY)));
175 layout.addMenuItem(sections, (SectionView)generateFinancialsSection(initSectionView(CourseSections.FINANCIALS, LUUIConstants.FINANCIALS_LABEL_KEY)));
176
177
178 layout.addMenuItem(sections, new CollaboratorSectionView(CourseSections.PEOPLE_PERMISSONS, getLabel(LUUIConstants.SECTION_AUTHORS_AND_COLLABORATORS), COURSE_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((DataModelDefinition)modelDefinition);
183 layout.addMenuItem(sections, documentTool);
184
185
186 summaryConfigurer = GWT.create(CourseSummaryConfigurer.class);
187 summaryConfigurer.init(type, state, groupName,(DataModelDefinition)modelDefinition, stmtTypes, (Controller)layout, COURSE_PROPOSAL_MODEL);
188 layout.addSpecialMenuItem(summaryConfigurer.generateProposalSummarySection(true), "Review and Submit");
189
190
191 List<Enum<?>> excludedViews = new ArrayList<Enum<?>>();
192 excludedViews.add(CourseSections.DOCUMENTS);
193 excludedViews.add(CourseSections.COURSE_REQUISITES);
194 layout.addCommonButton(LUUIConstants.COURSE_SECTIONS, layout.getSaveButton(), excludedViews);
195 layout.addCommonButton(LUUIConstants.COURSE_SECTIONS, layout.getCancelButton(CourseSections.SUMMARY), excludedViews);
196
197
198
199 layout.addButtonForView(CourseSections.DOCUMENTS, getContinueButton(layout));
200 }
201 else{
202 summaryConfigurer = GWT.create(CourseSummaryConfigurer.class);
203 summaryConfigurer.init(type, state, groupName, (DataModelDefinition)modelDefinition, stmtTypes, (Controller)layout, COURSE_PROPOSAL_MODEL);
204 layout.removeMenuNavigation();
205 layout.addView(summaryConfigurer.generateProposalSummarySection(false));
206 }
207 layout.showPrint(true);
208 layout.setDefaultView(CourseSections.SUMMARY);
209 layout.addContentWidget(layout.getWfUtilities().getProposalStatusLabel());
210 final CommentTool commentTool = new CommentTool(CourseSections.COMMENTS, getLabel(LUUIConstants.TOOL_COMMENTS_LABEL_KEY), "kuali.comment.type.generalRemarks", "Proposal Comments");
211 commentTool.setController(layout);
212
213 layout.addContentWidget(new KSButton("Comments", ButtonStyle.DEFAULT_ANCHOR, new ClickHandler() {
214
215 @Override
216 public void onClick(ClickEvent event) {
217 commentTool.show();
218 }
219 }));
220
221
222 final DecisionPanel decisionPanel = new DecisionPanel(CourseSections.DECISIONS, getLabel(LUUIConstants.TOOL_DECISION_LABEL_KEY), "kuali.comment.type.generalRemarks");
223 layout.addView(decisionPanel);
224 layout.addContentWidget(new KSButton("Decisions", ButtonStyle.DEFAULT_ANCHOR, new ClickHandler() {
225
226 @Override
227 public void onClick(ClickEvent event) {
228 decisionPanel.show();
229 }
230 }));
231
232 }
233
234 protected KSButton getContinueButton(final CourseProposalController layout){
235 return new KSButton("Continue", new ClickHandler(){
236 public void onClick(ClickEvent event) {
237 layout.showNextViewOnMenu();
238 }
239 });
240 }
241
242 public void addCluStartSection(CourseProposalController layout) {
243 VerticalSectionView section = initSectionView(CourseSections.CLU_BEGIN, LUUIConstants.START_LABEL_KEY);
244 section.setController(layout);
245 addField(section, PROPOSAL_TITLE_PATH, generateMessageInfo(LUUIConstants.PROPOSAL_TITLE_LABEL_KEY));
246 addField(section, COURSE + "/" + COURSE_TITLE, generateMessageInfo(LUUIConstants.COURSE_TITLE_LABEL_KEY));
247
248
249 layout.addStartViewPopup(section);
250 layout.getStartPopup().setMaxHeight(600);
251 }
252
253 protected View generateCourseRequisitesSection(Controller layout, boolean showSaveButtons) {
254 return new CourseRequirementsViewController(layout, getLabel(LUUIConstants.REQUISITES_LABEL_KEY), CourseSections.COURSE_REQUISITES, false, showSaveButtons);
255 }
256
257 protected Section generateActiveDatesSection(Section section) {
258
259 FieldDescriptor fd = addField(section, PROPOSAL_PATH + "/" + PREV_START_TERM, generateMessageInfo(LUUIConstants.PROPOSAL_PREV_START_TERM));
260 fd.getFieldWidget().setVisible(false);
261 fd.hideLabel();
262
263 addField(section, COURSE + "/" + START_TERM, generateMessageInfo(LUUIConstants.START_TERM_LABEL_KEY));
264
265 addField(section, COURSE + "/" + PILOT_COURSE, generateMessageInfo(LUUIConstants.PILOT_COURSE_LABEL_KEY), new KSCheckBox(getLabel(LUUIConstants.PILOT_COURSE_TEXT_LABEL_KEY))).setIgnoreShowRequired(true);
266 addField(section, COURSE + "/" + END_TERM, generateMessageInfo(LUUIConstants.END_TERM_LABEL_KEY)).setIgnoreShowRequired(true);
267
268 return section;
269 }
270
271 protected VerticalSection generateActiveDateEndSection() {
272 VerticalSection endDate = initSection(getH3Title(LUUIConstants.END_DATE_LABEL_KEY), WITH_DIVIDER);
273 addField(endDate, COURSE + "/" + EXPIRATION_DATE, generateMessageInfo(LUUIConstants.EXPIRATION_DATE_LABEL_KEY));
274 return endDate;
275 }
276
277 protected VerticalSection generateActiveDateStartSection() {
278 VerticalSection startDate = initSection(getH3Title(LUUIConstants.START_DATE_LABEL_KEY), WITH_DIVIDER);
279 addField(startDate, COURSE + "/" + CreditCourseConstants.EFFECTIVE_DATE, generateMessageInfo(LUUIConstants.EFFECTIVE_DATE_LABEL_KEY));
280 return startDate;
281 }
282
283 protected Section generateGovernanceSection(Section section) {
284 addField(section, COURSE + "/" + CAMPUS_LOCATIONS, generateMessageInfo(LUUIConstants.CAMPUS_LOCATION_LABEL_KEY));
285 addField(section, COURSE + "/" + CURRICULUM_OVERSIGHT_ORGS_, generateMessageInfo(LUUIConstants.ACADEMIC_SUBJECT_ORGS_KEY));
286 addField(section, COURSE + "/" + ADMIN_ORGS, generateMessageInfo(LUUIConstants.ADMIN_ORG_LABEL_KEY));
287
288 return section;
289 }
290
291 public Section generateCourseInfoSection(Section section) {
292 addField(section, PROPOSAL_TITLE_PATH, generateMessageInfo(LUUIConstants.PROPOSAL_TITLE_LABEL_KEY));
293 addField(section, COURSE + "/" + COURSE_TITLE, generateMessageInfo(LUUIConstants.COURSE_TITLE_LABEL_KEY));
294 addField(section, COURSE + "/" + TRANSCRIPT_TITLE, generateMessageInfo(LUUIConstants.SHORT_TITLE_LABEL_KEY), new KSCharCount(getMetaData(COURSE + "/" + TRANSCRIPT_TITLE)));
295 section.addSection(generateCourseNumberSection());
296 FieldDescriptor instructorsFd = addField(section, COURSE + "/" + INSTRUCTORS, generateMessageInfo(LUUIConstants.INSTRUCTORS_LABEL_KEY));
297 instructorsFd.setWidgetBinding(new KeyListModelWigetBinding("personId"));
298
299 section.addSection(generateDescriptionRationaleSection());
300
301 return section;
302 }
303
304
305 protected GroupSection generateCourseNumberSection() {
306
307
308 GroupSection courseNumber = new GroupSection(getH4Title(""));
309 courseNumber.addStyleName(LUUIConstants.STYLE_SECTION);
310 courseNumber.addStyleName(LUUIConstants.STYLE_SECTION_DIVIDER);
311 addField(courseNumber, COURSE + "/" + SUBJECT_AREA, generateMessageInfo(LUUIConstants.SUBJECT_CODE_LABEL_KEY));
312 addField(courseNumber, COURSE + "/" + COURSE_NUMBER_SUFFIX, generateMessageInfo(LUUIConstants.COURSE_NUMBER_LABEL_KEY));
313
314
315
316 courseNumber.addSection(generateCrossListed_Ver_Joint_Section());
317
318 return courseNumber;
319 }
320
321 protected CollapsableSection generateCrossListed_Ver_Joint_Section() {
322 CollapsableSection result = new CollapsableSection(getLabel(LUUIConstants.CL_V_J_LABEL_KEY));
323
324
325
326
327 SpanPanel crslabelpan = new SpanPanel();
328 crslabelpan.setStyleName("ks-multiplicity-section-label");
329 crslabelpan.setHTML("Cross Listed Courses");
330 crslabelpan.setVisible(true);
331 result.addWidget(crslabelpan);
332 addMultiplicityFields(result, COURSE + QueryPath.getPathSeparator() + CROSS_LISTINGS,
333 LUUIConstants.ADD_CROSS_LISTED_LABEL_KEY,
334 LUUIConstants.CROSS_LISTED_ITEM_LABEL_KEY,
335 Arrays.asList(
336 new MultiplicityFieldConfig(
337 SUBJECT_AREA,
338 LUUIConstants.SUBJECT_CODE_LABEL_KEY, null, null, true),
339 new MultiplicityFieldConfig(
340 COURSE_NUMBER_SUFFIX,
341 LUUIConstants.COURSE_NUMBER_LABEL_KEY, null, null, true)),
342 null,
343 null,0);
344 SpanPanel jntlabelpan = new SpanPanel();
345 jntlabelpan.setStyleName("ks-multiplicity-section-label");
346 jntlabelpan.setHTML("Jointly Offered Courses");
347 jntlabelpan.setVisible(true);
348 result.addWidget(jntlabelpan);
349 addMultiplicityFields(result, COURSE + QueryPath.getPathSeparator() + JOINTS,
350 LUUIConstants.ADD_EXISTING_LABEL_KEY,
351 LUUIConstants.JOINT_OFFER_ITEM_LABEL_KEY,
352 Arrays.asList(
353 new MultiplicityFieldConfig(
354 CreditCourseJointsConstants.COURSE_ID,
355 LUUIConstants.COURSE_NUMBER_OR_TITLE_LABEL_KEY, null, null, true)),
356 null,
357 null,0);
358 SpanPanel vsnlabelpan = new SpanPanel();
359 vsnlabelpan.setStyleName("ks-multiplicity-section-label");
360 vsnlabelpan.setHTML("Version Codes");
361 vsnlabelpan.setVisible(true);
362 result.addWidget(vsnlabelpan);
363 addMultiplicityFields(result, COURSE + QueryPath.getPathSeparator() + VERSIONS,
364 LUUIConstants.ADD_VERSION_CODE_LABEL_KEY,
365 LUUIConstants.VERSION_CODE_LABEL_KEY,
366 Arrays.asList(
367 new MultiplicityFieldConfig(
368 "variationCode",
369 LUUIConstants.VERSION_CODE_LABEL_KEY, null, null, true),
370 new MultiplicityFieldConfig(
371 "variationTitle",
372 LUUIConstants.TITLE_LABEL_KEY, null, null, true)
373 ),
374 null,
375 null,0);
376 if(this.getClass().getName().contains("CourseProposalConfigurer"))
377 result.getLayout().setVisible(true);
378 else {
379 result.getLayout().setVisible(false);
380 }
381 return result;
382 }
383
384 protected void addFeeMultiplicityFields(Section section,
385 String path, String addItemlabelMessageKey,
386 String itemLabelMessageKey, List<MultiplicityFieldConfig> fieldConfigs,
387 Map<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>> swappableFieldsDefinition,
388 List<String> deletionParentKeys) {
389 MultiplicityConfiguration config = setupMultiplicityConfig(
390 MultiplicityConfiguration.MultiplicityType.GROUP,
391 MultiplicityConfiguration.StyleType.TOP_LEVEL_GROUP,
392 path, addItemlabelMessageKey, itemLabelMessageKey,
393 fieldConfigs, swappableFieldsDefinition, deletionParentKeys);
394 MultiplicitySection ms = null;
395 ms = new MultiplicitySection(config, swappableFieldsDefinition, deletionParentKeys);
396 section.addSection(ms);
397
398 }
399
400 protected MultiplicityConfiguration setupMultiplicityConfig(
401 MultiplicityConfiguration.MultiplicityType multiplicityType,
402 MultiplicityConfiguration.StyleType styleType,
403 String path, String addItemlabelMessageKey,
404 String itemLabelMessageKey, List<MultiplicityFieldConfig> fieldConfigs,
405 Map<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>> swappableFieldsDefinition,
406 List<String> deletionParentKeys) {
407 QueryPath parentPath = QueryPath.concat(path);
408 MultiplicityConfiguration config = new MultiplicityConfiguration(multiplicityType,
409 styleType, getMetaData(parentPath.toString()));
410 config.setAddItemLabel(getLabel(addItemlabelMessageKey));
411 config.setItemLabel(getLabel(itemLabelMessageKey));
412 config.setUpdateable(true);
413
414 FieldDescriptor parentFd = buildMultiplicityParentFieldDescriptor(path, getLabel(itemLabelMessageKey), null);
415 config.setParent(parentFd);
416
417 if (fieldConfigs != null) {
418 for (MultiplicityFieldConfig fieldConfig : fieldConfigs) {
419 MultiplicityFieldConfiguration fc = buildMultiplicityFD(fieldConfig.getFieldKey(),
420 fieldConfig.getLabelKey(), parentPath.toString());
421 config.addFieldConfiguration(fc);
422 if (fieldConfig.isNextLine()) {
423 config.nextLine();
424 }
425 }
426 }
427 return config;
428 }
429
430 protected MultiplicitySection addMultiplicityFields(Section section,
431 String path, String addItemlabelMessageKey,
432 String itemLabelMessageKey, List<MultiplicityFieldConfig> fieldConfigs,
433 Map<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>> swappableFieldsDefinition,
434 List<String> deletionParentKeys,int defaultItemsCreated) {
435 MultiplicityConfiguration config = setupMultiplicityConfig(
436 MultiplicityConfiguration.MultiplicityType.GROUP,
437 MultiplicityConfiguration.StyleType.TOP_LEVEL_GROUP,
438 path, addItemlabelMessageKey, itemLabelMessageKey,
439 fieldConfigs, swappableFieldsDefinition, deletionParentKeys);
440 config.setDefaultItemsCreated(defaultItemsCreated);
441 MultiplicitySection ms = null;
442 ms = new MultiplicitySection(config, swappableFieldsDefinition, deletionParentKeys);
443 section.addSection(ms);
444 return ms;
445 }
446
447 protected Metadata getMetaData(String fieldKey) {
448 return modelDefinition.getMetadata(QueryPath.concat(fieldKey));
449 }
450
451 protected MultiplicityFieldConfiguration buildMultiplicityFD(
452 String fieldKey, String labelKey, String parentPath) {
453
454 QueryPath fieldPath = QueryPath.concat(parentPath, QueryPath.getWildCard(), fieldKey);
455 Metadata meta = modelDefinition.getMetadata(fieldPath);
456
457 MultiplicityFieldConfiguration fd = new MultiplicityFieldConfiguration(
458 fieldPath.toString(), generateMessageInfo(labelKey), meta, null);
459
460
461 return fd;
462
463 }
464
465 protected FieldDescriptor buildMultiplicityParentFieldDescriptor(String fieldKey, String messageKey, String parentPath) {
466 QueryPath path = QueryPath.concat(parentPath, fieldKey);
467 Metadata meta = modelDefinition.getMetadata(path);
468
469 FieldDescriptor fd = new FieldDescriptor(path.toString(), generateMessageInfo(messageKey), meta);
470 fd.hideLabel();
471 return fd;
472 }
473
474 protected VerticalSection generateCourseInfoShortTitleSection() {
475 VerticalSection shortTitle = initSection(getH3Title(LUUIConstants.SHORT_TITLE_LABEL_KEY), WITH_DIVIDER);
476 addField(shortTitle, COURSE + "/" + TRANSCRIPT_TITLE, null);
477 return shortTitle;
478 }
479
480 protected VerticalSection generateLongTitleSection() {
481 VerticalSection longTitle = initSection(getH3Title(LUUIConstants.TITLE_LABEL_KEY), WITH_DIVIDER);
482 addField(longTitle, COURSE + "/" + COURSE_TITLE, null);
483 return longTitle;
484 }
485
486 protected VerticalSection generateDescriptionRationaleSection() {
487 SectionTitle title = getH4Title(LUUIConstants.PROPOSAL_TITLE_SECTION_LABEL_KEY);
488 VerticalSection description = initSection(title, !WITH_DIVIDER);
489 title.setStyleName("cluProposalTitleSection");
490
491
492 addField(description, COURSE + "/" + DESCRIPTION + "/" + RichTextInfoConstants.PLAIN, generateMessageInfo(LUUIConstants.DESCRIPTION_LABEL_KEY));
493 addField(description, "proposal/rationale", generateMessageInfo(LUUIConstants.PROPOSAL_RATIONALE_LABEL_KEY),
494 new KSCharCount(modelDefinition.getMetadata(QueryPath.parse("proposal/rationale"))));
495
496 return description;
497 }
498
499 public Section generateCourseLogisticsSection(Section section) {
500 if (section instanceof SectionView){
501 ((SectionView)section).setInstructions(getLabel(LUUIConstants.LOGISTICS_LABEL_KEY + "-instruct") + "<br><br>");
502 }
503
504 section.addSection(generateSchedulingSection());
505 section.addSection(generateDurationSection());
506 section.addSection(generateLearningResultsSection());
507 section.addSection(generateCourseFormatsSection());
508
509 return section;
510 }
511
512 protected Section generateLearningResultsSection() {
513 VerticalSection learningResults = initSection(getH3Title(LUUIConstants.LEARNING_RESULTS_LABEL_KEY), WITH_DIVIDER);
514 learningResults.setInstructions(getLabel(LUUIConstants.LEARNING_RESULTS_LABEL_KEY + "-instruct") + "<br><br><br>");
515
516 learningResults.addSection(generateGradesAssessmentsSection());
517 learningResults.addSection(generateStudentRegistrationOptionsSection());
518 learningResults.addSection(generateFinalExamSection());
519 learningResults.addSection(generateOutcomesSection());
520
521 return learningResults;
522 }
523
524 protected Section generateOutcomesSection() {
525
526 String path = COURSE + QueryPath.getPathSeparator() + CREDIT_OPTIONS;
527 QueryPath creditTypeFullPath = QueryPath.concat(path, QueryPath.getWildCard(), CreditCourseConstants.TYPE);
528 QueryPath creditOptionFixedFullPath = QueryPath.concat(path, QueryPath.getWildCard(), CREDIT_OPTION_FIXED_CREDITS);
529 QueryPath creditOptionMinFullPath = QueryPath.concat(path, QueryPath.getWildCard(), CREDIT_OPTION_MIN_CREDITS);
530 QueryPath creditOptionMaxFullPath = QueryPath.concat(path, QueryPath.getWildCard(), CREDIT_OPTION_MAX_CREDITS);
531 QueryPath creditResultValuesFullPath = QueryPath.concat(path, QueryPath.getWildCard(), "resultValues");
532
533 VerticalSection courseOutcomes = initSection(getH3Title(LUUIConstants.LEARNING_RESULT_OUTCOME_LABEL_KEY), WITH_DIVIDER);
534 Map<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>> swappableFieldsDefinition =
535 new HashMap<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>>();
536 SwapCompositeCondition fixedCreditCondition = new SwapCompositeCondition(
537 CompositeConditionOperator.AND);
538 fixedCreditCondition.getChildrenConditions().add(
539 makeCondition(creditTypeFullPath, LUUIConstants.LEARNING_RESULT_OUTCOME_TYPE_LABEL_KEY, "kuali.resultComponentType.credit.degree.fixed")
540 );
541 fixedCreditCondition.setConditionId("1");
542 SwapCompositeCondition multipleCreditCondition = new SwapCompositeCondition(
543 CompositeConditionOperator.AND);
544 multipleCreditCondition.getChildrenConditions().add(
545 makeCondition(creditTypeFullPath, LUUIConstants.LEARNING_RESULT_OUTCOME_TYPE_LABEL_KEY, "kuali.resultComponentType.credit.degree.multiple")
546 );
547 multipleCreditCondition.setConditionId("2");
548 SwapCompositeCondition variableCreditCondition = new SwapCompositeCondition(
549 CompositeConditionOperator.AND);
550 variableCreditCondition.getChildrenConditions().add(
551 makeCondition(creditTypeFullPath, LUUIConstants.LEARNING_RESULT_OUTCOME_TYPE_LABEL_KEY, "kuali.resultComponentType.credit.degree.range")
552 );
553 variableCreditCondition.setConditionId("3");
554
555 swappableFieldsDefinition.put(fixedCreditCondition,
556 Arrays.asList(
557 new SwapCompositeConditionFieldConfig(
558 new MultiplicityFieldConfiguration(
559 creditOptionFixedFullPath.toString(),
560 generateMessageInfo(LUUIConstants.CREDIT_OPTION_FIXED_CREDITS_LABEL_KEY),
561 modelDefinition.getMetadata(creditOptionFixedFullPath),
562 null),
563 null
564 )
565 )
566 );
567 MultiplicityFieldWidgetInitializer multipleCreditInitializer =
568 new MultiplicityFieldWidgetInitializer() {
569 @Override
570 public ModelWidgetBinding<?> getModelWidgetBindingInstance() {
571 return new ListOfStringBinding();
572 }
573 @Override
574 public Widget getNewWidget() {
575 return new ListOfStringWidget("Add Item");
576 }
577 };
578
579 swappableFieldsDefinition.put(multipleCreditCondition,
580 Arrays.asList(
581 new SwapCompositeConditionFieldConfig(
582 new MultiplicityFieldConfiguration(
583 creditResultValuesFullPath.toString(),
584 generateMessageInfo(LUUIConstants.CREDIT_OPTION_FIXED_CREDITS_LABEL_KEY),
585 modelDefinition.getMetadata(creditResultValuesFullPath),
586 multipleCreditInitializer),
587 null
588 )
589 )
590 );
591 swappableFieldsDefinition.put(variableCreditCondition,
592 Arrays.asList(
593 new SwapCompositeConditionFieldConfig(
594 new MultiplicityFieldConfiguration(
595 creditOptionMinFullPath.toString(),
596 generateMessageInfo(LUUIConstants.CREDIT_OPTION_MIN_CREDITS_LABEL_KEY),
597 modelDefinition.getMetadata(creditOptionMinFullPath),
598 null),
599 null
600 ),
601 new SwapCompositeConditionFieldConfig(
602 new MultiplicityFieldConfiguration(
603 creditOptionMaxFullPath.toString(),
604 generateMessageInfo(LUUIConstants.CREDIT_OPTION_MAX_CREDITS_LABEL_KEY),
605 modelDefinition.getMetadata(creditOptionMaxFullPath),
606 null),
607 null
608 )
609 )
610 );
611
612 MultiplicitySection ms = addMultiplicityFields(
613 courseOutcomes,
614 path,
615 LUUIConstants.LEARNING_RESULT_OUTCOME_LABEL_KEY,
616 LUUIConstants.LEARNING_RESULT_OUTCOME_LABEL_KEY,
617 Arrays.asList(
618 new MultiplicityFieldConfig(
619 CreditCourseConstants.TYPE,
620 LUUIConstants.LEARNING_RESULT_OUTCOME_TYPE_LABEL_KEY,
621 null, null, true)
622 ), swappableFieldsDefinition, null,1);
623
624 courseOutcomes.setRequired(ms.getConfig().getParentFd().getFieldElement().getRequiredPanel());
625 return courseOutcomes;
626
627 }
628
629 protected Section generateStudentRegistrationOptionsSection() {
630 VerticalSection studentRegistrationOptionsSection = initSection(getH3Title(LUUIConstants.LEARNING_RESULTS_STUDENT_REGISTRATION_LABEL_KEY), WITH_DIVIDER);
631
632 addField(studentRegistrationOptionsSection, COURSE + "/" + AUDIT, generateMessageInfo(LUUIConstants.LEARNING_RESULT_AUDIT_LABEL_KEY), new KSCheckBox(getLabel(LUUIConstants.LEARNING_RESULT_AUDIT_TEXT_LABEL_KEY)));
633 addField(studentRegistrationOptionsSection, COURSE + "/" + PASS_FAIL, generateMessageInfo(LUUIConstants.LEARNING_RESULT_PASS_FAIL_LABEL_KEY), new KSCheckBox(getLabel(LUUIConstants.LEARNING_RESULT_PASS_FAIL_TEXT_LABEL_KEY)));
634
635 return studentRegistrationOptionsSection;
636 }
637
638 protected Section generateGradesAssessmentsSection() {
639 VerticalSection gradesAssessments = initSection(getH3Title(LUUIConstants.LEARNING_RESULTS_GRADES_ASSESSMENTS_LABEL_KEY), WITH_DIVIDER);
640
641 addField(gradesAssessments, COURSE + "/" + GRADING_OPTIONS, generateMessageInfo(LUUIConstants.LEARNING_RESULT_ASSESSMENT_SCALE_LABEL_KEY));
642
643 return gradesAssessments;
644 }
645
646 protected VerticalSection generateCourseFormatsSection() {
647
648 VerticalSection courseFormats = initSection(getH3Title(LUUIConstants.FORMATS_LABEL_KEY), WITH_DIVIDER);
649 courseFormats.setHelp(getLabel(LUUIConstants.FORMATS_LABEL_KEY + "-help"));
650 courseFormats.setInstructions(getLabel(LUUIConstants.FORMATS_LABEL_KEY + "-instruct"));
651 MultiplicityConfiguration courseFormatConfig = setupMultiplicityConfig(
652 MultiplicityConfiguration.MultiplicityType.GROUP,
653 MultiplicityConfiguration.StyleType.TOP_LEVEL_GROUP,
654 COURSE + "/" + FORMATS, LUUIConstants.COURSE_ADD_FORMAT_LABEL_KEY,
655 LUUIConstants.FORMAT_LABEL_KEY,
656 null, null, null);
657 courseFormatConfig.setDefaultItemsCreated(1);
658 MultiplicityConfiguration activitiesConfig = setupMultiplicityConfig(
659 MultiplicityConfiguration.MultiplicityType.GROUP,
660 MultiplicityConfiguration.StyleType.SUB_LEVEL_GROUP,
661 COURSE + "/" + FORMATS + "/*/" + ACTIVITIES,
662 LUUIConstants.ADD_ACTIVITY_LABEL_KEY,
663 LUUIConstants.ACTIVITY_LITERAL_LABEL_KEY,
664 Arrays.asList(
665 new MultiplicityFieldConfig(
666 ACTIVITY_TYPE,
667 LUUIConstants.ACTIVITY_TYPE_LABEL_KEY,
668 null,
669 null,
670 true),
671 new MultiplicityFieldConfig(
672 CONTACT_HOURS + "/" + "unitQuantity",
673 LUUIConstants.CONTACT_HOURS_LABEL_KEY,
674 null,
675 null,
676 false),
677 new MultiplicityFieldConfig(
678 CONTACT_HOURS + "/" + "unitTypeKey",
679 LUUIConstants.CONTACT_HOURS_FREQUENCY_LABEL_KEY,
680 null,
681 null,
682 true),
683 new MultiplicityFieldConfig(
684 CreditCourseActivityConstants.DURATION + "/" + "atpDurationTypeKey",
685 LUUIConstants.COURSE_FORMATS_DURATION_TYPE_LABEL_KEY,
686 null,
687 null,
688 false),
689 new MultiplicityFieldConfig(
690 CreditCourseActivityConstants.DURATION + "/" + "timeQuantity",
691 LUUIConstants.DURATION_QUANTITY_LABEL_KEY,
692 null,
693 null,
694 true),
695 new MultiplicityFieldConfig(
696 DEFAULT_ENROLLMENT_ESTIMATE,
697 LUUIConstants.CLASS_SIZE_LABEL_KEY,
698 null,
699 null,
700 true)
701 ), null, null);
702 activitiesConfig.setDefaultItemsCreated(1);
703 courseFormatConfig.setNestedConfig(activitiesConfig);
704
705
706 MultiplicitySection ms = null;
707 ms = new MultiplicitySection(courseFormatConfig,
708 null, null);
709 courseFormats.addSection(ms);
710 courseFormats.setRequired(courseFormatConfig.getParentFd().getFieldElement().getRequiredPanel());
711 return courseFormats;
712 }
713
714 protected VerticalSection generateSchedulingSection() {
715 VerticalSection scheduling = initSection(getH3Title(LUUIConstants.SCHEDULING_LABEL_KEY), WITH_DIVIDER);
716 addField(scheduling, COURSE + "/" + TERMS_OFFERED, generateMessageInfo(LUUIConstants.TERMS_OFFERED_LABEL_KEY));
717 return scheduling;
718 }
719
720 protected VerticalSection generateDurationSection() {
721 VerticalSection duration = initSection(getH3Title(LUUIConstants.DURATION_LITERAL_LABEL_KEY), WITH_DIVIDER);
722 duration.setInstructions(getLabel(LUUIConstants.DURATION_LITERAL_LABEL_KEY + "-instruct"));
723 GroupSection duration_group = new GroupSection();
724 addField(duration_group, COURSE + "/" + CreditCourseConstants.DURATION + "/" + "atpDurationTypeKey", generateMessageInfo(LUUIConstants.DURATION_TYPE_LABEL_KEY));
725 addField(duration_group, COURSE + "/" + CreditCourseConstants.DURATION + "/" + "timeQuantity", generateMessageInfo(LUUIConstants.DURATION_QUANTITY_LABEL_KEY));
726
727 duration.addSection(duration_group);
728 return duration;
729 }
730
731 protected VerticalSection generateFinalExamSection() {
732 VerticalSection finalExam = initSection(getH3Title(LUUIConstants.FINAL_EXAM_LABEL_KEY), WITH_DIVIDER);
733 GroupSection finalExam_group = new GroupSection();
734 GroupSection finalExamRationale_group = new GroupSection();
735 GroupSection finalExamRationale_group2 = new GroupSection();
736
737 FieldDescriptor field = addField(finalExam_group, COURSE + "/" + CreditCourseConstants.FINAL_EXAM, generateMessageInfo(LUUIConstants.FINAL_EXAM_STATUS_LABEL_KEY));
738
739 if (field.isVisible()){
740 KSSelectItemWidgetAbstract picker = (KSSelectItemWidgetAbstract) (((KSPicker) field.getFieldWidget()).getInputWidget());
741 final FieldDescriptor rationaleField = addField(finalExamRationale_group, COURSE + "/" + CreditCourseConstants.FINAL_EXAM_RATIONALE, generateMessageInfo(LUUIConstants.FINAL_EXAM_RATIONALE_LABEL_KEY));
742 rationaleField.setIgnoreShowRequired(true);
743 final FieldDescriptor rationaleField2 = addField(finalExamRationale_group2, COURSE + "/" + CreditCourseConstants.FINAL_EXAM_RATIONALE, generateMessageInfo(LUUIConstants.FINAL_EXAM_RATIONALE_LABEL_KEY));
744 rationaleField2.setIgnoreShowRequired(true);
745
746
747 final String altKey = "ALT";
748 final String noneKey = "None";
749 SwapSection swapSection = new SwapSection(picker);
750 swapSection.addSection(finalExamRationale_group, altKey);
751 swapSection.addSection(finalExamRationale_group2, noneKey);
752 swapSection.setSwapEventHandler(new SwapEventHandler() {
753
754 @Override
755 public void onShowSwappableSection(String key, Section section) {
756 progressiveEnableAndRequireSection(true, section);
757 }
758
759 @Override
760 public void onRemoveSwappableSection(String key, Section section) {
761 progressiveEnableAndRequireSection(false, section);
762 }
763 });
764 finalExam.addSection(finalExam_group);
765
766 finalExam.addSection(swapSection);
767 return finalExam;
768 } else {
769 return new VerticalSection();
770 }
771
772 }
773
774 protected void progressiveEnableAndRequireSection(boolean enableAndRequire, Section section){
775 if (section != null){
776 List<FieldDescriptor> fields = section.getFields();
777 if ((fields != null) && (fields.size() > 0)){
778 BaseSection.progressiveEnableAndRequireFields(enableAndRequire, fields.toArray(new FieldDescriptor[fields.size()]));
779 }
780 }
781 }
782
783 protected VerticalSection generateInstructorsSection() {
784 VerticalSection instructors = initSection(getH3Title(LUUIConstants.INSTRUCTOR_LABEL_KEY), WITH_DIVIDER);
785 addField(instructors, COURSE + "/" + PRIMARY_INSTRUCTOR + "/personId");
786 return instructors;
787 }
788
789 protected SectionView generateLearningObjectivesSection() {
790 VerticalSectionView section = initSectionView(CourseSections.LEARNING_OBJECTIVES, LUUIConstants.LEARNING_OBJECTIVES_LABEL_KEY);
791 section.setInstructions(getLabel(LUUIConstants.LEARNING_OBJECTIVES_LABEL_KEY + "-instruct", QueryPath.concat(COURSE, COURSE_SPECIFIC_LOS, "*", "loInfo", "desc", "plain").toString()));
792 section.addSection(generateLearningObjectivesNestedSection());
793 return section;
794 }
795
796 protected VerticalSection generateLearningObjectivesNestedSection() {
797 final VerticalSection los = initSection(null, NO_DIVIDER);
798
799 QueryPath path = QueryPath.concat(COURSE, COURSE_SPECIFIC_LOS, "*", "loInfo", "descr");
800 Metadata meta = modelDefinition.getMetadata(path);
801
802 LOBuilder loBuilder = new LOBuilder(type, state, groupName, "kuali.loRepository.key.singleUse", COURSE_SPECIFIC_LOS, meta);
803 final FieldDescriptor fd = addField(los, CreditCourseConstants.COURSE_SPECIFIC_LOS, null,loBuilder, COURSE);
804
805 loBuilder.addValueChangeHandler(new ValueChangeHandler<List<OutlineNode<LOPicker>>>(){
806 @Override
807 public void onValueChange(ValueChangeEvent<List<OutlineNode<LOPicker>>> event) {
808 los.setIsDirty(true);
809 }
810 });
811
812
813
814 fd.setWidgetBinding(LOBuilderBinding.INSTANCE);
815
816 los.addStyleName("KS-LUM-Section-Divider");
817 return los;
818 }
819
820 public class PersonList extends KSDropDown {
821 final SimpleListItems people = new SimpleListItems();
822
823 public PersonList() {
824 final PersonList us = this;
825 final String userId = Application.getApplicationContext().getSecurityContext().getUserId();
826
827
828 people.addItem(userId, userId);
829 us.setListItems(people);
830 us.selectItem(userId);
831 us.setBlankFirstItem(false);
832 this.setEnabled(false);
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860 }
861
862 @Override
863 public boolean isMultipleSelect() {
864 return true;
865 }
866 }
867
868 public class ProposerPersonList extends KSLabelList {
869 public ProposerPersonList() {
870 SimpleListItems list = new SimpleListItems();
871
872 super.setListItems(list);
873 }
874 }
875
876 protected VerticalSection generateShortTitleSection() {
877 VerticalSection shortTitle = initSection(getH3Title(LUUIConstants.SHORT_TITLE_LABEL_KEY), WITH_DIVIDER);
878 addField(shortTitle, "cluInfo/officialIdentifier/shortName", null);
879 return shortTitle;
880 }
881
882 protected VerticalSectionView initSectionView(Enum<?> viewEnum, String labelKey) {
883 VerticalSectionView section = new VerticalSectionView(viewEnum, getLabel(labelKey), this.getModelId());
884 section.addStyleName(LUUIConstants.STYLE_SECTION);
885 return section;
886 }
887
888
889 protected VerticalSection initSection(SectionTitle title, boolean withDivider) {
890 VerticalSection section;
891 if (title != null) {
892 section = new VerticalSection(title);
893 } else {
894 section = new VerticalSection();
895 }
896 section.addStyleName(LUUIConstants.STYLE_SECTION);
897 if (withDivider)
898 section.addStyleName(LUUIConstants.STYLE_SECTION_DIVIDER);
899 return section;
900 }
901
902 @Override
903 public MessageKeyInfo generateMessageInfo(String labelKey) {
904 return new MessageKeyInfo(groupName, type, state, labelKey);
905 }
906
907
908 protected Section generateFinancialsSection(Section section) {
909
910 VerticalSection justiFee = initSection(getH3Title(LUUIConstants.COURSE_FEE_TITLE), WITH_DIVIDER);
911 SpanPanel courseFeeInstruction = new SpanPanel();
912 courseFeeInstruction.setStyleName("ks-form-module-elements-instruction");
913 courseFeeInstruction.setHTML(getLabel(LUUIConstants.COURSE_FEE_TITLE + FieldLayoutComponent.INSTRUCT_MESSAGE_KEY));
914 courseFeeInstruction.setVisible(true);
915 justiFee.addWidget(courseFeeInstruction);
916
917
918
919 addField(justiFee, COURSE + "/" + "feeJustification" + "/" + RichTextInfoConstants.PLAIN, generateMessageInfo(LUUIConstants.JUSTIFICATION_FEE));
920 section.addSection(justiFee);
921 Map<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>> swappableFieldsDefinition =
922 new HashMap<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>>();
923
924
925
926
927
928
929
930 QueryPath feesPath = QueryPath.concat(COURSE, FEES);
931 QueryPath rateTypeFieldPath = QueryPath.concat(feesPath.toString(), QueryPath.getWildCard(), "rateType");
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
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