Coverage Report - org.kuali.student.common.ui.client.configurable.mvc.sections.BaseSection
 
Classes in this File Line Coverage Branch Coverage Complexity
BaseSection
0%
0/218
0%
0/126
2.568
BaseSection$1
0%
0/16
0%
0/8
2.568
BaseSection$1$1
0%
0/5
N/A
2.568
BaseSection$1$2
0%
0/5
N/A
2.568
 
 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.sections;
 17  
 
 18  
 import java.util.ArrayList;
 19  
 import java.util.List;
 20  
 
 21  
 import org.kuali.student.common.ui.client.configurable.mvc.CanProcessValidationResults;
 22  
 import org.kuali.student.common.ui.client.configurable.mvc.FieldDescriptor;
 23  
 import org.kuali.student.common.ui.client.configurable.mvc.LayoutController;
 24  
 import org.kuali.student.common.ui.client.configurable.mvc.ValidationEventBinding;
 25  
 import org.kuali.student.common.ui.client.configurable.mvc.ValidationEventBindingImpl;
 26  
 import org.kuali.student.common.ui.client.configurable.mvc.binding.ModelWidgetBinding;
 27  
 import org.kuali.student.common.ui.client.configurable.mvc.binding.ModelWidgetBindingSupport;
 28  
 import org.kuali.student.common.ui.client.configurable.mvc.multiplicity.MultiplicityComposite;
 29  
 import org.kuali.student.common.ui.client.configurable.mvc.multiplicity.MultiplicityGroup;
 30  
 import org.kuali.student.common.ui.client.configurable.mvc.multiplicity.MultiplicityGroupItem;
 31  
 import org.kuali.student.common.ui.client.configurable.mvc.multiplicity.MultiplicityItem;
 32  
 import org.kuali.student.common.ui.client.event.ContentDirtyEvent;
 33  
 import org.kuali.student.common.ui.client.event.ValidateRequestEvent;
 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.widgets.field.layout.element.AbbrPanel;
 40  
 import org.kuali.student.common.ui.client.widgets.field.layout.element.FieldElement;
 41  
 import org.kuali.student.common.ui.client.widgets.field.layout.element.SpanPanel;
 42  
 import org.kuali.student.common.ui.client.widgets.field.layout.layouts.FieldLayout;
 43  
 import org.kuali.student.core.assembly.data.Data;
 44  
 import org.kuali.student.core.assembly.data.Data.Key;
 45  
 import org.kuali.student.core.assembly.data.QueryPath;
 46  
 import org.kuali.student.core.validation.dto.ValidationResultInfo;
 47  
 import org.kuali.student.core.validation.dto.ValidationResultInfo.ErrorLevel;
 48  
 
 49  
 import com.google.gwt.core.client.GWT;
 50  
 import com.google.gwt.user.client.ui.Widget;
 51  
 
 52  
 /**
 53  
  * The base section is the base implementation of the section interface.
 54  
  * @author Kuali Student
 55  
  *
 56  
  */
 57  0
 public abstract class BaseSection extends SpanPanel implements Section{
 58  
 
 59  
         protected FieldLayout layout;
 60  
 
 61  0
         protected ArrayList<Section> sections = new ArrayList<Section>();
 62  0
         protected ArrayList<FieldDescriptor> fields = new ArrayList<FieldDescriptor>();
 63  0
         protected LayoutController layoutController = null;
 64  0
         protected boolean isValidationEnabled = true;
 65  0
         protected boolean isDirty = false;
 66  
 
 67  
         /**
 68  
          * Adds a field to this section.  Adds the field to this section's layout.
 69  
          * Attaches an event handler for lost focus events on the field widget
 70  
          * to validate against the metadata defined in its FieldDescriptor as well as firing events for dirty
 71  
          * field handling.
 72  
          * 
 73  
          * Note if a field has been marked as hidden in the dictionary, this method will not add this field to the layout.
 74  
          * If it is not visible the key returned by making call to addField is null.
 75  
          * 
 76  
          * @param field
 77  
          * @return key/path of this field
 78  
          */
 79  
         @Override
 80  
         public String addField(final FieldDescriptor fieldDescriptor) {
 81  0
                 String key = null;
 82  
                 
 83  0
                 if (fieldDescriptor.isVisible()){
 84  0
                         fields.add(fieldDescriptor);
 85  0
                 key = layout.addField(fieldDescriptor.getFieldElement());
 86  
         
 87  0
                 ValidationEventBinding binding = new ValidationEventBindingImpl();
 88  0
                 if(fieldDescriptor.getValidationRequestCallback()== null){
 89  0
                     fieldDescriptor.setValidationCallBack(new Callback<Boolean>() {
 90  
                         @Override
 91  
                         public void exec(Boolean result) {
 92  0
                                 final ModelWidgetBinding mwb = fieldDescriptor.getModelWidgetBinding();
 93  0
                                 if (mwb != null) {
 94  0
                                     final Widget w = fieldDescriptor.getFieldWidget();
 95  0
                                     final String modelId = fieldDescriptor.getModelId();
 96  
                                     final Controller parent;
 97  0
                                 Controller findResult = LayoutController.findParentLayout(w);
 98  0
                                 if(BaseSection.this instanceof View){
 99  0
                                         findResult = ((View)BaseSection.this).getController();
 100  
                                 }
 101  0
                                 parent = findResult;
 102  0
                                 if(parent != null){
 103  0
                                         if (modelId == null) {
 104  0
                                                 parent.requestModel(new ModelRequestCallback<DataModel>() {
 105  
         
 106  
                                                         @Override
 107  
                                                         public void onModelReady(DataModel model) {
 108  0
                                                                 validateField(fieldDescriptor, model, parent);
 109  
                                                                                                    
 110  0
                                                         }
 111  
         
 112  
                                                         @Override
 113  
                                                         public void onRequestFail(Throwable cause) {
 114  0
                                                                 GWT.log("Unable to retrieve model to validate " + fieldDescriptor.getFieldKey(), null);
 115  0
                                                         }
 116  
         
 117  
                                                 });
 118  
                                         } else {
 119  0
                                                 parent.requestModel(modelId, new ModelRequestCallback<DataModel>() {
 120  
         
 121  
                                                         @Override
 122  
                                                         public void onModelReady(DataModel model) {
 123  0
                                                                 validateField(fieldDescriptor, model, parent);
 124  0
                                                         }
 125  
         
 126  
                                                         @Override
 127  
                                                         public void onRequestFail(Throwable cause) {
 128  0
                                                                 GWT.log("Unable to retrieve model to validate " + fieldDescriptor.getFieldKey(), null);
 129  0
                                                         }
 130  
         
 131  
                                                 });                                }
 132  
                                         }
 133  0
                             } else {
 134  0
                                 GWT.log(fieldDescriptor.getFieldKey() + " has no widget binding.", null);
 135  
                             }
 136  0
                         }
 137  
                     });
 138  
                 }
 139  0
                 binding.bind(fieldDescriptor);
 140  
                 }               
 141  
                 
 142  0
         return key;
 143  
         }
 144  
 
 145  
         private void validateField(
 146  
                         final FieldDescriptor fieldDescriptor, final DataModel model, Controller controller) {
 147  0
                 Widget w = fieldDescriptor.getFieldWidget();
 148  0
                 ModelWidgetBinding mwb = fieldDescriptor.getModelWidgetBinding();
 149  0
                 if(fieldDescriptor.getFieldKey() != null){
 150  0
                         mwb.setModelValue(w, model, fieldDescriptor.getFieldKey());
 151  0
                         dirtyCheckField(fieldDescriptor, model);
 152  0
                         ValidateRequestEvent e = new ValidateRequestEvent();
 153  0
                         e.setFieldDescriptor(fieldDescriptor);
 154  0
                         e.setValidateSingleField(true);
 155  0
                         controller.fireApplicationEvent(e);
 156  
                 }
 157  0
         }
 158  
 
 159  
         private void dirtyCheckField(FieldDescriptor fieldDescriptor, DataModel model){
 160  0
         QueryPath fieldPath = QueryPath.parse(fieldDescriptor.getFieldKey());
 161  0
                 QueryPath qPathDirty = fieldPath.subPath(0, fieldPath.size() - 1);
 162  0
             qPathDirty.add(ModelWidgetBindingSupport.RUNTIME_ROOT);
 163  0
             qPathDirty.add(ModelWidgetBindingSupport.DIRTY_PATH);
 164  0
             qPathDirty.add(fieldPath.get(fieldPath.size()-1));
 165  0
             Boolean dirty = false;
 166  
 
 167  0
             if(ensureDirtyFlagPath(model.getRoot(), qPathDirty)){
 168  0
                     dirty = model.get(qPathDirty);
 169  
             }
 170  0
             if(dirty){
 171  0
                     setIsDirty(true);
 172  0
                     fieldDescriptor.setDirty(true);
 173  
             }
 174  0
         }
 175  
 
 176  
     protected boolean ensureDirtyFlagPath(Data root, QueryPath path) {
 177  0
         Data current = root;
 178  0
         boolean containsFlag = false;
 179  0
         for (int i = 0; i < path.size(); i++) {
 180  0
             Key key = path.get(i);
 181  0
             if(i == path.size() - 1){
 182  0
                     containsFlag = current.containsKey(key);
 183  0
                     break;
 184  
             }
 185  0
             Data d = current.get(key);
 186  0
             if (d == null) {
 187  0
                 containsFlag = false;
 188  0
                 break;
 189  
             }
 190  0
             current = d;
 191  
         }
 192  0
         return containsFlag;
 193  
     }
 194  
 
 195  
         /** 
 196  
          * Adds a section to this section's layout.
 197  
          * 
 198  
          * @see org.kuali.student.common.ui.client.configurable.mvc.sections.Section#addSection(org.kuali.student.common.ui.client.configurable.mvc.sections.Section)
 199  
          */
 200  
         @Override
 201  
         public String addSection(Section section) {
 202  
 
 203  0
         section.setLayoutController(layoutController);
 204  0
                 sections.add(section);
 205  0
         String key = layout.addLayout(section.getLayout());
 206  0
         return key;
 207  
         }
 208  
 
 209  
         /**
 210  
          * Removes a section from this section's layout.
 211  
          * 
 212  
          * @see org.kuali.student.common.ui.client.configurable.mvc.sections.Section#removeSection(org.kuali.student.common.ui.client.configurable.mvc.sections.Section)
 213  
          */
 214  
         @Override
 215  
         public void removeSection(Section section){
 216  0
                 sections.remove(section);
 217  0
                 layout.removeLayoutElement(section.getLayout());
 218  0
         }
 219  
 
 220  
         /**
 221  
          * Clear all validation errors from the layout (removes all red highlight and error text shown on the
 222  
          * screen)
 223  
          */
 224  
         protected void clearValidation() {
 225  0
                 layout.clearValidation();
 226  
 
 227  0
         }
 228  
 
 229  
         /**
 230  
          * Gets all the fields in a section and its subsections.
 231  
          * 
 232  
          * @see org.kuali.student.common.ui.client.configurable.mvc.sections.Section#getFields()
 233  
          */
 234  
         @Override
 235  
         public List<FieldDescriptor> getFields() {
 236  0
         List<FieldDescriptor> allFields = new ArrayList<FieldDescriptor>();
 237  0
         allFields.addAll(fields);
 238  
 
 239  0
         for(Section ns: sections){
 240  0
             allFields.addAll(ns.getFields());
 241  
         }
 242  0
         return allFields;
 243  
         }
 244  
 
 245  
         /**
 246  
          * Gets all the fields in this section, but does not include fields in its nested sections.
 247  
          * @see org.kuali.student.common.ui.client.configurable.mvc.sections.Section#getUnnestedFields()
 248  
          */
 249  
         @Override
 250  
         public List<FieldDescriptor> getUnnestedFields() {
 251  0
         return fields;
 252  
         }
 253  
 
 254  
         /**
 255  
          * Gets all nested sections contained in this section
 256  
          * @see org.kuali.student.common.ui.client.configurable.mvc.sections.Section#getSections()
 257  
          */
 258  
         @Override
 259  
         public List<Section> getSections() {
 260  0
                 return sections;
 261  
         }
 262  
 
 263  
         /**
 264  
          * Processes the validation results passed in and displays the appropriate message on the screen next
 265  
          * to the corresponding field or section.  If clearAllValidation is true, it will clear all validation before
 266  
          * displaying the errors (otherwise will append these errors to the ones already visible on the section).
 267  
          * @see org.kuali.student.common.ui.client.configurable.mvc.sections.Section#processValidationResults(java.util.List, boolean)
 268  
          */
 269  
         @Override
 270  
         public ErrorLevel processValidationResults(List<ValidationResultInfo> results, boolean clearAllValidation){
 271  0
                 if(clearAllValidation){
 272  0
                         this.clearValidation();
 273  
                 }
 274  0
                 ErrorLevel status = ErrorLevel.OK;
 275  
 
 276  0
                 if (isValidationEnabled){
 277  
 
 278  0
                         for(FieldDescriptor f: this.fields){
 279  
 
 280  0
                                 if(f.hasHadFocus()){
 281  0
                                         for(ValidationResultInfo vr: results){
 282  0
                         String vrElement = vr.getElement();
 283  0
                         if(vrElement.startsWith("/")){
 284  0
                             vrElement = vrElement.substring(1);
 285  
                         }
 286  0
                                                 if(vrElement.equals(f.getFieldKey())){
 287  0
                                                         FieldElement element = f.getFieldElement();
 288  0
                                                         if (element != null){
 289  0
                                                                 ErrorLevel fieldStatus = element.processValidationResult(vr);
 290  0
                                                                 if(fieldStatus.getLevel() > status.getLevel()){
 291  0
                                                                         status = fieldStatus;
 292  
                                                                 }
 293  
                                                         }
 294  
                                                 }
 295  0
                                         }
 296  
                                 }
 297  
 
 298  0
                                 if(f.getFieldWidget() instanceof MultiplicityComposite ){
 299  0
                                         MultiplicityComposite mc = (MultiplicityComposite) f.getFieldWidget();
 300  
 
 301  
                                         //possibly return error state from processValidationResults to give composite title bar a separate color
 302  0
                             for(MultiplicityItem item: mc.getItems()){
 303  0
                                     if(item.getItemWidget() instanceof Section && !item.isDeleted()){
 304  0
                                             ErrorLevel fieldStatus = ((Section)item.getItemWidget()).processValidationResults(results, clearAllValidation);
 305  0
                                                         if(fieldStatus.getLevel() > status.getLevel()){
 306  0
                                                                 status = fieldStatus;
 307  
                                                         }
 308  0
                                     }
 309  
                             }
 310  
                                 }
 311  
                                 // TODO Can we do this without checking for instanceof  MG??
 312  0
                                 if(f.getFieldWidget() instanceof MultiplicityGroup ){
 313  0
                                         MultiplicityGroup mg = (MultiplicityGroup) f.getFieldWidget();
 314  
 
 315  
                                         //possibly return error state from processValidationResults to give composite title bar a separate color
 316  0
                             for(MultiplicityGroupItem item: mg.getItems()){
 317  0
                                     if(item.getItemWidget() instanceof Section && !item.isDeleted()){
 318  0
                                             ErrorLevel fieldStatus = ((Section)item.getItemWidget()).processValidationResults(results, clearAllValidation);
 319  0
                                                         if(fieldStatus.getLevel() > status.getLevel()){
 320  0
                                                                 status = fieldStatus;
 321  
                                                         }
 322  0
                                     }
 323  
                             }
 324  
                                 }
 325  0
                 if (f.getFieldWidget() instanceof CanProcessValidationResults) {
 326  0
                     ErrorLevel fieldStatus = ((CanProcessValidationResults) f.getFieldWidget()).processValidationResults(f, results, clearAllValidation);
 327  0
                     if (fieldStatus.getLevel() > status.getLevel()) {
 328  0
                         status = fieldStatus;
 329  
                     }
 330  0
                 }
 331  
                         }
 332  
 
 333  0
                 for(Section s: sections){
 334  0
                     ErrorLevel subsectionStatus = s.processValidationResults(results,clearAllValidation);
 335  0
                     if(subsectionStatus.getLevel() > status.getLevel()){
 336  0
                             status = subsectionStatus;
 337  
                     }
 338  0
                 }
 339  
                 }
 340  
 
 341  0
         return status;
 342  
         }
 343  
 
 344  
         /**
 345  
          * Same as processValidationResults(results, true)
 346  
          * @see org.kuali.student.common.ui.client.configurable.mvc.sections.Section#processValidationResults(java.util.List)
 347  
          */
 348  
         @Override
 349  
         public ErrorLevel processValidationResults(List<ValidationResultInfo> results) {
 350  0
                 return processValidationResults(results, true);
 351  
         }
 352  
 
 353  
         /**
 354  
          * Gets the defined controller for this section if one exists.
 355  
          * 
 356  
          * @see org.kuali.student.common.ui.client.configurable.mvc.HasLayoutController#getLayoutController()
 357  
          */
 358  
         @Override
 359  
         public LayoutController getLayoutController() {
 360  0
                 return this.layoutController;
 361  
         }
 362  
 
 363  
         @Override
 364  
         public void setLayoutController(LayoutController controller) {
 365  0
                 this.layoutController = controller;
 366  0
         }
 367  
 
 368  
 
 369  
         /**
 370  
          * Use this to add widgets to a sections layout.  DO NOT use the add(Widget widget) call.
 371  
          * @see org.kuali.student.common.ui.client.configurable.mvc.sections.Section#addWidget(com.google.gwt.user.client.ui.Widget)
 372  
          */
 373  
         @Override
 374  
         public String addWidget(Widget w) {
 375  0
                 return layout.addWidget(w);
 376  
         }
 377  
 
 378  
     /**
 379  
      * Sets the fields has had focus flag.  This flag is used for determining if the user has interacted with
 380  
      * any fields on the page or if the fields need to be assumed to have been interacted with.  Used for determining
 381  
      * when validation is necessary on a particular section.
 382  
      * @see org.kuali.student.common.ui.client.configurable.mvc.sections.Section#setFieldHasHadFocusFlags(boolean)
 383  
      */
 384  
     public void setFieldHasHadFocusFlags(boolean hadFocus) {
 385  0
         for(FieldDescriptor f: fields){
 386  0
             f.setHasHadFocus(hadFocus);
 387  0
             if(f.getFieldWidget() instanceof MultiplicityComposite){
 388  0
                                 MultiplicityComposite mc = (MultiplicityComposite) f.getFieldWidget();
 389  
 
 390  0
                     for(MultiplicityItem item: mc.getItems()){
 391  0
                             if(item.getItemWidget() instanceof Section && !item.isDeleted()){
 392  0
                                     ((Section) item.getItemWidget()).setFieldHasHadFocusFlags(hadFocus);
 393  
                             }
 394  
                     }
 395  0
             }else if(f.getFieldWidget() instanceof MultiplicityGroup){
 396  0
                     MultiplicityGroup mg = (MultiplicityGroup) f.getFieldWidget();
 397  
 
 398  0
                     for(MultiplicityGroupItem item: mg.getItems()){
 399  0
                             if(item.getItemWidget() instanceof Section && !item.isDeleted()){
 400  0
                                     ((Section) item.getItemWidget()).setFieldHasHadFocusFlags(hadFocus);
 401  
                             }
 402  
                     }
 403  0
             }
 404  
         }
 405  
 
 406  0
         for(Section s: sections){
 407  0
             s.setFieldHasHadFocusFlags(hadFocus);
 408  
         }
 409  
 
 410  0
     }
 411  
 
 412  
     /**
 413  
      * A section can turn off all validation by setting this flag
 414  
      * @see org.kuali.student.common.ui.client.configurable.mvc.sections.Section#enableValidation(boolean)
 415  
      */
 416  
     @Override
 417  
     public void enableValidation(boolean enableValidation) {
 418  0
             this.isValidationEnabled = enableValidation;
 419  0
     }
 420  
 
 421  
     @Override
 422  
     public boolean isValidationEnabled() {
 423  0
                 return isValidationEnabled;
 424  
         }
 425  
 
 426  
         /**
 427  
          * Update the model passed in with data from the fields on this section.  This method will use the 
 428  
          * modelWidgetBinding defined in each of this sections fields to determine how to add this data to the
 429  
          * model.
 430  
          * @see org.kuali.student.common.ui.client.configurable.mvc.sections.Section#updateModel(org.kuali.student.common.ui.client.mvc.DataModel)
 431  
          */
 432  
         @Override
 433  
     public void updateModel(DataModel model){
 434  0
         SectionBinding.INSTANCE.setModelValue(this, model, "");
 435  0
     }
 436  
 
 437  
     /**
 438  
      * Updates the section's fields with data from the model passed in.  This effects all the data input and
 439  
      * display widgets on the particular section.  This method will use the 
 440  
          * modelWidgetBinding defined in each of this sections fields to determine how to interpret data from the
 441  
          * model and display it on the fields corresponding widget.
 442  
          * 
 443  
      * @see org.kuali.student.common.ui.client.configurable.mvc.sections.Section#updateWidgetData(org.kuali.student.common.ui.client.mvc.DataModel)
 444  
      */
 445  
     @Override
 446  
     public void updateWidgetData(DataModel model) {
 447  0
         SectionBinding.INSTANCE.setWidgetValue(this, model, "");
 448  0
     }
 449  
 
 450  
     /**
 451  
      * Resets all the dirty and focus flags on fields.
 452  
      * @see org.kuali.student.common.ui.client.configurable.mvc.sections.Section#resetFieldInteractionFlags()
 453  
      */
 454  
     @Override
 455  
     public void resetFieldInteractionFlags() {
 456  0
             this.isDirty = false;
 457  0
         for(FieldDescriptor f: fields){
 458  0
             f.setDirty(false);
 459  0
             f.setHasHadFocus(false);
 460  
         }
 461  
 
 462  0
         for(Section s: sections){
 463  0
             s.resetFieldInteractionFlags();
 464  
         }
 465  
 
 466  0
     }
 467  
 
 468  
     @Override
 469  
     public void resetDirtyFlags() {
 470  0
             this.isDirty = false;
 471  0
         for(FieldDescriptor f: fields){
 472  0
             f.setDirty(false);
 473  
         }
 474  
 
 475  0
         for(Section s: sections){
 476  0
             s.resetDirtyFlags();
 477  
         }
 478  0
     }
 479  
 
 480  
 
 481  
         /**
 482  
          * Same as addSection except with an option user defined key (for retrieval of the section if necessary).
 483  
          * 
 484  
          * @see org.kuali.student.common.ui.client.configurable.mvc.sections.Section#addSection(java.lang.String, org.kuali.student.common.ui.client.configurable.mvc.sections.Section)
 485  
          */
 486  
         @Override
 487  
         public String addSection(String key, Section section) {
 488  0
         sections.add(section);
 489  0
         section.getLayout().setKey(key);
 490  0
         String rkey = layout.addLayout(section.getLayout());
 491  0
         return rkey;
 492  
         }
 493  
 
 494  
         @Override
 495  
         public FieldDescriptor getField(String fieldKey) {
 496  0
                 for(FieldDescriptor f: fields){
 497  0
                         if(f.getFieldKey().equals(fieldKey)){
 498  0
                                 return f;
 499  
                         }
 500  
                 }
 501  0
                 return null;
 502  
         }
 503  
 
 504  
         /**
 505  
          * Gets this sections fieldLayout.  The fieldLayout is used to determine how sections will layout the
 506  
          * ui and contains things such as the title and validation panels.
 507  
          * 
 508  
          * @see org.kuali.student.common.ui.client.configurable.mvc.sections.Section#getLayout()
 509  
          */
 510  
         @Override
 511  
         public FieldLayout getLayout() {
 512  0
                 return layout;
 513  
         }
 514  
 
 515  
         @Override
 516  
         public Section getSection(String sectionKey) {
 517  0
                 for(Section s: sections){
 518  0
                         if(s.getLayout().getKey().equals(sectionKey)){
 519  0
                                 return s;
 520  
                         }
 521  
                 }
 522  0
                 return null;
 523  
         }
 524  
 
 525  
         @Override
 526  
         public void removeField(String fieldKey) {
 527  0
                 int index = 0;
 528  0
                 boolean found = false;
 529  0
                 for(FieldDescriptor f: fields){
 530  0
                         if(f.getFieldKey().equals(fieldKey)){
 531  0
                                 index = fields.indexOf(f);
 532  0
                                 found = true;
 533  0
                                 break;
 534  
                         }
 535  
                 }
 536  0
                 if(found){
 537  0
                         fields.remove(index);
 538  
                 }
 539  0
                 layout.removeLayoutElement(fieldKey);
 540  
 
 541  0
         }
 542  
 
 543  
         @Override
 544  
         public void removeField(FieldDescriptor field) {
 545  
 
 546  0
                 fields.remove(field);
 547  0
                 layout.removeLayoutElement(field.getFieldKey());
 548  
 
 549  0
         }
 550  
 
 551  
         @Override
 552  
         public void removeSection(String sectionKey) {
 553  0
                 int index = 0;
 554  0
                 boolean found = false;
 555  0
                 for(Section s: sections){
 556  0
                         if(s.getLayout().getKey().equals(sectionKey)){
 557  0
                                 index = sections.indexOf(s);
 558  0
                                 found = true;
 559  0
                                 break;
 560  
                         }
 561  
                 }
 562  0
                 if(found){
 563  0
                         sections.remove(index);
 564  
                 }
 565  0
                 layout.removeLayoutElement(sectionKey);
 566  
 
 567  0
         }
 568  
 
 569  
         @Override
 570  
         public void removeWidget(Widget widget) {
 571  0
                 layout.removeLayoutElement(widget);
 572  
 
 573  0
         }
 574  
 
 575  
         @Override
 576  
         public void removeWidget(String key) {
 577  0
                 layout.removeLayoutElement(key);
 578  
 
 579  0
         }
 580  
 
 581  
         /**
 582  
          * Returns true if this this section is considered dirty (the user may have entered data into this
 583  
          * section)
 584  
          * 
 585  
          * @see org.kuali.student.common.ui.client.configurable.mvc.sections.Section#isDirty()
 586  
          */
 587  
         public boolean isDirty(){
 588  0
                 if(!this.isDirty){
 589  
                         //Check child sections for dirtyness
 590  0
                         for(Section s: sections){
 591  0
                                 if(s.isDirty()){
 592  0
                                         setIsDirty(true);
 593  0
                                         break;
 594  
                                 }
 595  
                         }
 596  
                 }
 597  0
                 return isDirty;
 598  
         }
 599  
 
 600  
     public void setIsDirty(boolean state) {
 601  
                 //Should this trust layoutController to be already set?
 602  0
             if (layoutController == null){
 603  0
                     layoutController = LayoutController.findParentLayout(layout);
 604  
             }
 605  0
             if (isDirty != state){
 606  0
                 isDirty = state;
 607  0
                     if (layoutController != null && isDirty){
 608  0
                             layoutController.fireApplicationEvent(new ContentDirtyEvent());
 609  
                     }
 610  
             }
 611  0
     }
 612  
 
 613  
         /**
 614  
          * DO NOT use this method for adding sections, fields, or widgets to sections
 615  
          */
 616  
         @Override
 617  
         public void add(Widget w) {
 618  0
                 super.add(w);
 619  0
         }
 620  
 
 621  
         /**
 622  
          * Adds a style to this section's underlying layout.
 623  
          * @see com.google.gwt.user.client.ui.UIObject#addStyleName(java.lang.String)
 624  
          */
 625  
         @Override
 626  
         public void addStyleName(String style) {
 627  0
                 layout.addStyleName(style);
 628  0
         }
 629  
 
 630  
         @Override
 631  
         public void setStyleName(String style) {
 632  0
                 layout.setStyleName(style);
 633  0
         }
 634  
 
 635  
         /**
 636  
          * Sets instructions for this entire section (appears next to section title)
 637  
          * @param html
 638  
          */
 639  
         public void setInstructions(String html){
 640  0
                 layout.setInstructions(html);
 641  0
         }
 642  
 
 643  
         /**
 644  
          * Sets help for this entire section (appears next to section title)
 645  
          * @param html
 646  
          */
 647  
         public void setHelp(String html){
 648  0
                 layout.setHelp(html);
 649  0
         }
 650  
         
 651  
         /**
 652  
          * Sets required for this entire section (appears next to section title)
 653  
          * @param required
 654  
          */
 655  
         public void setRequired(AbbrPanel required){
 656  0
                 layout.setRequired(required);
 657  0
         }
 658  
 }