Coverage Report - org.kuali.student.lum.lu.ui.course.client.configuration.CourseProposalConfigurer
 
Classes in this File Line Coverage Branch Coverage Complexity
CourseProposalConfigurer
0%
0/371
0%
0/26
1.408
CourseProposalConfigurer$1
0%
0/3
N/A
1.408
CourseProposalConfigurer$2
0%
0/3
N/A
1.408
CourseProposalConfigurer$3
0%
0/3
N/A
1.408
CourseProposalConfigurer$4
0%
0/3
N/A
1.408
CourseProposalConfigurer$5
0%
0/5
N/A
1.408
CourseProposalConfigurer$6
0%
0/3
N/A
1.408
CourseProposalConfigurer$CourseSections
0%
0/4
N/A
1.408
CourseProposalConfigurer$KeyListModelWigetBinding
0%
0/63
0%
0/32
1.408
CourseProposalConfigurer$MultiplicityFieldConfig
0%
0/16
N/A
1.408
CourseProposalConfigurer$PersonList
0%
0/11
N/A
1.408
CourseProposalConfigurer$ProposerPersonList
0%
0/4
N/A
1.408
 
 1  
 /**
 2  
  * Copyright 2010 The Kuali Foundation Licensed under the
 3  
  * Educational Community License, Version 2.0 (the "License"); you may
 4  
  * not use this file except in compliance with the License. You may
 5  
  * obtain a copy of the License at
 6  
  *
 7  
  * http://www.osedu.org/licenses/ECL-2.0
 8  
  *
 9  
  * Unless required by applicable law or agreed to in writing,
 10  
  * software distributed under the License is distributed on an "AS IS"
 11  
  * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 12  
  * or implied. See the License for the specific language governing
 13  
  * permissions and limitations under the License.
 14  
  */
 15  
 
 16  
 /*
 17  
  * Copyright 2009 The Kuali Foundation Licensed under the
 18  
  * Educational Community License, Version 2.0 (the "License"); you may
 19  
  * not use this file except in compliance with the License. You may
 20  
  * obtain a copy of the License at
 21  
  *
 22  
  * http://www.osedu.org/licenses/ECL-2.0
 23  
  *
 24  
  * Unless required by applicable law or agreed to in writing,
 25  
  * software distributed under the License is distributed on an "AS IS"
 26  
  * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 27  
  * or implied. See the License for the specific language governing
 28  
  * permissions and limitations under the License.
 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.assembly.data.Data;
 39  
 import org.kuali.student.common.assembly.data.Data.Value;
 40  
 import org.kuali.student.common.assembly.data.Metadata;
 41  
 import org.kuali.student.common.assembly.data.QueryPath;
 42  
 import org.kuali.student.common.dto.DtoConstants;
 43  
 import org.kuali.student.common.ui.client.application.Application;
 44  
 import org.kuali.student.common.ui.client.configurable.mvc.FieldDescriptor;
 45  
 import org.kuali.student.common.ui.client.configurable.mvc.SectionTitle;
 46  
 import org.kuali.student.common.ui.client.configurable.mvc.binding.HasDataValueBinding;
 47  
 import org.kuali.student.common.ui.client.configurable.mvc.binding.ListOfStringBinding;
 48  
 import org.kuali.student.common.ui.client.configurable.mvc.binding.ModelWidgetBinding;
 49  
 import org.kuali.student.common.ui.client.configurable.mvc.binding.ModelWidgetBindingSupport;
 50  
 import org.kuali.student.common.ui.client.configurable.mvc.multiplicity.CompositeConditionOperator;
 51  
 import org.kuali.student.common.ui.client.configurable.mvc.multiplicity.MultiplicityConfiguration;
 52  
 import org.kuali.student.common.ui.client.configurable.mvc.multiplicity.MultiplicityFieldConfiguration;
 53  
 import org.kuali.student.common.ui.client.configurable.mvc.multiplicity.MultiplicityFieldWidgetInitializer;
 54  
 import org.kuali.student.common.ui.client.configurable.mvc.multiplicity.SwapCompositeCondition;
 55  
 import org.kuali.student.common.ui.client.configurable.mvc.multiplicity.SwapCompositeConditionFieldConfig;
 56  
 import org.kuali.student.common.ui.client.configurable.mvc.multiplicity.SwapCondition;
 57  
 import org.kuali.student.common.ui.client.configurable.mvc.sections.BaseSection;
 58  
 import org.kuali.student.common.ui.client.configurable.mvc.sections.CollapsableSection;
 59  
 import org.kuali.student.common.ui.client.configurable.mvc.sections.GroupSection;
 60  
 import org.kuali.student.common.ui.client.configurable.mvc.sections.MultiplicitySection;
 61  
 import org.kuali.student.common.ui.client.configurable.mvc.sections.Section;
 62  
 import org.kuali.student.common.ui.client.configurable.mvc.sections.SwapEventHandler;
 63  
 import org.kuali.student.common.ui.client.configurable.mvc.sections.SwapSection;
 64  
 import org.kuali.student.common.ui.client.configurable.mvc.sections.VerticalSection;
 65  
 import org.kuali.student.common.ui.client.configurable.mvc.views.SectionView;
 66  
 import org.kuali.student.common.ui.client.configurable.mvc.views.VerticalSectionView;
 67  
 import org.kuali.student.common.ui.client.mvc.Controller;
 68  
 import org.kuali.student.common.ui.client.mvc.DataModel;
 69  
 import org.kuali.student.common.ui.client.mvc.DataModelDefinition;
 70  
 import org.kuali.student.common.ui.client.mvc.HasDataValue;
 71  
 import org.kuali.student.common.ui.client.mvc.View;
 72  
 import org.kuali.student.common.ui.client.widgets.KSButton;
 73  
 import org.kuali.student.common.ui.client.widgets.KSButtonAbstract.ButtonStyle;
 74  
 import org.kuali.student.common.ui.client.widgets.KSCharCount;
 75  
 import org.kuali.student.common.ui.client.widgets.KSCheckBox;
 76  
 import org.kuali.student.common.ui.client.widgets.KSDropDown;
 77  
 import org.kuali.student.common.ui.client.widgets.ListOfStringWidget;
 78  
 import org.kuali.student.common.ui.client.widgets.field.layout.element.MessageKeyInfo;
 79  
 import org.kuali.student.common.ui.client.widgets.field.layout.element.SpanPanel;
 80  
 import org.kuali.student.common.ui.client.widgets.field.layout.layouts.FieldLayoutComponent;
 81  
 import org.kuali.student.common.ui.client.widgets.list.KSLabelList;
 82  
 import org.kuali.student.common.ui.client.widgets.list.KSSelectItemWidgetAbstract;
 83  
 import org.kuali.student.common.ui.client.widgets.list.KSSelectedList;
 84  
 import org.kuali.student.common.ui.client.widgets.list.impl.SimpleListItems;
 85  
 import org.kuali.student.common.ui.client.widgets.search.KSPicker;
 86  
 import org.kuali.student.core.comments.ui.client.widgets.commenttool.CommentTool;
 87  
 import org.kuali.student.core.comments.ui.client.widgets.decisiontool.DecisionPanel;
 88  
 import org.kuali.student.core.document.ui.client.widgets.documenttool.DocumentTool;
 89  
 import org.kuali.student.core.statement.dto.StatementTypeInfo;
 90  
 import org.kuali.student.core.workflow.ui.client.views.CollaboratorSectionView;
 91  
 import org.kuali.student.lum.common.client.lo.LOBuilder;
 92  
 import org.kuali.student.lum.common.client.lo.LOBuilderBinding;
 93  
 import org.kuali.student.lum.common.client.lo.LOPicker;
 94  
 import org.kuali.student.lum.common.client.lo.OutlineNode;
 95  
 import org.kuali.student.lum.common.client.lu.LUUIConstants;
 96  
 import org.kuali.student.lum.lu.assembly.data.client.constants.base.RichTextInfoConstants;
 97  
 import org.kuali.student.lum.lu.assembly.data.client.constants.orch.CreditCourseActivityConstants;
 98  
 import org.kuali.student.lum.lu.assembly.data.client.constants.orch.CreditCourseConstants;
 99  
 import org.kuali.student.lum.lu.assembly.data.client.constants.orch.CreditCourseJointsConstants;
 100  
 import org.kuali.student.lum.lu.ui.course.client.controllers.CourseProposalController;
 101  
 import org.kuali.student.lum.lu.ui.course.client.requirements.CourseRequirementsViewController;
 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  
  * This is the configuration factory class for creating a proposal.
 113  
  *
 114  
  * @author Kuali Student Team
 115  
  */
 116  0
 public class CourseProposalConfigurer extends AbstractCourseConfigurer {
 117  
 
 118  0
     protected boolean WITH_DIVIDER = true;
 119  0
     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  0
     public enum CourseSections {
 134  0
         CLU_BEGIN, PEOPLE_PERMISSONS, SUMMARY, AUTHORS_RATIONALE, GOVERNANCE, COURSE_LOGISTICS, COURSE_INFO, LEARNING_OBJECTIVES,
 135  0
         COURSE_REQUISITES, ACTIVE_DATES, FINANCIALS, ATTACHMENTS, COMMENTS, DECISIONS, DOCUMENTS,
 136  0
         PROGRAM_INFO, ASSEMBLER_TEST, WF_APPROVE_DIALOG
 137  
     }
 138  
 
 139  
     public void setStatementTypes(List<StatementTypeInfo> stmtTypes) {
 140  0
         this.stmtTypes = stmtTypes;
 141  0
     }
 142  
 
 143  
     /**
 144  
      * Sets up all the views, sections, and views of the CourseProposalController.  This should be called
 145  
      * once for initialization and setup per CourseProposalController instance.
 146  
      * 
 147  
      * @param layout
 148  
      */
 149  
     public void configure(final CourseProposalController layout) {
 150  0
             type = "course";
 151  0
         state = DtoConstants.STATE_DRAFT;
 152  0
             groupName = LUUIConstants.COURSE_GROUP_NAME;
 153  
 
 154  0
             if (modelDefinition.getMetadata().isCanEdit()) {
 155  0
                 addCluStartSection(layout);
 156  0
             String sections = getLabel(LUUIConstants.COURSE_SECTIONS);
 157  
 
 158  
             //ProposalInformation
 159  
             //layout.addSection(new String[] {editTabLabel, getLabel(LUConstants.PROPOSAL_INFORMATION_LABEL_KEY)}, generateAuthorsRationaleSection());
 160  
 
 161  0
             layout.addMenu(sections);
 162  
             
 163  
             
 164  
             //Course Content
 165  0
             layout.addMenuItem(sections, (SectionView)generateCourseInfoSection(initSectionView(CourseSections.COURSE_INFO, LUUIConstants.INFORMATION_LABEL_KEY)));
 166  0
             layout.addMenuItem(sections, (SectionView)generateGovernanceSection(initSectionView(CourseSections.GOVERNANCE, LUUIConstants.GOVERNANCE_LABEL_KEY)));
 167  0
             layout.addMenuItem(sections, (SectionView)generateCourseLogisticsSection(initSectionView(CourseSections.COURSE_LOGISTICS, LUUIConstants.LOGISTICS_LABEL_KEY)));
 168  0
             layout.addMenuItem(sections, generateLearningObjectivesSection());
 169  
 
 170  
             //Student Eligibility
 171  0
             layout.addMenuItem(sections, generateCourseRequisitesSection(layout,true));
 172  
 
 173  
             //Administrative
 174  0
             layout.addMenuItem(sections, (SectionView)generateActiveDatesSection(initSectionView(CourseSections.ACTIVE_DATES, LUUIConstants.ACTIVE_DATES_LABEL_KEY)));
 175  0
             layout.addMenuItem(sections, (SectionView)generateFinancialsSection(initSectionView(CourseSections.FINANCIALS, LUUIConstants.FINANCIALS_LABEL_KEY)));
 176  
             
 177  
             //Authors & Collaborators
 178  0
             layout.addMenuItem(sections, new CollaboratorSectionView(CourseSections.PEOPLE_PERMISSONS, getLabel(LUUIConstants.SECTION_AUTHORS_AND_COLLABORATORS), COURSE_PROPOSAL_MODEL));
 179  
             
 180  
             //Documents
 181  0
             documentTool = new DocumentTool(LUUIConstants.REF_DOC_RELATION_PROPOSAL_TYPE,CourseSections.DOCUMENTS, getLabel(LUUIConstants.TOOL_DOCUMENTS_LABEL_KEY));
 182  0
             documentTool.setModelDefinition((DataModelDefinition)modelDefinition);
 183  0
             layout.addMenuItem(sections, documentTool);
 184  
             
 185  
             //Summary
 186  0
             summaryConfigurer = GWT.create(CourseSummaryConfigurer.class);
 187  0
             summaryConfigurer.init(type, state, groupName,(DataModelDefinition)modelDefinition, stmtTypes, (Controller)layout, COURSE_PROPOSAL_MODEL);
 188  0
             layout.addSpecialMenuItem(summaryConfigurer.generateProposalSummarySection(true), "Review and Submit");
 189  
             
 190  
             //Add common buttons to sections except for sections with specific button behavior
 191  0
             List<Enum<?>> excludedViews = new ArrayList<Enum<?>>();
 192  0
             excludedViews.add(CourseSections.DOCUMENTS);
 193  0
             excludedViews.add(CourseSections.COURSE_REQUISITES);
 194  0
             layout.addCommonButton(LUUIConstants.COURSE_SECTIONS, layout.getSaveButton(), excludedViews);
 195  0
             layout.addCommonButton(LUUIConstants.COURSE_SECTIONS, layout.getCancelButton(CourseSections.SUMMARY), excludedViews);
 196  
 
 197  
             //Specific buttons for certain views
 198  
             //TODO people and permissions will use a different button than continue
 199  0
             layout.addButtonForView(CourseSections.DOCUMENTS, getContinueButton(layout));
 200  0
         }
 201  
         else{
 202  0
                  summaryConfigurer = GWT.create(CourseSummaryConfigurer.class);
 203  0
                  summaryConfigurer.init(type, state, groupName, (DataModelDefinition)modelDefinition, stmtTypes, (Controller)layout, COURSE_PROPOSAL_MODEL);
 204  0
                  layout.removeMenuNavigation();
 205  0
              layout.addView(summaryConfigurer.generateProposalSummarySection(false));
 206  
         }
 207  0
         layout.showPrint(true);
 208  0
         layout.setDefaultView(CourseSections.SUMMARY);
 209  0
         layout.addContentWidget(layout.getWfUtilities().getProposalStatusLabel());
 210  0
         final CommentTool commentTool = new CommentTool(CourseSections.COMMENTS, getLabel(LUUIConstants.TOOL_COMMENTS_LABEL_KEY), "kuali.comment.type.generalRemarks", "Proposal Comments");
 211  0
         commentTool.setController(layout);
 212  
         
 213  0
         layout.addContentWidget(new KSButton("Comments", ButtonStyle.DEFAULT_ANCHOR, new ClickHandler() {
 214  
             
 215  
             @Override
 216  
             public void onClick(ClickEvent event) {
 217  0
                 commentTool.show();
 218  0
             }
 219  
         }));
 220  
 
 221  
         
 222  0
         final DecisionPanel decisionPanel = new DecisionPanel(CourseSections.DECISIONS, getLabel(LUUIConstants.TOOL_DECISION_LABEL_KEY), "kuali.comment.type.generalRemarks");
 223  0
         layout.addView(decisionPanel);
 224  0
         layout.addContentWidget(new KSButton("Decisions", ButtonStyle.DEFAULT_ANCHOR, new ClickHandler() {
 225  
 
 226  
             @Override
 227  
             public void onClick(ClickEvent event) {
 228  0
                     decisionPanel.show();
 229  0
             }
 230  
         }));
 231  
         
 232  0
     }
 233  
     
 234  
     protected KSButton getContinueButton(final CourseProposalController layout){
 235  0
         return new KSButton("Continue", new ClickHandler(){
 236  
                     public void onClick(ClickEvent event) {
 237  0
                             layout.showNextViewOnMenu();
 238  0
                     }
 239  
                 });
 240  
     }
 241  
 
 242  
     public void addCluStartSection(CourseProposalController layout) {
 243  0
         VerticalSectionView section = initSectionView(CourseSections.CLU_BEGIN, LUUIConstants.START_LABEL_KEY);
 244  0
         section.setController(layout);
 245  0
         addField(section, PROPOSAL_TITLE_PATH, generateMessageInfo(LUUIConstants.PROPOSAL_TITLE_LABEL_KEY));
 246  0
         addField(section, COURSE + "/" + COURSE_TITLE, generateMessageInfo(LUUIConstants.COURSE_TITLE_LABEL_KEY));
 247  
         //addField(section, "proposal/rationale", generateMessageInfo(LUConstants.PROPOSAL_RATIONALE_LABEL_KEY));
 248  
         //addField(section, PROPOSAL + "/" + PROPOSER_PERSON, generateMessageInfo(LUConstants.PROPOSAL_PERSON_LABEL_KEY), new PersonList()) ;
 249  0
         layout.addStartViewPopup(section);
 250  0
         layout.getStartPopup().setMaxHeight(600);
 251  0
     }
 252  
 
 253  
     protected View generateCourseRequisitesSection(Controller layout, boolean showSaveButtons) {
 254  0
         return new CourseRequirementsViewController(layout, getLabel(LUUIConstants.REQUISITES_LABEL_KEY), CourseSections.COURSE_REQUISITES, false, showSaveButtons);
 255  
     }
 256  
 
 257  
     protected Section generateActiveDatesSection(Section section) {
 258  
         //Add this field and hide it so it is available for cross field validation 
 259  0
             FieldDescriptor fd = addField(section, PROPOSAL_PATH + "/" + PREV_START_TERM, generateMessageInfo(LUUIConstants.PROPOSAL_PREV_START_TERM));
 260  0
         fd.getFieldWidget().setVisible(false);
 261  0
         fd.hideLabel();
 262  
         
 263  0
             addField(section, COURSE + "/" + START_TERM, generateMessageInfo(LUUIConstants.START_TERM_LABEL_KEY));
 264  
             
 265  0
         addField(section, COURSE + "/" + PILOT_COURSE, generateMessageInfo(LUUIConstants.PILOT_COURSE_LABEL_KEY), new KSCheckBox(getLabel(LUUIConstants.PILOT_COURSE_TEXT_LABEL_KEY))).setIgnoreShowRequired(true);
 266  0
         addField(section, COURSE + "/" + END_TERM, generateMessageInfo(LUUIConstants.END_TERM_LABEL_KEY)).setIgnoreShowRequired(true);
 267  
 
 268  0
         return section;
 269  
     }
 270  
     
 271  
     protected VerticalSection generateActiveDateEndSection() {
 272  0
         VerticalSection endDate = initSection(getH3Title(LUUIConstants.END_DATE_LABEL_KEY), WITH_DIVIDER);
 273  0
         addField(endDate, COURSE + "/" + EXPIRATION_DATE, generateMessageInfo(LUUIConstants.EXPIRATION_DATE_LABEL_KEY));
 274  0
         return endDate;
 275  
     }
 276  
 
 277  
     protected VerticalSection generateActiveDateStartSection() {
 278  0
         VerticalSection startDate = initSection(getH3Title(LUUIConstants.START_DATE_LABEL_KEY), WITH_DIVIDER);
 279  0
         addField(startDate, COURSE + "/" + CreditCourseConstants.EFFECTIVE_DATE, generateMessageInfo(LUUIConstants.EFFECTIVE_DATE_LABEL_KEY));
 280  0
         return startDate;
 281  
     }
 282  
 
 283  
     protected Section generateGovernanceSection(Section section) {
 284  0
         addField(section, COURSE + "/" + CAMPUS_LOCATIONS, generateMessageInfo(LUUIConstants.CAMPUS_LOCATION_LABEL_KEY));
 285  0
         addField(section, COURSE + "/" + CURRICULUM_OVERSIGHT_ORGS_, generateMessageInfo(LUUIConstants.ACADEMIC_SUBJECT_ORGS_KEY));
 286  0
         addField(section, COURSE + "/" + ADMIN_ORGS, generateMessageInfo(LUUIConstants.ADMIN_ORG_LABEL_KEY));
 287  
 
 288  0
         return section;
 289  
     }
 290  
 
 291  
     public Section generateCourseInfoSection(Section section) {
 292  0
         addField(section, PROPOSAL_TITLE_PATH, generateMessageInfo(LUUIConstants.PROPOSAL_TITLE_LABEL_KEY));
 293  0
         addField(section, COURSE + "/" + COURSE_TITLE, generateMessageInfo(LUUIConstants.COURSE_TITLE_LABEL_KEY));
 294  0
         addField(section, COURSE + "/" + TRANSCRIPT_TITLE, generateMessageInfo(LUUIConstants.SHORT_TITLE_LABEL_KEY), new KSCharCount(getMetaData(COURSE + "/" + TRANSCRIPT_TITLE)));
 295  0
         section.addSection(generateCourseNumberSection());
 296  0
             FieldDescriptor instructorsFd = addField(section, COURSE + "/" + INSTRUCTORS, generateMessageInfo(LUUIConstants.INSTRUCTORS_LABEL_KEY));
 297  0
         instructorsFd.setWidgetBinding(new KeyListModelWigetBinding("personId"));
 298  
 
 299  0
         section.addSection(generateDescriptionRationaleSection());
 300  
         
 301  0
         return section;
 302  
     }
 303  
             
 304  
 
 305  
     protected GroupSection generateCourseNumberSection() {
 306  
 
 307  
         //COURSE NUMBER
 308  0
         GroupSection courseNumber = new GroupSection(getH4Title(""));
 309  0
         courseNumber.addStyleName(LUUIConstants.STYLE_SECTION);
 310  0
         courseNumber.addStyleName(LUUIConstants.STYLE_SECTION_DIVIDER);
 311  0
         addField(courseNumber, COURSE + "/" + SUBJECT_AREA, generateMessageInfo(LUUIConstants.SUBJECT_CODE_LABEL_KEY));
 312  0
         addField(courseNumber, COURSE + "/" + COURSE_NUMBER_SUFFIX, generateMessageInfo(LUUIConstants.COURSE_NUMBER_LABEL_KEY));
 313  
 //        addField(courseNumber, COURSE + "/" + SUBJECT_AREA);
 314  
 //        addField(courseNumber, COURSE + "/" + COURSE_NUMBER_SUFFIX);
 315  
 
 316  0
         courseNumber.addSection(generateCrossListed_Ver_Joint_Section());
 317  
 
 318  0
         return courseNumber;
 319  
     }
 320  
 
 321  
     protected CollapsableSection generateCrossListed_Ver_Joint_Section() {
 322  0
         CollapsableSection result = new CollapsableSection(getLabel(LUUIConstants.CL_V_J_LABEL_KEY));
 323  
 
 324  
 //        addField(result, COURSE + "/" + CROSS_LISTINGS, null, new CrossListedList(COURSE + "/" + CROSS_LISTINGS));
 325  
 //        addField(result, COURSE + "/" + JOINTS, null, new OfferedJointlyList(COURSE + "/" + JOINTS));
 326  
 //        addField(result, COURSE + "/" + VERSIONS, null, new VersionCodeList(COURSE + "/" + VERSIONS));
 327  0
         SpanPanel crslabelpan = new SpanPanel();
 328  0
         crslabelpan.setStyleName("ks-multiplicity-section-label");
 329  0
         crslabelpan.setHTML("Cross Listed Courses");
 330  0
         crslabelpan.setVisible(true);
 331  0
         result.addWidget(crslabelpan);
 332  0
         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  0
         SpanPanel jntlabelpan = new SpanPanel();
 345  0
         jntlabelpan.setStyleName("ks-multiplicity-section-label");
 346  0
         jntlabelpan.setHTML("Jointly Offered Courses");
 347  0
         jntlabelpan.setVisible(true);
 348  0
         result.addWidget(jntlabelpan);
 349  0
         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  0
         SpanPanel vsnlabelpan = new SpanPanel();
 359  0
         vsnlabelpan.setStyleName("ks-multiplicity-section-label");
 360  0
         vsnlabelpan.setHTML("Version Codes");
 361  0
         vsnlabelpan.setVisible(true);
 362  0
         result.addWidget(vsnlabelpan);
 363  0
         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  0
         result.getLayout().setVisible(false);
 377  0
         return result;
 378  
     }
 379  
     
 380  
     protected void addFeeMultiplicityFields(Section section,  
 381  
             String path, String addItemlabelMessageKey,
 382  
             String itemLabelMessageKey, List<MultiplicityFieldConfig> fieldConfigs,
 383  
             Map<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>> swappableFieldsDefinition,
 384  
             List<String> deletionParentKeys) {
 385  0
         MultiplicityConfiguration config = setupMultiplicityConfig(
 386  
                 MultiplicityConfiguration.MultiplicityType.GROUP,
 387  
                 MultiplicityConfiguration.StyleType.TOP_LEVEL_GROUP,
 388  
                 path, addItemlabelMessageKey, itemLabelMessageKey,
 389  
                 fieldConfigs, swappableFieldsDefinition, deletionParentKeys);
 390  0
         MultiplicitySection ms = null;
 391  0
         ms = new MultiplicitySection(config, swappableFieldsDefinition, deletionParentKeys);
 392  0
         section.addSection(ms);
 393  
 
 394  0
     }
 395  
     
 396  
     protected MultiplicityConfiguration setupMultiplicityConfig(
 397  
             MultiplicityConfiguration.MultiplicityType multiplicityType,
 398  
             MultiplicityConfiguration.StyleType styleType,
 399  
             String path, String addItemlabelMessageKey,
 400  
             String itemLabelMessageKey, List<MultiplicityFieldConfig> fieldConfigs,
 401  
             Map<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>> swappableFieldsDefinition,
 402  
             List<String> deletionParentKeys) {
 403  0
         QueryPath parentPath = QueryPath.concat(path);
 404  0
         MultiplicityConfiguration config = new MultiplicityConfiguration(multiplicityType,
 405  
                 styleType, getMetaData(parentPath.toString()));
 406  0
         config.setAddItemLabel(getLabel(addItemlabelMessageKey));
 407  0
         config.setItemLabel(getLabel(itemLabelMessageKey));
 408  0
         config.setUpdateable(true);
 409  
 
 410  0
         FieldDescriptor parentFd = buildMultiplicityParentFieldDescriptor(path, getLabel(itemLabelMessageKey), null);
 411  0
         config.setParent(parentFd);
 412  
 
 413  0
         if (fieldConfigs != null) {
 414  0
             for (MultiplicityFieldConfig fieldConfig : fieldConfigs) {
 415  0
                 MultiplicityFieldConfiguration fc = buildMultiplicityFD(fieldConfig.getFieldKey(),
 416  
                         fieldConfig.getLabelKey(), parentPath.toString());
 417  0
                 config.addFieldConfiguration(fc);
 418  0
                 if (fieldConfig.isNextLine()) {
 419  0
                     config.nextLine();
 420  
                 }
 421  0
             }
 422  
         }
 423  0
         return config;
 424  
     }
 425  
 
 426  
     protected MultiplicitySection addMultiplicityFields(Section section,  
 427  
             String path, String addItemlabelMessageKey,
 428  
             String itemLabelMessageKey, List<MultiplicityFieldConfig> fieldConfigs,
 429  
             Map<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>> swappableFieldsDefinition,
 430  
             List<String> deletionParentKeys,int defaultItemsCreated) {
 431  0
         MultiplicityConfiguration config = setupMultiplicityConfig(
 432  
                 MultiplicityConfiguration.MultiplicityType.GROUP,
 433  
                 MultiplicityConfiguration.StyleType.TOP_LEVEL_GROUP,
 434  
                 path, addItemlabelMessageKey, itemLabelMessageKey,
 435  
                 fieldConfigs, swappableFieldsDefinition, deletionParentKeys);
 436  0
         config.setDefaultItemsCreated(defaultItemsCreated);
 437  0
         MultiplicitySection ms = null;
 438  0
         ms = new MultiplicitySection(config, swappableFieldsDefinition, deletionParentKeys);
 439  0
         section.addSection(ms);
 440  0
         return ms;
 441  
     }
 442  
 
 443  
     protected Metadata getMetaData(String fieldKey) {
 444  0
         return modelDefinition.getMetadata(QueryPath.concat(fieldKey));
 445  
     }
 446  
 
 447  
     protected MultiplicityFieldConfiguration buildMultiplicityFD(
 448  
             String fieldKey, String labelKey, String parentPath) {
 449  
 
 450  0
         QueryPath fieldPath = QueryPath.concat(parentPath, QueryPath.getWildCard(), fieldKey);
 451  0
         Metadata meta = modelDefinition.getMetadata(fieldPath);
 452  
 
 453  0
         MultiplicityFieldConfiguration fd = new MultiplicityFieldConfiguration(
 454  
                 fieldPath.toString(), generateMessageInfo(labelKey), meta, null);
 455  
         
 456  
 
 457  0
         return fd;
 458  
 
 459  
     }
 460  
 
 461  
     protected FieldDescriptor buildMultiplicityParentFieldDescriptor(String fieldKey, String messageKey, String parentPath) {
 462  0
         QueryPath path = QueryPath.concat(parentPath, fieldKey);
 463  0
         Metadata meta = modelDefinition.getMetadata(path);
 464  
 
 465  0
         FieldDescriptor fd = new FieldDescriptor(path.toString(), generateMessageInfo(messageKey), meta);
 466  0
         fd.hideLabel();
 467  0
         return fd;
 468  
     }
 469  
 
 470  
     protected VerticalSection generateCourseInfoShortTitleSection() {
 471  0
         VerticalSection shortTitle = initSection(getH3Title(LUUIConstants.SHORT_TITLE_LABEL_KEY), WITH_DIVIDER);
 472  0
         addField(shortTitle, COURSE + "/" + TRANSCRIPT_TITLE, null);
 473  0
         return shortTitle;
 474  
     }
 475  
 
 476  
     protected VerticalSection generateLongTitleSection() {
 477  0
         VerticalSection longTitle = initSection(getH3Title(LUUIConstants.TITLE_LABEL_KEY), WITH_DIVIDER);
 478  0
         addField(longTitle, COURSE + "/" + COURSE_TITLE, null);
 479  0
         return longTitle;
 480  
     }
 481  
 
 482  
     protected VerticalSection generateDescriptionRationaleSection() {
 483  0
         SectionTitle title = getH4Title(LUUIConstants.PROPOSAL_TITLE_SECTION_LABEL_KEY);
 484  0
         VerticalSection description = initSection(title, !WITH_DIVIDER);
 485  0
         title.setStyleName("cluProposalTitleSection");
 486  
         //FIXME [KSCOR-225] Temporary fix til we have a real rich text editor
 487  
         //addField(description, COURSE + "/" + DESCRIPTION, null);
 488  0
         addField(description, COURSE + "/" + DESCRIPTION + "/" + RichTextInfoConstants.PLAIN, generateMessageInfo(LUUIConstants.DESCRIPTION_LABEL_KEY));
 489  0
         addField(description, "proposal/rationale", generateMessageInfo(LUUIConstants.PROPOSAL_RATIONALE_LABEL_KEY),
 490  
                 new KSCharCount(modelDefinition.getMetadata(QueryPath.parse("proposal/rationale"))));
 491  
 
 492  0
         return description;
 493  
     }
 494  
 
 495  
     public Section generateCourseLogisticsSection(Section section) {
 496  0
             if (section instanceof SectionView){
 497  0
                     ((SectionView)section).setInstructions(getLabel(LUUIConstants.LOGISTICS_LABEL_KEY + "-instruct") + "<br><br>");
 498  
             }
 499  
 
 500  0
         section.addSection(generateSchedulingSection());
 501  0
         section.addSection(generateDurationSection());
 502  0
         section.addSection(generateLearningResultsSection());
 503  0
         section.addSection(generateCourseFormatsSection());
 504  
 
 505  0
         return section;
 506  
     }
 507  
 
 508  
     protected Section generateLearningResultsSection() {
 509  0
         VerticalSection learningResults = initSection(getH3Title(LUUIConstants.LEARNING_RESULTS_LABEL_KEY), WITH_DIVIDER);
 510  0
         learningResults.setInstructions(getLabel(LUUIConstants.LEARNING_RESULTS_LABEL_KEY + "-instruct") + "<br><br><br>");
 511  
 
 512  0
         learningResults.addSection(generateGradesAssessmentsSection());
 513  0
         learningResults.addSection(generateStudentRegistrationOptionsSection());
 514  0
         learningResults.addSection(generateFinalExamSection());
 515  0
         learningResults.addSection(generateOutcomesSection());
 516  
 
 517  0
         return learningResults;
 518  
     }
 519  
 
 520  
     protected Section generateOutcomesSection() {
 521  
 
 522  0
         String path = COURSE + QueryPath.getPathSeparator() + CREDIT_OPTIONS;
 523  0
         QueryPath creditTypeFullPath = QueryPath.concat(path, QueryPath.getWildCard(), CreditCourseConstants.TYPE);
 524  0
         QueryPath creditOptionFixedFullPath = QueryPath.concat(path, QueryPath.getWildCard(), CREDIT_OPTION_FIXED_CREDITS);
 525  0
         QueryPath creditOptionMinFullPath = QueryPath.concat(path, QueryPath.getWildCard(), CREDIT_OPTION_MIN_CREDITS);
 526  0
         QueryPath creditOptionMaxFullPath = QueryPath.concat(path, QueryPath.getWildCard(), CREDIT_OPTION_MAX_CREDITS);
 527  0
         QueryPath creditResultValuesFullPath = QueryPath.concat(path, QueryPath.getWildCard(), "resultValues");
 528  
 
 529  0
         VerticalSection courseOutcomes = initSection(getH3Title(LUUIConstants.LEARNING_RESULT_OUTCOME_LABEL_KEY), WITH_DIVIDER);
 530  0
         Map<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>> swappableFieldsDefinition =
 531  
             new HashMap<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>>();
 532  0
         SwapCompositeCondition fixedCreditCondition = new SwapCompositeCondition(
 533  
                 CompositeConditionOperator.AND);
 534  0
         fixedCreditCondition.getChildrenConditions().add(
 535  
                 makeCondition(creditTypeFullPath, LUUIConstants.LEARNING_RESULT_OUTCOME_TYPE_LABEL_KEY, "kuali.resultComponentType.credit.degree.fixed")
 536  
         );
 537  0
         fixedCreditCondition.setConditionId("1");
 538  0
         SwapCompositeCondition multipleCreditCondition = new SwapCompositeCondition(
 539  
                 CompositeConditionOperator.AND);
 540  0
         multipleCreditCondition.getChildrenConditions().add(
 541  
                 makeCondition(creditTypeFullPath, LUUIConstants.LEARNING_RESULT_OUTCOME_TYPE_LABEL_KEY, "kuali.resultComponentType.credit.degree.multiple")
 542  
         );
 543  0
         multipleCreditCondition.setConditionId("2");
 544  0
         SwapCompositeCondition variableCreditCondition = new SwapCompositeCondition(
 545  
                 CompositeConditionOperator.AND);
 546  0
         variableCreditCondition.getChildrenConditions().add(
 547  
                 makeCondition(creditTypeFullPath, LUUIConstants.LEARNING_RESULT_OUTCOME_TYPE_LABEL_KEY, "kuali.resultComponentType.credit.degree.range")
 548  
         );
 549  0
         variableCreditCondition.setConditionId("3");
 550  
         
 551  0
         swappableFieldsDefinition.put(fixedCreditCondition,
 552  
                 Arrays.asList(
 553  
                         new SwapCompositeConditionFieldConfig(
 554  
                                 new MultiplicityFieldConfiguration(
 555  
                                         creditOptionFixedFullPath.toString(), 
 556  
                                         generateMessageInfo(LUUIConstants.CREDIT_OPTION_FIXED_CREDITS_LABEL_KEY),
 557  
                                         modelDefinition.getMetadata(creditOptionFixedFullPath),
 558  
                                         null),
 559  
                                 null
 560  
                         )
 561  
                 )
 562  
         );
 563  0
         MultiplicityFieldWidgetInitializer multipleCreditInitializer = 
 564  0
             new MultiplicityFieldWidgetInitializer() {
 565  
                 @Override
 566  
                 public ModelWidgetBinding<?> getModelWidgetBindingInstance() {
 567  0
                     return new ListOfStringBinding();
 568  
                 }
 569  
                 @Override
 570  
                 public Widget getNewWidget() {
 571  0
                     return new ListOfStringWidget("Add Item");
 572  
                 }
 573  
         };
 574  
         
 575  0
         swappableFieldsDefinition.put(multipleCreditCondition,
 576  
                 Arrays.asList(
 577  
                         new SwapCompositeConditionFieldConfig(
 578  
                                 new MultiplicityFieldConfiguration(
 579  
                                         creditResultValuesFullPath.toString(),
 580  
                                         generateMessageInfo(LUUIConstants.CREDIT_OPTION_FIXED_CREDITS_LABEL_KEY),
 581  
                                         modelDefinition.getMetadata(creditResultValuesFullPath),
 582  
                                         multipleCreditInitializer),
 583  
                                 null
 584  
                         )
 585  
                 )
 586  
         );
 587  0
         swappableFieldsDefinition.put(variableCreditCondition,
 588  
                 Arrays.asList(
 589  
                         new SwapCompositeConditionFieldConfig(
 590  
                                 new MultiplicityFieldConfiguration(
 591  
                                         creditOptionMinFullPath.toString(), 
 592  
                                         generateMessageInfo(LUUIConstants.CREDIT_OPTION_MIN_CREDITS_LABEL_KEY),
 593  
                                         modelDefinition.getMetadata(creditOptionMinFullPath),
 594  
                                         null),
 595  
                                 null
 596  
                         ),
 597  
                         new SwapCompositeConditionFieldConfig(
 598  
                                 new MultiplicityFieldConfiguration(
 599  
                                         creditOptionMaxFullPath.toString(), 
 600  
                                         generateMessageInfo(LUUIConstants.CREDIT_OPTION_MAX_CREDITS_LABEL_KEY),
 601  
                                         modelDefinition.getMetadata(creditOptionMaxFullPath),
 602  
                                         null),
 603  
                                 null
 604  
                         )
 605  
                 )
 606  
         );
 607  
         
 608  0
         MultiplicitySection ms = addMultiplicityFields(
 609  
                 courseOutcomes, 
 610  
                 path, 
 611  
                 LUUIConstants.LEARNING_RESULT_OUTCOME_LABEL_KEY,
 612  
                 LUUIConstants.LEARNING_RESULT_OUTCOME_LABEL_KEY,
 613  
                 Arrays.asList(
 614  
                                 new MultiplicityFieldConfig(
 615  
                                 CreditCourseConstants.TYPE,
 616  
                                 LUUIConstants.LEARNING_RESULT_OUTCOME_TYPE_LABEL_KEY,
 617  
                                 null, null, true)
 618  
                 ), swappableFieldsDefinition, null,1);
 619  
         //Set the required panel
 620  0
         courseOutcomes.setRequired(ms.getConfig().getParentFd().getFieldElement().getRequiredPanel());
 621  0
         return courseOutcomes;
 622  
 
 623  
     }
 624  
 
 625  
     protected Section generateStudentRegistrationOptionsSection() {
 626  0
         VerticalSection studentRegistrationOptionsSection = initSection(getH3Title(LUUIConstants.LEARNING_RESULTS_STUDENT_REGISTRATION_LABEL_KEY), WITH_DIVIDER);
 627  
 
 628  0
         addField(studentRegistrationOptionsSection, COURSE + "/" + AUDIT, generateMessageInfo(LUUIConstants.LEARNING_RESULT_AUDIT_LABEL_KEY), new KSCheckBox(getLabel(LUUIConstants.LEARNING_RESULT_AUDIT_TEXT_LABEL_KEY)));
 629  0
         addField(studentRegistrationOptionsSection, COURSE + "/" + PASS_FAIL, generateMessageInfo(LUUIConstants.LEARNING_RESULT_PASS_FAIL_LABEL_KEY), new KSCheckBox(getLabel(LUUIConstants.LEARNING_RESULT_PASS_FAIL_TEXT_LABEL_KEY)));
 630  
 
 631  0
         return studentRegistrationOptionsSection;
 632  
     }
 633  
 
 634  
     protected Section generateGradesAssessmentsSection() {
 635  0
         VerticalSection gradesAssessments = initSection(getH3Title(LUUIConstants.LEARNING_RESULTS_GRADES_ASSESSMENTS_LABEL_KEY), WITH_DIVIDER);
 636  
 
 637  0
         addField(gradesAssessments, COURSE + "/" + GRADING_OPTIONS, generateMessageInfo(LUUIConstants.LEARNING_RESULT_ASSESSMENT_SCALE_LABEL_KEY));
 638  
 
 639  0
         return gradesAssessments;
 640  
     }
 641  
 
 642  
     protected VerticalSection generateCourseFormatsSection() {
 643  
         //COURSE FORMATS
 644  0
         VerticalSection courseFormats = initSection(getH3Title(LUUIConstants.FORMATS_LABEL_KEY), WITH_DIVIDER);
 645  0
         courseFormats.setHelp(getLabel(LUUIConstants.FORMATS_LABEL_KEY + "-help"));
 646  0
         courseFormats.setInstructions(getLabel(LUUIConstants.FORMATS_LABEL_KEY + "-instruct"));
 647  0
         MultiplicityConfiguration courseFormatConfig = setupMultiplicityConfig(
 648  
                 MultiplicityConfiguration.MultiplicityType.GROUP,
 649  
                 MultiplicityConfiguration.StyleType.TOP_LEVEL_GROUP,
 650  
                 COURSE + "/" + FORMATS, LUUIConstants.COURSE_ADD_FORMAT_LABEL_KEY,
 651  
                 LUUIConstants.FORMAT_LABEL_KEY,
 652  
                 null, null, null);
 653  0
         courseFormatConfig.setDefaultItemsCreated(1);
 654  0
         MultiplicityConfiguration activitiesConfig = setupMultiplicityConfig(
 655  
                 MultiplicityConfiguration.MultiplicityType.GROUP,
 656  
                 MultiplicityConfiguration.StyleType.SUB_LEVEL_GROUP,
 657  
                 COURSE + "/" + FORMATS + "/*/" + ACTIVITIES, 
 658  
                 LUUIConstants.ADD_ACTIVITY_LABEL_KEY,
 659  
                 LUUIConstants.ACTIVITY_LITERAL_LABEL_KEY,
 660  
                 Arrays.asList(
 661  
                         new MultiplicityFieldConfig(
 662  
                                 ACTIVITY_TYPE,
 663  
                                 LUUIConstants.ACTIVITY_TYPE_LABEL_KEY,
 664  
                                 null,
 665  
                                 null,
 666  
                                 true),
 667  
                         new MultiplicityFieldConfig(
 668  
                                 CONTACT_HOURS + "/" + "unitQuantity",
 669  
                                 LUUIConstants.CONTACT_HOURS_LABEL_KEY,
 670  
                                 null,
 671  
                                 null,
 672  
                                 false),
 673  
                         new MultiplicityFieldConfig(
 674  
                                 CONTACT_HOURS + "/" + "unitType",
 675  
                                 LUUIConstants.CONTACT_HOURS_FREQUENCY_LABEL_KEY,
 676  
                                 null,
 677  
                                 null,
 678  
                                 true),
 679  
                         new MultiplicityFieldConfig(
 680  
                                 CreditCourseActivityConstants.DURATION + "/" + "atpDurationTypeKey",
 681  
                                 LUUIConstants.COURSE_FORMATS_DURATION_TYPE_LABEL_KEY,
 682  
                                 null,
 683  
                                 null,
 684  
                                 false),
 685  
                         new MultiplicityFieldConfig(
 686  
                                 CreditCourseActivityConstants.DURATION + "/" + "timeQuantity",
 687  
                                 LUUIConstants.DURATION_QUANTITY_LABEL_KEY,
 688  
                                 null,
 689  
                                 null,
 690  
                                 true),
 691  
                         new MultiplicityFieldConfig(
 692  
                                 DEFAULT_ENROLLMENT_ESTIMATE,
 693  
                                 LUUIConstants.CLASS_SIZE_LABEL_KEY,
 694  
                                 null,
 695  
                                 null,
 696  
                                 true)
 697  
                 ), null, null);
 698  0
         activitiesConfig.setDefaultItemsCreated(1);
 699  0
         courseFormatConfig.setNestedConfig(activitiesConfig);
 700  
         
 701  
 
 702  0
         MultiplicitySection ms = null;
 703  0
         ms = new MultiplicitySection(courseFormatConfig, 
 704  
                 null, null);
 705  0
         courseFormats.addSection(ms);
 706  0
         courseFormats.setRequired(courseFormatConfig.getParentFd().getFieldElement().getRequiredPanel());
 707  0
         return courseFormats;
 708  
     }
 709  
 
 710  
     protected VerticalSection generateSchedulingSection() {
 711  0
         VerticalSection scheduling = initSection(getH3Title(LUUIConstants.SCHEDULING_LABEL_KEY), WITH_DIVIDER);
 712  0
         addField(scheduling, COURSE + "/" + TERMS_OFFERED, generateMessageInfo(LUUIConstants.TERMS_OFFERED_LABEL_KEY));
 713  0
         return scheduling;
 714  
     }
 715  
 
 716  
     protected VerticalSection generateDurationSection() {
 717  0
         VerticalSection duration = initSection(getH3Title(LUUIConstants.DURATION_LITERAL_LABEL_KEY), WITH_DIVIDER);
 718  0
         duration.setInstructions(getLabel(LUUIConstants.DURATION_LITERAL_LABEL_KEY + "-instruct"));
 719  0
         GroupSection duration_group = new GroupSection();
 720  0
         addField(duration_group, COURSE + "/" + CreditCourseConstants.DURATION + "/" + "atpDurationTypeKey", generateMessageInfo(LUUIConstants.DURATION_TYPE_LABEL_KEY));
 721  0
         addField(duration_group, COURSE + "/" + CreditCourseConstants.DURATION + "/" + "timeQuantity", generateMessageInfo(LUUIConstants.DURATION_QUANTITY_LABEL_KEY));
 722  
 
 723  0
         duration.addSection(duration_group);
 724  0
         return duration;
 725  
     }
 726  
 
 727  
     protected VerticalSection generateFinalExamSection() {
 728  0
         VerticalSection finalExam = initSection(getH3Title(LUUIConstants.FINAL_EXAM_LABEL_KEY), WITH_DIVIDER);
 729  0
         GroupSection finalExam_group = new GroupSection();
 730  0
         GroupSection finalExamRationale_group = new GroupSection();
 731  0
         GroupSection finalExamRationale_group2 = new GroupSection();
 732  
 
 733  0
         FieldDescriptor field = addField(finalExam_group, COURSE + "/" + CreditCourseConstants.FINAL_EXAM, generateMessageInfo(LUUIConstants.FINAL_EXAM_STATUS_LABEL_KEY));
 734  
 
 735  0
         if (field.isVisible()){
 736  0
                 KSSelectItemWidgetAbstract picker = (KSSelectItemWidgetAbstract) (((KSPicker) field.getFieldWidget()).getInputWidget());
 737  0
                 final FieldDescriptor rationaleField = addField(finalExamRationale_group, COURSE + "/" + CreditCourseConstants.FINAL_EXAM_RATIONALE, generateMessageInfo(LUUIConstants.FINAL_EXAM_RATIONALE_LABEL_KEY));
 738  0
                 rationaleField.setIgnoreShowRequired(true);
 739  0
                 final FieldDescriptor rationaleField2 = addField(finalExamRationale_group2, COURSE + "/" + CreditCourseConstants.FINAL_EXAM_RATIONALE, generateMessageInfo(LUUIConstants.FINAL_EXAM_RATIONALE_LABEL_KEY));
 740  0
                 rationaleField2.setIgnoreShowRequired(true);
 741  
                 
 742  
                 // Create SwapSection.
 743  0
                 final String altKey = "ALT";
 744  0
                 final String noneKey = "None";
 745  0
                 SwapSection swapSection = new SwapSection(picker);
 746  0
                 swapSection.addSection(finalExamRationale_group, altKey);
 747  0
                 swapSection.addSection(finalExamRationale_group2, noneKey);
 748  0
                 swapSection.setSwapEventHandler(new SwapEventHandler() {
 749  
                 
 750  
                 @Override
 751  
                 public void onShowSwappableSection(String key, Section section) {
 752  0
                     progressiveEnableAndRequireSection(true, section);
 753  0
                 }
 754  
                 
 755  
                 @Override
 756  
                 public void onRemoveSwappableSection(String key, Section section) {
 757  0
                     progressiveEnableAndRequireSection(false, section);
 758  0
                 }
 759  
             });
 760  0
                 finalExam.addSection(finalExam_group);
 761  
                
 762  0
                 finalExam.addSection(swapSection);
 763  0
                 return finalExam;
 764  
         } else {
 765  0
                 return new VerticalSection();
 766  
         }
 767  
 
 768  
     }
 769  
     
 770  
     protected void progressiveEnableAndRequireSection(boolean enableAndRequire, Section section){
 771  0
         if (section != null){
 772  0
             List<FieldDescriptor> fields = section.getFields(); 
 773  0
             if ((fields != null) && (fields.size() > 0)){
 774  0
                 BaseSection.progressiveEnableAndRequireFields(enableAndRequire, fields.toArray(new FieldDescriptor[fields.size()]));
 775  
             }
 776  
         }
 777  0
     }
 778  
 
 779  
     protected VerticalSection generateInstructorsSection() {
 780  0
         VerticalSection instructors = initSection(getH3Title(LUUIConstants.INSTRUCTOR_LABEL_KEY), WITH_DIVIDER);
 781  0
         addField(instructors, COURSE + "/" + PRIMARY_INSTRUCTOR + "/personId");
 782  0
         return instructors;
 783  
     }
 784  
 
 785  
     protected SectionView generateLearningObjectivesSection() {
 786  0
         VerticalSectionView section = initSectionView(CourseSections.LEARNING_OBJECTIVES, LUUIConstants.LEARNING_OBJECTIVES_LABEL_KEY);
 787  0
         section.setInstructions(getLabel(LUUIConstants.LEARNING_OBJECTIVES_LABEL_KEY + "-instruct", QueryPath.concat(COURSE, COURSE_SPECIFIC_LOS, "*", "loInfo", "desc", "plain").toString())); 
 788  0
         section.addSection(generateLearningObjectivesNestedSection());
 789  0
         return section;
 790  
     }
 791  
 
 792  
     protected VerticalSection generateLearningObjectivesNestedSection() {
 793  0
         final VerticalSection los = initSection(null, NO_DIVIDER);
 794  
 
 795  0
         QueryPath path = QueryPath.concat(COURSE, COURSE_SPECIFIC_LOS, "*", "loInfo", "desc");
 796  0
         Metadata meta = modelDefinition.getMetadata(path);
 797  
 
 798  0
         LOBuilder loBuilder = new LOBuilder(type, state, groupName, "kuali.loRepository.key.singleUse", COURSE_SPECIFIC_LOS, meta);
 799  0
         final FieldDescriptor fd = addField(los, CreditCourseConstants.COURSE_SPECIFIC_LOS, null,loBuilder, COURSE);
 800  
         
 801  0
         loBuilder.addValueChangeHandler(new ValueChangeHandler<List<OutlineNode<LOPicker>>>(){
 802  
                         @Override
 803  
                         public void onValueChange(ValueChangeEvent<List<OutlineNode<LOPicker>>> event) {
 804  0
                                 los.setIsDirty(true);
 805  0
                         }                
 806  
         });
 807  
         
 808  
         // have to do this here, because decision on binding is done in ks-core,
 809  
         // and we obviously don't want ks-core referring to LOBuilder
 810  0
         fd.setWidgetBinding(LOBuilderBinding.INSTANCE);
 811  
 
 812  0
         los.addStyleName("KS-LUM-Section-Divider");
 813  0
         return los;
 814  
     }
 815  
 
 816  
     public class PersonList extends KSDropDown {
 817  0
         final SimpleListItems people = new SimpleListItems();
 818  
 
 819  0
         public PersonList() {
 820  0
             final PersonList us = this;
 821  0
             final String userId = Application.getApplicationContext().getSecurityContext().getUserId();
 822  
 
 823  
             //FIXME: [KSCOR-225] Commented out search code to display drop down with only current user, and disable select
 824  0
             people.addItem(userId, userId);
 825  0
             us.setListItems(people);
 826  0
             us.selectItem(userId);
 827  0
             us.setBlankFirstItem(false);
 828  0
             this.setEnabled(false);
 829  
 
 830  
             /*
 831  
                 SearchRpcServiceAsync searchRpcServiceAsync = GWT.create(SearchRpcService.class);
 832  
                 SearchRequest searchRequest = new SearchRequest();
 833  
                 searchRequest.setSearchKey("person.search.personQuickViewByGivenName");
 834  
                 searchRequest.setSortColumn("person.resultColumn.GivenName");
 835  
                 searchRequest.setSortDirection(SortDirection.ASC);
 836  
                 searchRpcServiceAsync.search(searchRequest, new KSAsyncCallback<SearchResult>() {
 837  
 
 838  
                     @Override
 839  
                     public void onSuccess(SearchResult result) {
 840  
                         for (SearchResultRow r : result.getRows()) {
 841  
                             people.addItem(r.getCells().get(0).getValue(), r.getCells().get(1).getValue());
 842  
                         }
 843  
                         us.setListItems(people);
 844  
                         us.selectItem(userId);
 845  
                     }
 846  
 
 847  
                     @Override
 848  
                     public void handleFailure(Throwable caught) {
 849  
                         Window.alert("Unable to contact the SearchService for the list of users");
 850  
                         people.addItem(userId, userId);
 851  
                         us.setListItems(people);
 852  
                         us.selectItem(userId);
 853  
                     }
 854  
                 });
 855  
              */
 856  0
         }
 857  
 
 858  
         @Override
 859  
         public boolean isMultipleSelect() {
 860  0
             return true;
 861  
         }
 862  
     }
 863  
 
 864  
     public class ProposerPersonList extends KSLabelList {
 865  0
         public ProposerPersonList() {
 866  0
             SimpleListItems list = new SimpleListItems();
 867  
 
 868  0
             super.setListItems(list);
 869  0
         }
 870  
     }
 871  
 
 872  
     protected VerticalSection generateShortTitleSection() {
 873  0
         VerticalSection shortTitle = initSection(getH3Title(LUUIConstants.SHORT_TITLE_LABEL_KEY), WITH_DIVIDER);
 874  0
         addField(shortTitle, "cluInfo/officialIdentifier/shortName", null);
 875  0
         return shortTitle;
 876  
     }
 877  
 
 878  
     protected VerticalSectionView initSectionView(Enum<?> viewEnum, String labelKey) {
 879  0
         VerticalSectionView section = new VerticalSectionView(viewEnum, getLabel(labelKey), this.getModelId());
 880  0
         section.addStyleName(LUUIConstants.STYLE_SECTION);
 881  0
         return section;
 882  
     }
 883  
 
 884  
 
 885  
     protected VerticalSection initSection(SectionTitle title, boolean withDivider) {
 886  
         VerticalSection section;
 887  0
         if (title != null) {
 888  0
             section = new VerticalSection(title);
 889  
         } else {
 890  0
             section = new VerticalSection();
 891  
         }
 892  0
         section.addStyleName(LUUIConstants.STYLE_SECTION);
 893  0
         if (withDivider)
 894  0
             section.addStyleName(LUUIConstants.STYLE_SECTION_DIVIDER);
 895  0
         return section;
 896  
     }
 897  
 
 898  
     @Override
 899  
     public MessageKeyInfo generateMessageInfo(String labelKey) {
 900  0
         return new MessageKeyInfo(groupName, type, state, labelKey);
 901  
     }
 902  
 
 903  
     
 904  
     protected Section generateFinancialsSection(Section section) {
 905  
 
 906  0
         VerticalSection justiFee = initSection(getH3Title(LUUIConstants.COURSE_FEE_TITLE), WITH_DIVIDER);
 907  0
         SpanPanel courseFeeInstruction = new SpanPanel();
 908  0
         courseFeeInstruction.setStyleName("ks-form-module-elements-instruction");
 909  0
         courseFeeInstruction.setHTML(getLabel(LUUIConstants.COURSE_FEE_TITLE + FieldLayoutComponent.INSTRUCT_MESSAGE_KEY));
 910  0
         courseFeeInstruction.setVisible(true);
 911  0
         justiFee.addWidget(courseFeeInstruction);
 912  
         
 913  
 //        addField(description, COURSE + "/" + PROPOSAL_DESCRIPTION + "/" + RichTextInfoConstants.PLAIN, generateMessageInfo(LUConstants.DESCRIPTION_LABEL_KEY));
 914  
 
 915  0
         addField(justiFee, COURSE + "/" + "feeJustification" + "/" + RichTextInfoConstants.PLAIN,  generateMessageInfo(LUUIConstants.JUSTIFICATION_FEE));
 916  0
         section.addSection(justiFee);
 917  0
         Map<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>> swappableFieldsDefinition =
 918  
             new HashMap<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>>();
 919  
         
 920  
         // condition: 
 921  
         //    if rateType field is Variable Rate Fee
 922  
         //    if rateType field is Fixed Rate Fee
 923  
         //    if rateType field is Multiple Rate Fee
 924  
         //    if rateType field is Per Credit Fee
 925  
 //        String feesPathString = COURSE + QueryPath.getPathSeparator() + FEES;
 926  0
         QueryPath feesPath = QueryPath.concat(COURSE, FEES);
 927  0
         QueryPath rateTypeFieldPath = QueryPath.concat(feesPath.toString(), QueryPath.getWildCard(), "rateType");
 928  
 //        fees/*/feeAmounts/currencyQuantity
 929  0
         QueryPath deletionPath = QueryPath.concat(feesPath.toString(), QueryPath.getWildCard(), "feeAmounts");
 930  0
         QueryPath singularFeeAmountFieldPath = QueryPath.concat(feesPath.toString(), QueryPath.getWildCard(), "feeAmounts", "0", "currencyQuantity"); 
 931  0
         QueryPath minFeeAmountFieldPath = QueryPath.concat(feesPath.toString(), QueryPath.getWildCard(), "feeAmounts", "0", "currencyQuantity"); 
 932  0
         QueryPath maxFeeAmountFieldPath = QueryPath.concat(feesPath.toString(), QueryPath.getWildCard(), "feeAmounts", "1", "currencyQuantity"); 
 933  0
         Metadata feeAmountFieldMeta = modelDefinition.getMetadata(singularFeeAmountFieldPath);
 934  
         
 935  0
         SwapCompositeCondition variableRateCondition = new SwapCompositeCondition(
 936  
                 CompositeConditionOperator.AND);
 937  0
         variableRateCondition.getChildrenConditions().add(
 938  
                 makeCondition(rateTypeFieldPath, "Rate Type", "variableRateFee")
 939  
         );
 940  0
         variableRateCondition.setConditionId("0");
 941  
         
 942  0
         SwapCompositeCondition fixedRateCondition = new SwapCompositeCondition(
 943  
                 CompositeConditionOperator.AND);
 944  0
         fixedRateCondition.getChildrenConditions().add(
 945  
                 makeCondition(rateTypeFieldPath, "Rate Type", "fixedRateFee")
 946  
         );
 947  0
         fixedRateCondition.setConditionId("1");
 948  
 
 949  0
         SwapCompositeCondition perCreditRateCondition = new SwapCompositeCondition(
 950  
                 CompositeConditionOperator.AND);
 951  0
         perCreditRateCondition.getChildrenConditions().add(
 952  
                 makeCondition(rateTypeFieldPath, "Rate Type", "perCreditFee")
 953  
         );
 954  0
         perCreditRateCondition.setConditionId("2");
 955  
 
 956  0
         SwapCompositeCondition multipleRateCondition = new SwapCompositeCondition(
 957  
                 CompositeConditionOperator.AND);
 958  0
         multipleRateCondition.getChildrenConditions().add(
 959  
                 makeCondition(rateTypeFieldPath, "Rate Type", "multipleRateFee")
 960  
         );
 961  0
         multipleRateCondition.setConditionId("3");
 962  
 
 963  0
         swappableFieldsDefinition.put(variableRateCondition,
 964  
                 Arrays.asList(
 965  
                         new SwapCompositeConditionFieldConfig(
 966  
                                 new MultiplicityFieldConfiguration(
 967  
                                         minFeeAmountFieldPath.toString(), 
 968  
                                         new MessageKeyInfo("Mininum Amount"), feeAmountFieldMeta,
 969  
                                         null),
 970  
                                 null
 971  
                         ),
 972  
                         new SwapCompositeConditionFieldConfig(
 973  
                                 new MultiplicityFieldConfiguration(
 974  
                                         maxFeeAmountFieldPath.toString(), 
 975  
                                         new MessageKeyInfo("Maximum Amount"), feeAmountFieldMeta,
 976  
                                         null),
 977  
                                 null
 978  
                         ))
 979  
         );
 980  
         
 981  0
         swappableFieldsDefinition.put(fixedRateCondition,
 982  
                 Arrays.asList(
 983  
                         new SwapCompositeConditionFieldConfig(
 984  
                                 new MultiplicityFieldConfiguration(
 985  
                                         singularFeeAmountFieldPath.toString(), 
 986  
                                         new MessageKeyInfo("Amount"), feeAmountFieldMeta,
 987  
                                         null), 
 988  
                                 null))
 989  
         );
 990  
 
 991  0
         swappableFieldsDefinition.put(perCreditRateCondition,
 992  
                 Arrays.asList(
 993  
                         new SwapCompositeConditionFieldConfig(
 994  
                                 new MultiplicityFieldConfiguration(
 995  
                                         singularFeeAmountFieldPath.toString(), 
 996  
                                         new MessageKeyInfo("Amount"), feeAmountFieldMeta,
 997  
                                         null),
 998  
                                 null))
 999  
         );
 1000  
         
 1001  0
         MultiplicityConfiguration multipleFeesConfig = setupMultiplicityConfig(
 1002  
                 MultiplicityConfiguration.MultiplicityType.GROUP,
 1003  
                 MultiplicityConfiguration.StyleType.BORDERLESS_TABLE,
 1004  
                 COURSE + QueryPath.getPathSeparator() + FEES + QueryPath.getPathSeparator() + 
 1005  
                     QueryPath.getWildCard() + QueryPath.getPathSeparator() + "feeAmounts",
 1006  
                 LUUIConstants.ADD_ANOTHER_FEE,
 1007  
                 LUUIConstants.FEE,
 1008  
                 Arrays.asList(
 1009  
                         new MultiplicityFieldConfig(
 1010  
                                 "currencyQuantity", 
 1011  
                                 "Amount", null, null, true)),
 1012  
                 null,
 1013  
                 null);
 1014  0
         swappableFieldsDefinition.put(multipleRateCondition,
 1015  
                 Arrays.asList(
 1016  
                         new SwapCompositeConditionFieldConfig(
 1017  
                                 null, multipleFeesConfig
 1018  
                                 ))
 1019  
                 );
 1020  
 
 1021  0
         addFeeMultiplicityFields(justiFee, 
 1022  
                 COURSE + QueryPath.getPathSeparator() + FEES,
 1023  
                 LUUIConstants.ADD_A_FEE,
 1024  
                 LUUIConstants.FEE,
 1025  
                 Arrays.asList(
 1026  
                         new MultiplicityFieldConfig(
 1027  
                                 "feeType", 
 1028  
                                 "Fee Type", null, null, true),
 1029  
                         new MultiplicityFieldConfig(
 1030  
                                 "rateType", 
 1031  
                                 "Rate Type", null, null, true)),
 1032  
                 swappableFieldsDefinition,
 1033  
                 Arrays.asList(
 1034  
                         deletionPath.toString()));
 1035  
         
 1036  0
         section.addSection(justiFee);
 1037  
         
 1038  
         
 1039  0
         VerticalSection financialSection = initSection(getH3Title(LUUIConstants.FINANCIAL_INFORMATION), WITH_DIVIDER);
 1040  0
         SpanPanel financialInfoInstruction = new SpanPanel();
 1041  0
         financialInfoInstruction.setStyleName("ks-form-module-elements-instruction");
 1042  0
         financialInfoInstruction.setHTML(getLabel(LUUIConstants.FINANCIAL_INFORMATION + FieldLayoutComponent.INSTRUCT_MESSAGE_KEY));
 1043  0
         financialInfoInstruction.setVisible(true);
 1044  0
         financialSection.addWidget(financialInfoInstruction);
 1045  0
         SpanPanel revenuepan = new SpanPanel();
 1046  0
         revenuepan.setStyleName("ks-multiplicity-section-label");
 1047  0
         revenuepan.setHTML("<br>Revenue");
 1048  0
         revenuepan.setVisible(true);
 1049  0
         financialSection.addWidget(revenuepan);
 1050  0
         setupRevenueSection(financialSection);
 1051  0
         SpanPanel expendpan = new SpanPanel();
 1052  0
         expendpan.setStyleName("ks-multiplicity-section-label");
 1053  0
         expendpan.setHTML("<br>Expenditures");
 1054  0
         expendpan.setVisible(true);
 1055  0
         financialSection.addWidget(expendpan);
 1056  0
         setupExpenditureSection(financialSection);
 1057  0
         section.addSection(financialSection);
 1058  
 
 1059  0
         return section;
 1060  
     }
 1061  
     
 1062  
     protected void setupRevenueSection(Section parentSection) {
 1063  
         // TODO customize multiplicity and change "Percentage" label into LUConstants.AMOUNT
 1064  0
         QueryPath revenuePath = QueryPath.concat(COURSE, "revenues");
 1065  0
         QueryPath affiliatedOrgIdSubPath = QueryPath.concat("affiliatedOrgs", "0", "orgId");
 1066  0
         QueryPath percentageSubPath = QueryPath.concat("affiliatedOrgs", "0", "percentage");
 1067  0
         addMultiplicityFields(parentSection, 
 1068  
                 revenuePath.toString(), 
 1069  
                 LUUIConstants.ADD_ANOTHER_ORGANIZATION, 
 1070  
                 LUUIConstants.REVENUE,
 1071  
                 Arrays.asList(
 1072  
                         new MultiplicityFieldConfig(
 1073  
                                 affiliatedOrgIdSubPath.toString(), 
 1074  
                                 LUUIConstants.REVENUE, null, null, true),
 1075  
                         new MultiplicityFieldConfig(
 1076  
                                 percentageSubPath.toString(), 
 1077  
                                 "Percentage", null, null, true)                                
 1078  
                 ),
 1079  
                 null,
 1080  
                 null,
 1081  
                 0);
 1082  0
     }
 1083  
     
 1084  
     protected void setupExpenditureSection(Section parentSection) {
 1085  
         // TODO customize multiplicity and change "Percentage" label into LUConstants.AMOUNT
 1086  0
         QueryPath expenditureAffiliatedOrgPath = QueryPath.concat(COURSE, "expenditure", "affiliatedOrgs");
 1087  0
         QueryPath affiliatedOrgIdSubPath = QueryPath.concat("orgId");
 1088  0
         QueryPath percentageSubPath = QueryPath.concat("percentage");
 1089  0
         addMultiplicityFields(parentSection, 
 1090  
                 expenditureAffiliatedOrgPath.toString(), 
 1091  
                 LUUIConstants.ADD_ANOTHER_ORGANIZATION, 
 1092  
                 LUUIConstants.EXPENDITURE,
 1093  
                 Arrays.asList(
 1094  
                         new MultiplicityFieldConfig(
 1095  
                                 affiliatedOrgIdSubPath.toString(), 
 1096  
                                 LUUIConstants.EXPENDITURE, null, null, true),
 1097  
                         new MultiplicityFieldConfig(
 1098  
                                 percentageSubPath.toString(), 
 1099  
                                 "Percentage", null, null, true)                                
 1100  
                 ),
 1101  
                 null,
 1102  
                 null,
 1103  
                 0);
 1104  0
     }
 1105  
     
 1106  
     protected SwapCondition makeCondition(QueryPath fieldPath, String messageLabelKey, 
 1107  
             String value) {
 1108  0
         SwapCondition swapCondition = new SwapCondition();
 1109  0
         swapCondition.setFd(new FieldDescriptor(
 1110  
                 fieldPath.toString(), 
 1111  
                 new MessageKeyInfo(messageLabelKey),
 1112  
                 modelDefinition.getMetadata(fieldPath)));
 1113  0
         swapCondition.setValue(value);
 1114  0
         return swapCondition;
 1115  
     }
 1116  
 
 1117  
 
 1118  
     @Override
 1119  
     public String getCourseTitlePath() {
 1120  0
         return COURSE_TITLE_PATH;
 1121  
     }
 1122  
 
 1123  
     @Override
 1124  
     public String getProposalPath() {
 1125  0
         return PROPOSAL_PATH;
 1126  
     }
 1127  
 
 1128  
     @Override
 1129  
     public String getProposalTitlePath() {
 1130  0
         return PROPOSAL_TITLE_PATH;
 1131  
     }
 1132  
 
 1133  
     @Override
 1134  
     public Class<? extends Enum<?>> getViewsEnum() {
 1135  0
         return CourseProposalConfigurer.CourseSections.class;
 1136  
     }
 1137  
 
 1138  
 
 1139  
     @Override
 1140  
     public String getSectionTitle(DataModel model) {
 1141  
 
 1142  0
         StringBuffer sb = new StringBuffer();
 1143  0
         sb.append("Modify Course: ");
 1144  0
         sb.append(model.get("courseCode"));
 1145  0
         sb.append(" - ");
 1146  0
         sb.append(model.get("transcriptTitle"));
 1147  
 
 1148  0
         return sb.toString();
 1149  
     }
 1150  
 
 1151  
     @Override
 1152  
     public String getProposalHeaderTitle(DataModel model) {
 1153  0
         StringBuffer sb = new StringBuffer();
 1154  0
         if (model.get("copyOfCourseId") != null) {
 1155  0
             sb.append("Modify Course: ");
 1156  0
             sb.append(model.get("courseCode"));
 1157  0
             sb.append(" - ");
 1158  0
             sb.append(model.get("transcriptTitle"));
 1159  
         } else {
 1160  0
             sb.append("New Course: ");
 1161  0
             sb.append(model.get(getCourseTitlePath()));
 1162  
         }
 1163  
 
 1164  0
         return sb.toString();
 1165  
     }
 1166  
 
 1167  
     public CourseSummaryConfigurer getSummaryConfigurer() {
 1168  0
         return summaryConfigurer;
 1169  
     }
 1170  
 
 1171  0
     public static class KeyListModelWigetBinding extends ModelWidgetBindingSupport<HasDataValue> {
 1172  
         protected String key;
 1173  0
         HasDataValueBinding hasDataValueBinding = HasDataValueBinding.INSTANCE;
 1174  
 
 1175  0
         public KeyListModelWigetBinding(String key) {
 1176  0
             this.key = key;
 1177  0
         }
 1178  
 
 1179  
         @Override
 1180  
         public void setModelValue(HasDataValue widget, DataModel model, String path) {
 1181  
             // convert from the structure path/0/<id> into path/0/<key>/<id>
 1182  0
             hasDataValueBinding.setModelValue(widget, model, path);
 1183  
 
 1184  0
             QueryPath qPath = QueryPath.parse(path);
 1185  0
             Value value = ((KSSelectedList) widget).getValueWithTranslations();
 1186  
 
 1187  0
             Data idsData = null;
 1188  0
             Data idsDataStruct = null;
 1189  
 
 1190  0
             if (value != null) {
 1191  0
                 idsData = value.get();
 1192  
             }
 1193  0
             if (idsData != null) {
 1194  0
                 for (Data.Property p : idsData) {
 1195  0
                     if (!"_runtimeData".equals(p.getKey())) {
 1196  0
                         String id = p.getValue();
 1197  
                         // old translation path path/_runtimeData/0/id-translation
 1198  0
                         QueryPath translationPath = new QueryPath();
 1199  0
                         translationPath.add(new Data.StringKey(qPath.toString()));
 1200  0
                         translationPath.add(new Data.StringKey("_runtimeData"));
 1201  0
                         translationPath.add(new Data.IntegerKey((Integer) p.getKey()));
 1202  0
                         translationPath.add(new Data.StringKey("id-translation"));
 1203  
 
 1204  0
                         Data idItem = new Data();
 1205  0
                         String translation = model.get(translationPath.toString());
 1206  0
                         Data idItemRuntime = new Data();
 1207  0
                         Data idItemTranslation = new Data();
 1208  0
                         idsDataStruct = (idsDataStruct == null) ? new Data() : idsDataStruct;
 1209  0
                         idItem.set(this.key, id);
 1210  
                         // new translation path/0/_runtimeData/<key>/id-translation
 1211  0
                         idItemTranslation.set("id-translation", translation);
 1212  0
                         idItemRuntime.set(this.key, idItemTranslation);
 1213  0
                         idItem.set("_runtimeData", idItemRuntime);
 1214  0
                         idsDataStruct.add(idItem);
 1215  0
                     }
 1216  
                 }
 1217  
             }
 1218  
 
 1219  0
             model.set(qPath, idsDataStruct);
 1220  0
         }
 1221  
 
 1222  
         @Override
 1223  
         public void setWidgetValue(HasDataValue widget, DataModel model, String path) {
 1224  0
             DataModel middleManModel = new DataModel();
 1225  0
             if (model != null && model.getRoot() != null) {
 1226  0
                 middleManModel = new DataModel(model.getDefinition(), model.getRoot().copy());
 1227  
             }
 1228  
             // convert from the structure path/0/<key>/<id> into path/0/<id>
 1229  0
             QueryPath qPath = QueryPath.parse(path);
 1230  0
             Object value = null;
 1231  0
             Data idsData = null;
 1232  0
             Data newIdsData = null;
 1233  0
             Data newIdsRuntimeData = null;
 1234  
 
 1235  0
             if (middleManModel != null) {
 1236  0
                 value = middleManModel.get(qPath);
 1237  
             }
 1238  
 
 1239  0
             if (value != null) {
 1240  0
                 idsData = (Data) value;
 1241  0
                 if (idsData != null) {
 1242  0
                     for (Data.Property p : idsData) {
 1243  0
                         if (!"_runtimeData".equals(p.getKey())) {
 1244  0
                             Data idItem = p.getValue();
 1245  0
                             String id = idItem.get(key);
 1246  0
                             Data runtimeData = idItem.get("_runtimeData");
 1247  
                             // KSLAB-1790 - sometime runtimeData isn't there; no idea why
 1248  0
                             Data translationData = null != runtimeData ? ((Data) runtimeData.get(key)) : new Data();
 1249  0
                             newIdsData = (newIdsData == null) ? new Data() : newIdsData;
 1250  0
                             newIdsData.add(id);
 1251  0
                             newIdsRuntimeData = (newIdsRuntimeData == null) ? new Data() : newIdsRuntimeData;
 1252  0
                             newIdsRuntimeData.add(translationData);
 1253  0
                         }
 1254  
                     }
 1255  
                 }
 1256  
             }
 1257  0
             if (newIdsData != null) {
 1258  0
                 newIdsData.set("_runtimeData", newIdsRuntimeData);
 1259  0
                 middleManModel.set(qPath, newIdsData);
 1260  0
                 hasDataValueBinding.setWidgetValue(widget, middleManModel, path);
 1261  
             }
 1262  0
         }
 1263  
     }
 1264  
 
 1265  
 
 1266  0
     public static class MultiplicityFieldConfig {
 1267  
         protected String fieldKey;
 1268  
         protected String labelKey;
 1269  
         boolean nextLine;
 1270  
         
 1271  0
         public MultiplicityFieldConfig() {
 1272  0
         }
 1273  
         public MultiplicityFieldConfig(String fieldKey, String labelKey,
 1274  0
                 Widget fieldWidget, ModelWidgetBinding<?> modelWidgetBinding, boolean nextLine) {
 1275  0
             setFieldKey(fieldKey);
 1276  0
             setLabelKey(labelKey);
 1277  0
             setNextLine(nextLine);
 1278  0
         }
 1279  
         public String getFieldKey() {
 1280  0
             return fieldKey;
 1281  
         }
 1282  
         public void setFieldKey(String fieldKey) {
 1283  0
             this.fieldKey = fieldKey;
 1284  0
         }
 1285  
         public String getLabelKey() {
 1286  0
             return labelKey;
 1287  
         }
 1288  
         public void setLabelKey(String labelKey) {
 1289  0
             this.labelKey = labelKey;
 1290  0
         }
 1291  
         public boolean isNextLine() {
 1292  0
             return nextLine;
 1293  
         }
 1294  
         public void setNextLine(boolean nextLine) {
 1295  0
             this.nextLine = nextLine;
 1296  0
         }
 1297  
     }
 1298  
 }
 1299  
 
 1300  
 
 1301  
 
 1302