Coverage Report - org.kuali.rice.kns.uif.layout.TableLayoutManager
 
Classes in this File Line Coverage Branch Coverage Complexity
TableLayoutManager
0%
0/153
0%
0/78
2.143
 
 1  
 /*
 2  
  * Copyright 2007 The Kuali Foundation
 3  
  *
 4  
  * Licensed under the Educational Community License, Version 1.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  * http://www.opensource.org/licenses/ecl1.php
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 package org.kuali.rice.kns.uif.layout;
 17  
 
 18  
 import java.util.ArrayList;
 19  
 import java.util.List;
 20  
 
 21  
 import org.kuali.rice.kns.uif.UifConstants;
 22  
 import org.kuali.rice.kns.uif.container.CollectionGroup;
 23  
 import org.kuali.rice.kns.uif.container.Container;
 24  
 import org.kuali.rice.kns.uif.container.View;
 25  
 import org.kuali.rice.kns.uif.core.Component;
 26  
 import org.kuali.rice.kns.uif.field.ActionField;
 27  
 import org.kuali.rice.kns.uif.field.AttributeField;
 28  
 import org.kuali.rice.kns.uif.field.Field;
 29  
 import org.kuali.rice.kns.uif.field.GroupField;
 30  
 import org.kuali.rice.kns.uif.field.LabelField;
 31  
 import org.kuali.rice.kns.uif.field.MessageField;
 32  
 import org.kuali.rice.kns.uif.util.ComponentFactory;
 33  
 import org.kuali.rice.kns.uif.util.ComponentUtils;
 34  
 import org.kuali.rice.kns.uif.widget.TableTools;
 35  
 
 36  
 /**
 37  
  * Layout manager that works with <code>CollectionGroup</code> components and
 38  
  * renders the collection as a Table
 39  
  * 
 40  
  * <p>
 41  
  * Based on the fields defined, the <code>TableLayoutManager</code> will
 42  
  * dynamically create instances of the fields for each collection row. In
 43  
  * addition, the manager can create standard fields like the action and sequence
 44  
  * fields for each row. The manager supports options inherited from the
 45  
  * <code>GridLayoutManager</code> such as rowSpan, colSpan, and cell width
 46  
  * settings.
 47  
  * </p>
 48  
  * 
 49  
  * @author Kuali Rice Team (rice.collab@kuali.org)
 50  
  */
 51  
 public class TableLayoutManager extends GridLayoutManager implements CollectionLayoutManager {
 52  
         private static final long serialVersionUID = 3622267585541524208L;
 53  
 
 54  
         private boolean useShortLabels;
 55  
         private boolean repeatHeader;
 56  
         private LabelField headerFieldPrototype;
 57  
 
 58  
         private boolean renderSequenceField;
 59  
         private String conditionalRenderSequenceField;
 60  
         private boolean generateAutoSequence;
 61  
         private Field sequenceFieldPrototype;
 62  
 
 63  
         private GroupField actionFieldPrototype;
 64  
 
 65  
         private GroupField subCollectionGroupFieldPrototype;
 66  
 
 67  
         // internal counter for the data columns (not including sequence, action)
 68  
         private int numberOfDataColumns;
 69  
 
 70  
         private List<LabelField> headerFields;
 71  
         private List<Field> dataFields;
 72  
 
 73  
         private TableTools tableTools;
 74  0
         private boolean headerAdded = false;
 75  
 
 76  0
         public TableLayoutManager() {
 77  0
                 useShortLabels = true;
 78  0
                 repeatHeader = false;
 79  0
                 renderSequenceField = true;
 80  0
                 generateAutoSequence = false;
 81  
 
 82  0
                 headerFields = new ArrayList<LabelField>();
 83  0
                 dataFields = new ArrayList<Field>();
 84  0
         }
 85  
         
 86  
         /**
 87  
          * The following actions are performed:
 88  
          * 
 89  
          * <ul>
 90  
          * <li>Sets sequence field prototype if auto sequence is true</li>
 91  
          * <li>Initializes the prototypes</li>
 92  
          * </ul>
 93  
          * 
 94  
          * @see org.kuali.rice.kns.uif.layout.BoxLayoutManager#performInitialization(org.kuali.rice.kns.uif.container.View,
 95  
          *      org.kuali.rice.kns.uif.container.Container)
 96  
          */
 97  
         @Override
 98  
         public void performInitialization(View view, Container container) {
 99  0
                 super.performInitialization(view, container);
 100  
                 
 101  0
         if (generateAutoSequence && !(sequenceFieldPrototype instanceof MessageField)) {
 102  0
             sequenceFieldPrototype = ComponentFactory.getMessageField();
 103  
         }
 104  
 
 105  0
                 view.getViewHelperService().performComponentInitialization(view, headerFieldPrototype);
 106  0
                 view.getViewHelperService().performComponentInitialization(view, sequenceFieldPrototype);
 107  0
                 view.getViewHelperService().performComponentInitialization(view, actionFieldPrototype);
 108  0
                 view.getViewHelperService().performComponentInitialization(view, subCollectionGroupFieldPrototype);
 109  0
         }
 110  
 
 111  
         /**
 112  
          * Sets up the final column count for rendering based on whether the
 113  
          * sequence and action fields have been generated
 114  
          * 
 115  
          * @see org.kuali.rice.kns.uif.layout.LayoutManagerBase#performFinalize(org.kuali.rice.kns.uif.container.View,
 116  
          *      java.lang.Object, org.kuali.rice.kns.uif.container.Container)
 117  
          */
 118  
         @Override
 119  
         public void performFinalize(View view, Object model, Container container) {
 120  0
                 super.performFinalize(view, model, container);
 121  
 
 122  0
                 CollectionGroup collectionGroup = (CollectionGroup) container;
 123  
 
 124  0
                 int totalColumns = getNumberOfDataColumns();
 125  0
                 if (renderSequenceField) {
 126  0
                         totalColumns++;
 127  
                 }
 128  
 
 129  0
                 if (collectionGroup.isRenderLineActions() && !collectionGroup.isReadOnly()) {
 130  0
                         totalColumns++;
 131  
                 }
 132  
 
 133  0
                 setNumberOfColumns(totalColumns);
 134  
 
 135  0
         }
 136  
 
 137  
         /**
 138  
          * Assembles the field instances for the collection line. The given sequence
 139  
          * field prototype is copied for the line sequence field. Likewise a copy of
 140  
          * the actionFieldPrototype is made and the given actions are set as the
 141  
          * items for the action field. Finally the generated items are assembled
 142  
          * together into the dataFields list with the given lineFields.
 143  
          * 
 144  
          * @see org.kuali.rice.kns.uif.layout.CollectionLayoutManager#buildLine(org.kuali.rice.kns.uif.container.View,
 145  
          *      java.lang.Object, org.kuali.rice.kns.uif.container.CollectionGroup,
 146  
          *      java.util.List, java.util.List, java.lang.String, java.util.List,
 147  
          *      java.lang.String, java.lang.Object, int)
 148  
          */
 149  
         public void buildLine(View view, Object model, CollectionGroup collectionGroup, List<Field> lineFields,
 150  
                         List<GroupField> subCollectionFields, String bindingPath, List<ActionField> actions, String idSuffix,
 151  
                         Object currentLine, int lineIndex) {
 152  0
                 boolean isAddLine = lineIndex == -1;
 153  
                 
 154  
         // if add line or first line set number of data columns
 155  0
         if (isAddLine || ((!collectionGroup.isRenderAddLine() || collectionGroup.isReadOnly()) && (lineIndex == 0))) {
 156  0
             if (isSuppressLineWrapping()) {
 157  0
                 setNumberOfDataColumns(lineFields.size());
 158  
             } else {
 159  0
                 setNumberOfDataColumns(getNumberOfColumns());
 160  
             }
 161  
         }
 162  
 
 163  
                 // if add line build table header first
 164  
                 // TODO: implement repeat header
 165  0
                 if (!headerAdded) {
 166  0
                         headerFields = new ArrayList<LabelField>();
 167  0
                         dataFields = new ArrayList<Field>();
 168  
 
 169  0
                         buildTableHeaderRows(collectionGroup, lineFields);
 170  0
                         ComponentUtils.pushObjectToContext(headerFields, UifConstants.ContextVariableNames.LINE, currentLine);
 171  0
                         ComponentUtils.pushObjectToContext(headerFields, UifConstants.ContextVariableNames.INDEX, new Integer(
 172  
                                         lineIndex));
 173  0
                         headerAdded = true;
 174  
                 }
 175  
 
 176  
                 // set label field rendered to true on line fields
 177  0
                 for (Field field : lineFields) {
 178  0
                         field.setLabelFieldRendered(true);
 179  
 
 180  
                         // don't display summary message
 181  
                         // TODO: remove once we have modifier
 182  0
                         ComponentUtils.setComponentPropertyDeep(field, "summaryMessageField.render", new Boolean(false));
 183  
                 }
 184  
 
 185  0
                 int rowCount = calculateNumberOfRows(collectionGroup.getItems());
 186  0
                 int rowSpan = rowCount + subCollectionFields.size();
 187  
 
 188  
                 // sequence field is always first and should span all rows for the line
 189  0
                 if (renderSequenceField) {
 190  0
                         Field sequenceField = null;
 191  0
             if (!isAddLine) {
 192  0
                 sequenceField = ComponentUtils.copy(sequenceFieldPrototype, idSuffix);
 193  
 
 194  0
                 if (generateAutoSequence && (sequenceField instanceof MessageField)) {
 195  0
                     ((MessageField) sequenceField).setMessageText(Integer.toString(lineIndex + 1));
 196  
                 }
 197  
             }
 198  
                         else {
 199  0
                                 sequenceField = ComponentUtils.copy(collectionGroup.getAddLineLabelField(), idSuffix);
 200  
                         }
 201  0
                         sequenceField.setRowSpan(rowSpan);
 202  
 
 203  0
                         if (sequenceField instanceof AttributeField) {
 204  0
                                 ((AttributeField) sequenceField).getBindingInfo().setBindByNamePrefix(bindingPath);
 205  
                         }
 206  
 
 207  0
                         ComponentUtils.updateContextForLine(sequenceField, currentLine, lineIndex);
 208  
 
 209  0
                         dataFields.add(sequenceField);
 210  
                 }
 211  
 
 212  
                 // now add the fields in the correct position
 213  0
                 int cellPosition = 0;
 214  0
                 for (Field lineField : lineFields) {
 215  0
                         dataFields.add(lineField);
 216  
 
 217  0
                         cellPosition += lineField.getColSpan();
 218  
 
 219  
                         // action field should be in last column
 220  0
                         if ((cellPosition == getNumberOfDataColumns()) && collectionGroup.isRenderLineActions()
 221  
                                         && !collectionGroup.isReadOnly()) {
 222  0
                                 GroupField lineActionsField = ComponentUtils.copy(actionFieldPrototype, idSuffix);
 223  
 
 224  0
                                 ComponentUtils.updateContextForLine(lineActionsField, currentLine, lineIndex);
 225  0
                                 lineActionsField.setRowSpan(rowSpan);
 226  0
                                 lineActionsField.setItems(actions);
 227  
 
 228  0
                                 dataFields.add(lineActionsField);
 229  0
                         }
 230  
                 }
 231  
 
 232  
                 // update colspan on sub-collection fields
 233  0
                 for (GroupField subCollectionField : subCollectionFields) {
 234  0
                         subCollectionField.setColSpan(numberOfDataColumns);
 235  
                 }
 236  
 
 237  
                 // add sub-collection fields to end of data fields
 238  0
                 dataFields.addAll(subCollectionFields);
 239  0
         }
 240  
 
 241  
         /**
 242  
          * Create the <code>LabelField</code> instances that will be used to render
 243  
          * the table header
 244  
          * 
 245  
          * <p>
 246  
          * For each column, a copy of headerFieldPrototype is made that determines
 247  
          * the label configuration. The actual label text comes from the field for
 248  
          * which the header applies to. The first column is always the sequence (if
 249  
          * enabled) and the last column contains the actions. Both the sequence and
 250  
          * action header fields will span all rows for the header.
 251  
          * </p>
 252  
          * 
 253  
          * <p>
 254  
          * The headerFields list will contain the final list of header fields built
 255  
          * </p>
 256  
          * 
 257  
          * @param collectionGroup
 258  
          *            - CollectionGroup container the table applies to
 259  
          * @param lineFields - fields for the data columns from which the headers are pulled
 260  
          */
 261  
         protected void buildTableHeaderRows(CollectionGroup collectionGroup, List<Field> lineFields) {
 262  
                 // row count needed to determine the row span for the sequence and
 263  
                 // action fields, since they should span all rows for the line
 264  0
                 int rowCount = calculateNumberOfRows(collectionGroup.getItems());
 265  
 
 266  
                 // first column is sequence label
 267  0
                 if (renderSequenceField) {
 268  0
                         sequenceFieldPrototype.setLabelFieldRendered(true);
 269  0
                         sequenceFieldPrototype.setRowSpan(rowCount);
 270  0
                         addHeaderField(sequenceFieldPrototype, 1);
 271  
                 }
 272  
 
 273  
                 // pull out label fields from the container's items
 274  0
                 int cellPosition = 0;
 275  0
                 for (Field field : lineFields) {
 276  0
                     if (!field.isRender()) {
 277  0
                         continue;
 278  
                     }
 279  
                     
 280  0
                         cellPosition += field.getColSpan();
 281  0
                         addHeaderField(field, cellPosition);
 282  
 
 283  
                         // add action header as last column in row
 284  0
                         if ((cellPosition == getNumberOfDataColumns()) && collectionGroup.isRenderLineActions()
 285  
                                         && !collectionGroup.isReadOnly()) {
 286  0
                                 actionFieldPrototype.setLabelFieldRendered(true);
 287  0
                                 actionFieldPrototype.setRowSpan(rowCount);
 288  0
                                 addHeaderField(actionFieldPrototype, cellPosition);
 289  
                         }
 290  
                 }
 291  0
         }
 292  
 
 293  
         /**
 294  
          * Creates a new instance of the header field prototype and then sets the
 295  
          * label to the short (if useShortLabels is set to true) or long label of
 296  
          * the given component. After created the header field is added to the list
 297  
          * making up the table header
 298  
          * 
 299  
          * @param field
 300  
          *            - field instance the header field is being created for
 301  
          * @param column
 302  
          *            - column number for the header, used for setting the id
 303  
          */
 304  
         protected void addHeaderField(Field field, int column) {
 305  0
                 LabelField headerField = ComponentUtils.copy(headerFieldPrototype, "_c" + column);
 306  0
                 if (useShortLabels) {
 307  0
                         headerField.setLabelText(field.getLabel());
 308  
                 }
 309  
                 else {
 310  0
                         headerField.setLabelText(field.getLabel());
 311  
                 }
 312  
 
 313  0
                 headerField.setRowSpan(field.getRowSpan());
 314  0
                 headerField.setColSpan(field.getColSpan());
 315  
 
 316  0
                 if ((field.getRequired() != null) && field.getRequired().booleanValue()) {
 317  0
                         headerField.getRequiredMessageField().setRender(true);
 318  
                 }
 319  
                 else {
 320  0
                         headerField.getRequiredMessageField().setRender(false);
 321  
                 }
 322  
 
 323  0
                 headerFields.add(headerField);
 324  0
         }
 325  
 
 326  
         /**
 327  
          * Calculates how many rows will be needed per collection line to display
 328  
          * the list of fields. Assumption is made that the total number of cells the
 329  
          * fields take up is evenly divisible by the configured number of columns
 330  
          * 
 331  
          * @param items
 332  
          *            - list of items that make up one collection line
 333  
          * @return int number of rows
 334  
          */
 335  
         protected int calculateNumberOfRows(List<? extends Field> items) {
 336  0
                 int rowCount = 0;
 337  
                 
 338  
                 // check flag that indicates only one row should be created
 339  0
                 if (isSuppressLineWrapping()) {
 340  0
                     return 1;
 341  
                 }
 342  
 
 343  0
                 int cellCount = 0;
 344  0
                 for (Field field : items) {
 345  0
                         cellCount += field.getColSpan() + field.getRowSpan() - 1;
 346  
                 }
 347  
 
 348  0
                 if (cellCount != 0) {
 349  0
                         rowCount = cellCount / getNumberOfDataColumns();
 350  
                 }
 351  
 
 352  0
                 return rowCount;
 353  
         }
 354  
 
 355  
         /**
 356  
          * @see org.kuali.rice.kns.uif.layout.ContainerAware#getSupportedContainer()
 357  
          */
 358  
         @Override
 359  
         public Class<? extends Container> getSupportedContainer() {
 360  0
                 return CollectionGroup.class;
 361  
         }
 362  
 
 363  
         /**
 364  
          * @see org.kuali.rice.kns.uif.layout.LayoutManagerBase#getNestedComponents()
 365  
          */
 366  
         @Override
 367  
         public List<Component> getNestedComponents() {
 368  0
                 List<Component> components = super.getNestedComponents();
 369  
 
 370  0
                 components.add(tableTools);
 371  0
                 components.addAll(headerFields);
 372  0
                 components.addAll(dataFields);
 373  
 
 374  0
                 return components;
 375  
         }
 376  
 
 377  
         /**
 378  
          * Indicates whether the short label for the collection field should be used
 379  
          * as the table header or the regular label
 380  
          * 
 381  
          * @return boolean true if short label should be used, false if long label
 382  
          *         should be used
 383  
          */
 384  
         public boolean isUseShortLabels() {
 385  0
                 return this.useShortLabels;
 386  
         }
 387  
 
 388  
         /**
 389  
          * Setter for the use short label indicator
 390  
          * 
 391  
          * @param useShortLabels
 392  
          */
 393  
         public void setUseShortLabels(boolean useShortLabels) {
 394  0
                 this.useShortLabels = useShortLabels;
 395  0
         }
 396  
 
 397  
         /**
 398  
          * Indicates whether the header should be repeated before each collection
 399  
          * row. If false the header is only rendered at the beginning of the table
 400  
          * 
 401  
          * @return boolean true if header should be repeated, false if it should
 402  
          *         only be rendered once
 403  
          */
 404  
         public boolean isRepeatHeader() {
 405  0
                 return this.repeatHeader;
 406  
         }
 407  
 
 408  
         /**
 409  
          * Setter for the repeat header indicator
 410  
          * 
 411  
          * @param repeatHeader
 412  
          */
 413  
         public void setRepeatHeader(boolean repeatHeader) {
 414  0
                 this.repeatHeader = repeatHeader;
 415  0
         }
 416  
 
 417  
         /**
 418  
          * <code>LabelField</code> instance to use as a prototype for creating the
 419  
          * tables header fields. For each header field the prototype will be copied
 420  
          * and adjusted as necessary
 421  
          * 
 422  
          * @return LabelField instance to serve as prototype
 423  
          */
 424  
         public LabelField getHeaderFieldPrototype() {
 425  0
                 return this.headerFieldPrototype;
 426  
         }
 427  
 
 428  
         /**
 429  
          * Setter for the header field prototype
 430  
          * 
 431  
          * @param headerFieldPrototype
 432  
          */
 433  
         public void setHeaderFieldPrototype(LabelField headerFieldPrototype) {
 434  0
                 this.headerFieldPrototype = headerFieldPrototype;
 435  0
         }
 436  
 
 437  
         /**
 438  
          * List of <code>LabelField</code> instances that should be rendered to make
 439  
          * up the tables header
 440  
          * 
 441  
          * @return List of label field instances
 442  
          */
 443  
         public List<LabelField> getHeaderFields() {
 444  0
                 return this.headerFields;
 445  
         }
 446  
 
 447  
         /**
 448  
          * Indicates whether the sequence field should be rendered for the
 449  
          * collection
 450  
          * 
 451  
          * @return boolean true if sequence field should be rendered, false if not
 452  
          */
 453  
         public boolean isRenderSequenceField() {
 454  0
                 return this.renderSequenceField;
 455  
         }
 456  
 
 457  
         /**
 458  
          * Setter for the render sequence field indicator
 459  
          * 
 460  
          * @param renderSequenceField
 461  
          */
 462  
         public void setRenderSequenceField(boolean renderSequenceField) {
 463  0
                 this.renderSequenceField = renderSequenceField;
 464  0
         }
 465  
 
 466  
         /**
 467  
          * Expression language string for conditionally setting the render sequence
 468  
          * field property
 469  
          * 
 470  
          * @return String el that should evaluate to boolean
 471  
          */
 472  
         public String getConditionalRenderSequenceField() {
 473  0
                 return this.conditionalRenderSequenceField;
 474  
         }
 475  
 
 476  
         /**
 477  
          * Setter for the conditional render sequence field string
 478  
          * 
 479  
          * @param conditionalRenderSequenceField
 480  
          */
 481  
         public void setConditionalRenderSequenceField(String conditionalRenderSequenceField) {
 482  0
                 this.conditionalRenderSequenceField = conditionalRenderSequenceField;
 483  0
         }
 484  
 
 485  
         /**
 486  
          * Attribute name to use as sequence value. For each collection line the
 487  
          * value of this field on the line will be retrieved and used as the
 488  
          * sequence value
 489  
          * 
 490  
          * @return String sequence property name
 491  
          */
 492  
     public String getSequencePropertyName() {
 493  0
         if ((sequenceFieldPrototype != null) && (sequenceFieldPrototype instanceof AttributeField)) {
 494  0
             return ((AttributeField) sequenceFieldPrototype).getPropertyName();
 495  
         }
 496  
 
 497  0
         return null;
 498  
     }
 499  
 
 500  
     /**
 501  
      * Setter for the sequence property name
 502  
      * 
 503  
      * @param sequencePropertyName
 504  
      */
 505  
     public void setSequencePropertyName(String sequencePropertyName) {
 506  0
         if ((sequenceFieldPrototype != null) && (sequenceFieldPrototype instanceof AttributeField)) {
 507  0
             ((AttributeField) sequenceFieldPrototype).setPropertyName(sequencePropertyName);
 508  
         }
 509  0
     }
 510  
         
 511  
     /**
 512  
      * Indicates whether the sequence field should be generated with the current
 513  
      * line number
 514  
      * 
 515  
      * <p>
 516  
      * If set to true the sequence field prototype will be changed to a message
 517  
      * field (if not already a message field) and the text will be set to the
 518  
      * current line number
 519  
      * </p>
 520  
      * 
 521  
      * @return boolean true if the sequence field should be generated from the
 522  
      *         line number, false if not
 523  
      */
 524  
     public boolean isGenerateAutoSequence() {
 525  0
         return this.generateAutoSequence;
 526  
     }
 527  
 
 528  
     /**
 529  
      * Setter for the generate auto sequence field
 530  
      * 
 531  
      * @param generateAutoSequence
 532  
      */
 533  
     public void setGenerateAutoSequence(boolean generateAutoSequence) {
 534  0
         this.generateAutoSequence = generateAutoSequence;
 535  0
     }
 536  
 
 537  
     /**
 538  
          * <code>Field</code> instance to serve as a prototype for the
 539  
          * sequence field. For each collection line this instance is copied and
 540  
          * adjusted as necessary
 541  
          * 
 542  
          * @return Attribute field instance
 543  
          */
 544  
         public Field getSequenceFieldPrototype() {
 545  0
                 return this.sequenceFieldPrototype;
 546  
         }
 547  
 
 548  
         /**
 549  
          * Setter for the sequence field prototype
 550  
          * 
 551  
          * @param sequenceFieldPrototype
 552  
          */
 553  
         public void setSequenceFieldPrototype(Field sequenceFieldPrototype) {
 554  0
                 this.sequenceFieldPrototype = sequenceFieldPrototype;
 555  0
         }
 556  
 
 557  
         /**
 558  
          * <code>GroupField</code> instance to serve as a prototype for the actions
 559  
          * column. For each collection line this instance is copied and adjusted as
 560  
          * necessary. Note the actual actions for the group come from the collection
 561  
          * groups actions List
 562  
          * (org.kuali.rice.kns.uif.container.CollectionGroup.getActionFields()). The
 563  
          * GroupField prototype is useful for setting styling of the actions column
 564  
          * and for the layout of the action fields. Note also the label associated
 565  
          * with the prototype is used for the action column header
 566  
          * 
 567  
          * @return GroupField instance
 568  
          */
 569  
         public GroupField getActionFieldPrototype() {
 570  0
                 return this.actionFieldPrototype;
 571  
         }
 572  
 
 573  
         /**
 574  
          * Setter for the action field prototype
 575  
          * 
 576  
          * @param actionFieldPrototype
 577  
          */
 578  
         public void setActionFieldPrototype(GroupField actionFieldPrototype) {
 579  0
                 this.actionFieldPrototype = actionFieldPrototype;
 580  0
         }
 581  
 
 582  
         /**
 583  
          * @see org.kuali.rice.kns.uif.layout.CollectionLayoutManager#getSubCollectionGroupFieldPrototype()
 584  
          */
 585  
         public GroupField getSubCollectionGroupFieldPrototype() {
 586  0
                 return this.subCollectionGroupFieldPrototype;
 587  
         }
 588  
 
 589  
         /**
 590  
          * Setter for the sub-collection field group prototype
 591  
          * 
 592  
          * @param subCollectionGroupFieldPrototype
 593  
          */
 594  
         public void setSubCollectionGroupFieldPrototype(GroupField subCollectionGroupFieldPrototype) {
 595  0
                 this.subCollectionGroupFieldPrototype = subCollectionGroupFieldPrototype;
 596  0
         }
 597  
 
 598  
         /**
 599  
          * List of <code>Field</code> instances that make up the tables body. Pulled
 600  
          * by the layout manager template to send through the Grid layout
 601  
          * 
 602  
          * @return List<Field> table body fields
 603  
          */
 604  
         public List<Field> getDataFields() {
 605  0
                 return this.dataFields;
 606  
         }
 607  
 
 608  
         /**
 609  
          * Widget associated with the table to add functionality such as sorting,
 610  
          * paging, and export
 611  
          * 
 612  
          * @return TableTools instance
 613  
          */
 614  
         public TableTools getTableTools() {
 615  0
                 return this.tableTools;
 616  
         }
 617  
 
 618  
         /**
 619  
          * Setter for the table tools widget
 620  
          * 
 621  
          * @param tableTools
 622  
          */
 623  
         public void setTableTools(TableTools tableTools) {
 624  0
                 this.tableTools = tableTools;
 625  0
         }
 626  
 
 627  
         /**
 628  
      * @return the numberOfDataColumns
 629  
      */
 630  
     public int getNumberOfDataColumns() {
 631  0
             return this.numberOfDataColumns;
 632  
     }
 633  
 
 634  
         /**
 635  
      * @param numberOfDataColumns the numberOfDataColumns to set
 636  
      */
 637  
     public void setNumberOfDataColumns(int numberOfDataColumns) {
 638  0
             this.numberOfDataColumns = numberOfDataColumns;
 639  0
     }
 640  
 
 641  
 }