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.common.validation.dto.ValidationResultInfo;
 44  
 import org.kuali.student.common.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  
      */
 76  
     public LayoutController(){
 77  0
         super();
 78  
         //Global section update Event handling
 79  0
                 addApplicationEventHandler(SectionUpdateEvent.TYPE, new SectionUpdateHandler(){
 80  
 
 81  
                         @Override
 82  
                         public void onSectionUpdate(final SectionUpdateEvent event) {
 83  0
                                 LayoutController.this.requestModel(new ModelRequestCallback<DataModel>(){
 84  
 
 85  
                                         @Override
 86  
                                         public void onRequestFail(Throwable cause) {
 87  0
                                                 GWT.log("Unable to retrieve model for section update", cause);
 88  0
                                         }
 89  
 
 90  
                                         @Override
 91  
                                         public void onModelReady(DataModel model) {
 92  0
                                                 event.getSection().updateModel(model);
 93  0
                                                 event.getSection().updateWidgetData(model);
 94  
                                                 
 95  0
                                         }
 96  
                                 });
 97  
                                 
 98  0
                         }
 99  
                 });
 100  
                 //Global validation Event handling
 101  0
         addApplicationEventHandler(ValidateRequestEvent.TYPE, new ValidateRequestHandler() {
 102  
 
 103  
             @Override
 104  
             public void onValidateRequest(final ValidateRequestEvent event) {
 105  0
                     FieldDescriptor originatingField = event.getFieldDescriptor();
 106  0
                     String modelId = null;
 107  0
                     if (originatingField != null) {
 108  0
                             modelId = originatingField.getModelId();
 109  
                     }
 110  0
                     if (modelId == null) {
 111  0
                             requestModel(new ModelRequestCallback<DataModel>() {
 112  
                                     @Override
 113  
                                     public void onModelReady(DataModel model) {
 114  0
                                             validate(model, event);
 115  0
                                     }
 116  
 
 117  
                                     @Override
 118  
                                     public void onRequestFail(Throwable cause) {
 119  0
                                             GWT.log("Unable to retrieve model for validation", cause);
 120  0
                                     }
 121  
 
 122  
                             });
 123  
                     } else {
 124  0
                             requestModel(modelId, new ModelRequestCallback<DataModel>() {
 125  
                                     @Override
 126  
                                     public void onModelReady(DataModel model) {
 127  0
                                             validate(model, event);
 128  0
                                     }
 129  
 
 130  
                                     @Override
 131  
                                     public void onRequestFail(Throwable cause) {
 132  0
                                             GWT.log("Unable to retrieve model for validation", cause);
 133  0
                                     }
 134  
 
 135  
                             });
 136  
                     }
 137  0
             }
 138  
 
 139  
         });
 140  0
     }
 141  
     
 142  
     private void validate(DataModel model, final ValidateRequestEvent event) {
 143  0
             if(event.validateSingleField()){
 144  0
                     model.validateField(event.getFieldDescriptor(), new Callback<List<ValidationResultInfo>>() {
 145  
                 @Override
 146  
                 public void exec(List<ValidationResultInfo> result) {
 147  0
                         if(event.getFieldDescriptor() != null){
 148  
                                 //We dont need to traverse since it is single field, so don't do isValid call here
 149  
                                 //instead add the error messages directly
 150  0
                                 FieldElement element = event.getFieldDescriptor().getFieldElement();
 151  0
                                 if(element != null){
 152  0
                                         element.clearValidationPanel();
 153  0
                                         for(int i = 0; i < result.size(); i++){
 154  0
                                             ValidationResultInfo vr = result.get(i);
 155  0
                                             if(vr.getElement().equals(event.getFieldDescriptor().getFieldKey()) 
 156  
                                                             && event.getFieldDescriptor().hasHadFocus()){
 157  0
                                                                     element.processValidationResult(vr);
 158  
                                             }
 159  
                                     }
 160  
                                 }
 161  
                         }
 162  
                         
 163  0
                 }
 164  
                     });
 165  
             }
 166  
             else{
 167  0
             model.validate(new Callback<List<ValidationResultInfo>>() {
 168  
                 @Override
 169  
                 public void exec(List<ValidationResultInfo> result) {
 170  0
                     isValid(result, false, true);
 171  0
                 }
 172  
             });
 173  
             }
 174  0
     }
 175  
     
 176  
     /**
 177  
      * Check to see if the list of validation results have an error.
 178  
      * @param list
 179  
      * @return
 180  
      */
 181  
     public ErrorLevel checkForErrors(List<ValidationResultInfo> list){
 182  0
                 ErrorLevel errorLevel = ErrorLevel.OK;
 183  
                 
 184  0
                 for(ValidationResultInfo vr: list){
 185  0
                         if(vr.getErrorLevel().getLevel() > errorLevel.getLevel()){
 186  0
                                 errorLevel = vr.getErrorLevel();
 187  
                         }
 188  0
                         if(errorLevel.equals(ErrorLevel.ERROR)){
 189  0
                                 break;
 190  
                         }
 191  
                 }
 192  
             
 193  0
             return errorLevel;
 194  
             
 195  
     }
 196  
     
 197  
     /**
 198  
      * Finds the first parent LayoutController of this LayoutController, returns null if this
 199  
      * is the top level LayoutController.
 200  
      * @param w
 201  
      * @return
 202  
      */
 203  
     public static LayoutController findParentLayout(Widget w){
 204  0
         LayoutController result = null;
 205  
         while (true) {
 206  0
             if (w == null) {
 207  0
                 break;
 208  0
             } else if (w instanceof HasLayoutController) {
 209  0
                     result = ((HasLayoutController)w).getLayoutController();
 210  0
                     if (result != null) {
 211  0
                             break;
 212  
                     }
 213  0
             } else if (w instanceof LayoutController) {
 214  0
                 result = (LayoutController) w;
 215  0
                 break;
 216  
             }
 217  0
             w = w.getParent();
 218  
             
 219  
         }
 220  0
         return result;
 221  
     }
 222  
     
 223  
         /**
 224  
          * @see org.kuali.student.common.ui.client.configurable.mvc.layouts.ViewLayoutController#addStartViewPopup(org.kuali.student.common.ui.client.mvc.View)
 225  
          */
 226  
         public void addStartViewPopup(final View view){
 227  0
             startPopupView = view;
 228  0
             if(startViewWindow == null){
 229  0
                     startViewWindow = new KSLightBox();
 230  
             }
 231  
 
 232  0
             FlowPanel panel = new FlowPanel();
 233  0
             panel.add(view.asWidget());
 234  0
             KSButton save = new KSButton("Save",new ClickHandler(){
 235  
             public void onClick(ClickEvent event) {
 236  0
                 view.updateModel();
 237  0
                 SaveActionEvent saveActionEvent = new SaveActionEvent(true);
 238  
 
 239  0
                 saveActionEvent.setActionCompleteCallback(new ActionCompleteCallback(){
 240  
                     public void onActionComplete(ActionEvent action) {
 241  0
                         startViewWindow.hide();
 242  0
                     }
 243  
                 });
 244  
                 
 245  
 
 246  0
                 fireApplicationEvent(saveActionEvent);
 247  0
             }
 248  
             });
 249  0
             startViewWindow.addButton(save);
 250  
             
 251  0
             KSButton cancel = new KSButton("Cancel", new ClickHandler(){
 252  
             public void onClick(ClickEvent event) {
 253  0
                 startViewWindow.hide();
 254  0
             }
 255  
             });
 256  0
             startViewWindow.addButton(cancel);
 257  
 
 258  0
             if(view instanceof SectionView){
 259  0
                     ((SectionView) view).setController(this);
 260  
             }
 261  0
             startViewWindow.setWidget(panel);
 262  0
         }
 263  
         
 264  
     /**
 265  
      * @return true if the start popup is showing
 266  
      */
 267  
     public boolean isStartViewShowing(){
 268  0
         if(startViewWindow == null){
 269  0
             return false;
 270  
         }
 271  0
             return startViewWindow.isShowing();
 272  
     }
 273  
 
 274  
     public View getStartPopupView(){
 275  0
         return startPopupView;
 276  
     }
 277  
     
 278  
     public void showStartPopup(final Callback<Boolean> onReadyCallback){
 279  0
         startPopupView.beforeShow(new Callback<Boolean>() {
 280  
                         @Override
 281  
                         public void exec(Boolean result) {
 282  0
                                 if (result) {
 283  0
                                         startViewWindow.show();
 284  
                                 }
 285  0
                                 onReadyCallback.exec(result);
 286  0
                         }
 287  
         });
 288  0
     }
 289  
     
 290  
     public KSLightBox getStartPopup(){
 291  0
         return startViewWindow;
 292  
     }
 293  
 
 294  
 
 295  
     /*New methods*/
 296  
         
 297  
         /**
 298  
          * @see org.kuali.student.common.ui.client.configurable.mvc.layouts.ViewLayoutController#addView(org.kuali.student.common.ui.client.mvc.View)
 299  
          */
 300  
         public void addView(View view){
 301  0
                 viewMap.put(view.getViewEnum(), view);
 302  0
                 viewEnumMap.put(view.getViewEnum().toString(), view.getViewEnum());
 303  0
                 if(view instanceof SectionView){
 304  0
                         ((SectionView) view).setController(this);
 305  
                 }
 306  0
                 else if(view instanceof ToolView){
 307  0
                         ((ToolView) view).setController(this);
 308  
                 }
 309  0
         }
 310  
         
 311  
         /**
 312  
          * @see org.kuali.student.common.ui.client.configurable.mvc.layouts.ViewLayoutController#setDefaultView(java.lang.Enum)
 313  
          */
 314  
         public <V extends Enum<?>> void setDefaultView(V viewType){
 315  0
                 this.defaultView = viewType;
 316  0
         }
 317  
         
 318  
         public Enum<?> getDefaultView(){
 319  0
                 return this.defaultView;
 320  
         }
 321  
         
 322  
         /**
 323  
          * @see org.kuali.student.common.ui.client.mvc.View#updateModel()
 324  
          */
 325  
         public abstract void updateModel();
 326  
         
 327  
         /**
 328  
          * Update the model with a single views information
 329  
          * @param viewType
 330  
          */
 331  
         public void updateModelFromView(Enum<?> viewType){
 332  0
                 View v = viewMap.get(viewType);
 333  0
                 if(v != null){
 334  0
                         v.updateModel();
 335  
                 }
 336  0
         }
 337  
         
 338  
         /**
 339  
          * Update a the model from the view that is currently being shown by this controller
 340  
          */
 341  
         public void updateModelFromCurrentView(){
 342  0
         if(this.getCurrentView() != null){
 343  0
                     this.getCurrentView().updateModel();
 344  
         }
 345  0
         }
 346  
 
 347  
         @Override
 348  
         public <V extends Enum<?>> void getView(V viewType, Callback<View> callback) {
 349  0
                 callback.exec(viewMap.get(viewType));
 350  0
         }
 351  
 
 352  
         @Override
 353  
         public Enum<?> getViewEnumValue(String enumValue) {
 354  0
                 return viewEnumMap.get(enumValue);
 355  
         }
 356  
 
 357  
         @Override
 358  
         public void showDefaultView(final Callback<Boolean> onReadyCallback) {
 359  0
                 HistoryManager.setLogNavigationHistory(false);
 360  
                 //turn of history support for default showing until view is ready
 361  0
                 if(defaultView != null){
 362  0
                         showView(defaultView, onReadyCallback);
 363  
                 }
 364  0
                 else if(!viewMap.isEmpty()){                
 365  0
                         if(defaultView == null){
 366  0
                                 showView(viewMap.entrySet().iterator().next().getKey(), onReadyCallback);
 367  
                         }        
 368  
                 }
 369  
                 
 370  0
         }
 371  
         
 372  
         /**
 373  
          * Show the view that was the first one added and will likely be the first one in a layout's menu, for
 374  
          * example.  Note that this is different than show default view.
 375  
          * 
 376  
          * @param onReadyCallback
 377  
          */
 378  
         public void showFirstView(Callback<Boolean> onReadyCallback){
 379  0
                 HistoryManager.setLogNavigationHistory(false);
 380  0
                 if(!viewMap.isEmpty()){        
 381  0
                         showView(viewMap.entrySet().iterator().next().getKey(), onReadyCallback);
 382  
                 }
 383  
                 else{
 384  0
                         showDefaultView(onReadyCallback);
 385  
                 }
 386  0
         }
 387  
         
 388  
         /**
 389  
           * Check to see if current/all section(s) is valid (ie. does not contain any errors) - also displays
 390  
           * them in the ui if possible
 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  
 }