Coverage Report - org.kuali.student.common.ui.client.configurable.mvc.multiplicity.MultiplicityGroup
 
Classes in this File Line Coverage Branch Coverage Complexity
MultiplicityGroup
0%
0/219
0%
0/88
1.905
MultiplicityGroup$1
0%
0/5
N/A
1.905
MultiplicityGroup$2
0%
0/3
N/A
1.905
MultiplicityGroup$3
0%
0/3
N/A
1.905
MultiplicityGroup$4
0%
0/3
N/A
1.905
MultiplicityGroup$ConditionChoices
0%
0/41
0%
0/4
1.905
MultiplicityGroup$SwappableFieldsHelper
0%
0/43
0%
0/20
1.905
 
 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  
  * <p/>
 7  
  * http://www.osedu.org/licenses/ECL-2.0
 8  
  * <p/>
 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  
  * <p/>
 15  
  */
 16  
 package org.kuali.student.common.ui.client.configurable.mvc.multiplicity;
 17  
 
 18  
 import java.util.ArrayList;
 19  
 import java.util.HashMap;
 20  
 import java.util.List;
 21  
 import java.util.Map;
 22  
 import java.util.Set;
 23  
 import java.util.Map.Entry;
 24  
 
 25  
 import org.kuali.student.common.assembly.data.Data;
 26  
 import org.kuali.student.common.assembly.data.MetadataInterrogator;
 27  
 import org.kuali.student.common.assembly.data.QueryPath;
 28  
 import org.kuali.student.common.ui.client.configurable.mvc.FieldDescriptor;
 29  
 import org.kuali.student.common.ui.client.configurable.mvc.binding.ModelWidgetBinding;
 30  
 import org.kuali.student.common.ui.client.configurable.mvc.sections.BaseSection;
 31  
 import org.kuali.student.common.ui.client.configurable.mvc.sections.GroupSection;
 32  
 import org.kuali.student.common.ui.client.configurable.mvc.sections.MultiplicitySection;
 33  
 import org.kuali.student.common.ui.client.configurable.mvc.sections.Section;
 34  
 import org.kuali.student.common.ui.client.configurable.mvc.sections.SwapSection;
 35  
 import org.kuali.student.common.ui.client.configurable.mvc.sections.VerticalSection;
 36  
 import org.kuali.student.common.ui.client.mvc.Callback;
 37  
 import org.kuali.student.common.ui.client.mvc.DataModel;
 38  
 import org.kuali.student.common.ui.client.util.DebugIdUtils;
 39  
 import org.kuali.student.common.ui.client.widgets.KSButton;
 40  
 import org.kuali.student.common.ui.client.widgets.KSButtonAbstract.ButtonStyle;
 41  
 import org.kuali.student.common.ui.client.widgets.ListOfStringWidget;
 42  
 import org.kuali.student.common.ui.client.widgets.list.KSRadioButtonList;
 43  
 import org.kuali.student.common.ui.client.widgets.list.KSSelectItemWidgetAbstract;
 44  
 import org.kuali.student.common.ui.client.widgets.list.ListItems;
 45  
 import org.kuali.student.common.ui.client.widgets.list.SelectionChangeEvent;
 46  
 import org.kuali.student.common.ui.client.widgets.list.SelectionChangeHandler;
 47  
 import org.kuali.student.common.ui.client.widgets.list.impl.KSRadioButtonListImpl;
 48  
 import org.kuali.student.common.ui.client.widgets.list.impl.SimpleListItems;
 49  
 import org.kuali.student.common.ui.client.widgets.search.KSPicker;
 50  
 
 51  
 import com.google.gwt.core.client.GWT;
 52  
 import com.google.gwt.event.dom.client.BlurHandler;
 53  
 import com.google.gwt.event.dom.client.ClickEvent;
 54  
 import com.google.gwt.event.dom.client.ClickHandler;
 55  
 import com.google.gwt.event.dom.client.FocusHandler;
 56  
 import com.google.gwt.event.shared.HandlerRegistration;
 57  
 import com.google.gwt.user.client.ui.Composite;
 58  
 import com.google.gwt.user.client.ui.FlowPanel;
 59  
 import com.google.gwt.user.client.ui.Widget;
 60  
 
 61  
 
 62  0
 public class MultiplicityGroup extends Composite {
 63  
 
 64  
     private MultiplicityConfiguration config;
 65  
 
 66  0
     private List<MultiplicityGroupItem> items = new ArrayList<MultiplicityGroupItem>();
 67  0
     private List<MultiplicityGroupItem> removed = new ArrayList<MultiplicityGroupItem>();
 68  
 
 69  0
     private FlowPanel mainPanel = new FlowPanel();
 70  0
     private FlowPanel itemsPanel = new FlowPanel();
 71  0
     private boolean loaded = false;
 72  0
     private int itemCount = 0;
 73  
     private String parentPath;
 74  0
     private boolean isDirty = false;
 75  
 
 76  
     private Map<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>> swappableFieldsDefinition;
 77  
     private List<String> deletionParentKeys;
 78  
 
 79  0
     public MultiplicityGroup() {
 80  0
     }
 81  
 
 82  
     public MultiplicityGroup(MultiplicityConfiguration config,
 83  
             Map<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>> swappableFieldsDefinition,
 84  0
             List<String> deletionParentKeys) {
 85  0
         this.config = config;
 86  0
         initWidget(mainPanel);
 87  0
         this.swappableFieldsDefinition = swappableFieldsDefinition;
 88  0
         this.deletionParentKeys = deletionParentKeys;
 89  0
     }
 90  
 
 91  
 
 92  
     /**
 93  
      * Creates an instance of a MultiplicityGroup based on the options in the MultiplicityConfiguration
 94  
      *
 95  
      * A MultiplicityGroup uses GroupSection to display data in a variable grid.  May be multiple rows and multiple fields per row based on
 96  
      * the defs in the MultiplicityConfiguration.
 97  
      *
 98  
      * May contain one or more MultiplicityItemSections based on user action, dictionary defs or data found in the model.
 99  
      *
 100  
      * @param config
 101  
      */
 102  0
     public MultiplicityGroup(MultiplicityConfiguration config){
 103  0
         this.config = config;
 104  0
         initWidget(mainPanel);
 105  0
     }
 106  
 
 107  0
     protected Callback<MultiplicityGroupItem> removeCallback = new Callback<MultiplicityGroupItem>(){
 108  
 
 109  
         public void exec(MultiplicityGroupItem itemToRemove) {
 110  0
             itemToRemove.setDeleted(true);
 111  0
             removed.add(itemToRemove);
 112  0
             itemsPanel.remove(itemToRemove);
 113  0
         }
 114  
     };
 115  
 
 116  
     public void onLoad() {
 117  0
         if (!loaded) {
 118  0
             mainPanel.add(itemsPanel);
 119  
 
 120  0
             if(config.isUpdateable()){
 121  0
                 Widget addWidget = generateAddWidget();
 122  0
                 mainPanel.add(addWidget);
 123  
             }
 124  
 
 125  0
             loaded = true;
 126  
         }
 127  
 
 128  0
         if (!loaded || itemCount == 0){
 129  0
                 Integer minOccurs = MetadataInterrogator.getLargestMinOccurs(config.getMetaData());
 130  
                 
 131  0
                 if (minOccurs != null && minOccurs > 0) {
 132  0
                     for (int i=0; i < minOccurs; i++){
 133  0
                             createItem();
 134  
                     }
 135  
                 }
 136  0
                 else if(config.getDefaultItemsCreated() != 0){
 137  0
                         for (int i=0; i < config.getDefaultItemsCreated(); i++){
 138  0
                             createItem();
 139  
                     }
 140  
                 }
 141  
 
 142  
         }
 143  0
     }
 144  
 
 145  
     private Widget generateAddWidget() {
 146  
             KSButton addWidget;
 147  0
             if(config.getStyleType() == MultiplicityConfiguration.StyleType.TOP_LEVEL_GROUP){
 148  0
                     addWidget = new KSButton(config.getAddItemLabel(), ButtonStyle.FORM_LARGE);
 149  
             }
 150  
             else{
 151  0
                     addWidget = new KSButton(config.getAddItemLabel(), ButtonStyle.FORM_SMALL);
 152  
             }
 153  0
         addWidget.addClickHandler(new ClickHandler(){
 154  
             public void onClick(ClickEvent event) {
 155  0
                 createItem();
 156  0
             }
 157  
         });
 158  0
         addWidget.ensureDebugId(DebugIdUtils.createWebDriverSafeDebugId(this.getElement().getId() + "-" + config.getAddItemLabel()));
 159  0
         return addWidget;
 160  
     }
 161  
 
 162  
     /**
 163  
      * This adds an empty item to the multiplicity group
 164  
      *
 165  
      * @return
 166  
      */
 167  
         public MultiplicityGroupItem createItem(){
 168  
 
 169  0
                 itemCount++;
 170  
 
 171  0
                 MultiplicityGroupItem item = new MultiplicityGroupItem(config.getItemLabel() + " " + itemCount, config.getStyleType(), config.isUpdateable());
 172  
 
 173  0
         Widget itemWidget = createWidget();
 174  
 
 175  0
             if (item != null){
 176  0
                     item.setItemKey(new Integer(itemCount -1));
 177  0
                     item.setItemWidget(itemWidget);
 178  0
                     item.setRemoveCallback(removeCallback);
 179  0
             } else if (itemWidget instanceof MultiplicityGroupItem){
 180  0
                     item = (MultiplicityGroupItem)itemWidget;
 181  0
                     item.setItemKey(new Integer(itemCount -1));
 182  
             }
 183  0
             items.add(item);
 184  0
             item.redraw();
 185  0
             itemsPanel.add(item);
 186  0
         isDirty = true;
 187  
 
 188  0
         return item;
 189  
         }
 190  
 
 191  
         public FlowPanel getItemsPanel() {
 192  0
             return itemsPanel;
 193  
         }
 194  
 
 195  
     private Widget createWidget() {
 196  
 
 197  0
                 GroupSection section = new GroupSection();
 198  0
         final SwappableFieldsHelper helper = new SwappableFieldsHelper();
 199  
         // helperFieldKeys maps the paths with asterisks into absolute paths
 200  0
         final Map<String, String> helperFieldKeys = new HashMap<String, String>();
 201  0
         SwapSection swapSection = null;
 202  
 
 203  
                 //TODO might want fields and nested multiplicities at the same time. Remove if/else
 204  
 
 205  0
                 if (config.getNestedConfig() != null) {
 206  0
             MultiplicitySection ms = new MultiplicitySection(config.getNestedConfig().copy());
 207  0
                         String p = config.getNestedConfig().getParentFd().getFieldKey().replace('*', Character.forDigit(itemCount-1, 10));
 208  0
                     ms.setParentPath(p);
 209  0
             section.addSection(ms);
 210  0
                 }
 211  
                 else {
 212  0
                         for (Integer row  : config.getFields().keySet()) {
 213  0
                                 List<MultiplicityFieldConfiguration> fieldConfigs = config.getFields().get(row);
 214  0
                                 for (MultiplicityFieldConfiguration fieldConfig : fieldConfigs) {
 215  
                     //TODO  Should copy widgets/bindings too?
 216  0
                     FieldDescriptor newfd = null;
 217  0
                     Widget fieldWidget = null;
 218  0
                     if (fieldConfig.getFieldWidgetInitializer() != null) {
 219  0
                         fieldWidget = fieldConfig.getFieldWidgetInitializer().getNewWidget();
 220  0
                         ModelWidgetBinding mwb = fieldConfig.getFieldWidgetInitializer()
 221  
                             .getModelWidgetBindingInstance();
 222  0
                         newfd = new FieldDescriptor(
 223  
                                 translatePath(fieldConfig.getFieldPath()),
 224  
                                 fieldConfig.getMessageKeyInfo(),
 225  
                                 fieldConfig.getMetadata(),
 226  
                                 fieldWidget);
 227  0
                         newfd.setWidgetBinding(mwb);
 228  0
                     } else {
 229  0
                         newfd = new FieldDescriptor(
 230  
                                 translatePath(fieldConfig.getFieldPath()),
 231  
                                 fieldConfig.getMessageKeyInfo(),
 232  
                                 fieldConfig.getMetadata());
 233  0
                         fieldWidget = newfd.getFieldWidget();
 234  
                     }
 235  0
                     newfd.getFieldElement().setRequired(fieldConfig.isRequired());
 236  0
                     section.addField(newfd);
 237  0
                     helperFieldKeys.put(fieldConfig.getFieldPath(), newfd.getFieldKey());
 238  
 
 239  
                     // add handlers to all select field that can be selected and triggers
 240  
                     // selection change event to notify the swap section to switch section.
 241  0
                     if (fieldWidget instanceof KSSelectItemWidgetAbstract) {
 242  0
                         ((KSSelectItemWidgetAbstract)fieldWidget).addSelectionChangeHandler(new SelectionChangeHandler() {
 243  
                             @Override
 244  
                             public void onSelectionChange(SelectionChangeEvent event) {
 245  0
                                 helper.updateFieldDisplay();
 246  0
                             }
 247  
                         });
 248  0
                     } else if (fieldWidget instanceof KSPicker) {
 249  0
                         Widget inputWidget = ((KSPicker)fieldWidget).getInputWidget();
 250  0
                         if (inputWidget instanceof KSSelectItemWidgetAbstract) {
 251  0
                             ((KSSelectItemWidgetAbstract)inputWidget).addSelectionChangeHandler(new SelectionChangeHandler() {
 252  
                                 @Override
 253  
                                 public void onSelectionChange(SelectionChangeEvent event) {
 254  0
                                     helper.updateFieldDisplay();
 255  0
                                 }
 256  
                             });
 257  
                         }
 258  
                     }
 259  0
                                 }
 260  0
                                 section.nextLine();
 261  0
                         }
 262  0
             if (swappableFieldsDefinition != null) {
 263  0
                 ConditionChoices conditionChoices = new ConditionChoices(
 264  
                         new ArrayList<SwapCompositeCondition>(
 265  
                                 swappableFieldsDefinition.keySet()));
 266  0
                 List<String> newDeletionParentKeys = null;
 267  0
                 swapSection = new SwapSection(conditionChoices);
 268  0
                 if (deletionParentKeys != null) {
 269  0
                     for (String deletionParentKey : deletionParentKeys) {
 270  0
                         newDeletionParentKeys = (newDeletionParentKeys == null)?
 271  
                                 new ArrayList<String>() : newDeletionParentKeys;
 272  0
                         newDeletionParentKeys.add(translatePath(deletionParentKey));
 273  
                     }
 274  
                 }
 275  0
                 swapSection.setDeletionParentKey(newDeletionParentKeys);
 276  0
                 helper.setConditionChoices(conditionChoices);
 277  
                 // go through swappableFieldsDefinition and create and add the fields
 278  
                 // into conditionSection
 279  0
                 for (Entry<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>> entry : swappableFieldsDefinition.entrySet()) {
 280  0
                     SwapCompositeCondition condition = entry.getKey();
 281  0
                     List<SwapCompositeConditionFieldConfig> fieldConfigs = entry.getValue();
 282  0
                     Section conditionSection = new VerticalSection();
 283  0
                     if (fieldConfigs != null) {
 284  0
                         for (SwapCompositeConditionFieldConfig conditionFieldConfig : fieldConfigs) {
 285  0
                             if (conditionFieldConfig.useMultiplicity()) {
 286  0
                                 MultiplicityConfiguration newSubMultiplicityConfig =
 287  
                                     configSwappableMultiplicitySection(
 288  
                                             conditionFieldConfig.getMultiplicityConfiguration());
 289  0
                                 MultiplicitySection subMultiplicitySection =
 290  
                                     new MultiplicitySection(newSubMultiplicityConfig);
 291  0
                                 conditionSection.addSection(subMultiplicitySection);
 292  0
                             } else {
 293  0
                                 MultiplicityFieldConfiguration fieldConfig =
 294  
                                     conditionFieldConfig.getMultiplicityFieldConfiguration();
 295  0
                                 FieldDescriptor concreteFieldDescriptor = new FieldDescriptor(
 296  
                                         translatePath(fieldConfig.getFieldPath()),
 297  
                                         fieldConfig.getMessageKeyInfo(),
 298  
                                         fieldConfig.getMetadata());
 299  0
                                 concreteFieldDescriptor.getFieldElement().setRequired(fieldConfig.isRequired());
 300  0
                                 if (fieldConfig.getFieldWidgetInitializer() != null) {
 301  0
                                     Widget fieldWidget = fieldConfig.getFieldWidgetInitializer().getNewWidget();
 302  0
                                     ModelWidgetBinding mwb = fieldConfig.getFieldWidgetInitializer()
 303  
                                         .getModelWidgetBindingInstance();
 304  0
                                     concreteFieldDescriptor.setFieldWidget(fieldWidget);
 305  0
                                     if(fieldWidget instanceof ListOfStringWidget){
 306  0
                                             ((ListOfStringWidget)fieldWidget).setFd(concreteFieldDescriptor);
 307  
                                     }
 308  
 
 309  0
                                     concreteFieldDescriptor.setWidgetBinding(mwb);
 310  
                                 }
 311  0
                                 conditionSection.addField(concreteFieldDescriptor);
 312  0
                                 helperFieldKeys.put(fieldConfig.getFieldPath(), translatePath(fieldConfig.getFieldPath()));
 313  0
                             }
 314  
                         }
 315  
                     }
 316  0
                     swapSection.addSection(conditionSection, condition.getConditionId());
 317  0
                 }
 318  0
                 section.addWidget(conditionChoices);
 319  0
                 section.addSection(swapSection);
 320  0
                 helper.setSwapSection(swapSection);
 321  
             }
 322  
 
 323  0
             helper.setParentSection(section);
 324  0
             helper.setSwappableFieldsDefinition(swappableFieldsDefinition);
 325  0
             helper.setHelperFieldKeys(helperFieldKeys);
 326  
         }
 327  0
                 return section;
 328  
         }
 329  
 
 330  
     public MultiplicityConfiguration configSwappableMultiplicitySection(MultiplicityConfiguration origConfig) {
 331  0
         MultiplicityConfiguration newSubMultiplicityConfig =
 332  
             origConfig.copy();
 333  
 
 334  0
         FieldDescriptor parentFd = origConfig.getParentFd();
 335  0
         FieldDescriptor subMultParentConfig =
 336  
             new FieldDescriptor(
 337  
                     translatePath(parentFd.getFieldKey()),
 338  
                     parentFd.getMessageKey(),
 339  
                     parentFd.getMetadata());
 340  0
         subMultParentConfig.getFieldElement().setRequired(parentFd.getFieldElement().isRequired());
 341  0
         newSubMultiplicityConfig.setParent(subMultParentConfig);
 342  0
         Map<Integer, List<MultiplicityFieldConfiguration>> fieldConfigsMap = newSubMultiplicityConfig.getFields();
 343  0
         Map<Integer, List<MultiplicityFieldConfiguration>> newFieldsMap = new HashMap<Integer, List<MultiplicityFieldConfiguration>>();
 344  0
         int lineCounter = 0;
 345  0
         if (fieldConfigsMap != null) {
 346  0
             for (List<MultiplicityFieldConfiguration> fieldConfigsInLine : fieldConfigsMap.values()) {
 347  0
                 List<MultiplicityFieldConfiguration> newFieldConfigs = new ArrayList<MultiplicityFieldConfiguration>();
 348  0
                 for (MultiplicityFieldConfiguration fieldConfig : fieldConfigsInLine) {
 349  0
                     String configParentKey = (parentFd.getFieldKey() == null)? "" : parentFd.getFieldKey();
 350  0
                     String configFieldKey = (fieldConfig.getFieldPath() == null)? "" : fieldConfig.getFieldPath();
 351  0
                     String trimmedFieldKey = null;
 352  0
                     MultiplicityFieldConfiguration newFieldConfig = null;
 353  0
                     trimmedFieldKey = configFieldKey.substring(configParentKey.length());
 354  
 
 355  0
                     QueryPath fieldPath = QueryPath.concat(subMultParentConfig.getFieldKey(),
 356  
                             trimmedFieldKey);;
 357  0
                     newFieldConfig = new MultiplicityFieldConfiguration(
 358  
                             fieldPath.toString(), fieldConfig.getMessageKeyInfo(), fieldConfig.getMetadata(),
 359  
                             fieldConfig.getFieldWidgetInitializer());
 360  0
                     newFieldConfig.setRequired(fieldConfig.isRequired());
 361  0
                     newFieldConfigs.add(newFieldConfig);
 362  
 
 363  0
                 }
 364  0
                 newFieldsMap.put(Integer.valueOf(lineCounter), newFieldConfigs);
 365  0
                 lineCounter++;
 366  0
             }
 367  
         }
 368  0
         newSubMultiplicityConfig.setFields(newFieldsMap);
 369  
 
 370  0
         return newSubMultiplicityConfig;
 371  
     }
 372  
 
 373  
     public String translatePath(String path) {
 374  
         String fieldPath;
 375  0
         if (parentPath != null) {
 376  0
             QueryPath parent = QueryPath.concat(parentPath);
 377  0
             int i = parent.size();
 378  
 
 379  0
             QueryPath subPath = QueryPath.concat(path);
 380  0
             String itemPath =  subPath.subPath(i, subPath.size()).toString();
 381  
 
 382  0
             QueryPath qp = QueryPath.concat(parentPath, itemPath);
 383  0
             fieldPath = qp.toString();
 384  0
         }
 385  
         else {
 386  0
             fieldPath = path;
 387  
         }
 388  
 
 389  0
         fieldPath = fieldPath.replace('*', Character.forDigit(itemCount-1, 10));
 390  0
         return fieldPath;
 391  
     }
 392  
 
 393  
 
 394  
     public void clear(){
 395  0
         itemsPanel.clear();
 396  0
         items.clear();
 397  0
         removed.clear();
 398  0
         itemCount = 0;
 399  0
     }
 400  
 
 401  
     public void redraw(){
 402  0
         for (MultiplicityGroupItem item:items){
 403  0
             item.redraw();
 404  
         }
 405  0
     }
 406  
 
 407  
     public void incrementItemKey(){
 408  0
                 itemCount++;
 409  0
         }
 410  
 
 411  
     /**
 412  
          * This returns the index key for the model for the item currently being added by addItem
 413  
          * This is useful, if you need to refer to the index in the createItem method
 414  
          * @return
 415  
          */
 416  
         public int getAddItemKey(){
 417  0
                 return itemCount-1;
 418  
         }
 419  
 
 420  
 
 421  
     public List<MultiplicityGroupItem> getItems() {
 422  0
         return items;
 423  
     }
 424  
 
 425  
     public List<MultiplicityGroupItem> getRemovedItems() {
 426  0
         return removed;
 427  
     }
 428  
 
 429  
         public int getItemCount() {
 430  0
                 return itemCount;
 431  
         }
 432  
 
 433  
         public void setItemCount(int itemCount) {
 434  0
                 this.itemCount = itemCount;
 435  0
         }
 436  
 
 437  
         public String getParentPath() {
 438  0
                 return parentPath;
 439  
         }
 440  
 
 441  
     /**
 442  
      * Allows the parentpath for this instance to be set, e.g. course/formats/0/activities
 443  
      *
 444  
      * @param parentPath
 445  
      */
 446  
     public void setParentPath(String parentPath) {
 447  0
                 this.parentPath = parentPath;
 448  0
         }
 449  
 
 450  
         public MultiplicityConfiguration getConfig() {
 451  0
                 return config;
 452  
         }
 453  
 
 454  
         public void setConfig(MultiplicityConfiguration config) {
 455  0
                 this.config = config;
 456  0
         }
 457  
 
 458  
     public void resetDirtyFlags() {
 459  0
             isDirty = false;
 460  0
                 for (MultiplicityGroupItem item:items){
 461  0
                         item.resetDirtyFlags();
 462  0
                         Widget itemWidget = item.getItemWidget();
 463  0
                         if (itemWidget instanceof BaseSection){
 464  0
                                 ((BaseSection)itemWidget).resetDirtyFlags();
 465  
                         }
 466  0
                 }
 467  0
     }
 468  
 
 469  
         public boolean isDirty(){
 470  0
         isDirty = false;
 471  0
         if (removed != null && !removed.isEmpty()){
 472  0
                 isDirty = true;
 473  
         } else {
 474  0
                         for (MultiplicityGroupItem item:items){
 475  0
                                 if (item.isDirty()){
 476  0
                                         isDirty = true;
 477  0
                                         break;
 478  
                                 } else {
 479  0
                                         Widget itemWidget = item.getItemWidget();
 480  0
                                         if (itemWidget instanceof BaseSection && ((BaseSection)itemWidget).isDirty()){
 481  0
                                                 isDirty = true;
 482  0
                                                 break;
 483  
                                         }
 484  0
                                 }
 485  
                         }
 486  
         }
 487  0
                 return isDirty;
 488  
         }
 489  
 
 490  
         public void setIsDirty(boolean dirty){
 491  0
                 isDirty = dirty;
 492  0
         }
 493  
 
 494  
     public class ConditionChoices extends KSRadioButtonList{
 495  0
         private KSRadioButtonListImpl selectItemWidget = GWT.create(KSRadioButtonListImpl.class);
 496  0
         public ConditionChoices(List<SwapCompositeCondition> conditions){
 497  0
             SimpleListItems choices = new SimpleListItems();
 498  0
             if (conditions != null) {
 499  0
                 for (SwapCompositeCondition condition : conditions) {
 500  0
                     choices.addItem(condition.getConditionId(), condition.getConditionId());
 501  
                 }
 502  
             }
 503  0
             selectItemWidget.setListItems(choices);
 504  0
         }
 505  
 
 506  
         /**
 507  
          * @see org.kuali.student.common.ui.client.widgets.list.KSSelectItemWidgetAbstract#deSelectItem(java.lang.String)
 508  
          */
 509  
         public void deSelectItem(String id) {
 510  0
             selectItemWidget.deSelectItem(id);
 511  0
         }
 512  
 
 513  
         /**
 514  
          * @see org.kuali.student.common.ui.client.widgets.list.KSSelectItemWidgetAbstract#getSelectedItems()
 515  
          */
 516  
         public List<String> getSelectedItems() {
 517  0
             return selectItemWidget.getSelectedItems();
 518  
         }
 519  
 
 520  
         /**
 521  
          * @see org.kuali.student.common.ui.client.widgets.list.KSSelectItemWidgetAbstract#selectItem(java.lang.String)
 522  
          */
 523  
         public void selectItem(String id) {
 524  0
             selectItemWidget.selectItem(id);
 525  0
         }
 526  
 
 527  
         public void setListItems(ListItems listItems) {
 528  0
             selectItemWidget.setListItems(listItems);
 529  0
         }
 530  
 
 531  
         /**
 532  
          * Use to set number of columns to use when displaying list
 533  
          *
 534  
          */
 535  
         public void setColumnSize(int cols){
 536  0
             selectItemWidget.setColumnSize(cols);
 537  0
         }
 538  
 
 539  0
         public void setMultipleSelect(boolean isMultipleSelect) {}
 540  
 
 541  
         /**
 542  
          * This overridden method is not used
 543  
          *
 544  
          * @see org.kuali.student.common.ui.client.widgets.list.KSSelectItemWidgetAbstract#onLoad()
 545  
          */
 546  
         @Override
 547  0
         public void onLoad() {}
 548  
 
 549  
         public HandlerRegistration addSelectionChangeHandler(SelectionChangeHandler handler) {
 550  0
             return selectItemWidget.addSelectionChangeHandler(handler);
 551  
         }
 552  
 
 553  
         public ListItems getListItems() {
 554  0
             return selectItemWidget.getListItems();
 555  
         }
 556  
 
 557  
         public String getName() {
 558  0
             return selectItemWidget.getName();
 559  
         }
 560  
 
 561  
         public void setName(String name) {
 562  0
             selectItemWidget.setName(name);
 563  0
         }
 564  
 
 565  
         @Override
 566  
         public void setEnabled(boolean b) {
 567  0
             selectItemWidget.setEnabled(b);
 568  0
         }
 569  
 
 570  
         @Override
 571  
         public boolean isEnabled() {
 572  0
             return selectItemWidget.isEnabled();
 573  
         }
 574  
 
 575  
         @Override
 576  
         public boolean isMultipleSelect() {
 577  0
             return selectItemWidget.isMultipleSelect();
 578  
         }
 579  
 
 580  
         @Override
 581  
         public void redraw() {
 582  0
             selectItemWidget.redraw();
 583  0
         }
 584  
 
 585  
         @Override
 586  
         public void clear() {
 587  0
             selectItemWidget.clear();
 588  0
         }
 589  
 
 590  
         @Override
 591  
         public HandlerRegistration addBlurHandler(BlurHandler handler) {
 592  0
             return selectItemWidget.addBlurHandler(handler);
 593  
         }
 594  
 
 595  
         @Override
 596  
         public HandlerRegistration addFocusHandler(FocusHandler handler) {
 597  0
             return selectItemWidget.addFocusHandler(handler);
 598  
         }
 599  
 
 600  
         public void addWidgetReadyCallback(Callback<Widget> callback) {
 601  0
             selectItemWidget.addWidgetReadyCallback(callback);
 602  0
         }
 603  
 
 604  
         public boolean isInitialized() {
 605  0
             return selectItemWidget.isInitialized();
 606  
         }
 607  
 
 608  
         public void setInitialized(boolean initialized) {
 609  0
             selectItemWidget.setInitialized(initialized);
 610  0
         }
 611  
 
 612  
         /**
 613  
          * By default if the list items used by the checkbox has multiple attributes, the checkbox
 614  
          * generated will display all attributes as columns. Set this property to true if this
 615  
          * behavior is not desired.
 616  
          *
 617  
          * @param ignoreMultiple
 618  
          */
 619  
         public void setIgnoreMultipleAttributes(boolean ignoreMultiple){
 620  0
             selectItemWidget.setIgnoreMultipleAttributes(ignoreMultiple);
 621  0
         }
 622  
     }
 623  
 
 624  0
     public class SwappableFieldsHelper {
 625  
 
 626  
         private GroupSection parentSection;
 627  0
         private Map<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>> swappableFieldsDefinition =
 628  
             new HashMap<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>>();
 629  
         private Map<String, String> helperFieldKeys;
 630  
         private ConditionChoices conditionChoices;
 631  
         private SwapSection swapSection;
 632  
         public void updateFieldDisplay() {
 633  0
             Set<Entry<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>>> entries =
 634  
                 (swappableFieldsDefinition == null)? null : swappableFieldsDefinition.entrySet();
 635  0
             if (parentSection == null) {
 636  0
                 throw new RuntimeException("parentSection cannot be null");
 637  
             }
 638  0
             if (entries != null) {
 639  0
                 for (Entry<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>> entry : entries) {
 640  0
                     SwapCompositeCondition condition = entry.getKey();
 641  0
                     if (condition.evaluate(parentSection, helperFieldKeys)) {
 642  
                         // clear values in the widgets
 643  0
                         List<Section> deletedSections = swapSection.getDeletedSections();
 644  0
                         List<FieldDescriptor> fields = null;
 645  0
                         if (deletedSections != null) {
 646  0
                             for (Section deletedSection : deletedSections) {
 647  0
                                 fields = (fields == null)? new ArrayList() : fields;
 648  0
                                 fields.addAll(deletedSection.getFields());
 649  
                             }
 650  
                         }
 651  0
                         if (fields != null) {
 652  0
                             for (FieldDescriptor field : fields) {
 653  0
                                 Widget fieldWidget = field.getFieldWidget();
 654  0
                                 DataModel dataModel = new DataModel();
 655  0
                                 dataModel.setRoot(new Data());
 656  0
                                 ((ModelWidgetBinding)field.getModelWidgetBinding())
 657  
                                 .setWidgetValue(fieldWidget,
 658  
                                         dataModel, field.getFieldKey());
 659  0
                             }
 660  
                         }
 661  
                         // trigger SectionChangeEvent to notify the selection widget
 662  
                         // that the selected condition has changed.
 663  0
                         SelectionChangeEvent selectionChangeEvent =
 664  
                             new SelectionChangeEvent(conditionChoices);
 665  0
                         selectionChangeEvent.setUserInitiated(true);
 666  0
                         conditionChoices.selectItem(condition.getConditionId());
 667  0
                         conditionChoices.fireEvent(selectionChangeEvent);
 668  
                     }
 669  0
                 }
 670  
             }
 671  0
         }
 672  
         public GroupSection getParentSection() {
 673  0
             return parentSection;
 674  
         }
 675  
         public void setParentSection(GroupSection parentSection) {
 676  0
             this.parentSection = parentSection;
 677  0
         }
 678  
         public Map<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>> getSwappableFieldsDefinition() {
 679  0
             return swappableFieldsDefinition;
 680  
         }
 681  
         public void setSwappableFieldsDefinition(Map<SwapCompositeCondition, List<SwapCompositeConditionFieldConfig>> swappableFieldsDefinition) {
 682  0
             this.swappableFieldsDefinition = swappableFieldsDefinition;
 683  0
         }
 684  
         public Map<String, String> getHelperFieldKeys() {
 685  0
             return helperFieldKeys;
 686  
         }
 687  
         public void setHelperFieldKeys(Map<String, String> helperFieldKeys) {
 688  0
             this.helperFieldKeys = helperFieldKeys;
 689  0
         }
 690  
         public ConditionChoices getConditionChoices() {
 691  0
             return conditionChoices;
 692  
         }
 693  
         public void setConditionChoices(ConditionChoices conditionChoices) {
 694  0
             this.conditionChoices = conditionChoices;
 695  0
         }
 696  
         public SwapSection getSwapSection() {
 697  0
             return swapSection;
 698  
         }
 699  
         public void setSwapSection(SwapSection swapSection) {
 700  0
             this.swapSection = swapSection;
 701  0
         }
 702  
     }
 703  
 
 704  
 }