Coverage Report - org.kuali.student.lum.lu.ui.course.client.configuration.CourseProposalConfigurer
 
Classes in this File Line Coverage Branch Coverage Complexity
CourseProposalConfigurer
0%
0/355
0%
0/20
1.382
CourseProposalConfigurer$1
0%
0/3
N/A
1.382
CourseProposalConfigurer$2
0%
0/3
N/A
1.382
CourseProposalConfigurer$3
0%
0/3
N/A
1.382
CourseProposalConfigurer$4
0%
0/3
N/A
1.382
CourseProposalConfigurer$5
0%
0/4
N/A
1.382
CourseProposalConfigurer$CourseSections
0%
0/4
N/A
1.382
CourseProposalConfigurer$KeyListModelWigetBinding
0%
0/63
0%
0/32
1.382
CourseProposalConfigurer$MultiplicityFieldConfig
0%
0/16
N/A
1.382
CourseProposalConfigurer$PersonList
0%
0/11
N/A
1.382
CourseProposalConfigurer$ProposerPersonList
0%
0/4
N/A
1.382
 
 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.CollapsableSection;
 58  
 import org.kuali.student.common.ui.client.configurable.mvc.sections.GroupSection;
 59  
 import org.kuali.student.common.ui.client.configurable.mvc.sections.MultiplicitySection;
 60  
 import org.kuali.student.common.ui.client.configurable.mvc.sections.Section;
 61  
 import org.kuali.student.common.ui.client.configurable.mvc.sections.SwapSection;
 62  
 import org.kuali.student.common.ui.client.configurable.mvc.sections.VerticalSection;
 63  
 import org.kuali.student.common.ui.client.configurable.mvc.views.SectionView;
 64  
 import org.kuali.student.common.ui.client.configurable.mvc.views.VerticalSectionView;
 65  
 import org.kuali.student.common.ui.client.mvc.Controller;
 66  
 import org.kuali.student.common.ui.client.mvc.DataModel;
 67  
 import org.kuali.student.common.ui.client.mvc.DataModelDefinition;
 68  
 import org.kuali.student.common.ui.client.mvc.HasDataValue;
 69  
 import org.kuali.student.common.ui.client.mvc.View;
 70  
 import org.kuali.student.common.ui.client.widgets.KSButton;
 71  
 import org.kuali.student.common.ui.client.widgets.KSButtonAbstract.ButtonStyle;
 72  
 import org.kuali.student.common.ui.client.widgets.KSCheckBox;
 73  
 import org.kuali.student.common.ui.client.widgets.KSDropDown;
 74  
 import org.kuali.student.common.ui.client.widgets.ListOfStringWidget;
 75  
 import org.kuali.student.common.ui.client.widgets.field.layout.element.MessageKeyInfo;
 76  
 import org.kuali.student.common.ui.client.widgets.field.layout.element.SpanPanel;
 77  
 import org.kuali.student.common.ui.client.widgets.field.layout.layouts.FieldLayoutComponent;
 78  
 import org.kuali.student.common.ui.client.widgets.list.KSLabelList;
 79  
 import org.kuali.student.common.ui.client.widgets.list.KSSelectItemWidgetAbstract;
 80  
 import org.kuali.student.common.ui.client.widgets.list.KSSelectedList;
 81  
 import org.kuali.student.common.ui.client.widgets.list.impl.SimpleListItems;
 82  
 import org.kuali.student.common.ui.client.widgets.search.KSPicker;
 83  
 import org.kuali.student.core.comments.ui.client.widgets.commenttool.CommentTool;
 84  
 import org.kuali.student.core.comments.ui.client.widgets.decisiontool.DecisionPanel;
 85  
 import org.kuali.student.core.document.ui.client.widgets.documenttool.DocumentTool;
 86  
 import org.kuali.student.core.statement.dto.StatementTypeInfo;
 87  
 import org.kuali.student.core.workflow.ui.client.views.CollaboratorSectionView;
 88  
 import org.kuali.student.lum.common.client.lo.LOBuilder;
 89  
 import org.kuali.student.lum.common.client.lo.LOBuilderBinding;
 90  
 import org.kuali.student.lum.common.client.lo.LOPicker;
 91  
 import org.kuali.student.lum.common.client.lo.OutlineNode;
 92  
 import org.kuali.student.lum.common.client.lu.LUUIConstants;
 93  
 import org.kuali.student.lum.lu.assembly.data.client.constants.base.RichTextInfoConstants;
 94  
 import org.kuali.student.lum.lu.assembly.data.client.constants.orch.CreditCourseActivityConstants;
 95  
 import org.kuali.student.lum.lu.assembly.data.client.constants.orch.CreditCourseConstants;
 96  
 import org.kuali.student.lum.lu.assembly.data.client.constants.orch.CreditCourseJointsConstants;
 97  
 import org.kuali.student.lum.lu.ui.course.client.controllers.CourseProposalController;
 98  
 import org.kuali.student.lum.lu.ui.course.client.requirements.CourseRequirementsViewController;
 99  
 
 100  
 import com.google.gwt.event.dom.client.ClickEvent;
 101  
 import com.google.gwt.event.dom.client.ClickHandler;
 102  
 import com.google.gwt.event.logical.shared.ValueChangeEvent;
 103  
 import com.google.gwt.event.logical.shared.ValueChangeHandler;
 104  
 import com.google.gwt.user.client.ui.Widget;
 105  
 
 106  
 
 107  
 /**
 108  
  * This is the configuration factory class for creating a proposal.
 109  
  *
 110  
  * @author Kuali Student Team
 111  
  */
 112  0
 public class CourseProposalConfigurer extends AbstractCourseConfigurer {
 113  
 
 114  0
     protected boolean WITH_DIVIDER = true;
 115  0
     protected boolean NO_DIVIDER = false;
 116  
   
 117  
     public static final String PROPOSAL_PATH = "proposal";
 118  
     public static final String PROPOSAL_TITLE_PATH = "proposal/name";
 119  
     public static final String COURSE_TITLE_PATH = "/courseTitle";
 120  
    
 121  
 
 122  
     protected DocumentTool documentTool;    
 123  
     protected CourseSummaryConfigurer summaryConfigurer;
 124  
 
 125  
     protected List<StatementTypeInfo> stmtTypes;
 126  
     
 127  
     public static final String COURSE = "";
 128  
 
 129  0
     public enum CourseSections {
 130  0
         CLU_BEGIN, PEOPLE_PERMISSONS, SUMMARY, AUTHORS_RATIONALE, GOVERNANCE, COURSE_LOGISTICS, COURSE_INFO, LEARNING_OBJECTIVES,
 131  0
         COURSE_REQUISITES, ACTIVE_DATES, FINANCIALS, ATTACHMENTS, COMMENTS,DECISIONS, DOCUMENTS,
 132  0
         PROGRAM_INFO, ASSEMBLER_TEST, WF_APPROVE_DIALOG
 133  
     }
 134  
 
 135  
     public void setStatementTypes(List<StatementTypeInfo> stmtTypes) {
 136  0
         this.stmtTypes = stmtTypes;
 137  0
     }
 138  
 
 139  
     /**
 140  
      * Sets up all the views, sections, and views of the CourseProposalController.  This should be called
 141  
      * once for initialization and setup per CourseProposalController instance.
 142  
      * 
 143  
      * @param layout
 144  
      */
 145  
     public void configure(final CourseProposalController layout) {
 146  0
             type = "course";
 147  0
         state = DtoConstants.STATE_DRAFT;
 148  0
             groupName = LUUIConstants.COURSE_GROUP_NAME;
 149  
 
 150  0
             if (modelDefinition.getMetadata().isCanEdit()) {
 151  0
                 addCluStartSection(layout);
 152  0
             String sections = getLabel(LUUIConstants.COURSE_SECTIONS);
 153  
 
 154  
             //ProposalInformation
 155  
             //layout.addSection(new String[] {editTabLabel, getLabel(LUConstants.PROPOSAL_INFORMATION_LABEL_KEY)}, generateAuthorsRationaleSection());
 156  
 
 157  0
             layout.addMenu(sections);
 158  
             
 159  
             
 160  
             //Course Content
 161  0
             layout.addMenuItem(sections, (SectionView)generateCourseInfoSection(initSectionView(CourseSections.COURSE_INFO, LUUIConstants.INFORMATION_LABEL_KEY)));
 162  0
             layout.addMenuItem(sections, (SectionView)generateGovernanceSection(initSectionView(CourseSections.GOVERNANCE, LUUIConstants.GOVERNANCE_LABEL_KEY)));
 163  0
             layout.addMenuItem(sections, (SectionView)generateCourseLogisticsSection(initSectionView(CourseSections.COURSE_LOGISTICS, LUUIConstants.LOGISTICS_LABEL_KEY)));
 164  0
             layout.addMenuItem(sections, generateLearningObjectivesSection());
 165  
 
 166  
             //Student Eligibility
 167  0
             layout.addMenuItem(sections, generateCourseRequisitesSection(layout,true));
 168  
 
 169  
             //Administrative
 170  0
             layout.addMenuItem(sections, (SectionView)generateActiveDatesSection(initSectionView(CourseSections.ACTIVE_DATES, LUUIConstants.ACTIVE_DATES_LABEL_KEY)));
 171  0
             layout.addMenuItem(sections, (SectionView)generateFinancialsSection(initSectionView(CourseSections.FINANCIALS, LUUIConstants.FINANCIALS_LABEL_KEY)));
 172  
             
 173  
             //Authors & Collaborators
 174  0
             layout.addMenuItem(sections, new CollaboratorSectionView(CourseSections.PEOPLE_PERMISSONS, LUUIConstants.SECTION_AUTHORS_AND_COLLABORATORS,COURSE_PROPOSAL_MODEL));
 175  
             
 176  
             //Documents
 177  0
             documentTool = new DocumentTool(LUUIConstants.REF_DOC_RELATION_PROPOSAL_TYPE,CourseSections.DOCUMENTS, getLabel(LUUIConstants.TOOL_DOCUMENTS_LABEL_KEY));
 178  0
             documentTool.setModelDefinition((DataModelDefinition)modelDefinition);
 179  0
             layout.addMenuItem(sections, documentTool);
 180  
             
 181  
             //Summary
 182  0
             summaryConfigurer = new CourseSummaryConfigurer(type, state, groupName,(DataModelDefinition)modelDefinition, stmtTypes, (Controller)layout, COURSE_PROPOSAL_MODEL);
 183  0
             layout.addSpecialMenuItem(summaryConfigurer.generateProposalSummarySection(true), "Review and Submit");
 184  
             
 185  
             //Add common buttons to sections except for sections with specific button behavior
 186  0
             List<Enum<?>> excludedViews = new ArrayList<Enum<?>>();
 187  0
             excludedViews.add(CourseSections.DOCUMENTS);
 188  0
             excludedViews.add(CourseSections.COURSE_REQUISITES);
 189  0
             layout.addCommonButton(LUUIConstants.COURSE_SECTIONS, layout.getSaveButton(), excludedViews);
 190  0
             layout.addCommonButton(LUUIConstants.COURSE_SECTIONS, layout.getCancelButton(CourseSections.SUMMARY), excludedViews);
 191  
 
 192  
             //Specific buttons for certain views
 193  
             //TODO people and permissions will use a different button than continue
 194  0
             layout.addButtonForView(CourseSections.DOCUMENTS, getContinueButton(layout));
 195  0
         }
 196  
         else{
 197  0
                  CourseSummaryConfigurer summaryConfigurer = new CourseSummaryConfigurer(type, state, groupName, (DataModelDefinition)modelDefinition, stmtTypes, (Controller)layout, COURSE_PROPOSAL_MODEL);
 198  0
                  layout.removeMenuNavigation();
 199  0
              layout.addView(summaryConfigurer.generateProposalSummarySection(false));
 200  
         }
 201  0
         layout.showPrint(true);
 202  0
         layout.setDefaultView(CourseSections.SUMMARY);
 203  0
         layout.addContentWidget(layout.getWfUtilities().getWorkflowStatusLabel());
 204  0
         final CommentTool commentTool = new CommentTool(CourseSections.COMMENTS, getLabel(LUUIConstants.TOOL_COMMENTS_LABEL_KEY), "kuali.comment.type.generalRemarks", "Proposal Comments");
 205  0
         commentTool.setController(layout);
 206  
         
 207  0
         layout.addContentWidget(new KSButton("Comments", ButtonStyle.DEFAULT_ANCHOR, new ClickHandler() {
 208  
             
 209  
             @Override
 210  
             public void onClick(ClickEvent event) {
 211  0
                 commentTool.show();
 212  0
             }
 213  
         }));
 214  
 
 215  
         
 216  0
         final DecisionPanel decisionPanel = new DecisionPanel(CourseSections.DECISIONS, getLabel(LUUIConstants.TOOL_DECISION_LABEL_KEY), "kuali.comment.type.generalRemarks");
 217  0
         layout.addView(decisionPanel);
 218  0
         layout.addContentWidget(new KSButton("Decisions", ButtonStyle.DEFAULT_ANCHOR, new ClickHandler() {
 219  
 
 220  
             @Override
 221  
             public void onClick(ClickEvent event) {
 222  0
                     decisionPanel.show();
 223  0
             }
 224  
         }));
 225  
         
 226  0
     }
 227  
     
 228  
     protected KSButton getContinueButton(final CourseProposalController layout){
 229  0
         return new KSButton("Continue", new ClickHandler(){
 230  
                     public void onClick(ClickEvent event) {
 231  0
                             layout.showNextViewOnMenu();
 232  0
                     }
 233  
                 });
 234  
     }
 235  
 
 236  
     public void addCluStartSection(CourseProposalController layout) {
 237  0
         VerticalSectionView section = initSectionView(CourseSections.CLU_BEGIN, LUUIConstants.START_LABEL_KEY);
 238  0
         section.setController(layout);
 239  0
         addField(section, PROPOSAL_TITLE_PATH, generateMessageInfo(LUUIConstants.PROPOSAL_TITLE_LABEL_KEY));
 240  0
         addField(section, COURSE + "/" + COURSE_TITLE, generateMessageInfo(LUUIConstants.COURSE_TITLE_LABEL_KEY));
 241  
         //addField(section, "proposal/rationale", generateMessageInfo(LUConstants.PROPOSAL_RATIONALE_LABEL_KEY));
 242  
         //addField(section, PROPOSAL + "/" + PROPOSER_PERSON, generateMessageInfo(LUConstants.PROPOSAL_PERSON_LABEL_KEY), new PersonList()) ;
 243  0
         layout.addStartViewPopup(section);
 244  0
         layout.getStartPopup().setMaxHeight(600);
 245  0
     }
 246  
 
 247  
     protected View generateCourseRequisitesSection(Controller layout, boolean showSaveButtons) {
 248  0
         return new CourseRequirementsViewController(layout, getLabel(LUUIConstants.REQUISITES_LABEL_KEY), CourseSections.COURSE_REQUISITES, false, showSaveButtons);
 249  
     }
 250  
 
 251  
     protected Section generateActiveDatesSection(Section section) {
 252  
         
 253  0
             addField(section, COURSE + "/" + START_TERM, generateMessageInfo(LUUIConstants.START_TERM_LABEL_KEY));
 254  
             
 255  0
         addField(section, COURSE + "/" + PILOT_COURSE, generateMessageInfo(LUUIConstants.PILOT_COURSE_LABEL_KEY), new KSCheckBox(getLabel(LUUIConstants.PILOT_COURSE_TEXT_LABEL_KEY)));
 256  0
         addField(section, COURSE + "/" + END_TERM, generateMessageInfo(LUUIConstants.END_TERM_LABEL_KEY));
 257  
 
 258  0
         return section;
 259  
     }
 260  
     
 261  
     protected VerticalSection generateActiveDateEndSection() {
 262  0
         VerticalSection endDate = initSection(getH3Title(LUUIConstants.END_DATE_LABEL_KEY), WITH_DIVIDER);
 263  0
         addField(endDate, COURSE + "/" + EXPIRATION_DATE, generateMessageInfo(LUUIConstants.EXPIRATION_DATE_LABEL_KEY));
 264  0
         return endDate;
 265  
     }
 266  
 
 267  
     protected VerticalSection generateActiveDateStartSection() {
 268  0
         VerticalSection startDate = initSection(getH3Title(LUUIConstants.START_DATE_LABEL_KEY), WITH_DIVIDER);
 269  0
         addField(startDate, COURSE + "/" + CreditCourseConstants.EFFECTIVE_DATE, generateMessageInfo(LUUIConstants.EFFECTIVE_DATE_LABEL_KEY));
 270  0
         return startDate;
 271  
     }
 272  
 
 273  
     protected Section generateGovernanceSection(Section section) {
 274  0
         addField(section, COURSE + "/" + CAMPUS_LOCATIONS, generateMessageInfo(LUUIConstants.CAMPUS_LOCATION_LABEL_KEY));
 275  0
         addField(section, COURSE + "/" + CURRICULUM_OVERSIGHT_ORGS_, generateMessageInfo(LUUIConstants.ACADEMIC_SUBJECT_ORGS_KEY));
 276  0
         addField(section, COURSE + "/" + ADMIN_ORGS, generateMessageInfo(LUUIConstants.ADMIN_ORG_LABEL_KEY));
 277  
 
 278  0
         return section;
 279  
     }
 280  
 
 281  
     public Section generateCourseInfoSection(Section section) {
 282  0
         addField(section, PROPOSAL_TITLE_PATH, generateMessageInfo(LUUIConstants.PROPOSAL_TITLE_LABEL_KEY));
 283  0
         addField(section, COURSE + "/" + COURSE_TITLE, generateMessageInfo(LUUIConstants.COURSE_TITLE_LABEL_KEY));
 284  0
         addField(section, COURSE + "/" + TRANSCRIPT_TITLE, generateMessageInfo(LUUIConstants.SHORT_TITLE_LABEL_KEY));
 285  0
         section.addSection(generateCourseNumberSection());
 286  0
             FieldDescriptor instructorsFd = addField(section, COURSE + "/" + INSTRUCTORS, generateMessageInfo(LUUIConstants.INSTRUCTORS_LABEL_KEY));
 287  0
         instructorsFd.setWidgetBinding(new KeyListModelWigetBinding("personId"));
 288  
 
 289  0
         section.addSection(generateDescriptionRationaleSection());
 290  
         
 291  0
         return section;
 292  
     }
 293  
             
 294  
 
 295  
     protected GroupSection generateCourseNumberSection() {
 296  
 
 297  
         //COURSE NUMBER
 298  0
         GroupSection courseNumber = new GroupSection(getH4Title(""));
 299  0
         courseNumber.addStyleName(LUUIConstants.STYLE_SECTION);
 300  0
         courseNumber.addStyleName(LUUIConstants.STYLE_SECTION_DIVIDER);
 301  0
         addField(courseNumber, COURSE + "/" + SUBJECT_AREA, generateMessageInfo(LUUIConstants.SUBJECT_CODE_LABEL_KEY));
 302  0
         addField(courseNumber, COURSE + "/" + COURSE_NUMBER_SUFFIX, generateMessageInfo(LUUIConstants.COURSE_NUMBER_LABEL_KEY));
 303  
 //        addField(courseNumber, COURSE + "/" + SUBJECT_AREA);
 304  
 //        addField(courseNumber, COURSE + "/" + COURSE_NUMBER_SUFFIX);
 305  
 
 306  0
         courseNumber.addSection(generateCrossListed_Ver_Joint_Section());
 307  
 
 308  0
         return courseNumber;
 309  
     }
 310  
 
 311  
     protected CollapsableSection generateCrossListed_Ver_Joint_Section() {
 312  0
         CollapsableSection result = new CollapsableSection(getLabel(LUUIConstants.CL_V_J_LABEL_KEY));
 313  
 
 314  
 //        addField(result, COURSE + "/" + CROSS_LISTINGS, null, new CrossListedList(COURSE + "/" + CROSS_LISTINGS));
 315  
 //        addField(result, COURSE + "/" + JOINTS, null, new OfferedJointlyList(COURSE + "/" + JOINTS));
 316  
 //        addField(result, COURSE + "/" + VERSIONS, null, new VersionCodeList(COURSE + "/" + VERSIONS));
 317  0
         SpanPanel crslabelpan = new SpanPanel();
 318  0
         crslabelpan.setStyleName("ks-multiplicity-section-label");
 319  0
         crslabelpan.setHTML("Cross Listed Courses");
 320  0
         crslabelpan.setVisible(true);
 321  0
         result.addWidget(crslabelpan);
 322  0
         addMultiplicityFields(result, COURSE + QueryPath.getPathSeparator() + CROSS_LISTINGS,
 323  
                 LUUIConstants.ADD_CROSS_LISTED_LABEL_KEY,
 324  
                 LUUIConstants.CROSS_LISTED_ITEM_LABEL_KEY,
 325  
                 Arrays.asList(
 326  
                         new MultiplicityFieldConfig(
 327  
                                 SUBJECT_AREA, 
 328  
                                 LUUIConstants.SUBJECT_CODE_LABEL_KEY, null, null, true),
 329  
                         new MultiplicityFieldConfig(
 330  
                                 COURSE_NUMBER_SUFFIX, 
 331  
                                 LUUIConstants.COURSE_NUMBER_LABEL_KEY, null, null, true)),
 332  
                         null,
 333  
                         null,0);
 334  0
         SpanPanel jntlabelpan = new SpanPanel();
 335  0
         jntlabelpan.setStyleName("ks-multiplicity-section-label");
 336  0
         jntlabelpan.setHTML("Jointly Offered Courses");
 337  0
         jntlabelpan.setVisible(true);
 338  0
         result.addWidget(jntlabelpan);
 339  0
         addMultiplicityFields(result, COURSE + QueryPath.getPathSeparator() + JOINTS,
 340  
                 LUUIConstants.ADD_EXISTING_LABEL_KEY,
 341  
                 LUUIConstants.JOINT_OFFER_ITEM_LABEL_KEY,
 342  
                 Arrays.asList(
 343  
                         new MultiplicityFieldConfig(
 344  
                                 CreditCourseJointsConstants.COURSE_ID, 
 345  
                                 LUUIConstants.COURSE_NUMBER_OR_TITLE_LABEL_KEY, null, null, true)),
 346  
                                 null,
 347  
                                 null,0);
 348  0
         SpanPanel vsnlabelpan = new SpanPanel();
 349  0
         vsnlabelpan.setStyleName("ks-multiplicity-section-label");
 350  0
         vsnlabelpan.setHTML("Version Codes");
 351  0
         vsnlabelpan.setVisible(true);
 352  0
         result.addWidget(vsnlabelpan);
 353  0
         addMultiplicityFields(result, COURSE + QueryPath.getPathSeparator() + VERSIONS,
 354  
                 LUUIConstants.ADD_VERSION_CODE_LABEL_KEY,
 355  
                 LUUIConstants.VERSION_CODE_LABEL_KEY,
 356  
                 Arrays.asList(
 357  
                         new MultiplicityFieldConfig(
 358  
                                 "variationCode", 
 359  
                                 LUUIConstants.VERSION_CODE_LABEL_KEY, null, null, true), 
 360  
                         new MultiplicityFieldConfig(
 361  
                                 "variationTitle", 
 362  
                                 LUUIConstants.TITLE_LABEL_KEY, null, null, true)
 363  
                 ),
 364  
                 null,
 365  
                 null,0);
 366  0
         return result;
 367  
     }
 368  
     
 369  
     protected void addFeeMultiplicityFields(Section section,  
 370  
             String path, String addItemlabelMessageKey,
 371  
             String itemLabelMessageKey, List<MultiplicityFieldConfig> fieldConfigs,
 372  
             Map<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>> swappableFieldsDefinition,
 373  
             List<String> deletionParentKeys) {
 374  0
         MultiplicityConfiguration config = setupMultiplicityConfig(
 375  
                 MultiplicityConfiguration.MultiplicityType.GROUP,
 376  
                 MultiplicityConfiguration.StyleType.TOP_LEVEL_GROUP,
 377  
                 path, addItemlabelMessageKey, itemLabelMessageKey,
 378  
                 fieldConfigs, swappableFieldsDefinition, deletionParentKeys);
 379  0
         MultiplicitySection ms = null;
 380  0
         ms = new MultiplicitySection(config, swappableFieldsDefinition, deletionParentKeys);
 381  0
         section.addSection(ms);
 382  
 
 383  0
     }
 384  
     
 385  
     protected MultiplicityConfiguration setupMultiplicityConfig(
 386  
             MultiplicityConfiguration.MultiplicityType multiplicityType,
 387  
             MultiplicityConfiguration.StyleType styleType,
 388  
             String path, String addItemlabelMessageKey,
 389  
             String itemLabelMessageKey, List<MultiplicityFieldConfig> fieldConfigs,
 390  
             Map<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>> swappableFieldsDefinition,
 391  
             List<String> deletionParentKeys) {
 392  0
         QueryPath parentPath = QueryPath.concat(path);
 393  0
         MultiplicityConfiguration config = new MultiplicityConfiguration(multiplicityType,
 394  
                 styleType, getMetaData(parentPath.toString()));
 395  0
         config.setAddItemLabel(getLabel(addItemlabelMessageKey));
 396  0
         config.setItemLabel(getLabel(itemLabelMessageKey));
 397  0
         config.setUpdateable(true);
 398  
 
 399  0
         FieldDescriptor parentFd = buildMultiplicityParentFieldDescriptor(path, getLabel(itemLabelMessageKey), null);
 400  0
         config.setParent(parentFd);
 401  
 
 402  0
         if (fieldConfigs != null) {
 403  0
             for (MultiplicityFieldConfig fieldConfig : fieldConfigs) {
 404  0
                 MultiplicityFieldConfiguration fc = buildMultiplicityFD(fieldConfig.getFieldKey(),
 405  
                         fieldConfig.getLabelKey(), parentPath.toString());
 406  0
                 config.addFieldConfiguration(fc);
 407  0
                 if (fieldConfig.isNextLine()) {
 408  0
                     config.nextLine();
 409  
                 }
 410  0
             }
 411  
         }
 412  0
         return config;
 413  
     }
 414  
 
 415  
     protected MultiplicitySection addMultiplicityFields(Section section,  
 416  
             String path, String addItemlabelMessageKey,
 417  
             String itemLabelMessageKey, List<MultiplicityFieldConfig> fieldConfigs,
 418  
             Map<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>> swappableFieldsDefinition,
 419  
             List<String> deletionParentKeys,int defaultItemsCreated) {
 420  0
         MultiplicityConfiguration config = setupMultiplicityConfig(
 421  
                 MultiplicityConfiguration.MultiplicityType.GROUP,
 422  
                 MultiplicityConfiguration.StyleType.TOP_LEVEL_GROUP,
 423  
                 path, addItemlabelMessageKey, itemLabelMessageKey,
 424  
                 fieldConfigs, swappableFieldsDefinition, deletionParentKeys);
 425  0
         config.setDefaultItemsCreated(defaultItemsCreated);
 426  0
         MultiplicitySection ms = null;
 427  0
         ms = new MultiplicitySection(config, swappableFieldsDefinition, deletionParentKeys);
 428  0
         section.addSection(ms);
 429  0
         return ms;
 430  
     }
 431  
 
 432  
     protected Metadata getMetaData(String fieldKey) {
 433  0
         return modelDefinition.getMetadata(QueryPath.concat(fieldKey));
 434  
     }
 435  
 
 436  
     protected MultiplicityFieldConfiguration buildMultiplicityFD(
 437  
             String fieldKey, String labelKey, String parentPath) {
 438  
 
 439  0
         QueryPath fieldPath = QueryPath.concat(parentPath, QueryPath.getWildCard(), fieldKey);
 440  0
         Metadata meta = modelDefinition.getMetadata(fieldPath);
 441  
 
 442  0
         MultiplicityFieldConfiguration fd = new MultiplicityFieldConfiguration(
 443  
                 fieldPath.toString(), generateMessageInfo(labelKey), meta, null);
 444  
         
 445  
 
 446  0
         return fd;
 447  
 
 448  
     }
 449  
 
 450  
     protected FieldDescriptor buildMultiplicityParentFieldDescriptor(String fieldKey, String messageKey, String parentPath) {
 451  0
         QueryPath path = QueryPath.concat(parentPath, fieldKey);
 452  0
         Metadata meta = modelDefinition.getMetadata(path);
 453  
 
 454  0
         FieldDescriptor fd = new FieldDescriptor(path.toString(), generateMessageInfo(messageKey), meta);
 455  0
         fd.hideLabel();
 456  0
         return fd;
 457  
     }
 458  
 
 459  
     protected VerticalSection generateCourseInfoShortTitleSection() {
 460  0
         VerticalSection shortTitle = initSection(getH3Title(LUUIConstants.SHORT_TITLE_LABEL_KEY), WITH_DIVIDER);
 461  0
         addField(shortTitle, COURSE + "/" + TRANSCRIPT_TITLE, null);
 462  0
         return shortTitle;
 463  
     }
 464  
 
 465  
     protected VerticalSection generateLongTitleSection() {
 466  0
         VerticalSection longTitle = initSection(getH3Title(LUUIConstants.TITLE_LABEL_KEY), WITH_DIVIDER);
 467  0
         addField(longTitle, COURSE + "/" + COURSE_TITLE, null);
 468  0
         return longTitle;
 469  
     }
 470  
 
 471  
     protected VerticalSection generateDescriptionRationaleSection() {
 472  0
         SectionTitle title = getH4Title(LUUIConstants.PROPOSAL_TITLE_SECTION_LABEL_KEY);
 473  0
         VerticalSection description = initSection(title, !WITH_DIVIDER);
 474  0
         title.setStyleName("cluProposalTitleSection");
 475  
         //FIXME [KSCOR-225] Temporary fix til we have a real rich text editor
 476  
         //addField(description, COURSE + "/" + DESCRIPTION, null);
 477  0
         addField(description, COURSE + "/" + DESCRIPTION + "/" + RichTextInfoConstants.PLAIN, generateMessageInfo(LUUIConstants.DESCRIPTION_LABEL_KEY));
 478  0
         addField(description, "proposal/rationale", generateMessageInfo(LUUIConstants.PROPOSAL_RATIONALE_LABEL_KEY));
 479  0
         return description;
 480  
     }
 481  
 
 482  
     public Section generateCourseLogisticsSection(Section section) {
 483  0
             if (section instanceof SectionView){
 484  0
                     ((SectionView)section).setInstructions(getLabel(LUUIConstants.LOGISTICS_LABEL_KEY + "-instruct") + "<br><br>");
 485  
             }
 486  
 
 487  0
         section.addSection(generateSchedulingSection());
 488  0
         section.addSection(generateDurationSection());
 489  0
         section.addSection(generateLearningResultsSection());
 490  0
         section.addSection(generateCourseFormatsSection());
 491  
 
 492  0
         return section;
 493  
     }
 494  
 
 495  
     protected Section generateLearningResultsSection() {
 496  0
         VerticalSection learningResults = initSection(getH3Title(LUUIConstants.LEARNING_RESULTS_LABEL_KEY), WITH_DIVIDER);
 497  0
         learningResults.setInstructions(getLabel(LUUIConstants.LEARNING_RESULTS_LABEL_KEY + "-instruct") + "<br><br><br>");
 498  
 
 499  0
         learningResults.addSection(generateGradesAssessmentsSection());
 500  0
         learningResults.addSection(generateStudentRegistrationOptionsSection());
 501  0
         learningResults.addSection(generateFinalExamSection());
 502  0
         learningResults.addSection(generateOutcomesSection());
 503  
 
 504  0
         return learningResults;
 505  
     }
 506  
 
 507  
     protected Section generateOutcomesSection() {
 508  
 
 509  0
         String path = COURSE + QueryPath.getPathSeparator() + CREDIT_OPTIONS;
 510  0
         QueryPath creditTypeFullPath = QueryPath.concat(path, QueryPath.getWildCard(), CreditCourseConstants.TYPE);
 511  0
         QueryPath creditOptionFixedFullPath = QueryPath.concat(path, QueryPath.getWildCard(), CREDIT_OPTION_FIXED_CREDITS);
 512  0
         QueryPath creditOptionMinFullPath = QueryPath.concat(path, QueryPath.getWildCard(), CREDIT_OPTION_MIN_CREDITS);
 513  0
         QueryPath creditOptionMaxFullPath = QueryPath.concat(path, QueryPath.getWildCard(), CREDIT_OPTION_MAX_CREDITS);
 514  0
         QueryPath creditResultValuesFullPath = QueryPath.concat(path, QueryPath.getWildCard(), "resultValues");
 515  
 
 516  0
         VerticalSection courseOutcomes = initSection(getH3Title(LUUIConstants.LEARNING_RESULT_OUTCOME_LABEL_KEY), WITH_DIVIDER);
 517  0
         Map<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>> swappableFieldsDefinition =
 518  
             new HashMap<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>>();
 519  0
         SwapCompositeCondition fixedCreditCondition = new SwapCompositeCondition(
 520  
                 CompositeConditionOperator.AND);
 521  0
         fixedCreditCondition.getChildrenConditions().add(
 522  
                 makeCondition(creditTypeFullPath, LUUIConstants.LEARNING_RESULT_OUTCOME_TYPE_LABEL_KEY, "kuali.resultComponentType.credit.degree.fixed")
 523  
         );
 524  0
         fixedCreditCondition.setConditionId("1");
 525  0
         SwapCompositeCondition multipleCreditCondition = new SwapCompositeCondition(
 526  
                 CompositeConditionOperator.AND);
 527  0
         multipleCreditCondition.getChildrenConditions().add(
 528  
                 makeCondition(creditTypeFullPath, LUUIConstants.LEARNING_RESULT_OUTCOME_TYPE_LABEL_KEY, "kuali.resultComponentType.credit.degree.multiple")
 529  
         );
 530  0
         multipleCreditCondition.setConditionId("2");
 531  0
         SwapCompositeCondition variableCreditCondition = new SwapCompositeCondition(
 532  
                 CompositeConditionOperator.AND);
 533  0
         variableCreditCondition.getChildrenConditions().add(
 534  
                 makeCondition(creditTypeFullPath, LUUIConstants.LEARNING_RESULT_OUTCOME_TYPE_LABEL_KEY, "kuali.resultComponentType.credit.degree.range")
 535  
         );
 536  0
         variableCreditCondition.setConditionId("3");
 537  
         
 538  0
         swappableFieldsDefinition.put(fixedCreditCondition,
 539  
                 Arrays.asList(
 540  
                         new SwapCompositeConditionFieldConfig(
 541  
                                 new MultiplicityFieldConfiguration(
 542  
                                         creditOptionFixedFullPath.toString(), 
 543  
                                         generateMessageInfo(LUUIConstants.CREDIT_OPTION_FIXED_CREDITS_LABEL_KEY),
 544  
                                         modelDefinition.getMetadata(creditOptionFixedFullPath),
 545  
                                         null),
 546  
                                 null
 547  
                         )
 548  
                 )
 549  
         );
 550  0
         MultiplicityFieldWidgetInitializer multipleCreditInitializer = 
 551  0
             new MultiplicityFieldWidgetInitializer() {
 552  
                 @Override
 553  
                 public ModelWidgetBinding<?> getModelWidgetBindingInstance() {
 554  0
                     return new ListOfStringBinding();
 555  
                 }
 556  
                 @Override
 557  
                 public Widget getNewWidget() {
 558  0
                     return new ListOfStringWidget("Add Item");
 559  
                 }
 560  
         };
 561  
         
 562  0
         swappableFieldsDefinition.put(multipleCreditCondition,
 563  
                 Arrays.asList(
 564  
                         new SwapCompositeConditionFieldConfig(
 565  
                                 new MultiplicityFieldConfiguration(
 566  
                                         creditResultValuesFullPath.toString(),
 567  
                                         generateMessageInfo(LUUIConstants.CREDIT_OPTION_FIXED_CREDITS_LABEL_KEY),
 568  
                                         modelDefinition.getMetadata(creditResultValuesFullPath),
 569  
                                         multipleCreditInitializer),
 570  
                                 null
 571  
                         )
 572  
                 )
 573  
         );
 574  0
         swappableFieldsDefinition.put(variableCreditCondition,
 575  
                 Arrays.asList(
 576  
                         new SwapCompositeConditionFieldConfig(
 577  
                                 new MultiplicityFieldConfiguration(
 578  
                                         creditOptionMinFullPath.toString(), 
 579  
                                         generateMessageInfo(LUUIConstants.CREDIT_OPTION_MIN_CREDITS_LABEL_KEY),
 580  
                                         modelDefinition.getMetadata(creditOptionMinFullPath),
 581  
                                         null),
 582  
                                 null
 583  
                         ),
 584  
                         new SwapCompositeConditionFieldConfig(
 585  
                                 new MultiplicityFieldConfiguration(
 586  
                                         creditOptionMaxFullPath.toString(), 
 587  
                                         generateMessageInfo(LUUIConstants.CREDIT_OPTION_MAX_CREDITS_LABEL_KEY),
 588  
                                         modelDefinition.getMetadata(creditOptionMaxFullPath),
 589  
                                         null),
 590  
                                 null
 591  
                         )
 592  
                 )
 593  
         );
 594  
         
 595  0
         MultiplicitySection ms = addMultiplicityFields(
 596  
                 courseOutcomes, 
 597  
                 path, 
 598  
                 LUUIConstants.LEARNING_RESULT_OUTCOME_LABEL_KEY,
 599  
                 LUUIConstants.LEARNING_RESULT_OUTCOME_LABEL_KEY,
 600  
                 Arrays.asList(
 601  
                                 new MultiplicityFieldConfig(
 602  
                                 CreditCourseConstants.TYPE,
 603  
                                 LUUIConstants.LEARNING_RESULT_OUTCOME_TYPE_LABEL_KEY,
 604  
                                 null, null, true)
 605  
                 ), swappableFieldsDefinition, null,1);
 606  
         //Set the required panel
 607  0
         courseOutcomes.setRequired(ms.getConfig().getParentFd().getFieldElement().getRequiredPanel());
 608  0
         return courseOutcomes;
 609  
 
 610  
     }
 611  
 
 612  
     protected Section generateStudentRegistrationOptionsSection() {
 613  0
         VerticalSection studentRegistrationOptionsSection = initSection(getH3Title(LUUIConstants.LEARNING_RESULTS_STUDENT_REGISTRATION_LABEL_KEY), WITH_DIVIDER);
 614  
 
 615  0
         addField(studentRegistrationOptionsSection, COURSE + "/" + AUDIT, generateMessageInfo(LUUIConstants.LEARNING_RESULT_AUDIT_LABEL_KEY), new KSCheckBox(getLabel(LUUIConstants.LEARNING_RESULT_AUDIT_TEXT_LABEL_KEY)));
 616  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)));
 617  
 
 618  0
         return studentRegistrationOptionsSection;
 619  
     }
 620  
 
 621  
     protected Section generateGradesAssessmentsSection() {
 622  0
         VerticalSection gradesAssessments = initSection(getH3Title(LUUIConstants.LEARNING_RESULTS_GRADES_ASSESSMENTS_LABEL_KEY), WITH_DIVIDER);
 623  
 
 624  0
         addField(gradesAssessments, COURSE + "/" + GRADING_OPTIONS, generateMessageInfo(LUUIConstants.LEARNING_RESULT_ASSESSMENT_SCALE_LABEL_KEY));
 625  
 
 626  0
         return gradesAssessments;
 627  
     }
 628  
 
 629  
     protected VerticalSection generateCourseFormatsSection() {
 630  
         //COURSE FORMATS
 631  0
         VerticalSection courseFormats = initSection(getH3Title(LUUIConstants.FORMATS_LABEL_KEY), WITH_DIVIDER);
 632  0
         courseFormats.setHelp(getLabel(LUUIConstants.FORMATS_LABEL_KEY + "-help"));
 633  0
         courseFormats.setInstructions(getLabel(LUUIConstants.FORMATS_LABEL_KEY + "-instruct"));
 634  0
         MultiplicityConfiguration courseFormatConfig = setupMultiplicityConfig(
 635  
                 MultiplicityConfiguration.MultiplicityType.GROUP,
 636  
                 MultiplicityConfiguration.StyleType.TOP_LEVEL_GROUP,
 637  
                 COURSE + "/" + FORMATS, LUUIConstants.COURSE_ADD_FORMAT_LABEL_KEY,
 638  
                 LUUIConstants.FORMAT_LABEL_KEY,
 639  
                 null, null, null);
 640  0
         courseFormatConfig.setDefaultItemsCreated(1);
 641  0
         MultiplicityConfiguration activitiesConfig = setupMultiplicityConfig(
 642  
                 MultiplicityConfiguration.MultiplicityType.GROUP,
 643  
                 MultiplicityConfiguration.StyleType.SUB_LEVEL_GROUP,
 644  
                 COURSE + "/" + FORMATS + "/*/" + ACTIVITIES, 
 645  
                 LUUIConstants.ADD_ACTIVITY_LABEL_KEY,
 646  
                 LUUIConstants.ACTIVITY_LITERAL_LABEL_KEY,
 647  
                 Arrays.asList(
 648  
                         new MultiplicityFieldConfig(
 649  
                                 ACTIVITY_TYPE,
 650  
                                 LUUIConstants.ACTIVITY_TYPE_LABEL_KEY,
 651  
                                 null,
 652  
                                 null,
 653  
                                 true),
 654  
                         new MultiplicityFieldConfig(
 655  
                                 CONTACT_HOURS + "/" + "unitQuantity",
 656  
                                 LUUIConstants.CONTACT_HOURS_LABEL_KEY,
 657  
                                 null,
 658  
                                 null,
 659  
                                 false),
 660  
                         new MultiplicityFieldConfig(
 661  
                                 CONTACT_HOURS + "/" + "unitType",
 662  
                                 LUUIConstants.CONTACT_HOURS_FREQUENCY_LABEL_KEY,
 663  
                                 null,
 664  
                                 null,
 665  
                                 true),
 666  
                         new MultiplicityFieldConfig(
 667  
                                 CreditCourseActivityConstants.DURATION + "/" + "atpDurationTypeKey",
 668  
                                 LUUIConstants.COURSE_FORMATS_DURATION_TYPE_LABEL_KEY,
 669  
                                 null,
 670  
                                 null,
 671  
                                 false),
 672  
                         new MultiplicityFieldConfig(
 673  
                                 CreditCourseActivityConstants.DURATION + "/" + "timeQuantity",
 674  
                                 LUUIConstants.DURATION_QUANTITY_LABEL_KEY,
 675  
                                 null,
 676  
                                 null,
 677  
                                 true),
 678  
                         new MultiplicityFieldConfig(
 679  
                                 DEFAULT_ENROLLMENT_ESTIMATE,
 680  
                                 LUUIConstants.CLASS_SIZE_LABEL_KEY,
 681  
                                 null,
 682  
                                 null,
 683  
                                 true)
 684  
                 ), null, null);
 685  0
         activitiesConfig.setDefaultItemsCreated(1);
 686  0
         courseFormatConfig.setNestedConfig(activitiesConfig);
 687  
         
 688  
 
 689  0
         MultiplicitySection ms = null;
 690  0
         ms = new MultiplicitySection(courseFormatConfig, 
 691  
                 null, null);
 692  0
         courseFormats.addSection(ms);
 693  0
         courseFormats.setRequired(courseFormatConfig.getParentFd().getFieldElement().getRequiredPanel());
 694  0
         return courseFormats;
 695  
     }
 696  
 
 697  
     protected VerticalSection generateSchedulingSection() {
 698  0
         VerticalSection scheduling = initSection(getH3Title(LUUIConstants.SCHEDULING_LABEL_KEY), WITH_DIVIDER);
 699  0
         addField(scheduling, COURSE + "/" + TERMS_OFFERED, generateMessageInfo(LUUIConstants.TERMS_OFFERED_LABEL_KEY));
 700  0
         return scheduling;
 701  
     }
 702  
 
 703  
     protected VerticalSection generateDurationSection() {
 704  0
         VerticalSection duration = initSection(getH3Title(LUUIConstants.DURATION_LITERAL_LABEL_KEY), WITH_DIVIDER);
 705  0
         duration.setInstructions(getLabel(LUUIConstants.DURATION_LITERAL_LABEL_KEY + "-instruct"));
 706  0
         GroupSection duration_group = new GroupSection();
 707  0
         addField(duration_group, COURSE + "/" + CreditCourseConstants.DURATION + "/" + "atpDurationTypeKey", generateMessageInfo(LUUIConstants.DURATION_TYPE_LABEL_KEY));
 708  0
         addField(duration_group, COURSE + "/" + CreditCourseConstants.DURATION + "/" + "timeQuantity", generateMessageInfo(LUUIConstants.DURATION_QUANTITY_LABEL_KEY));
 709  
 
 710  0
         duration.addSection(duration_group);
 711  0
         return duration;
 712  
     }
 713  
 
 714  
     protected VerticalSection generateFinalExamSection() {
 715  0
         VerticalSection finalExam = initSection(getH3Title(LUUIConstants.FINAL_EXAM_LABEL_KEY), WITH_DIVIDER);
 716  0
         GroupSection finalExam_group = new GroupSection();
 717  0
         GroupSection finalExamRationale_group = new GroupSection();
 718  0
         GroupSection finalExamRationale_group2 = new GroupSection();
 719  
 
 720  0
         FieldDescriptor field = addField(finalExam_group, COURSE + "/" + CreditCourseConstants.FINAL_EXAM, generateMessageInfo(LUUIConstants.FINAL_EXAM_STATUS_LABEL_KEY));
 721  
 
 722  0
         if (field.isVisible()){
 723  0
                 KSSelectItemWidgetAbstract picker = (KSSelectItemWidgetAbstract) (((KSPicker) field.getFieldWidget()).getInputWidget());
 724  0
                 addField(finalExamRationale_group, COURSE + "/" + CreditCourseConstants.FINAL_EXAM_RATIONALE, generateMessageInfo(LUUIConstants.FINAL_EXAM_RATIONALE_LABEL_KEY));
 725  0
                 addField(finalExamRationale_group2, COURSE + "/" + CreditCourseConstants.FINAL_EXAM_RATIONALE, generateMessageInfo(LUUIConstants.FINAL_EXAM_RATIONALE_LABEL_KEY));
 726  0
                 SwapSection swapSection = new SwapSection(picker);
 727  0
                 swapSection.addSection(finalExamRationale_group, "ALT");
 728  0
                 swapSection.addSection(finalExamRationale_group2, "None");
 729  0
                 finalExam.addSection(finalExam_group);
 730  
         
 731  0
                 finalExam.addSection(swapSection);
 732  0
                 return finalExam;
 733  
         } else {
 734  0
                 return new VerticalSection();
 735  
         }
 736  
 
 737  
     }
 738  
 
 739  
     protected VerticalSection generateInstructorsSection() {
 740  0
         VerticalSection instructors = initSection(getH3Title(LUUIConstants.INSTRUCTOR_LABEL_KEY), WITH_DIVIDER);
 741  0
         addField(instructors, COURSE + "/" + PRIMARY_INSTRUCTOR + "/personId");
 742  0
         return instructors;
 743  
     }
 744  
 
 745  
     protected SectionView generateLearningObjectivesSection() {
 746  0
         VerticalSectionView section = initSectionView(CourseSections.LEARNING_OBJECTIVES, LUUIConstants.LEARNING_OBJECTIVES_LABEL_KEY);
 747  0
         section.setInstructions(getLabel(LUUIConstants.LEARNING_OBJECTIVES_LABEL_KEY + "-instruct"));
 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  
     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), COURSE_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  
     public MessageKeyInfo generateMessageInfo(String labelKey) {
 861  0
         return new MessageKeyInfo(groupName, type, state, labelKey);
 862  
     }
 863  
 
 864  
     
 865  
     protected Section generateFinancialsSection(Section section) {
 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 CourseProposalConfigurer.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  
     public CourseSummaryConfigurer getSummaryConfigurer() {
 1129  0
         return summaryConfigurer;
 1130  
     }
 1131  
 
 1132  0
     public static class KeyListModelWigetBinding extends ModelWidgetBindingSupport<HasDataValue> {
 1133  
         protected String key;
 1134  0
         HasDataValueBinding hasDataValueBinding = HasDataValueBinding.INSTANCE;
 1135  
 
 1136  0
         public KeyListModelWigetBinding(String key) {
 1137  0
             this.key = key;
 1138  0
         }
 1139  
 
 1140  
         @Override
 1141  
         public void setModelValue(HasDataValue widget, DataModel model, String path) {
 1142  
             // convert from the structure path/0/<id> into path/0/<key>/<id>
 1143  0
             hasDataValueBinding.setModelValue(widget, model, path);
 1144  
 
 1145  0
             QueryPath qPath = QueryPath.parse(path);
 1146  0
             Value value = ((KSSelectedList) widget).getValueWithTranslations();
 1147  
 
 1148  0
             Data idsData = null;
 1149  0
             Data idsDataStruct = null;
 1150  
 
 1151  0
             if (value != null) {
 1152  0
                 idsData = value.get();
 1153  
             }
 1154  0
             if (idsData != null) {
 1155  0
                 for (Data.Property p : idsData) {
 1156  0
                     if (!"_runtimeData".equals(p.getKey())) {
 1157  0
                         String id = p.getValue();
 1158  
                         // old translation path path/_runtimeData/0/id-translation
 1159  0
                         QueryPath translationPath = new QueryPath();
 1160  0
                         translationPath.add(new Data.StringKey(qPath.toString()));
 1161  0
                         translationPath.add(new Data.StringKey("_runtimeData"));
 1162  0
                         translationPath.add(new Data.IntegerKey((Integer) p.getKey()));
 1163  0
                         translationPath.add(new Data.StringKey("id-translation"));
 1164  
 
 1165  0
                         Data idItem = new Data();
 1166  0
                         String translation = model.get(translationPath.toString());
 1167  0
                         Data idItemRuntime = new Data();
 1168  0
                         Data idItemTranslation = new Data();
 1169  0
                         idsDataStruct = (idsDataStruct == null) ? new Data() : idsDataStruct;
 1170  0
                         idItem.set(this.key, id);
 1171  
                         // new translation path/0/_runtimeData/<key>/id-translation
 1172  0
                         idItemTranslation.set("id-translation", translation);
 1173  0
                         idItemRuntime.set(this.key, idItemTranslation);
 1174  0
                         idItem.set("_runtimeData", idItemRuntime);
 1175  0
                         idsDataStruct.add(idItem);
 1176  0
                     }
 1177  
                 }
 1178  
             }
 1179  
 
 1180  0
             model.set(qPath, idsDataStruct);
 1181  0
         }
 1182  
 
 1183  
         @Override
 1184  
         public void setWidgetValue(HasDataValue widget, DataModel model, String path) {
 1185  0
             DataModel middleManModel = new DataModel();
 1186  0
             if (model != null && model.getRoot() != null) {
 1187  0
                 middleManModel = new DataModel(model.getDefinition(), model.getRoot().copy());
 1188  
             }
 1189  
             // convert from the structure path/0/<key>/<id> into path/0/<id>
 1190  0
             QueryPath qPath = QueryPath.parse(path);
 1191  0
             Object value = null;
 1192  0
             Data idsData = null;
 1193  0
             Data newIdsData = null;
 1194  0
             Data newIdsRuntimeData = null;
 1195  
 
 1196  0
             if (middleManModel != null) {
 1197  0
                 value = middleManModel.get(qPath);
 1198  
             }
 1199  
 
 1200  0
             if (value != null) {
 1201  0
                 idsData = (Data) value;
 1202  0
                 if (idsData != null) {
 1203  0
                     for (Data.Property p : idsData) {
 1204  0
                         if (!"_runtimeData".equals(p.getKey())) {
 1205  0
                             Data idItem = p.getValue();
 1206  0
                             String id = idItem.get(key);
 1207  0
                             Data runtimeData = idItem.get("_runtimeData");
 1208  
                             // KSLAB-1790 - sometime runtimeData isn't there; no idea why
 1209  0
                             Data translationData = null != runtimeData ? ((Data) runtimeData.get(key)) : new Data();
 1210  0
                             newIdsData = (newIdsData == null) ? new Data() : newIdsData;
 1211  0
                             newIdsData.add(id);
 1212  0
                             newIdsRuntimeData = (newIdsRuntimeData == null) ? new Data() : newIdsRuntimeData;
 1213  0
                             newIdsRuntimeData.add(translationData);
 1214  0
                         }
 1215  
                     }
 1216  
                 }
 1217  
             }
 1218  0
             if (newIdsData != null) {
 1219  0
                 newIdsData.set("_runtimeData", newIdsRuntimeData);
 1220  0
                 middleManModel.set(qPath, newIdsData);
 1221  0
                 hasDataValueBinding.setWidgetValue(widget, middleManModel, path);
 1222  
             }
 1223  0
         }
 1224  
     }
 1225  
 
 1226  
 
 1227  0
     public static class MultiplicityFieldConfig {
 1228  
         protected String fieldKey;
 1229  
         protected String labelKey;
 1230  
         boolean nextLine;
 1231  
         
 1232  0
         public MultiplicityFieldConfig() {
 1233  0
         }
 1234  
         public MultiplicityFieldConfig(String fieldKey, String labelKey,
 1235  0
                 Widget fieldWidget, ModelWidgetBinding<?> modelWidgetBinding, boolean nextLine) {
 1236  0
             setFieldKey(fieldKey);
 1237  0
             setLabelKey(labelKey);
 1238  0
             setNextLine(nextLine);
 1239  0
         }
 1240  
         public String getFieldKey() {
 1241  0
             return fieldKey;
 1242  
         }
 1243  
         public void setFieldKey(String fieldKey) {
 1244  0
             this.fieldKey = fieldKey;
 1245  0
         }
 1246  
         public String getLabelKey() {
 1247  0
             return labelKey;
 1248  
         }
 1249  
         public void setLabelKey(String labelKey) {
 1250  0
             this.labelKey = labelKey;
 1251  0
         }
 1252  
         public boolean isNextLine() {
 1253  0
             return nextLine;
 1254  
         }
 1255  
         public void setNextLine(boolean nextLine) {
 1256  0
             this.nextLine = nextLine;
 1257  0
         }
 1258  
     }
 1259  
 }
 1260  
 
 1261  
 
 1262  
 
 1263