Clover Coverage Report - KS Common 1.2.1-SNAPSHOT (Aggregated)
Coverage timestamp: Wed Nov 2 2011 04:55:08 EST
../../../../../../../../img/srcFileCovDistChart0.png 29% of files have more coverage
162   597   95   3.18
82   400   0.59   51
51     1.86  
1    
 
  LayoutController       Line # 64 162 0% 95 295 0% 0.0
 
No Tests
 
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    *
7    * http://www.osedu.org/licenses/ECL-2.0
8    *
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    */
15   
16    package org.kuali.student.common.ui.client.configurable.mvc;
17   
18    import java.util.HashMap;
19    import java.util.LinkedHashMap;
20    import java.util.List;
21    import java.util.Map;
22    import java.util.Map.Entry;
23   
24    import org.kuali.student.common.assembly.data.QueryPath;
25    import org.kuali.student.common.ui.client.application.Application;
26    import org.kuali.student.common.ui.client.configurable.mvc.layouts.MenuSectionController;
27    import org.kuali.student.common.ui.client.configurable.mvc.layouts.TabMenuController;
28    import org.kuali.student.common.ui.client.configurable.mvc.layouts.ViewLayoutController;
29    import org.kuali.student.common.ui.client.configurable.mvc.sections.Section;
30    import org.kuali.student.common.ui.client.configurable.mvc.views.SectionView;
31    import org.kuali.student.common.ui.client.event.ActionEvent;
32    import org.kuali.student.common.ui.client.event.SaveActionEvent;
33    import org.kuali.student.common.ui.client.event.SectionUpdateEvent;
34    import org.kuali.student.common.ui.client.event.SectionUpdateHandler;
35    import org.kuali.student.common.ui.client.event.ValidateRequestEvent;
36    import org.kuali.student.common.ui.client.event.ValidateRequestHandler;
37    import org.kuali.student.common.ui.client.mvc.ActionCompleteCallback;
38    import org.kuali.student.common.ui.client.mvc.Callback;
39    import org.kuali.student.common.ui.client.mvc.Controller;
40    import org.kuali.student.common.ui.client.mvc.DataModel;
41    import org.kuali.student.common.ui.client.mvc.ModelRequestCallback;
42    import org.kuali.student.common.ui.client.mvc.View;
43    import org.kuali.student.common.ui.client.mvc.history.HistoryManager;
44    import org.kuali.student.common.ui.client.widgets.KSButton;
45    import org.kuali.student.common.ui.client.widgets.KSLightBox;
46    import org.kuali.student.common.ui.client.widgets.field.layout.element.FieldElement;
47    import org.kuali.student.common.validation.dto.ValidationResultInfo;
48    import org.kuali.student.common.validation.dto.ValidationResultInfo.ErrorLevel;
49   
50    import com.google.gwt.core.client.GWT;
51    import com.google.gwt.event.dom.client.ClickEvent;
52    import com.google.gwt.event.dom.client.ClickHandler;
53    import com.google.gwt.user.client.ui.FlowPanel;
54    import com.google.gwt.user.client.ui.Widget;
55   
56    /**
57    * The LayoutController is a central piece of the UIF. This controller is also itself a view.
58    * As such, LayoutControllers can also have other LayoutControllers as their views.
59    *
60    * @see Controller
61    * @author Kuali Student Team
62    *
63    */
 
64    public abstract class LayoutController extends Controller implements ViewLayoutController, View {
65   
66    protected Map<Enum<?>, View> viewMap = new LinkedHashMap<Enum<?>, View>();
67    protected Map<String, Enum<?>> viewEnumMap = new HashMap<String, Enum<?>>();
68    protected Enum<?> defaultView;
69   
70    protected String name;
71    protected Enum<?> viewType;
72   
73    protected View startPopupView;
74    protected KSLightBox startViewWindow;
75   
76    /**
77    * Constructor
78    * Sets up event handlers fro section update events and validation request events.
79    */
 
80  0 toggle public LayoutController(){
81  0 super();
82    //Global section update Event handling
83  0 addApplicationEventHandler(SectionUpdateEvent.TYPE, new SectionUpdateHandler(){
84   
 
85  0 toggle @Override
86    public void onSectionUpdate(final SectionUpdateEvent event) {
87  0 LayoutController.this.requestModel(new ModelRequestCallback<DataModel>(){
88   
 
89  0 toggle @Override
90    public void onRequestFail(Throwable cause) {
91  0 GWT.log("Unable to retrieve model for section update", cause);
92    }
93   
 
94  0 toggle @Override
95    public void onModelReady(DataModel model) {
96  0 event.getSection().updateModel(model);
97  0 event.getSection().updateWidgetData(model);
98   
99    }
100    });
101   
102    }
103    });
104    //Global validation Event handling
105  0 addApplicationEventHandler(ValidateRequestEvent.TYPE, new ValidateRequestHandler() {
106   
 
107  0 toggle @Override
108    public void onValidateRequest(final ValidateRequestEvent event) {
109  0 FieldDescriptor originatingField = event.getFieldDescriptor();
110  0 String modelId = null;
111  0 if (originatingField != null) {
112  0 modelId = originatingField.getModelId();
113    }
114  0 if (modelId == null) {
115  0 requestModel(new ModelRequestCallback<DataModel>() {
 
116  0 toggle @Override
117    public void onModelReady(DataModel model) {
118  0 validate(model, event);
119    }
120   
 
121  0 toggle @Override
122    public void onRequestFail(Throwable cause) {
123  0 GWT.log("Unable to retrieve model for validation", cause);
124    }
125   
126    });
127    } else {
128  0 requestModel(modelId, new ModelRequestCallback<DataModel>() {
 
129  0 toggle @Override
130    public void onModelReady(DataModel model) {
131  0 validate(model, event);
132    }
133   
 
134  0 toggle @Override
135    public void onRequestFail(Throwable cause) {
136  0 GWT.log("Unable to retrieve model for validation", cause);
137    }
138   
139    });
140    }
141    }
142   
143    });
144    }
145   
 
146  0 toggle private void validate(DataModel model, final ValidateRequestEvent event) {
147  0 if(event.validateSingleField()){
148  0 model.validateField(event.getFieldDescriptor(), new Callback<List<ValidationResultInfo>>() {
 
149  0 toggle @Override
150    public void exec(List<ValidationResultInfo> result) {
151  0 if(event.getFieldDescriptor() != null) {
152    // We dont need to traverse since it is single field, so don't do isValid call here
153    // instead add the error messages directly
154  0 FieldElement element = event.getFieldDescriptor().getFieldElement();
155  0 Widget w = event.getFieldDescriptor().getFieldWidget();
156  0 if(element != null) {
157  0 element.clearValidationErrors();
158   
159  0 if ((w instanceof CanProcessValidationResults) && ((CanProcessValidationResults) w).doesOnTheFlyValidation()) {
160  0 ((CanProcessValidationResults) w).Validate(event, result);
161    } else {
162  0 for(int i = 0; i < result.size(); i++) {
163  0 ValidationResultInfo vr = result.get(i);
164  0 if (vr.getElement().equals(event.getFieldDescriptor().getFieldKey()) && event.getFieldDescriptor().hasHadFocus()) {
165  0 element.processValidationResult(vr);
166    }
167    }
168    }
169    }
170    }
171   
172    }
173    });
174    } else {
175  0 model.validate(new Callback<List<ValidationResultInfo>>() {
 
176  0 toggle @Override
177    public void exec(List<ValidationResultInfo> result) {
178  0 isValid(result, false, true);
179    }
180    });
181    }
182    }
183   
184    /**
185    * Check to see if the list of validation results have an error.
186    * @param list
187    * @return
188    */
 
189  0 toggle public ErrorLevel checkForErrors(List<ValidationResultInfo> list){
190  0 ErrorLevel errorLevel = ErrorLevel.OK;
191   
192  0 for(ValidationResultInfo vr: list){
193  0 if(vr.getErrorLevel().getLevel() > errorLevel.getLevel()){
194  0 errorLevel = vr.getErrorLevel();
195    }
196  0 if(errorLevel.equals(ErrorLevel.ERROR)){
197  0 break;
198    }
199    }
200   
201  0 return errorLevel;
202   
203    }
204   
205    /**
206    * Finds the first parent LayoutController of this LayoutController, returns null if this
207    * is the top level LayoutController.
208    * @param w
209    * @return
210    */
 
211  0 toggle public static LayoutController findParentLayout(Widget w){
212  0 LayoutController result = null;
213  0 while (true) {
214  0 if (w == null) {
215  0 break;
216  0 } else if (w instanceof HasLayoutController) {
217  0 result = ((HasLayoutController)w).getLayoutController();
218  0 if (result != null) {
219  0 break;
220    }
221  0 } else if (w instanceof LayoutController) {
222  0 result = (LayoutController) w;
223  0 break;
224    }
225  0 w = w.getParent();
226   
227    }
228  0 return result;
229    }
230   
231    /**
232    * @see org.kuali.student.common.ui.client.configurable.mvc.layouts.ViewLayoutController#addStartViewPopup(org.kuali.student.common.ui.client.mvc.View)
233    */
 
234  0 toggle public void addStartViewPopup(final View view){
235  0 startPopupView = view;
236  0 if(startViewWindow == null){
237  0 startViewWindow = new KSLightBox();
238    }
239   
240  0 FlowPanel panel = new FlowPanel();
241  0 panel.add(view.asWidget());
242  0 KSButton save = new KSButton("Save",new ClickHandler(){
 
243  0 toggle public void onClick(ClickEvent event) {
244  0 view.updateModel();
245  0 SaveActionEvent saveActionEvent = new SaveActionEvent(true);
246   
247  0 saveActionEvent.setActionCompleteCallback(new ActionCompleteCallback(){
 
248  0 toggle public void onActionComplete(ActionEvent action) {
249  0 startViewWindow.hide();
250    }
251    });
252   
253   
254  0 fireApplicationEvent(saveActionEvent);
255    }
256    });
257  0 startViewWindow.addButton(save);
258   
259  0 KSButton cancel = new KSButton("Cancel", new ClickHandler(){
 
260  0 toggle public void onClick(ClickEvent event) {
261  0 startViewWindow.hide();
262    }
263    });
264  0 startViewWindow.addButton(cancel);
265   
266  0 if(view instanceof SectionView){
267  0 ((SectionView) view).setController(this);
268    }
269  0 startViewWindow.setWidget(panel);
270    }
271   
272    /**
273    * @return true if the start popup is showing
274    */
 
275  0 toggle public boolean isStartViewShowing(){
276  0 if(startViewWindow == null){
277  0 return false;
278    }
279  0 return startViewWindow.isShowing();
280    }
281   
 
282  0 toggle public View getStartPopupView(){
283  0 return startPopupView;
284    }
285   
 
286  0 toggle public void showStartPopup(final Callback<Boolean> onReadyCallback){
287  0 startPopupView.beforeShow(new Callback<Boolean>() {
 
288  0 toggle @Override
289    public void exec(Boolean result) {
290  0 if (result) {
291  0 startViewWindow.show();
292    }
293  0 onReadyCallback.exec(result);
294    }
295    });
296    }
297   
 
298  0 toggle public KSLightBox getStartPopup(){
299  0 return startViewWindow;
300    }
301   
302   
303    /*New methods*/
304   
305    /**
306    * @see org.kuali.student.common.ui.client.configurable.mvc.layouts.ViewLayoutController#addView(org.kuali.student.common.ui.client.mvc.View)
307    */
 
308  0 toggle public void addView(View view){
309  0 viewMap.put(view.getViewEnum(), view);
310  0 viewEnumMap.put(view.getViewEnum().toString(), view.getViewEnum());
311  0 if(view instanceof SectionView){
312  0 ((SectionView) view).setController(this);
313    }
314  0 else if(view instanceof ToolView){
315  0 ((ToolView) view).setController(this);
316    }
317    }
318   
319    /**
320    * @see org.kuali.student.common.ui.client.configurable.mvc.layouts.ViewLayoutController#setDefaultView(java.lang.Enum)
321    */
 
322  0 toggle public <V extends Enum<?>> void setDefaultView(V viewType){
323  0 this.defaultView = viewType;
324    }
325   
 
326  0 toggle public Enum<?> getDefaultView(){
327  0 return this.defaultView;
328    }
329   
330    /**
331    * @see org.kuali.student.common.ui.client.mvc.View#updateModel()
332    */
333    public abstract void updateModel();
334   
335    /**
336    * Update the model with a single views information
337    * @param viewType
338    */
 
339  0 toggle public void updateModelFromView(Enum<?> viewType){
340  0 View v = viewMap.get(viewType);
341  0 if(v != null){
342  0 v.updateModel();
343    }
344    }
345   
346    /**
347    * Update a the model from the view that is currently being shown by this controller
348    */
 
349  0 toggle public void updateModelFromCurrentView(){
350  0 if(this.getCurrentView() != null){
351  0 this.getCurrentView().updateModel();
352    }
353    }
354   
 
355  0 toggle @Override
356    public <V extends Enum<?>> void getView(V viewType, Callback<View> callback) {
357  0 callback.exec(viewMap.get(viewType));
358    }
359   
 
360  0 toggle @Override
361    public Enum<?> getViewEnumValue(String enumValue) {
362  0 return viewEnumMap.get(enumValue);
363    }
364   
 
365  0 toggle @Override
366    public void showDefaultView(final Callback<Boolean> onReadyCallback) {
367  0 HistoryManager.setLogNavigationHistory(false);
368    //turn of history support for default showing until view is ready
369  0 if(defaultView != null){
370  0 showView(defaultView, onReadyCallback);
371    }
372  0 else if(!viewMap.isEmpty()){
373  0 if(defaultView == null){
374  0 showView(viewMap.entrySet().iterator().next().getKey(), onReadyCallback);
375    }
376    }
377   
378    }
379   
380    /**
381    * Show the view that was the first one added and will likely be the first one in a layout's menu, for
382    * example. Note that this is different than show default view.
383    *
384    * @param onReadyCallback
385    */
 
386  0 toggle public void showFirstView(Callback<Boolean> onReadyCallback){
387  0 HistoryManager.setLogNavigationHistory(false);
388  0 if(!viewMap.isEmpty()){
389  0 showView(viewMap.entrySet().iterator().next().getKey(), onReadyCallback);
390    }
391    else{
392  0 showDefaultView(onReadyCallback);
393    }
394    }
395   
396    /**
397    * Check to see if current/all section(s) is valid (ie. does not contain any errors) - also displays
398    * them in the ui if possible
399    *
400    * @param validationResults List of validation results for the layouts model.
401    * @param checkCurrentSectionOnly true if errors should be checked on current section only, false if all sections should be checked
402    * @return true if the specified sections (all or current) has any validation errors
403    */
 
404  0 toggle public boolean isValid(List<ValidationResultInfo> validationResults, boolean checkCurrentSectionOnly){
405  0 return isValid(validationResults, checkCurrentSectionOnly, true);
406    }
407   
408    /**
409    * @see LayoutController#isValid(List, boolean)
410    * @param validationResults
411    * @param checkCurrentSectionOnly
412    * @param allFields
413    * @return
414    */
 
415  0 toggle public boolean isValid(List<ValidationResultInfo> validationResults, boolean checkCurrentSectionOnly, boolean allFields){
416   
417  0 boolean isValid = true;
418   
419  0 clearAllWarnings();
420   
421  0 if (checkCurrentSectionOnly){
422    //Check for validation errors on the currently displayed section only
423  0 View v = getCurrentView();
424  0 if(v instanceof Section){
425  0 isValid = isValid(validationResults, (Section)v, allFields);
426    }
427  0 if(this.isStartViewShowing()){
428  0 if(startPopupView instanceof Section){
429  0 isValid = isValid(validationResults, ((Section) startPopupView), allFields) && isValid;
430    }
431    }
432    } else {
433    //Check for validation errors on all sections
434  0 String errorSections = "";
435  0 StringBuilder errorSectionsbuffer = new StringBuilder();
436  0 errorSectionsbuffer.append(errorSections);
437  0 for (Entry<Enum<?>, View> entry:viewMap.entrySet()) {
438  0 View v = entry.getValue();
439  0 if (v instanceof Section){
440  0 if (!isValid(validationResults, (Section)v, allFields)){
441  0 isValid = false;
442  0 errorSectionsbuffer.append(((SectionView)v).getName() + ", ");
443    }
444    }
445    }
446  0 if(this.isStartViewShowing()){
447  0 if(startPopupView instanceof Section){
448  0 isValid = isValid(validationResults, ((Section) startPopupView), allFields) && isValid;
449    }
450    }
451  0 errorSections = errorSectionsbuffer.toString();
452  0 if (!errorSections.isEmpty()){
453  0 errorSections = errorSections.substring(0, errorSections.length()-2);
454    //container.addMessage("Following section(s) has errors & must be corrected: " + errorSections);
455    }
456    }
457   
458  0 return isValid;
459    }
460   
 
461  0 toggle private boolean isValid(List<ValidationResultInfo> validationResults, Section section, boolean allFields){
462  0 ErrorLevel status;
463  0 if(allFields){
464  0 section.setFieldHasHadFocusFlags(true);
465  0 status = section.processValidationResults(validationResults);
466    }
467    else{
468  0 status = section.processValidationResults(validationResults, false);
469    }
470   
471  0 return (status != ErrorLevel.ERROR);
472    }
473   
474    /**
475    * This clears all warnings that currently displayed on all fields and sections.
476    */
 
477  0 toggle protected void clearAllWarnings(){
478  0 for (Entry<Enum<?>, View> entry:viewMap.entrySet()) {
479  0 View v = entry.getValue();
480  0 if (v instanceof Section){
481  0 ((Section)v).clearValidationWarnings();
482    }
483    }
484    }
485   
486    /**
487    * This particular implementation of beforeViewChange checks to see if all its view contains a Controller
488    * and if it does checks with that controller to see if it is ok to change the view. OkToChange callback
489    * will be exec with true if the view is allowed to be changed at this time. This method can be overriden
490    * to provide additional functionality to stop a view from being changed when there is some additional
491    * processing that needs to occur in the ui before the view changes.
492    *
493    * @see org.kuali.student.common.ui.client.mvc.Controller#beforeViewChange(java.lang.Enum, org.kuali.student.common.ui.client.mvc.Callback)
494    */
 
495  0 toggle @Override
496    public void beforeViewChange(Enum<?> viewChangingTo, Callback<Boolean> okToChange) {
497   
498  0 if(this.getCurrentView() instanceof Controller){
499  0 ((Controller)this.getCurrentView()).beforeViewChange(viewChangingTo, okToChange);
500    }
501    else{
502  0 okToChange.exec(true);
503    }
504   
505  0 this.showExport(isExportButtonActive());
506    }
507   
508    /**
509    * Shows warnings stored to the application context
510    * (i.e: dark-yellow highlighting of conflicts during review of a Course Proposal)
511    */
 
512  0 toggle protected void showWarnings(){
513  0 if (!Application.getApplicationContext().getValidationWarnings().isEmpty()){
514  0 isValid(Application.getApplicationContext().getValidationWarnings(), true);
515    }
516    }
517   
 
518  0 toggle @Override
519    public Widget asWidget() {
520  0 return this;
521    }
522   
 
523  0 toggle @Override
524    public boolean beforeHide() {
525  0 return true;
526    }
527   
528    /**
529    * Default implementation does nothing on before show. Override to do other things before THIS view is
530    * shown.
531    * @see org.kuali.student.common.ui.client.mvc.View#beforeShow(org.kuali.student.common.ui.client.mvc.Callback)
532    */
 
533  0 toggle @Override
534    public void beforeShow(Callback<Boolean> onReadyCallback) {
535  0 onReadyCallback.exec(true);
536    }
537   
 
538  0 toggle @Override
539    public Controller getController() {
540  0 return parentController;
541    }
542   
 
543  0 toggle @Override
544    public String getName() {
545  0 if(name == null && viewType != null){
546  0 return viewType.toString();
547    }
548    else{
549  0 return name;
550    }
551    }
552   
 
553  0 toggle @Override
554    public Enum<?> getViewEnum() {
555  0 return viewType;
556    }
557   
 
558  0 toggle public void setViewEnum(Enum<?> viewType){
559  0 this.viewType= viewType;
560    }
561   
562    /**
563    * Sets the name of this LayoutController. This name is used in the breadcrumb and window's title.
564    * Setting the name to the empty string will omit the breadcrumb - this is sometimes desired.
565    * @param name
566    */
 
567  0 toggle public void setName(String name){
568  0 this.name = name;
569    }
570   
 
571  0 toggle public void setController(Controller controller){
572  0 parentController = controller;
573    }
574   
 
575  0 toggle @Override
576    public void collectBreadcrumbNames(List<String> names) {
577  0 names.add(this.getName());
578  0 if(this.getCurrentView() != null){
579  0 this.getCurrentView().collectBreadcrumbNames(names);
580    }
581    }
582   
 
583  0 toggle @Override
584    public void clear() {
585   
586    }
587   
 
588  0 toggle public boolean isExportButtonActive() {
589  0 return false;
590    }
591   
 
592  0 toggle @Override
593    public void showExport(boolean show) {
594    // TODO Auto-generated method stub
595   
596    }
597    }