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