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