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.sections;
17
18 import java.util.ArrayList;
19 import java.util.HashSet;
20 import java.util.List;
21
22 import org.kuali.student.common.ui.client.application.Application;
23 import org.kuali.student.common.ui.client.configurable.mvc.CanProcessValidationResults;
24 import org.kuali.student.common.ui.client.configurable.mvc.FieldDescriptor;
25 import org.kuali.student.common.ui.client.configurable.mvc.LayoutController;
26 import org.kuali.student.common.ui.client.configurable.mvc.ValidationEventBinding;
27 import org.kuali.student.common.ui.client.configurable.mvc.ValidationEventBindingImpl;
28 import org.kuali.student.common.ui.client.configurable.mvc.binding.ModelWidgetBinding;
29 import org.kuali.student.common.ui.client.configurable.mvc.binding.ModelWidgetBindingSupport;
30 import org.kuali.student.common.ui.client.configurable.mvc.multiplicity.MultiplicityComposite;
31 import org.kuali.student.common.ui.client.configurable.mvc.multiplicity.MultiplicityGroup;
32 import org.kuali.student.common.ui.client.configurable.mvc.multiplicity.MultiplicityGroupItem;
33 import org.kuali.student.common.ui.client.configurable.mvc.multiplicity.MultiplicityItem;
34 import org.kuali.student.common.ui.client.event.ContentDirtyEvent;
35 import org.kuali.student.common.ui.client.event.ValidateRequestEvent;
36 import org.kuali.student.common.ui.client.mvc.Callback;
37 import org.kuali.student.common.ui.client.mvc.Controller;
38 import org.kuali.student.common.ui.client.mvc.DataModel;
39 import org.kuali.student.common.ui.client.mvc.HasCrossConstraints;
40 import org.kuali.student.common.ui.client.mvc.ModelRequestCallback;
41 import org.kuali.student.common.ui.client.mvc.View;
42 import org.kuali.student.common.ui.client.widgets.KSDropDown;
43 import org.kuali.student.common.ui.client.widgets.field.layout.element.AbbrPanel;
44 import org.kuali.student.common.ui.client.widgets.field.layout.element.FieldElement;
45 import org.kuali.student.common.ui.client.widgets.field.layout.element.SpanPanel;
46 import org.kuali.student.common.ui.client.widgets.field.layout.layouts.FieldLayout;
47 import org.kuali.student.common.ui.client.widgets.search.KSPicker;
48 import org.kuali.student.r1.common.assembly.data.Data;
49 import org.kuali.student.r1.common.assembly.data.Data.Key;
50 import org.kuali.student.r1.common.assembly.data.QueryPath;
51 import org.kuali.student.r2.common.dto.ValidationResultInfo;
52 import org.kuali.student.r2.common.infc.ValidationResult.ErrorLevel;
53
54 import com.google.gwt.core.client.GWT;
55 import com.google.gwt.user.client.ui.TextBoxBase;
56 import com.google.gwt.user.client.ui.Widget;
57
58
59
60
61
62
63 public abstract class BaseSection extends SpanPanel implements Section{
64
65 protected FieldLayout layout;
66
67 protected ArrayList<Section> sections = new ArrayList<Section>();
68 protected ArrayList<FieldDescriptor> fields = new ArrayList<FieldDescriptor>();
69 protected LayoutController layoutController = null;
70 protected boolean isValidationEnabled = true;
71 protected boolean isDirty = false;
72
73
74
75
76
77
78
79
80
81
82
83
84
85 @Override
86 public String addField(final FieldDescriptor fieldDescriptor) {
87 String key = null;
88
89 if (fieldDescriptor.isVisible()){
90 fields.add(fieldDescriptor);
91 key = layout.addField(fieldDescriptor.getFieldElement());
92
93 ValidationEventBinding binding = new ValidationEventBindingImpl();
94 if(fieldDescriptor.getValidationRequestCallback()== null){
95 fieldDescriptor.setValidationCallBack(new Callback<Boolean>() {
96 @Override
97 public void exec(Boolean result) {
98 final ModelWidgetBinding mwb = fieldDescriptor.getModelWidgetBinding();
99 if (mwb != null) {
100 final Widget w = fieldDescriptor.getFieldWidget();
101 final String modelId = fieldDescriptor.getModelId();
102 final Controller parent;
103 Controller findResult = LayoutController.findParentLayout(w);
104 if(BaseSection.this instanceof View){
105 findResult = ((View)BaseSection.this).getController();
106 }
107 parent = findResult;
108 if(parent != null){
109 if (modelId == null) {
110 parent.requestModel(new ModelRequestCallback<DataModel>() {
111
112 @Override
113 public void onModelReady(DataModel model) {
114 validateField(fieldDescriptor, model, parent);
115
116
117 HashSet<HasCrossConstraints> fds = Application.getApplicationContext().getCrossConstraint(null, Application.getApplicationContext().getParentPath()+fieldDescriptor.getFieldKey());
118 if(fds!=null){
119 for(HasCrossConstraints fd:fds){
120 fd.reprocessWithUpdatedConstraints();
121 }
122 }
123 }
124
125 @Override
126 public void onRequestFail(Throwable cause) {
127 GWT.log("Unable to retrieve model to validate " + fieldDescriptor.getFieldKey(), null);
128 }
129
130 });
131 } else {
132 parent.requestModel(modelId, new ModelRequestCallback<DataModel>() {
133
134 @Override
135 public void onModelReady(DataModel model) {
136 validateField(fieldDescriptor, model, parent);
137 }
138
139 @Override
140 public void onRequestFail(Throwable cause) {
141 GWT.log("Unable to retrieve model to validate " + fieldDescriptor.getFieldKey(), null);
142 }
143
144 }); }
145 }
146 } else {
147 GWT.log(fieldDescriptor.getFieldKey() + " has no widget binding.", null);
148 }
149 }
150 });
151 }
152 binding.bind(fieldDescriptor);
153 }
154
155 return key;
156 }
157
158 private void validateField(
159 final FieldDescriptor fieldDescriptor, final DataModel model, Controller controller) {
160 Widget w = fieldDescriptor.getFieldWidget();
161 ModelWidgetBinding mwb = fieldDescriptor.getModelWidgetBinding();
162 if(fieldDescriptor.getFieldKey() != null){
163 mwb.setModelValue(w, model, fieldDescriptor.getFieldKey());
164 dirtyCheckField(fieldDescriptor, model);
165 ValidateRequestEvent e = new ValidateRequestEvent();
166 e.setFieldDescriptor(fieldDescriptor);
167 e.setValidateSingleField(true);
168 controller.fireApplicationEvent(e);
169 }
170 }
171
172 private void dirtyCheckField(FieldDescriptor fieldDescriptor, DataModel model){
173 QueryPath fieldPath = QueryPath.parse(fieldDescriptor.getFieldKey());
174 QueryPath qPathDirty = fieldPath.subPath(0, fieldPath.size() - 1);
175 qPathDirty.add(ModelWidgetBindingSupport.RUNTIME_ROOT);
176 qPathDirty.add(ModelWidgetBindingSupport.DIRTY_PATH);
177 qPathDirty.add(fieldPath.get(fieldPath.size()-1));
178 Boolean dirty = false;
179
180 if(ensureDirtyFlagPath(model.getRoot(), qPathDirty)){
181 dirty = model.get(qPathDirty);
182 }
183 if(dirty){
184 setIsDirty(true);
185 fieldDescriptor.setDirty(true);
186 }
187 }
188
189 protected boolean ensureDirtyFlagPath(Data root, QueryPath path) {
190 Data current = root;
191 boolean containsFlag = false;
192 for (int i = 0; i < path.size(); i++) {
193 Key key = path.get(i);
194 if(i == path.size() - 1){
195 containsFlag = current.containsKey(key);
196 break;
197 }
198 Data d = current.get(key);
199 if (d == null) {
200 containsFlag = false;
201 break;
202 }
203 current = d;
204 }
205 return containsFlag;
206 }
207
208
209
210
211
212
213 @Override
214 public String addSection(Section section) {
215
216 section.setLayoutController(layoutController);
217 sections.add(section);
218 String key = layout.addLayout(section.getLayout());
219 return key;
220 }
221
222
223
224
225
226
227 @Override
228 public void removeSection(Section section){
229 sections.remove(section);
230 layout.removeLayoutElement(section.getLayout());
231 }
232
233
234
235
236
237 protected void clearValidationErrors() {
238 layout.clearValidationErrors();
239 }
240
241
242
243
244
245 public void clearValidationWarnings() {
246 layout.clearValidationWarnings();
247 }
248
249
250
251
252
253
254 @Override
255 public List<FieldDescriptor> getFields() {
256 List<FieldDescriptor> allFields = new ArrayList<FieldDescriptor>();
257 allFields.addAll(fields);
258
259 for(Section ns: sections){
260 allFields.addAll(ns.getFields());
261 }
262 return allFields;
263 }
264
265
266
267
268
269 @Override
270 public List<FieldDescriptor> getUnnestedFields() {
271 return fields;
272 }
273
274
275
276
277
278 @Override
279 public List<Section> getSections() {
280 return sections;
281 }
282
283
284
285
286
287
288
289 @Override
290 public ErrorLevel processValidationResults(List<ValidationResultInfo> results, boolean clearErrors){
291 if(clearErrors){
292 this.clearValidationErrors();
293 }
294 ErrorLevel status = ErrorLevel.OK;
295
296 if (isValidationEnabled){
297
298 for(FieldDescriptor f: this.fields){
299
300 if(f.hasHadFocus()){
301 for(ValidationResultInfo vr: results){
302 String vrElement = vr.getElement();
303 if(vrElement.startsWith("/")){
304 vrElement = vrElement.substring(1);
305 }
306
307 vrElement = vrElement.replaceFirst("^(\\S+)/[0-9]+$", "$1");
308
309
310 String parentPath = Application.getApplicationContext().getParentPath();
311 parentPath = parentPath==null?"":parentPath;
312
313 if((parentPath+vrElement).equals(parentPath+f.getFieldKey())){
314 FieldElement element = f.getFieldElement();
315 if (element != null){
316 ErrorLevel fieldStatus = element.processValidationResult(vr);
317 if(fieldStatus.getLevel() > status.getLevel()){
318 status = fieldStatus;
319 }
320 }
321 }
322 }
323 }
324
325 if(f.getFieldWidget() instanceof MultiplicityComposite ){
326 MultiplicityComposite mc = (MultiplicityComposite) f.getFieldWidget();
327
328
329 for(MultiplicityItem item: mc.getItems()){
330 if(item.getItemWidget() instanceof Section && !item.isDeleted()){
331 ErrorLevel fieldStatus = ((Section)item.getItemWidget()).processValidationResults(results, clearErrors);
332 if(fieldStatus.getLevel() > status.getLevel()){
333 status = fieldStatus;
334 }
335 }
336 }
337 }
338
339 if(f.getFieldWidget() instanceof MultiplicityGroup ){
340 MultiplicityGroup mg = (MultiplicityGroup) f.getFieldWidget();
341
342
343 for(MultiplicityGroupItem item: mg.getItems()){
344 if(item.getItemWidget() instanceof Section && !item.isDeleted()){
345 ErrorLevel fieldStatus = ((Section)item.getItemWidget()).processValidationResults(results, clearErrors);
346 if(fieldStatus.getLevel() > status.getLevel()){
347 status = fieldStatus;
348 }
349 }
350 }
351 }
352 if (f.getFieldWidget() instanceof CanProcessValidationResults) {
353 ErrorLevel fieldStatus = ((CanProcessValidationResults) f.getFieldWidget()).processValidationResults(f, results, clearErrors);
354 if (fieldStatus.getLevel() > status.getLevel()) {
355 status = fieldStatus;
356 }
357 }
358 }
359
360 for(Section s: sections){
361 ErrorLevel subsectionStatus = s.processValidationResults(results,clearErrors);
362 if(subsectionStatus.getLevel() > status.getLevel()){
363 status = subsectionStatus;
364 }
365 }
366 }
367
368 return status;
369 }
370
371
372
373
374
375 @Override
376 public ErrorLevel processValidationResults(List<ValidationResultInfo> results) {
377 return processValidationResults(results, true);
378 }
379
380
381
382
383
384
385 @Override
386 public LayoutController getLayoutController() {
387 return this.layoutController;
388 }
389
390 @Override
391 public void setLayoutController(LayoutController controller) {
392 this.layoutController = controller;
393 }
394
395
396
397
398
399
400 @Override
401 public String addWidget(Widget w) {
402 return layout.addWidget(w);
403 }
404
405
406
407
408
409
410
411 public void setFieldHasHadFocusFlags(boolean hadFocus) {
412 for(FieldDescriptor f: fields){
413 f.setHasHadFocus(hadFocus);
414 if(f.getFieldWidget() instanceof MultiplicityComposite){
415 MultiplicityComposite mc = (MultiplicityComposite) f.getFieldWidget();
416
417 for(MultiplicityItem item: mc.getItems()){
418 if(item.getItemWidget() instanceof Section && !item.isDeleted()){
419 ((Section) item.getItemWidget()).setFieldHasHadFocusFlags(hadFocus);
420 }
421 }
422 }else if(f.getFieldWidget() instanceof MultiplicityGroup){
423 MultiplicityGroup mg = (MultiplicityGroup) f.getFieldWidget();
424
425 for(MultiplicityGroupItem item: mg.getItems()){
426 if(item.getItemWidget() instanceof Section && !item.isDeleted()){
427 ((Section) item.getItemWidget()).setFieldHasHadFocusFlags(hadFocus);
428 }
429 }
430 }
431 }
432
433 for(Section s: sections){
434 s.setFieldHasHadFocusFlags(hadFocus);
435 }
436
437 }
438
439
440
441
442
443 @Override
444 public void enableValidation(boolean enableValidation) {
445 this.isValidationEnabled = enableValidation;
446 }
447
448 @Override
449 public boolean isValidationEnabled() {
450 return isValidationEnabled;
451 }
452
453
454
455
456
457
458
459 @Override
460 public void updateModel(DataModel model){
461 SectionBinding.INSTANCE.setModelValue(this, model, "");
462 }
463
464
465
466
467
468
469
470
471
472 @Override
473 public void updateWidgetData(DataModel model) {
474 SectionBinding.INSTANCE.setWidgetValue(this, model, "");
475 }
476
477
478
479
480
481 @Override
482 public void resetFieldInteractionFlags() {
483 this.isDirty = false;
484 for(FieldDescriptor f: fields){
485 f.setDirty(false);
486 f.setHasHadFocus(false);
487 }
488
489 for(Section s: sections){
490 s.resetFieldInteractionFlags();
491 }
492
493 }
494
495 @Override
496 public void resetDirtyFlags() {
497 this.isDirty = false;
498 for(FieldDescriptor f: fields){
499 f.setDirty(false);
500 }
501
502 for(Section s: sections){
503 s.resetDirtyFlags();
504 }
505 }
506
507
508
509
510
511
512
513 @Override
514 public String addSection(String key, Section section) {
515 sections.add(section);
516 section.getLayout().setKey(key);
517 String rkey = layout.addLayout(section.getLayout());
518 return rkey;
519 }
520
521 @Override
522 public FieldDescriptor getField(String fieldKey) {
523 for(FieldDescriptor f: fields){
524 if(f.getFieldKey().equals(fieldKey)){
525 return f;
526 }
527 }
528 return null;
529 }
530
531
532
533
534
535
536
537 @Override
538 public FieldLayout getLayout() {
539 return layout;
540 }
541
542 @Override
543 public Section getSection(String sectionKey) {
544 for(Section s: sections){
545 if(s.getLayout().getKey().equals(sectionKey)){
546 return s;
547 }
548 }
549 return null;
550 }
551
552 @Override
553 public void removeField(String fieldKey) {
554 int index = 0;
555 boolean found = false;
556 for(FieldDescriptor f: fields){
557 if(f.getFieldKey().equals(fieldKey)){
558 index = fields.indexOf(f);
559 found = true;
560 break;
561 }
562 }
563 if(found){
564 fields.remove(index);
565 }
566 layout.removeLayoutElement(fieldKey);
567
568 }
569
570 @Override
571 public void removeField(FieldDescriptor field) {
572
573 fields.remove(field);
574 layout.removeLayoutElement(field.getFieldKey());
575
576 }
577
578 @Override
579 public void removeSection(String sectionKey) {
580 int index = 0;
581 boolean found = false;
582 for(Section s: sections){
583 if(s.getLayout().getKey().equals(sectionKey)){
584 index = sections.indexOf(s);
585 found = true;
586 break;
587 }
588 }
589 if(found){
590 sections.remove(index);
591 }
592 layout.removeLayoutElement(sectionKey);
593
594 }
595
596 @Override
597 public void removeWidget(Widget widget) {
598 layout.removeLayoutElement(widget);
599
600 }
601
602 @Override
603 public void removeWidget(String key) {
604 layout.removeLayoutElement(key);
605
606 }
607
608
609
610
611
612
613
614 public boolean isDirty(){
615 if(!this.isDirty){
616
617 for(Section s: sections){
618 if(s.isDirty()){
619 setIsDirty(true);
620 break;
621 }
622 }
623 }
624 return isDirty;
625 }
626
627 public void setIsDirty(boolean state) {
628
629 if (layoutController == null){
630 layoutController = LayoutController.findParentLayout(layout);
631 }
632 if (isDirty != state){
633 isDirty = state;
634 if (layoutController != null && isDirty){
635 layoutController.fireApplicationEvent(new ContentDirtyEvent());
636 }
637 }
638 }
639
640
641
642
643 @Override
644 public void add(Widget w) {
645 super.add(w);
646 }
647
648
649
650
651
652 @Override
653 public void addStyleName(String style) {
654 layout.addStyleName(style);
655 }
656
657 @Override
658 public void setStyleName(String style) {
659 layout.setStyleName(style);
660 }
661
662
663
664
665
666 public void setInstructions(String html){
667 layout.setInstructions(html);
668 }
669
670
671
672
673
674 public void setHelp(String html){
675 layout.setHelp(html);
676 }
677
678
679
680
681
682 public void setRequired(AbbrPanel required){
683 layout.setRequired(required);
684 }
685
686 public void setSectionId(String id){
687 ((Widget)layout).getElement().setId(id);
688 }
689
690
691
692
693
694
695
696
697
698
699 public static void progressiveEnableFields(Boolean isEnabled, FieldDescriptor ... fieldDescriptors){
700
701 for (FieldDescriptor fd : fieldDescriptors){
702 enableField(isEnabled, fd);
703 }
704 }
705
706
707
708
709
710
711 public static void progressiveEnableAndRequireFields(Boolean isRequiredAndEnabled, FieldDescriptor ... fieldDescriptors){
712
713 for (FieldDescriptor fd : fieldDescriptors){
714 fd.setRequired(isRequiredAndEnabled);
715 enableField(isRequiredAndEnabled, fd);
716 }
717 }
718
719
720
721
722
723
724 public static void progressiveRequireFields(Boolean isRequired, FieldDescriptor ... fieldDescriptors){
725
726 for (FieldDescriptor fd : fieldDescriptors){
727 fd.setRequired(isRequired);
728 }
729 }
730
731
732
733
734
735
736
737 protected static void enableField(Boolean isEnabled, FieldDescriptor fd){
738
739 Widget widget = fd.getFieldWidget();
740
741 if (!isEnabled){
742 fd.getFieldElement().clearValidationErrors();
743 fd.getFieldElement().clearValidationWarnings();
744 }
745
746
747 if (widget instanceof KSPicker && ((KSPicker)widget).getInputWidget() instanceof KSDropDown){
748 ((KSDropDown)((KSPicker)widget).getInputWidget()).setEnabled(isEnabled);
749 } else if (widget instanceof TextBoxBase){
750 ((TextBoxBase)widget).setReadOnly(!isEnabled);
751 }
752 }
753
754
755 }