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