View Javadoc
1    package org.kuali.student.common.ui.client.widgets.table.summary;
2   
3   import java.util.ArrayList;
4   import java.util.Iterator;
5   import java.util.List;
6   import java.util.Map;
7   
8   import org.kuali.student.common.ui.client.application.Application;
9   import org.kuali.student.common.ui.client.configurable.mvc.FieldDescriptor;
10  import org.kuali.student.common.ui.client.configurable.mvc.FieldDescriptorReadOnly;
11  import org.kuali.student.common.ui.client.configurable.mvc.SectionTitle;
12  import org.kuali.student.common.ui.client.configurable.mvc.binding.ModelWidgetBinding;
13  import org.kuali.student.common.ui.client.configurable.mvc.multiplicity.MultiplicityConfiguration;
14  import org.kuali.student.common.ui.client.configurable.mvc.multiplicity.MultiplicityFieldConfiguration;
15  import org.kuali.student.common.ui.client.configurable.mvc.sections.Section;
16  import org.kuali.student.common.ui.client.configurable.mvc.sections.VerticalSection;
17  import org.kuali.student.common.ui.client.mvc.Controller;
18  import org.kuali.student.common.ui.client.mvc.DataModel;
19  import org.kuali.student.common.ui.client.mvc.ModelRequestCallback;
20  import org.kuali.student.r1.common.assembly.data.Data;
21  import org.kuali.student.r1.common.assembly.data.MetadataInterrogator;
22  import org.kuali.student.r1.common.assembly.data.QueryPath;
23  import org.kuali.student.r1.common.assembly.data.Data.Property;
24  import org.kuali.student.r2.common.dto.ValidationResultInfo;
25  import org.kuali.student.r2.common.infc.ValidationResult.ErrorLevel;
26  
27  import com.google.gwt.core.client.GWT;
28  import com.google.gwt.user.client.ui.Widget;
29  
30  public class SummaryTableSection extends VerticalSection {
31      SummaryTable summaryTable = new SummaryTable();
32      SummaryTableModel summaryTableModel = new SummaryTableModel();
33      Controller controller;
34      DataModel comparisonModel = null;
35      List<ShowRowConditionCallback> showRowCallbacks = new ArrayList<ShowRowConditionCallback>();
36      boolean isMissingFields= false;	//KSLAB-1985
37  	boolean hasWarnings= false;	//KSLAB-1985
38      
39      public boolean getIsMissingFields() {
40  		return isMissingFields;
41  	}
42  
43      public boolean getHasWarnings(){
44      	return hasWarnings;
45      }
46  
47      public SummaryTableSection() {
48          super();
49      }
50      
51      public SummaryTableSection(Controller controller) {
52          super();
53          init(controller);
54      }
55  
56      public SummaryTableSection(Controller controller, SectionTitle title) {
57          super(title);
58          init(controller);
59      }
60  
61      public void init(Controller controller) {
62          this.controller = controller;
63          this.addWidget(summaryTable);
64          summaryTable.setModel(summaryTableModel);
65      }
66  
67      public void setContentColumnHeader1(String title) {
68          summaryTableModel.setContentColumnHeader1(title);
69      }
70  
71      public void setContentColumnHeader2(String title) {
72          summaryTableModel.setContentColumnHeader2(title);
73      }
74  
75      public String getContentColumnHeader1() {
76          return summaryTableModel.getContentColumnHeader1();
77      }
78  
79      public String getContentColumnHeader2() {
80          return summaryTableModel.getContentColumnHeader2();
81      }
82  
83      public void setEditable(boolean bool) {
84          summaryTableModel.setEditable(bool);
85          summaryTable.doLayout();
86          summaryTable.markDiffs("rowDiffHighlight");
87      }
88      
89      public void addShowRowCallback(ShowRowConditionCallback callback){
90      	this.showRowCallbacks.add(callback);
91      }
92      
93      private void processShowConditions(SummaryTableFieldRow row, DataModel model, DataModel comparisonModel){
94      	for(int i =0; i < showRowCallbacks.size(); i++){
95      		showRowCallbacks.get(i).processShowConditions(row, model, comparisonModel);
96      	}
97      }
98  
99      public void addSummaryTableFieldBlock(SummaryTableFieldBlock section) {
100         summaryTableModel.addSection(section);
101     }
102     
103     @Override
104     public ErrorLevel processValidationResults(List<ValidationResultInfo> results) {    	
105     	//initialize condition parameters
106     	ErrorLevel status= ErrorLevel.OK;
107     	
108     	isMissingFields= false;    // Set-ness affects CourseSummaryConfigurer.resolveMissingFieldsWarnings()
109     	hasWarnings= false;    // Set-ness affects CourseSummaryConfigurer.resolveProposalSubmissionWarnings()
110     	
111     	// Process results
112     	for(int i = 0; i < results.size(); i++){
113     		ValidationResultInfo resultI= results.get(i);
114     		
115     		if(summaryTable.containsKey(results.get(i).getElement())){
116     			
117     			System.out.println(resultI.getElement() + " *** " + resultI.getErrorLevel() + " *** " + resultI.getMessage());
118     			
119     			if(resultI.getLevel().getLevel() > status.getLevel()){    				
120     				status= resultI.getLevel();
121     				
122     				if(resultI.getMessage().equals("Required")){	//KSLAB-1985
123     				    
124     					isMissingFields= true;
125     				}
126     			}
127     			
128     			if(this.isValidationEnabled){
129     			    
130         			summaryTable.highlightRow(resultI.getElement(), "rowHighlight");
131         		}
132     		}
133     	}
134     	
135     	List<ValidationResultInfo> warnings= Application.getApplicationContext().getValidationWarnings();
136     	ValidationResultInfo tempVr= new ValidationResultInfo();
137     	
138     	tempVr.setElement("");
139     	
140     	// Process ApplicationContext warnings
141     	for(int i = 0; i < warnings.size(); i++){    		
142     		//Reformat the validation element path based on how it can be referenced in sumaryTable rowMap
143     		String element= warnings.get(i).getElement();    
144     		
145     		if (element.startsWith("/")){    		    			
146     		    
147     			//Remove leading '/' since paths aren't stored this way in rowMap
148     			element= element.substring(1);
149     			
150     		} else if (element.matches(".*/[0-9]+")){ 
151     		    
152     			//Validation warnings returns path to individual items of simple multiplicity, 
153     			//stripping of the item index to highlight the entire field. 
154     			element= element.substring(0, element.lastIndexOf("/")); 
155     		}
156     		
157     		if(summaryTable.containsKey(element)){
158     			
159         		hasWarnings= true;
160     			
161         		if(warnings.get(i).getLevel().getLevel() > status.getLevel()){
162     				
163         		    status= warnings.get(i).getLevel();
164     			}
165         		    			
166        			summaryTable.highlightRow(element, "warning");    //Highlights related warning fields in Dark Yellow
167     		}
168     	}
169     	
170     	return status;
171     }
172     
173     @Override
174     public ErrorLevel processValidationResults(List<ValidationResultInfo> results, boolean clearErrors) {
175         
176     	if(clearErrors){
177     	    
178     		this.removeValidationHighlighting();
179     	}
180     	
181     	return this.processValidationResults(results);
182     }
183     
184     public void removeValidationHighlighting(){
185     	summaryTable.clearHighlightedRows("rowHighlight");
186     }
187     
188     protected int buildMultiplicityRows(DataModel model, DataModel compModel, SummaryTableMultiplicityFieldRow parentRow, 
189     		List<SummaryTableRow> rowList, int styleLevel, Integer parentNum){
190     	MultiplicityConfiguration config = parentRow.getConfig();
191     	int index = rowList.indexOf(parentRow) + 1;
192     	int fieldRowsCreated = 0;
193     	int number = 0;
194     	String path = parentRow.getConfig().getParentFd().getFieldKey();
195     	if(parentNum != null){
196     		path = path.replace("*", "" + parentNum);
197     	}
198     	Data data = null;
199     	if(model != null && model.isValidPath(path)){
200     		data = model.get(QueryPath.parse(path));
201     	}
202 		Data compData = null;
203 		if(compModel != null && compModel.isValidPath(path)){
204 			compData = compModel.get(QueryPath.parse(path));
205 		}
206     	if((data != null && data.size() > 0) || (compData != null && compData.size() > 0)){
207     		Iterator<Property> itr = null;
208     		if(data != null && compData != null){
209     			if(data.size() >= compData.size()){
210     				itr = data.iterator();
211     			} else{
212     				itr = compData.iterator();
213     			}
214     		} else if(data != null){
215     			itr = data.iterator();
216     		} else{
217     			itr = compData.iterator();
218     		}
219     		SummaryTableMultiplicityFieldRow currentMultiplicityRow = parentRow;
220             while (itr.hasNext()) {
221                 Property p = (Property) itr.next();
222                 if (p.getKey() instanceof Integer){
223                 	number = (Integer)p.getKey();
224                 }
225         		if(config.getItemLabel() != null && !config.getItemLabel().isEmpty()){
226         			currentMultiplicityRow.setTitle(config.getItemLabel() + " "+ (number + 1));
227         			currentMultiplicityRow.setKey(path);
228             		if(MetadataInterrogator.isRequired(config.getMetaData()) || 
229                 			MetadataInterrogator.isRequiredForNextState(config.getMetaData())){
230             			currentMultiplicityRow.setRequired(true);
231             		}
232             		currentMultiplicityRow.addTitleCellStyleName("summary-table-multiplicity-level-" + styleLevel);
233         		}
234         		else{
235         			currentMultiplicityRow.setShown(false);
236         		}
237 	    		//set has-data/requires data style here
238 	    		Map<Integer, List<MultiplicityFieldConfiguration>> fieldsCopy = config.getFields();
239 				for(int i = 0; i < config.getFields().size(); i++){
240 					for(int j = 0; j < config.getFields().get(i).size(); j++){
241 						//TODO handle custom widgets (multiplicity field widget initializer)
242 						MultiplicityFieldConfiguration field = fieldsCopy.get(i).get(j);
243 	    				String fieldKey = translatePath(field.getFieldPath(), path, number);
244 	    				FieldDescriptorReadOnly fd1 = new FieldDescriptorReadOnly(fieldKey, field.getMessageKeyInfo(), field.getMetadata());
245 	    				fd1.setOptional(field.isOptional());
246 	    				if(field.getModelWidgetBinding() != null){
247 	    					fd1.setWidgetBinding(field.getModelWidgetBinding());
248 	    				}
249 	    				FieldDescriptorReadOnly fd2 = new FieldDescriptorReadOnly(fieldKey, field.getMessageKeyInfo(), field.getMetadata());
250 	    				fd2.setOptional(field.isOptional());
251 	    				if(field.getModelWidgetBinding() != null){
252 	    					fd2.setWidgetBinding(field.getModelWidgetBinding());
253 	    				}
254 	    				SummaryTableFieldRow row = new SummaryTableFieldRow(fd1, fd2);
255 	    				row.setTemporaryRowFlag(true);
256 	    				rowList.add(index, row);
257 	    				index++;
258 	    				fieldRowsCreated++;
259 	    			}
260 				}
261 	    		if(config.getNestedConfig() != null){
262 	    			MultiplicityConfiguration nestedConfig = config.getNestedConfig();
263 	    			nestedConfig.getParentFd().getFieldKey().replace(config.getParentFd().getFieldKey(), path);
264 	    			SummaryTableMultiplicityFieldRow mRow = new SummaryTableMultiplicityFieldRow(nestedConfig);
265 	    			mRow.setTemporaryRowFlag(true);
266 	    			rowList.add(index, mRow);
267 	    			index++;
268 	    			fieldRowsCreated++;
269 	    			int result = buildMultiplicityRows(model, compModel, mRow, rowList, styleLevel + 1, number);
270 	    			index = index + result;
271 	    		}
272 	    		if(itr.hasNext()){
273 	    			SummaryTableMultiplicityFieldRow mRow = new SummaryTableMultiplicityFieldRow(config);
274 	    			mRow.setTemporaryRowFlag(true);
275 	    			rowList.add(index, mRow);
276 	    			index++;
277 	    			fieldRowsCreated++;
278 	    			currentMultiplicityRow = mRow;
279 	    		}
280             }
281     	}
282     	else{
283         	if(MetadataInterrogator.isRequired(config.getMetaData()) || 
284         			MetadataInterrogator.isRequiredForNextState(config.getMetaData())){
285         		if(config.getItemLabel() != null && !config.getItemLabel().isEmpty()){
286         			parentRow.setTitle(config.getItemLabel() + " "+ (number + 1));
287         			parentRow.setKey(path);
288             		parentRow.setRequired(true);
289             		parentRow.addTitleCellStyleName("summary-table-multiplicity-level-" + styleLevel);
290         		}
291         		else{
292         			parentRow.setShown(false);
293         		}
294         		//set has-data/requires data style here
295         		Map<Integer, List<MultiplicityFieldConfiguration>> fields = config.getFields();
296 				for(int i = 0; i < fields.size(); i++){
297 					for(int j = 0; j < fields.get(i).size(); j++){
298 						//TODO handle custom widgets (multiplicity field widget initializer)
299 						MultiplicityFieldConfiguration field = fields.get(i).get(j);
300 	    				String fieldKey = translatePath(field.getFieldPath(), path, number);
301 	    				FieldDescriptorReadOnly fd1 = new FieldDescriptorReadOnly(fieldKey, field.getMessageKeyInfo(), field.getMetadata());
302 	    				fd1.setOptional(field.isOptional());
303 	    				if(field.getModelWidgetBinding() != null){
304 	    					fd1.setWidgetBinding(field.getModelWidgetBinding());
305 	    				}
306 	    				FieldDescriptorReadOnly fd2 = new FieldDescriptorReadOnly(fieldKey, field.getMessageKeyInfo(), field.getMetadata());
307 	    				fd2.setOptional(field.isOptional());
308 	    				if(field.getModelWidgetBinding() != null){
309 	    					fd2.setWidgetBinding(field.getModelWidgetBinding());
310 	    				}
311 	    				SummaryTableFieldRow row = new SummaryTableFieldRow(fd1, fd2);
312 	    				row.setTemporaryRowFlag(true);
313 	    				rowList.add(index, row);
314 	    				index++;
315 	    				fieldRowsCreated++;
316 	    			}
317 				}
318 	    		if(config.getNestedConfig() != null){
319 	    			MultiplicityConfiguration nestedConfig = config.getNestedConfig();
320 	    			nestedConfig.getParentFd().getFieldKey().replace(config.getParentFd().getFieldKey(), path);
321 	    			SummaryTableMultiplicityFieldRow mRow = new SummaryTableMultiplicityFieldRow(nestedConfig);
322 	    			mRow.setTemporaryRowFlag(true);
323 	    			rowList.add(index, mRow);
324 	    			index++;
325 	    			fieldRowsCreated++;
326 	    			buildMultiplicityRows(null, null, mRow, rowList, styleLevel + 1, number);
327 	    		}
328         	}
329         	else{
330         		//Alternate label possibly here
331         		parentRow.setTitle(config.getItemLabel());
332         		parentRow.setRequired(false);
333         		parentRow.setKey(config.getParentFd().getFieldKey());
334         		//set unrequired style here
335         	}
336     	}
337     	return fieldRowsCreated;
338     }
339     
340     public String translatePath(String path, String parentPath, int num) {
341         String fieldPath;
342         if (parentPath != null) {
343             QueryPath parent = QueryPath.concat(parentPath);
344             int i = parent.size();
345 
346             QueryPath subPath = QueryPath.concat(path);
347             String itemPath =  subPath.subPath(i, subPath.size()).toString();
348 
349             QueryPath qp = QueryPath.concat(parentPath, itemPath);
350             fieldPath = qp.toString();
351         }
352         else {
353             fieldPath = path;
354         }
355 
356         fieldPath = fieldPath.replace("*", "" + num);
357         return fieldPath;
358     }
359     
360     @Override
361     public void updateWidgetData(final DataModel model) {
362     	
363         controller.requestModel("ComparisonModel", new ModelRequestCallback<DataModel>() {
364             @Override
365             public void onModelReady(DataModel otherModel) {
366                 comparisonModel = otherModel;
367                 updateTableData(model);
368             }
369 
370             @Override
371             public void onRequestFail(Throwable cause) {
372             	comparisonModel = null;
373             	updateTableData(model);
374                 //GWT.log("ComparisonModel cannot be found. " + cause.getLocalizedMessage(), null);
375             }
376         });
377     }
378     
379     private void resetSummaryTableRows(SummaryTableFieldBlock fieldBlock){
380     	List<SummaryTableRow> rowList = fieldBlock.getSectionRowList();
381     	List<SummaryTableRow> removeList = new ArrayList<SummaryTableRow>();
382         for (int j = 0; j < rowList.size(); j++) {
383         	 SummaryTableFieldRow fieldRow = (SummaryTableFieldRow) rowList.get(j);
384         	 if(fieldRow.isTemporaryRow()){
385         		 removeList.add(fieldRow);
386         	 }
387         	 if(!fieldRow.isShown()){
388         		 fieldRow.setShown(true);
389         	 }
390         }
391         rowList.removeAll(removeList);
392     }
393     
394     private void buildSummaryTableMultiplicity(DataModel model, DataModel compModel, SummaryTableFieldBlock fieldBlock){
395     	List<SummaryTableMultiplicityFieldRow> mRows = fieldBlock.getMultiplicityList();
396     	for(int i = 0; i < mRows.size(); i++){
397     		SummaryTableMultiplicityFieldRow mRow = mRows.get(i);
398     		
399     		buildMultiplicityRows(model, compModel, mRow, fieldBlock.getSectionRowList(), 1, null);
400     	}
401     }
402     
403     @SuppressWarnings("unchecked")
404 	private void updateTableData(DataModel model){
405     	List<SummaryTableBlock> sectionList = summaryTableModel.getSectionList();
406         for (int i = 0; i < sectionList.size(); i++) {
407             SummaryTableFieldBlock fieldBlock = (SummaryTableFieldBlock) sectionList.get(i);
408             resetSummaryTableRows(fieldBlock);
409             if(!fieldBlock.getMultiplicityList().isEmpty()){
410             	buildSummaryTableMultiplicity(model, comparisonModel, fieldBlock);
411             }
412             List<SummaryTableRow> rowList = fieldBlock.getSectionRowList();
413             
414             for (int j = 0; j < rowList.size(); j++) {
415                 SummaryTableFieldRow fieldRow = (SummaryTableFieldRow) rowList.get(j);
416                 FieldDescriptor field = fieldRow.getFieldDescriptor1();
417                 final FieldDescriptor field2 = fieldRow.getFieldDescriptor2();
418                 boolean optional = false;
419                 boolean firstValueEmpty = true;
420                 boolean secondValueEmpty = true;
421                 // for the first column
422                 if(field != null){
423                 	
424                 	if(field instanceof FieldDescriptorReadOnly){
425                 		optional = ((FieldDescriptorReadOnly)field).isOptional();
426                 	}
427                 	String fieldPath = QueryPath.getPathSeparator() + field.getFieldKey();
428                 	if(model.isValidPath(fieldPath)){
429                 	
430 	                	Object value = model.get(QueryPath.parse(fieldPath));
431 	                	if(value != null){
432                     		if(value instanceof String && ((String)value).isEmpty()){
433 		                		firstValueEmpty = true;
434 		                	}
435                     		else if(value instanceof Data && ((Data) value).size() == 0){
436                     			firstValueEmpty = true;
437                     		}
438                     		else{
439                     			firstValueEmpty = false;
440                     		}
441 	                	}
442                 	}
443 		                
444 	                ModelWidgetBinding binding = field.getModelWidgetBinding();
445 	                
446 		            if (binding != null) {
447 		                Widget w = field.getFieldWidget();
448 		                binding.setWidgetValue(w, model, fieldPath);
449 		            } else {
450 		                GWT.log(field.getFieldKey() + " has no widget binding.", null);
451 		            }
452                 	
453                 }
454 
455                 // the second column
456                 if (comparisonModel == null) {
457                 	if(fieldRow.getContentCellCount() == 2){
458                 		fieldRow.setContentCellCount(1);
459                 	}
460                 }else{
461                 	summaryTableModel.setContentColumnHeader1(model.getModelName());
462                 	summaryTableModel.setContentColumnHeader2(comparisonModel.getModelName());
463                 	if(fieldRow.getContentCellCount() == 1){
464                 		fieldRow.setContentCellCount(2);
465                 	}
466                 	if(field2 != null){
467 	                    
468 	                    String fieldPath2 = QueryPath.getPathSeparator() + field2.getFieldKey();
469 	                    if(comparisonModel.isValidPath(fieldPath2)){
470 	                    	
471 	                    	Object value = model.get(QueryPath.parse(fieldPath2));
472 	                    	if(value != null){
473 	                    		if(value instanceof String && ((String)value).isEmpty()){
474 			                		secondValueEmpty = true;
475 			                	}
476 	                    		else if(value instanceof Data && ((Data) value).size() == 0){
477 	                    			secondValueEmpty = true;
478 	                    		}
479 	                    		else{
480 	                    			secondValueEmpty = false;
481 	                    		}
482 		                	}
483 	                    	
484 	                    	ModelWidgetBinding binding2 = field2.getModelWidgetBinding();
485 	                    	
486 		                    if (binding2 != null) {
487 		                        Widget w = field2.getFieldWidget();
488 		                        binding2.setWidgetValue(w, comparisonModel, fieldPath2);
489 		                    } else {
490 		                        GWT.log(field2.getFieldKey() + " has no widget binding for the ComparisonModel.", null);
491 		                    }
492 	                    }
493                 	}
494                 }
495                 
496                 if(firstValueEmpty && secondValueEmpty && optional){
497                 	fieldRow.setShown(false);
498                 }
499                 processShowConditions(fieldRow, model, comparisonModel);
500             }
501             
502         }
503 
504         summaryTable.doLayout();
505         summaryTable.markDiffs("rowDiffHighlight");
506     }
507 
508     @Override
509     public String addField(FieldDescriptor fieldDescriptor) {
510         GWT.log("addField(FieldDescriptor fieldDescriptor) method not supported");
511         throw new UnsupportedOperationException("SummaryTableSection.addField(FieldDescriptor fieldDescriptor) method not supported");
512     }
513 
514     @Override
515     public String addSection(Section section) {
516         GWT.log("addSection(Section section) method not supported");
517         throw new UnsupportedOperationException("SummaryTableSection.addSection(Section section) method not supported");
518     }
519 
520     @Override
521     public String addSection(String key, Section section) {
522         GWT.log("addSection(String key, Section section) method not supported");
523         throw new UnsupportedOperationException("SummaryTableSection.addSection(String key, Section section) method not supported");
524     }
525 
526     public SummaryTable getSummaryTable() {
527         return summaryTable;
528     }
529 
530 }