Coverage Report - org.kuali.student.lum.lu.ui.course.client.configuration.CourseProposalConfigurer
 
Classes in this File Line Coverage Branch Coverage Complexity
CourseProposalConfigurer
0%
0/373
0%
0/28
1.423
CourseProposalConfigurer$1
0%
0/3
N/A
1.423
CourseProposalConfigurer$2
0%
0/3
N/A
1.423
CourseProposalConfigurer$3
0%
0/3
N/A
1.423
CourseProposalConfigurer$4
0%
0/3
N/A
1.423
CourseProposalConfigurer$5
0%
0/5
N/A
1.423
CourseProposalConfigurer$6
0%
0/3
N/A
1.423
CourseProposalConfigurer$CourseSections
0%
0/4
N/A
1.423
CourseProposalConfigurer$KeyListModelWigetBinding
0%
0/63
0%
0/32
1.423
CourseProposalConfigurer$MultiplicityFieldConfig
0%
0/16
N/A
1.423
CourseProposalConfigurer$PersonList
0%
0/11
N/A
1.423
CourseProposalConfigurer$ProposerPersonList
0%
0/4
N/A
1.423
 
 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
         if(this.getClass().getName().contains("CourseProposalConfigurer"))
 377  0
            result.getLayout().setVisible(true);
 378  
         else {
 379  0
                   result.getLayout().setVisible(false);
 380  
         }
 381  0
         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  0
         MultiplicityConfiguration config = setupMultiplicityConfig(
 390  
                 MultiplicityConfiguration.MultiplicityType.GROUP,
 391  
                 MultiplicityConfiguration.StyleType.TOP_LEVEL_GROUP,
 392  
                 path, addItemlabelMessageKey, itemLabelMessageKey,
 393  
                 fieldConfigs, swappableFieldsDefinition, deletionParentKeys);
 394  0
         MultiplicitySection ms = null;
 395  0
         ms = new MultiplicitySection(config, swappableFieldsDefinition, deletionParentKeys);
 396  0
         section.addSection(ms);
 397  
 
 398  0
     }
 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  0
         QueryPath parentPath = QueryPath.concat(path);
 408  0
         MultiplicityConfiguration config = new MultiplicityConfiguration(multiplicityType,
 409  
                 styleType, getMetaData(parentPath.toString()));
 410  0
         config.setAddItemLabel(getLabel(addItemlabelMessageKey));
 411  0
         config.setItemLabel(getLabel(itemLabelMessageKey));
 412  0
         config.setUpdateable(true);
 413  
 
 414  0
         FieldDescriptor parentFd = buildMultiplicityParentFieldDescriptor(path, getLabel(itemLabelMessageKey), null);
 415  0
         config.setParent(parentFd);
 416  
 
 417  0
         if (fieldConfigs != null) {
 418  0
             for (MultiplicityFieldConfig fieldConfig : fieldConfigs) {
 419  0
                 MultiplicityFieldConfiguration fc = buildMultiplicityFD(fieldConfig.getFieldKey(),
 420  
                         fieldConfig.getLabelKey(), parentPath.toString());
 421  0
                 config.addFieldConfiguration(fc);
 422  0
                 if (fieldConfig.isNextLine()) {
 423  0
                     config.nextLine();
 424  
                 }
 425  0
             }
 426  
         }
 427  0
         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  0
         MultiplicityConfiguration config = setupMultiplicityConfig(
 436  
                 MultiplicityConfiguration.MultiplicityType.GROUP,
 437  
                 MultiplicityConfiguration.StyleType.TOP_LEVEL_GROUP,
 438  
                 path, addItemlabelMessageKey, itemLabelMessageKey,
 439  
                 fieldConfigs, swappableFieldsDefinition, deletionParentKeys);
 440  0
         config.setDefaultItemsCreated(defaultItemsCreated);
 441  0
         MultiplicitySection ms = null;
 442  0
         ms = new MultiplicitySection(config, swappableFieldsDefinition, deletionParentKeys);
 443  0
         section.addSection(ms);
 444  0
         return ms;
 445  
     }
 446  
 
 447  
     protected Metadata getMetaData(String fieldKey) {
 448  0
         return modelDefinition.getMetadata(QueryPath.concat(fieldKey));
 449  
     }
 450  
 
 451  
     protected MultiplicityFieldConfiguration buildMultiplicityFD(
 452  
             String fieldKey, String labelKey, String parentPath) {
 453  
 
 454  0
         QueryPath fieldPath = QueryPath.concat(parentPath, QueryPath.getWildCard(), fieldKey);
 455  0
         Metadata meta = modelDefinition.getMetadata(fieldPath);
 456  
 
 457  0
         MultiplicityFieldConfiguration fd = new MultiplicityFieldConfiguration(
 458  
                 fieldPath.toString(), generateMessageInfo(labelKey), meta, null);
 459  
         
 460  
 
 461  0
         return fd;
 462  
 
 463  
     }
 464  
 
 465  
     protected FieldDescriptor buildMultiplicityParentFieldDescriptor(String fieldKey, String messageKey, String parentPath) {
 466  0
         QueryPath path = QueryPath.concat(parentPath, fieldKey);
 467  0
         Metadata meta = modelDefinition.getMetadata(path);
 468  
 
 469  0
         FieldDescriptor fd = new FieldDescriptor(path.toString(), generateMessageInfo(messageKey), meta);
 470  0
         fd.hideLabel();
 471  0
         return fd;
 472  
     }
 473  
 
 474  
     protected VerticalSection generateCourseInfoShortTitleSection() {
 475  0
         VerticalSection shortTitle = initSection(getH3Title(LUUIConstants.SHORT_TITLE_LABEL_KEY), WITH_DIVIDER);
 476  0
         addField(shortTitle, COURSE + "/" + TRANSCRIPT_TITLE, null);
 477  0
         return shortTitle;
 478  
     }
 479  
 
 480  
     protected VerticalSection generateLongTitleSection() {
 481  0
         VerticalSection longTitle = initSection(getH3Title(LUUIConstants.TITLE_LABEL_KEY), WITH_DIVIDER);
 482  0
         addField(longTitle, COURSE + "/" + COURSE_TITLE, null);
 483  0
         return longTitle;
 484  
     }
 485  
 
 486  
     protected VerticalSection generateDescriptionRationaleSection() {
 487  0
         SectionTitle title = getH4Title(LUUIConstants.PROPOSAL_TITLE_SECTION_LABEL_KEY);
 488  0
         VerticalSection description = initSection(title, !WITH_DIVIDER);
 489  0
         title.setStyleName("cluProposalTitleSection");
 490  
         //FIXME [KSCOR-225] Temporary fix til we have a real rich text editor
 491  
         //addField(description, COURSE + "/" + DESCRIPTION, null);
 492  0
         addField(description, COURSE + "/" + DESCRIPTION + "/" + RichTextInfoConstants.PLAIN, generateMessageInfo(LUUIConstants.DESCRIPTION_LABEL_KEY));
 493  0
         addField(description, "proposal/rationale", generateMessageInfo(LUUIConstants.PROPOSAL_RATIONALE_LABEL_KEY),
 494  
                 new KSCharCount(modelDefinition.getMetadata(QueryPath.parse("proposal/rationale"))));
 495  
 
 496  0
         return description;
 497  
     }
 498  
 
 499  
     public Section generateCourseLogisticsSection(Section section) {
 500  0
             if (section instanceof SectionView){
 501  0
                     ((SectionView)section).setInstructions(getLabel(LUUIConstants.LOGISTICS_LABEL_KEY + "-instruct") + "<br><br>");
 502  
             }
 503  
 
 504  0
         section.addSection(generateSchedulingSection());
 505  0
         section.addSection(generateDurationSection());
 506  0
         section.addSection(generateLearningResultsSection());
 507  0
         section.addSection(generateCourseFormatsSection());
 508  
 
 509  0
         return section;
 510  
     }
 511  
 
 512  
     protected Section generateLearningResultsSection() {
 513  0
         VerticalSection learningResults = initSection(getH3Title(LUUIConstants.LEARNING_RESULTS_LABEL_KEY), WITH_DIVIDER);
 514  0
         learningResults.setInstructions(getLabel(LUUIConstants.LEARNING_RESULTS_LABEL_KEY + "-instruct") + "<br><br><br>");
 515  
 
 516  0
         learningResults.addSection(generateGradesAssessmentsSection());
 517  0
         learningResults.addSection(generateStudentRegistrationOptionsSection());
 518  0
         learningResults.addSection(generateFinalExamSection());
 519  0
         learningResults.addSection(generateOutcomesSection());
 520  
 
 521  0
         return learningResults;
 522  
     }
 523  
 
 524  
     protected Section generateOutcomesSection() {
 525  
 
 526  0
         String path = COURSE + QueryPath.getPathSeparator() + CREDIT_OPTIONS;
 527  0
         QueryPath creditTypeFullPath = QueryPath.concat(path, QueryPath.getWildCard(), CreditCourseConstants.TYPE);
 528  0
         QueryPath creditOptionFixedFullPath = QueryPath.concat(path, QueryPath.getWildCard(), CREDIT_OPTION_FIXED_CREDITS);
 529  0
         QueryPath creditOptionMinFullPath = QueryPath.concat(path, QueryPath.getWildCard(), CREDIT_OPTION_MIN_CREDITS);
 530  0
         QueryPath creditOptionMaxFullPath = QueryPath.concat(path, QueryPath.getWildCard(), CREDIT_OPTION_MAX_CREDITS);
 531  0
         QueryPath creditResultValuesFullPath = QueryPath.concat(path, QueryPath.getWildCard(), "resultValues");
 532  
 
 533  0
         VerticalSection courseOutcomes = initSection(getH3Title(LUUIConstants.LEARNING_RESULT_OUTCOME_LABEL_KEY), WITH_DIVIDER);
 534  0
         Map<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>> swappableFieldsDefinition =
 535  
             new HashMap<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>>();
 536  0
         SwapCompositeCondition fixedCreditCondition = new SwapCompositeCondition(
 537  
                 CompositeConditionOperator.AND);
 538  0
         fixedCreditCondition.getChildrenConditions().add(
 539  
                 makeCondition(creditTypeFullPath, LUUIConstants.LEARNING_RESULT_OUTCOME_TYPE_LABEL_KEY, "kuali.resultComponentType.credit.degree.fixed")
 540  
         );
 541  0
         fixedCreditCondition.setConditionId("1");
 542  0
         SwapCompositeCondition multipleCreditCondition = new SwapCompositeCondition(
 543  
                 CompositeConditionOperator.AND);
 544  0
         multipleCreditCondition.getChildrenConditions().add(
 545  
                 makeCondition(creditTypeFullPath, LUUIConstants.LEARNING_RESULT_OUTCOME_TYPE_LABEL_KEY, "kuali.resultComponentType.credit.degree.multiple")
 546  
         );
 547  0
         multipleCreditCondition.setConditionId("2");
 548  0
         SwapCompositeCondition variableCreditCondition = new SwapCompositeCondition(
 549  
                 CompositeConditionOperator.AND);
 550  0
         variableCreditCondition.getChildrenConditions().add(
 551  
                 makeCondition(creditTypeFullPath, LUUIConstants.LEARNING_RESULT_OUTCOME_TYPE_LABEL_KEY, "kuali.resultComponentType.credit.degree.range")
 552  
         );
 553  0
         variableCreditCondition.setConditionId("3");
 554  
         
 555  0
         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  0
         MultiplicityFieldWidgetInitializer multipleCreditInitializer = 
 568  0
             new MultiplicityFieldWidgetInitializer() {
 569  
                 @Override
 570  
                 public ModelWidgetBinding<?> getModelWidgetBindingInstance() {
 571  0
                     return new ListOfStringBinding();
 572  
                 }
 573  
                 @Override
 574  
                 public Widget getNewWidget() {
 575  0
                     return new ListOfStringWidget("Add Item");
 576  
                 }
 577  
         };
 578  
         
 579  0
         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  0
         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  0
         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  
         //Set the required panel
 624  0
         courseOutcomes.setRequired(ms.getConfig().getParentFd().getFieldElement().getRequiredPanel());
 625  0
         return courseOutcomes;
 626  
 
 627  
     }
 628  
 
 629  
     protected Section generateStudentRegistrationOptionsSection() {
 630  0
         VerticalSection studentRegistrationOptionsSection = initSection(getH3Title(LUUIConstants.LEARNING_RESULTS_STUDENT_REGISTRATION_LABEL_KEY), WITH_DIVIDER);
 631  
 
 632  0
         addField(studentRegistrationOptionsSection, COURSE + "/" + AUDIT, generateMessageInfo(LUUIConstants.LEARNING_RESULT_AUDIT_LABEL_KEY), new KSCheckBox(getLabel(LUUIConstants.LEARNING_RESULT_AUDIT_TEXT_LABEL_KEY)));
 633  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)));
 634  
 
 635  0
         return studentRegistrationOptionsSection;
 636  
     }
 637  
 
 638  
     protected Section generateGradesAssessmentsSection() {
 639  0
         VerticalSection gradesAssessments = initSection(getH3Title(LUUIConstants.LEARNING_RESULTS_GRADES_ASSESSMENTS_LABEL_KEY), WITH_DIVIDER);
 640  
 
 641  0
         addField(gradesAssessments, COURSE + "/" + GRADING_OPTIONS, generateMessageInfo(LUUIConstants.LEARNING_RESULT_ASSESSMENT_SCALE_LABEL_KEY));
 642  
 
 643  0
         return gradesAssessments;
 644  
     }
 645  
 
 646  
     protected VerticalSection generateCourseFormatsSection() {
 647  
         //COURSE FORMATS
 648  0
         VerticalSection courseFormats = initSection(getH3Title(LUUIConstants.FORMATS_LABEL_KEY), WITH_DIVIDER);
 649  0
         courseFormats.setHelp(getLabel(LUUIConstants.FORMATS_LABEL_KEY + "-help"));
 650  0
         courseFormats.setInstructions(getLabel(LUUIConstants.FORMATS_LABEL_KEY + "-instruct"));
 651  0
         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  0
         courseFormatConfig.setDefaultItemsCreated(1);
 658  0
         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 + "/" + "unitType",
 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  0
         activitiesConfig.setDefaultItemsCreated(1);
 703  0
         courseFormatConfig.setNestedConfig(activitiesConfig);
 704  
         
 705  
 
 706  0
         MultiplicitySection ms = null;
 707  0
         ms = new MultiplicitySection(courseFormatConfig, 
 708  
                 null, null);
 709  0
         courseFormats.addSection(ms);
 710  0
         courseFormats.setRequired(courseFormatConfig.getParentFd().getFieldElement().getRequiredPanel());
 711  0
         return courseFormats;
 712  
     }
 713  
 
 714  
     protected VerticalSection generateSchedulingSection() {
 715  0
         VerticalSection scheduling = initSection(getH3Title(LUUIConstants.SCHEDULING_LABEL_KEY), WITH_DIVIDER);
 716  0
         addField(scheduling, COURSE + "/" + TERMS_OFFERED, generateMessageInfo(LUUIConstants.TERMS_OFFERED_LABEL_KEY));
 717  0
         return scheduling;
 718  
     }
 719  
 
 720  
     protected VerticalSection generateDurationSection() {
 721  0
         VerticalSection duration = initSection(getH3Title(LUUIConstants.DURATION_LITERAL_LABEL_KEY), WITH_DIVIDER);
 722  0
         duration.setInstructions(getLabel(LUUIConstants.DURATION_LITERAL_LABEL_KEY + "-instruct"));
 723  0
         GroupSection duration_group = new GroupSection();
 724  0
         addField(duration_group, COURSE + "/" + CreditCourseConstants.DURATION + "/" + "atpDurationTypeKey", generateMessageInfo(LUUIConstants.DURATION_TYPE_LABEL_KEY));
 725  0
         addField(duration_group, COURSE + "/" + CreditCourseConstants.DURATION + "/" + "timeQuantity", generateMessageInfo(LUUIConstants.DURATION_QUANTITY_LABEL_KEY));
 726  
 
 727  0
         duration.addSection(duration_group);
 728  0
         return duration;
 729  
     }
 730  
 
 731  
     protected VerticalSection generateFinalExamSection() {
 732  0
         VerticalSection finalExam = initSection(getH3Title(LUUIConstants.FINAL_EXAM_LABEL_KEY), WITH_DIVIDER);
 733  0
         GroupSection finalExam_group = new GroupSection();
 734  0
         GroupSection finalExamRationale_group = new GroupSection();
 735  0
         GroupSection finalExamRationale_group2 = new GroupSection();
 736  
 
 737  0
         FieldDescriptor field = addField(finalExam_group, COURSE + "/" + CreditCourseConstants.FINAL_EXAM, generateMessageInfo(LUUIConstants.FINAL_EXAM_STATUS_LABEL_KEY));
 738  
 
 739  0
         if (field.isVisible()){
 740  0
                 KSSelectItemWidgetAbstract picker = (KSSelectItemWidgetAbstract) (((KSPicker) field.getFieldWidget()).getInputWidget());
 741  0
                 final FieldDescriptor rationaleField = addField(finalExamRationale_group, COURSE + "/" + CreditCourseConstants.FINAL_EXAM_RATIONALE, generateMessageInfo(LUUIConstants.FINAL_EXAM_RATIONALE_LABEL_KEY));
 742  0
                 rationaleField.setIgnoreShowRequired(true);
 743  0
                 final FieldDescriptor rationaleField2 = addField(finalExamRationale_group2, COURSE + "/" + CreditCourseConstants.FINAL_EXAM_RATIONALE, generateMessageInfo(LUUIConstants.FINAL_EXAM_RATIONALE_LABEL_KEY));
 744  0
                 rationaleField2.setIgnoreShowRequired(true);
 745  
                 
 746  
                 // Create SwapSection.
 747  0
                 final String altKey = "ALT";
 748  0
                 final String noneKey = "None";
 749  0
                 SwapSection swapSection = new SwapSection(picker);
 750  0
                 swapSection.addSection(finalExamRationale_group, altKey);
 751  0
                 swapSection.addSection(finalExamRationale_group2, noneKey);
 752  0
                 swapSection.setSwapEventHandler(new SwapEventHandler() {
 753  
                 
 754  
                 @Override
 755  
                 public void onShowSwappableSection(String key, Section section) {
 756  0
                     progressiveEnableAndRequireSection(true, section);
 757  0
                 }
 758  
                 
 759  
                 @Override
 760  
                 public void onRemoveSwappableSection(String key, Section section) {
 761  0
                     progressiveEnableAndRequireSection(false, section);
 762  0
                 }
 763  
             });
 764  0
                 finalExam.addSection(finalExam_group);
 765  
                
 766  0
                 finalExam.addSection(swapSection);
 767  0
                 return finalExam;
 768  
         } else {
 769  0
                 return new VerticalSection();
 770  
         }
 771  
 
 772  
     }
 773  
     
 774  
     protected void progressiveEnableAndRequireSection(boolean enableAndRequire, Section section){
 775  0
         if (section != null){
 776  0
             List<FieldDescriptor> fields = section.getFields(); 
 777  0
             if ((fields != null) && (fields.size() > 0)){
 778  0
                 BaseSection.progressiveEnableAndRequireFields(enableAndRequire, fields.toArray(new FieldDescriptor[fields.size()]));
 779  
             }
 780  
         }
 781  0
     }
 782  
 
 783  
     protected VerticalSection generateInstructorsSection() {
 784  0
         VerticalSection instructors = initSection(getH3Title(LUUIConstants.INSTRUCTOR_LABEL_KEY), WITH_DIVIDER);
 785  0
         addField(instructors, COURSE + "/" + PRIMARY_INSTRUCTOR + "/personId");
 786  0
         return instructors;
 787  
     }
 788  
 
 789  
     protected SectionView generateLearningObjectivesSection() {
 790  0
         VerticalSectionView section = initSectionView(CourseSections.LEARNING_OBJECTIVES, LUUIConstants.LEARNING_OBJECTIVES_LABEL_KEY);
 791  0
         section.setInstructions(getLabel(LUUIConstants.LEARNING_OBJECTIVES_LABEL_KEY + "-instruct", QueryPath.concat(COURSE, COURSE_SPECIFIC_LOS, "*", "loInfo", "desc", "plain").toString())); 
 792  0
         section.addSection(generateLearningObjectivesNestedSection());
 793  0
         return section;
 794  
     }
 795  
 
 796  
     protected VerticalSection generateLearningObjectivesNestedSection() {
 797  0
         final VerticalSection los = initSection(null, NO_DIVIDER);
 798  
 
 799  0
         QueryPath path = QueryPath.concat(COURSE, COURSE_SPECIFIC_LOS, "*", "loInfo", "desc");
 800  0
         Metadata meta = modelDefinition.getMetadata(path);
 801  
 
 802  0
         LOBuilder loBuilder = new LOBuilder(type, state, groupName, "kuali.loRepository.key.singleUse", COURSE_SPECIFIC_LOS, meta);
 803  0
         final FieldDescriptor fd = addField(los, CreditCourseConstants.COURSE_SPECIFIC_LOS, null,loBuilder, COURSE);
 804  
         
 805  0
         loBuilder.addValueChangeHandler(new ValueChangeHandler<List<OutlineNode<LOPicker>>>(){
 806  
                         @Override
 807  
                         public void onValueChange(ValueChangeEvent<List<OutlineNode<LOPicker>>> event) {
 808  0
                                 los.setIsDirty(true);
 809  0
                         }                
 810  
         });
 811  
         
 812  
         // have to do this here, because decision on binding is done in ks-core,
 813  
         // and we obviously don't want ks-core referring to LOBuilder
 814  0
         fd.setWidgetBinding(LOBuilderBinding.INSTANCE);
 815  
 
 816  0
         los.addStyleName("KS-LUM-Section-Divider");
 817  0
         return los;
 818  
     }
 819  
 
 820  
     public class PersonList extends KSDropDown {
 821  0
         final SimpleListItems people = new SimpleListItems();
 822  
 
 823  0
         public PersonList() {
 824  0
             final PersonList us = this;
 825  0
             final String userId = Application.getApplicationContext().getSecurityContext().getUserId();
 826  
 
 827  
             //FIXME: [KSCOR-225] Commented out search code to display drop down with only current user, and disable select
 828  0
             people.addItem(userId, userId);
 829  0
             us.setListItems(people);
 830  0
             us.selectItem(userId);
 831  0
             us.setBlankFirstItem(false);
 832  0
             this.setEnabled(false);
 833  
 
 834  
             /*
 835  
                 SearchRpcServiceAsync searchRpcServiceAsync = GWT.create(SearchRpcService.class);
 836  
                 SearchRequest searchRequest = new SearchRequest();
 837  
                 searchRequest.setSearchKey("person.search.personQuickViewByGivenName");
 838  
                 searchRequest.setSortColumn("person.resultColumn.GivenName");
 839  
                 searchRequest.setSortDirection(SortDirection.ASC);
 840  
                 searchRpcServiceAsync.search(searchRequest, new KSAsyncCallback<SearchResult>() {
 841  
 
 842  
                     @Override
 843  
                     public void onSuccess(SearchResult result) {
 844  
                         for (SearchResultRow r : result.getRows()) {
 845  
                             people.addItem(r.getCells().get(0).getValue(), r.getCells().get(1).getValue());
 846  
                         }
 847  
                         us.setListItems(people);
 848  
                         us.selectItem(userId);
 849  
                     }
 850  
 
 851  
                     @Override
 852  
                     public void handleFailure(Throwable caught) {
 853  
                         Window.alert("Unable to contact the SearchService for the list of users");
 854  
                         people.addItem(userId, userId);
 855  
                         us.setListItems(people);
 856  
                         us.selectItem(userId);
 857  
                     }
 858  
                 });
 859  
              */
 860  0
         }
 861  
 
 862  
         @Override
 863  
         public boolean isMultipleSelect() {
 864  0
             return true;
 865  
         }
 866  
     }
 867  
 
 868  
     public class ProposerPersonList extends KSLabelList {
 869  0
         public ProposerPersonList() {
 870  0
             SimpleListItems list = new SimpleListItems();
 871  
 
 872  0
             super.setListItems(list);
 873  0
         }
 874  
     }
 875  
 
 876  
     protected VerticalSection generateShortTitleSection() {
 877  0
         VerticalSection shortTitle = initSection(getH3Title(LUUIConstants.SHORT_TITLE_LABEL_KEY), WITH_DIVIDER);
 878  0
         addField(shortTitle, "cluInfo/officialIdentifier/shortName", null);
 879  0
         return shortTitle;
 880  
     }
 881  
 
 882  
     protected VerticalSectionView initSectionView(Enum<?> viewEnum, String labelKey) {
 883  0
         VerticalSectionView section = new VerticalSectionView(viewEnum, getLabel(labelKey), this.getModelId());
 884  0
         section.addStyleName(LUUIConstants.STYLE_SECTION);
 885  0
         return section;
 886  
     }
 887  
 
 888  
 
 889  
     protected VerticalSection initSection(SectionTitle title, boolean withDivider) {
 890  
         VerticalSection section;
 891  0
         if (title != null) {
 892  0
             section = new VerticalSection(title);
 893  
         } else {
 894  0
             section = new VerticalSection();
 895  
         }
 896  0
         section.addStyleName(LUUIConstants.STYLE_SECTION);
 897  0
         if (withDivider)
 898  0
             section.addStyleName(LUUIConstants.STYLE_SECTION_DIVIDER);
 899  0
         return section;
 900  
     }
 901  
 
 902  
     @Override
 903  
     public MessageKeyInfo generateMessageInfo(String labelKey) {
 904  0
         return new MessageKeyInfo(groupName, type, state, labelKey);
 905  
     }
 906  
 
 907  
     
 908  
     protected Section generateFinancialsSection(Section section) {
 909  
 
 910  0
         VerticalSection justiFee = initSection(getH3Title(LUUIConstants.COURSE_FEE_TITLE), WITH_DIVIDER);
 911  0
         SpanPanel courseFeeInstruction = new SpanPanel();
 912  0
         courseFeeInstruction.setStyleName("ks-form-module-elements-instruction");
 913  0
         courseFeeInstruction.setHTML(getLabel(LUUIConstants.COURSE_FEE_TITLE + FieldLayoutComponent.INSTRUCT_MESSAGE_KEY));
 914  0
         courseFeeInstruction.setVisible(true);
 915  0
         justiFee.addWidget(courseFeeInstruction);
 916  
         
 917  
 //        addField(description, COURSE + "/" + PROPOSAL_DESCRIPTION + "/" + RichTextInfoConstants.PLAIN, generateMessageInfo(LUConstants.DESCRIPTION_LABEL_KEY));
 918  
 
 919  0
         addField(justiFee, COURSE + "/" + "feeJustification" + "/" + RichTextInfoConstants.PLAIN,  generateMessageInfo(LUUIConstants.JUSTIFICATION_FEE));
 920  0
         section.addSection(justiFee);
 921  0
         Map<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>> swappableFieldsDefinition =
 922  
             new HashMap<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>>();
 923  
         
 924  
         // condition: 
 925  
         //    if rateType field is Variable Rate Fee
 926  
         //    if rateType field is Fixed Rate Fee
 927  
         //    if rateType field is Multiple Rate Fee
 928  
         //    if rateType field is Per Credit Fee
 929  
 //        String feesPathString = COURSE + QueryPath.getPathSeparator() + FEES;
 930  0
         QueryPath feesPath = QueryPath.concat(COURSE, FEES);
 931  0
         QueryPath rateTypeFieldPath = QueryPath.concat(feesPath.toString(), QueryPath.getWildCard(), "rateType");
 932  
 //        fees/*/feeAmounts/currencyQuantity
 933  0
         QueryPath deletionPath = QueryPath.concat(feesPath.toString(), QueryPath.getWildCard(), "feeAmounts");
 934  0
         QueryPath singularFeeAmountFieldPath = QueryPath.concat(feesPath.toString(), QueryPath.getWildCard(), "feeAmounts", "0", "currencyQuantity"); 
 935  0
         QueryPath minFeeAmountFieldPath = QueryPath.concat(feesPath.toString(), QueryPath.getWildCard(), "feeAmounts", "0", "currencyQuantity"); 
 936  0
         QueryPath maxFeeAmountFieldPath = QueryPath.concat(feesPath.toString(), QueryPath.getWildCard(), "feeAmounts", "1", "currencyQuantity"); 
 937  0
         Metadata feeAmountFieldMeta = modelDefinition.getMetadata(singularFeeAmountFieldPath);
 938  
         
 939  0
         SwapCompositeCondition variableRateCondition = new SwapCompositeCondition(
 940  
                 CompositeConditionOperator.AND);
 941  0
         variableRateCondition.getChildrenConditions().add(
 942  
                 makeCondition(rateTypeFieldPath, "Rate Type", "variableRateFee")
 943  
         );
 944  0
         variableRateCondition.setConditionId("0");
 945  
         
 946  0
         SwapCompositeCondition fixedRateCondition = new SwapCompositeCondition(
 947  
                 CompositeConditionOperator.AND);
 948  0
         fixedRateCondition.getChildrenConditions().add(
 949  
                 makeCondition(rateTypeFieldPath, "Rate Type", "fixedRateFee")
 950  
         );
 951  0
         fixedRateCondition.setConditionId("1");
 952  
 
 953  0
         SwapCompositeCondition perCreditRateCondition = new SwapCompositeCondition(
 954  
                 CompositeConditionOperator.AND);
 955  0
         perCreditRateCondition.getChildrenConditions().add(
 956  
                 makeCondition(rateTypeFieldPath, "Rate Type", "perCreditFee")
 957  
         );
 958  0
         perCreditRateCondition.setConditionId("2");
 959  
 
 960  0
         SwapCompositeCondition multipleRateCondition = new SwapCompositeCondition(
 961  
                 CompositeConditionOperator.AND);
 962  0
         multipleRateCondition.getChildrenConditions().add(
 963  
                 makeCondition(rateTypeFieldPath, "Rate Type", "multipleRateFee")
 964  
         );
 965  0
         multipleRateCondition.setConditionId("3");
 966  
 
 967  0
         swappableFieldsDefinition.put(variableRateCondition,
 968  
                 Arrays.asList(
 969  
                         new SwapCompositeConditionFieldConfig(
 970  
                                 new MultiplicityFieldConfiguration(
 971  
                                         minFeeAmountFieldPath.toString(), 
 972  
                                         new MessageKeyInfo("Mininum Amount"), feeAmountFieldMeta,
 973  
                                         null),
 974  
                                 null
 975  
                         ),
 976  
                         new SwapCompositeConditionFieldConfig(
 977  
                                 new MultiplicityFieldConfiguration(
 978  
                                         maxFeeAmountFieldPath.toString(), 
 979  
                                         new MessageKeyInfo("Maximum Amount"), feeAmountFieldMeta,
 980  
                                         null),
 981  
                                 null
 982  
                         ))
 983  
         );
 984  
         
 985  0
         swappableFieldsDefinition.put(fixedRateCondition,
 986  
                 Arrays.asList(
 987  
                         new SwapCompositeConditionFieldConfig(
 988  
                                 new MultiplicityFieldConfiguration(
 989  
                                         singularFeeAmountFieldPath.toString(), 
 990  
                                         new MessageKeyInfo("Amount"), feeAmountFieldMeta,
 991  
                                         null), 
 992  
                                 null))
 993  
         );
 994  
 
 995  0
         swappableFieldsDefinition.put(perCreditRateCondition,
 996  
                 Arrays.asList(
 997  
                         new SwapCompositeConditionFieldConfig(
 998  
                                 new MultiplicityFieldConfiguration(
 999  
                                         singularFeeAmountFieldPath.toString(), 
 1000  
                                         new MessageKeyInfo("Amount"), feeAmountFieldMeta,
 1001  
                                         null),
 1002  
                                 null))
 1003  
         );
 1004  
         
 1005  0
         MultiplicityConfiguration multipleFeesConfig = setupMultiplicityConfig(
 1006  
                 MultiplicityConfiguration.MultiplicityType.GROUP,
 1007  
                 MultiplicityConfiguration.StyleType.BORDERLESS_TABLE,
 1008  
                 COURSE + QueryPath.getPathSeparator() + FEES + QueryPath.getPathSeparator() + 
 1009  
                     QueryPath.getWildCard() + QueryPath.getPathSeparator() + "feeAmounts",
 1010  
                 LUUIConstants.ADD_ANOTHER_FEE,
 1011  
                 LUUIConstants.FEE,
 1012  
                 Arrays.asList(
 1013  
                         new MultiplicityFieldConfig(
 1014  
                                 "currencyQuantity", 
 1015  
                                 "Amount", null, null, true)),
 1016  
                 null,
 1017  
                 null);
 1018  0
         swappableFieldsDefinition.put(multipleRateCondition,
 1019  
                 Arrays.asList(
 1020  
                         new SwapCompositeConditionFieldConfig(
 1021  
                                 null, multipleFeesConfig
 1022  
                                 ))
 1023  
                 );
 1024  
 
 1025  0
         addFeeMultiplicityFields(justiFee, 
 1026  
                 COURSE + QueryPath.getPathSeparator() + FEES,
 1027  
                 LUUIConstants.ADD_A_FEE,
 1028  
                 LUUIConstants.FEE,
 1029  
                 Arrays.asList(
 1030  
                         new MultiplicityFieldConfig(
 1031  
                                 "feeType", 
 1032  
                                 "Fee Type", null, null, true),
 1033  
                         new MultiplicityFieldConfig(
 1034  
                                 "rateType", 
 1035  
                                 "Rate Type", null, null, true)),
 1036  
                 swappableFieldsDefinition,
 1037  
                 Arrays.asList(
 1038  
                         deletionPath.toString()));
 1039  
         
 1040  0
         section.addSection(justiFee);
 1041  
         
 1042  
         
 1043  0
         VerticalSection financialSection = initSection(getH3Title(LUUIConstants.FINANCIAL_INFORMATION), WITH_DIVIDER);
 1044  0
         SpanPanel financialInfoInstruction = new SpanPanel();
 1045  0
         financialInfoInstruction.setStyleName("ks-form-module-elements-instruction");
 1046  0
         financialInfoInstruction.setHTML(getLabel(LUUIConstants.FINANCIAL_INFORMATION + FieldLayoutComponent.INSTRUCT_MESSAGE_KEY));
 1047  0
         financialInfoInstruction.setVisible(true);
 1048  0
         financialSection.addWidget(financialInfoInstruction);
 1049  0
         SpanPanel revenuepan = new SpanPanel();
 1050  0
         revenuepan.setStyleName("ks-multiplicity-section-label");
 1051  0
         revenuepan.setHTML("<br>Revenue");
 1052  0
         revenuepan.setVisible(true);
 1053  0
         financialSection.addWidget(revenuepan);
 1054  0
         setupRevenueSection(financialSection);
 1055  0
         SpanPanel expendpan = new SpanPanel();
 1056  0
         expendpan.setStyleName("ks-multiplicity-section-label");
 1057  0
         expendpan.setHTML("<br>Expenditures");
 1058  0
         expendpan.setVisible(true);
 1059  0
         financialSection.addWidget(expendpan);
 1060  0
         setupExpenditureSection(financialSection);
 1061  0
         section.addSection(financialSection);
 1062  
 
 1063  0
         return section;
 1064  
     }
 1065  
     
 1066  
     protected void setupRevenueSection(Section parentSection) {
 1067  
         // TODO customize multiplicity and change "Percentage" label into LUConstants.AMOUNT
 1068  0
         QueryPath revenuePath = QueryPath.concat(COURSE, "revenues");
 1069  0
         QueryPath affiliatedOrgIdSubPath = QueryPath.concat("affiliatedOrgs", "0", "orgId");
 1070  0
         QueryPath percentageSubPath = QueryPath.concat("affiliatedOrgs", "0", "percentage");
 1071  0
         addMultiplicityFields(parentSection, 
 1072  
                 revenuePath.toString(), 
 1073  
                 LUUIConstants.ADD_ANOTHER_ORGANIZATION, 
 1074  
                 LUUIConstants.REVENUE,
 1075  
                 Arrays.asList(
 1076  
                         new MultiplicityFieldConfig(
 1077  
                                 affiliatedOrgIdSubPath.toString(), 
 1078  
                                 LUUIConstants.REVENUE, null, null, true),
 1079  
                         new MultiplicityFieldConfig(
 1080  
                                 percentageSubPath.toString(), 
 1081  
                                 "Percentage", null, null, true)                                
 1082  
                 ),
 1083  
                 null,
 1084  
                 null,
 1085  
                 0);
 1086  0
     }
 1087  
     
 1088  
     protected void setupExpenditureSection(Section parentSection) {
 1089  
         // TODO customize multiplicity and change "Percentage" label into LUConstants.AMOUNT
 1090  0
         QueryPath expenditureAffiliatedOrgPath = QueryPath.concat(COURSE, "expenditure", "affiliatedOrgs");
 1091  0
         QueryPath affiliatedOrgIdSubPath = QueryPath.concat("orgId");
 1092  0
         QueryPath percentageSubPath = QueryPath.concat("percentage");
 1093  0
         addMultiplicityFields(parentSection, 
 1094  
                 expenditureAffiliatedOrgPath.toString(), 
 1095  
                 LUUIConstants.ADD_ANOTHER_ORGANIZATION, 
 1096  
                 LUUIConstants.EXPENDITURE,
 1097  
                 Arrays.asList(
 1098  
                         new MultiplicityFieldConfig(
 1099  
                                 affiliatedOrgIdSubPath.toString(), 
 1100  
                                 LUUIConstants.EXPENDITURE, null, null, true),
 1101  
                         new MultiplicityFieldConfig(
 1102  
                                 percentageSubPath.toString(), 
 1103  
                                 "Percentage", null, null, true)                                
 1104  
                 ),
 1105  
                 null,
 1106  
                 null,
 1107  
                 0);
 1108  0
     }
 1109  
     
 1110  
     protected SwapCondition makeCondition(QueryPath fieldPath, String messageLabelKey, 
 1111  
             String value) {
 1112  0
         SwapCondition swapCondition = new SwapCondition();
 1113  0
         swapCondition.setFd(new FieldDescriptor(
 1114  
                 fieldPath.toString(), 
 1115  
                 new MessageKeyInfo(messageLabelKey),
 1116  
                 modelDefinition.getMetadata(fieldPath)));
 1117  0
         swapCondition.setValue(value);
 1118  0
         return swapCondition;
 1119  
     }
 1120  
 
 1121  
 
 1122  
     @Override
 1123  
     public String getCourseTitlePath() {
 1124  0
         return COURSE_TITLE_PATH;
 1125  
     }
 1126  
 
 1127  
     @Override
 1128  
     public String getProposalPath() {
 1129  0
         return PROPOSAL_PATH;
 1130  
     }
 1131  
 
 1132  
     @Override
 1133  
     public String getProposalTitlePath() {
 1134  0
         return PROPOSAL_TITLE_PATH;
 1135  
     }
 1136  
 
 1137  
     @Override
 1138  
     public Class<? extends Enum<?>> getViewsEnum() {
 1139  0
         return CourseProposalConfigurer.CourseSections.class;
 1140  
     }
 1141  
 
 1142  
 
 1143  
     @Override
 1144  
     public String getSectionTitle(DataModel model) {
 1145  
 
 1146  0
         StringBuffer sb = new StringBuffer();
 1147  0
         sb.append("Modify Course: ");
 1148  0
         sb.append(model.get("courseCode"));
 1149  0
         sb.append(" - ");
 1150  0
         sb.append(model.get("transcriptTitle"));
 1151  
 
 1152  0
         return sb.toString();
 1153  
     }
 1154  
 
 1155  
     @Override
 1156  
     public String getProposalHeaderTitle(DataModel model) {
 1157  0
         StringBuffer sb = new StringBuffer();
 1158  0
         if (model.get("copyOfCourseId") != null) {
 1159  0
             sb.append("Modify Course: ");
 1160  0
             sb.append(model.get("courseCode"));
 1161  0
             sb.append(" - ");
 1162  0
             sb.append(model.get("transcriptTitle"));
 1163  
         } else {
 1164  0
             sb.append("New Course: ");
 1165  0
             sb.append(model.get(getCourseTitlePath()));
 1166  
         }
 1167  
 
 1168  0
         return sb.toString();
 1169  
     }
 1170  
 
 1171  
     public CourseSummaryConfigurer getSummaryConfigurer() {
 1172  0
         return summaryConfigurer;
 1173  
     }
 1174  
 
 1175  0
     public static class KeyListModelWigetBinding extends ModelWidgetBindingSupport<HasDataValue> {
 1176  
         protected String key;
 1177  0
         HasDataValueBinding hasDataValueBinding = HasDataValueBinding.INSTANCE;
 1178  
 
 1179  0
         public KeyListModelWigetBinding(String key) {
 1180  0
             this.key = key;
 1181  0
         }
 1182  
 
 1183  
         @Override
 1184  
         public void setModelValue(HasDataValue widget, DataModel model, String path) {
 1185  
             // convert from the structure path/0/<id> into path/0/<key>/<id>
 1186  0
             hasDataValueBinding.setModelValue(widget, model, path);
 1187  
 
 1188  0
             QueryPath qPath = QueryPath.parse(path);
 1189  0
             Value value = ((KSSelectedList) widget).getValueWithTranslations();
 1190  
 
 1191  0
             Data idsData = null;
 1192  0
             Data idsDataStruct = null;
 1193  
 
 1194  0
             if (value != null) {
 1195  0
                 idsData = value.get();
 1196  
             }
 1197  0
             if (idsData != null) {
 1198  0
                 for (Data.Property p : idsData) {
 1199  0
                     if (!"_runtimeData".equals(p.getKey())) {
 1200  0
                         String id = p.getValue();
 1201  
                         // old translation path path/_runtimeData/0/id-translation
 1202  0
                         QueryPath translationPath = new QueryPath();
 1203  0
                         translationPath.add(new Data.StringKey(qPath.toString()));
 1204  0
                         translationPath.add(new Data.StringKey("_runtimeData"));
 1205  0
                         translationPath.add(new Data.IntegerKey((Integer) p.getKey()));
 1206  0
                         translationPath.add(new Data.StringKey("id-translation"));
 1207  
 
 1208  0
                         Data idItem = new Data();
 1209  0
                         String translation = model.get(translationPath.toString());
 1210  0
                         Data idItemRuntime = new Data();
 1211  0
                         Data idItemTranslation = new Data();
 1212  0
                         idsDataStruct = (idsDataStruct == null) ? new Data() : idsDataStruct;
 1213  0
                         idItem.set(this.key, id);
 1214  
                         // new translation path/0/_runtimeData/<key>/id-translation
 1215  0
                         idItemTranslation.set("id-translation", translation);
 1216  0
                         idItemRuntime.set(this.key, idItemTranslation);
 1217  0
                         idItem.set("_runtimeData", idItemRuntime);
 1218  0
                         idsDataStruct.add(idItem);
 1219  0
                     }
 1220  
                 }
 1221  
             }
 1222  
 
 1223  0
             model.set(qPath, idsDataStruct);
 1224  0
         }
 1225  
 
 1226  
         @Override
 1227  
         public void setWidgetValue(HasDataValue widget, DataModel model, String path) {
 1228  0
             DataModel middleManModel = new DataModel();
 1229  0
             if (model != null && model.getRoot() != null) {
 1230  0
                 middleManModel = new DataModel(model.getDefinition(), model.getRoot().copy());
 1231  
             }
 1232  
             // convert from the structure path/0/<key>/<id> into path/0/<id>
 1233  0
             QueryPath qPath = QueryPath.parse(path);
 1234  0
             Object value = null;
 1235  0
             Data idsData = null;
 1236  0
             Data newIdsData = null;
 1237  0
             Data newIdsRuntimeData = null;
 1238  
 
 1239  0
             if (middleManModel != null) {
 1240  0
                 value = middleManModel.get(qPath);
 1241  
             }
 1242  
 
 1243  0
             if (value != null) {
 1244  0
                 idsData = (Data) value;
 1245  0
                 if (idsData != null) {
 1246  0
                     for (Data.Property p : idsData) {
 1247  0
                         if (!"_runtimeData".equals(p.getKey())) {
 1248  0
                             Data idItem = p.getValue();
 1249  0
                             String id = idItem.get(key);
 1250  0
                             Data runtimeData = idItem.get("_runtimeData");
 1251  
                             // KSLAB-1790 - sometime runtimeData isn't there; no idea why
 1252  0
                             Data translationData = null != runtimeData ? ((Data) runtimeData.get(key)) : new Data();
 1253  0
                             newIdsData = (newIdsData == null) ? new Data() : newIdsData;
 1254  0
                             newIdsData.add(id);
 1255  0
                             newIdsRuntimeData = (newIdsRuntimeData == null) ? new Data() : newIdsRuntimeData;
 1256  0
                             newIdsRuntimeData.add(translationData);
 1257  0
                         }
 1258  
                     }
 1259  
                 }
 1260  
             }
 1261  0
             if (newIdsData != null) {
 1262  0
                 newIdsData.set("_runtimeData", newIdsRuntimeData);
 1263  0
                 middleManModel.set(qPath, newIdsData);
 1264  0
                 hasDataValueBinding.setWidgetValue(widget, middleManModel, path);
 1265  
             }
 1266  0
         }
 1267  
     }
 1268  
 
 1269  
 
 1270  0
     public static class MultiplicityFieldConfig {
 1271  
         protected String fieldKey;
 1272  
         protected String labelKey;
 1273  
         boolean nextLine;
 1274  
         
 1275  0
         public MultiplicityFieldConfig() {
 1276  0
         }
 1277  
         public MultiplicityFieldConfig(String fieldKey, String labelKey,
 1278  0
                 Widget fieldWidget, ModelWidgetBinding<?> modelWidgetBinding, boolean nextLine) {
 1279  0
             setFieldKey(fieldKey);
 1280  0
             setLabelKey(labelKey);
 1281  0
             setNextLine(nextLine);
 1282  0
         }
 1283  
         public String getFieldKey() {
 1284  0
             return fieldKey;
 1285  
         }
 1286  
         public void setFieldKey(String fieldKey) {
 1287  0
             this.fieldKey = fieldKey;
 1288  0
         }
 1289  
         public String getLabelKey() {
 1290  0
             return labelKey;
 1291  
         }
 1292  
         public void setLabelKey(String labelKey) {
 1293  0
             this.labelKey = labelKey;
 1294  0
         }
 1295  
         public boolean isNextLine() {
 1296  0
             return nextLine;
 1297  
         }
 1298  
         public void setNextLine(boolean nextLine) {
 1299  0
             this.nextLine = nextLine;
 1300  0
         }
 1301  
     }
 1302  
 }
 1303  
 
 1304  
 
 1305  
 
 1306