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