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