View Javadoc

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