001/** 002 * Copyright 2005-2016 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.rice.krad.uif.layout; 017 018import org.apache.commons.lang.StringUtils; 019import org.kuali.rice.krad.uif.UifConstants; 020import org.kuali.rice.krad.uif.component.DataBinding; 021import org.kuali.rice.krad.uif.container.CollectionGroup; 022import org.kuali.rice.krad.uif.container.Container; 023import org.kuali.rice.krad.uif.container.Group; 024import org.kuali.rice.krad.uif.field.DataField; 025import org.kuali.rice.krad.uif.field.FieldGroup; 026import org.kuali.rice.krad.uif.field.InputField; 027import org.kuali.rice.krad.uif.view.View; 028import org.kuali.rice.krad.uif.component.Component; 029import org.kuali.rice.krad.uif.field.ActionField; 030import org.kuali.rice.krad.uif.field.Field; 031import org.kuali.rice.krad.uif.field.LabelField; 032import org.kuali.rice.krad.uif.field.MessageField; 033import org.kuali.rice.krad.uif.util.ComponentFactory; 034import org.kuali.rice.krad.uif.util.ComponentUtils; 035import org.kuali.rice.krad.uif.widget.RichTable; 036import org.kuali.rice.krad.web.form.UifFormBase; 037 038import java.util.ArrayList; 039import java.util.List; 040import java.util.Set; 041 042/** 043 * Layout manager that works with <code>CollectionGroup</code> components and 044 * renders the collection as a Table 045 * 046 * <p> 047 * Based on the fields defined, the <code>TableLayoutManager</code> will 048 * dynamically create instances of the fields for each collection row. In 049 * addition, the manager can create standard fields like the action and sequence 050 * fields for each row. The manager supports options inherited from the 051 * <code>GridLayoutManager</code> such as rowSpan, colSpan, and cell width 052 * settings. 053 * </p> 054 * 055 * @author Kuali Rice Team (rice.collab@kuali.org) 056 */ 057public class TableLayoutManager extends GridLayoutManager implements CollectionLayoutManager { 058 private static final long serialVersionUID = 3622267585541524208L; 059 060 private boolean useShortLabels; 061 private boolean repeatHeader; 062 private LabelField headerFieldPrototype; 063 064 private boolean renderSequenceField; 065 private boolean generateAutoSequence; 066 private Field sequenceFieldPrototype; 067 068 private FieldGroup actionFieldPrototype; 069 private FieldGroup subCollectionFieldGroupPrototype; 070 private Field selectFieldPrototype; 071 072 private boolean separateAddLine; 073 private Group addLineGroup; 074 075 // internal counter for the data columns (not including sequence, action) 076 private int numberOfDataColumns; 077 078 private List<LabelField> headerFields; 079 private List<Field> dataFields; 080 081 private RichTable richTable; 082 private boolean headerAdded = false; 083 084 private Set<String> hiddenColumns; 085 private Set<String> sortableColumns; 086 087 public TableLayoutManager() { 088 useShortLabels = true; 089 repeatHeader = false; 090 renderSequenceField = true; 091 generateAutoSequence = false; 092 separateAddLine = false; 093 094 headerFields = new ArrayList<LabelField>(); 095 dataFields = new ArrayList<Field>(); 096 } 097 098 /** 099 * The following actions are performed: 100 * 101 * <ul> 102 * <li>Sets sequence field prototype if auto sequence is true</li> 103 * <li>Initializes the prototypes</li> 104 * </ul> 105 * 106 * @see org.kuali.rice.krad.uif.layout.BoxLayoutManager#performInitialization(org.kuali.rice.krad.uif.view.View, 107 * java.lang.Object, org.kuali.rice.krad.uif.container.Container) 108 */ 109 @Override 110 public void performInitialization(View view, Object model, Container container) { 111 super.performInitialization(view, model, container); 112 113 if (generateAutoSequence && !(sequenceFieldPrototype instanceof MessageField)) { 114 sequenceFieldPrototype = ComponentFactory.getMessageField(); 115 view.assignComponentIds(sequenceFieldPrototype); 116 } 117 118 view.getViewHelperService().performComponentInitialization(view, model, headerFieldPrototype); 119 view.getViewHelperService().performComponentInitialization(view, model, sequenceFieldPrototype); 120 view.getViewHelperService().performComponentInitialization(view, model, actionFieldPrototype); 121 view.getViewHelperService().performComponentInitialization(view, model, subCollectionFieldGroupPrototype); 122 view.getViewHelperService().performComponentInitialization(view, model, selectFieldPrototype); 123 } 124 125 /** 126 * Sets up the final column count for rendering based on whether the 127 * sequence and action fields have been generated 128 * 129 * @see org.kuali.rice.krad.uif.layout.LayoutManagerBase#performFinalize(org.kuali.rice.krad.uif.view.View, 130 * java.lang.Object, org.kuali.rice.krad.uif.container.Container) 131 */ 132 @Override 133 public void performFinalize(View view, Object model, Container container) { 134 super.performFinalize(view, model, container); 135 136 UifFormBase formBase = (UifFormBase) model; 137 138 CollectionGroup collectionGroup = (CollectionGroup) container; 139 140 int totalColumns = getNumberOfDataColumns(); 141 if (renderSequenceField) { 142 totalColumns++; 143 } 144 145 if (collectionGroup.isRenderSelectField()) { 146 totalColumns++; 147 } 148 149 if (collectionGroup.isRenderLineActions() && !collectionGroup.isReadOnly()) { 150 totalColumns++; 151 } 152 153 if (collectionGroup.isRenderAddLine()){ 154 if(StringUtils.isBlank(this.getFirstLineStyle()) && !isSeparateAddLine()){ 155 this.setFirstLineStyle("kr-addLine"); 156 } 157 } 158 159 // if add line event, add highlighting for added row 160 if (UifConstants.ActionEvents.ADD_LINE.equals(formBase.getActionEvent())) { 161 String highlightScript = 162 "jq(\"#" + container.getId() + "_div > tr:first\").effect(\"highlight\",{}, 6000);"; 163 String onReadyScript = collectionGroup.getOnDocumentReadyScript(); 164 if (StringUtils.isNotBlank(onReadyScript)) { 165 highlightScript = onReadyScript + highlightScript; 166 } 167 collectionGroup.setOnDocumentReadyScript(highlightScript); 168 } 169 setNumberOfColumns(totalColumns); 170 } 171 172 /** 173 * Assembles the field instances for the collection line. The given sequence 174 * field prototype is copied for the line sequence field. Likewise a copy of 175 * the actionFieldPrototype is made and the given actions are set as the 176 * items for the action field. Finally the generated items are assembled 177 * together into the dataFields list with the given lineFields. 178 * 179 * @see org.kuali.rice.krad.uif.layout.CollectionLayoutManager#buildLine(org.kuali.rice.krad.uif.view.View, 180 * java.lang.Object, org.kuali.rice.krad.uif.container.CollectionGroup, 181 * java.util.List, java.util.List, java.lang.String, java.util.List, 182 * java.lang.String, java.lang.Object, int) 183 */ 184 public void buildLine(View view, Object model, CollectionGroup collectionGroup, List<Field> lineFields, 185 List<FieldGroup> subCollectionFields, String bindingPath, List<ActionField> actions, String idSuffix, 186 Object currentLine, int lineIndex) { 187 boolean isAddLine = lineIndex == -1; 188 189 // if separate add line prepare the add line group 190 if (isAddLine && separateAddLine) { 191 if (StringUtils.isBlank(addLineGroup.getTitle()) && StringUtils.isBlank( 192 addLineGroup.getHeader().getHeaderText())) { 193 addLineGroup.getHeader().setHeaderText(collectionGroup.getAddLineLabel()); 194 } 195 196 addLineGroup.setItems(lineFields); 197 198 List<Component> footerItems = new ArrayList<Component>(actions); 199 footerItems.addAll(addLineGroup.getFooter().getItems()); 200 addLineGroup.getFooter().setItems(footerItems); 201 202 return; 203 } 204 205 // if first line for table set number of data columns 206 if (dataFields.isEmpty()) { 207 if (isSuppressLineWrapping()) { 208 setNumberOfDataColumns(lineFields.size()); 209 } else { 210 setNumberOfDataColumns(getNumberOfColumns()); 211 } 212 } 213 214 // TODO: implement repeat header 215 if (!headerAdded) { 216 headerFields = new ArrayList<LabelField>(); 217 dataFields = new ArrayList<Field>(); 218 219 buildTableHeaderRows(collectionGroup, lineFields); 220 ComponentUtils.pushObjectToContext(headerFields, UifConstants.ContextVariableNames.LINE, currentLine); 221 ComponentUtils.pushObjectToContext(headerFields, UifConstants.ContextVariableNames.INDEX, new Integer( 222 lineIndex)); 223 headerAdded = true; 224 } 225 226 // set label field rendered to true on line fields 227 for (Field field : lineFields) { 228 field.setLabelFieldRendered(true); 229 230 // don't display summary message 231 // TODO: remove once we have modifier 232 ComponentUtils.setComponentPropertyDeep(field, "summaryMessageField.render", new Boolean(false)); 233 } 234 235 int rowCount = calculateNumberOfRows(lineFields); 236 int rowSpan = rowCount + subCollectionFields.size(); 237 238 // sequence field is always first and should span all rows for the line 239 if (renderSequenceField) { 240 Field sequenceField = null; 241 if (!isAddLine) { 242 sequenceField = ComponentUtils.copy(sequenceFieldPrototype, idSuffix); 243 244 if (generateAutoSequence && (sequenceField instanceof MessageField)) { 245 ((MessageField) sequenceField).setMessageText(Integer.toString(lineIndex + 1)); 246 } 247 } 248 else { 249 sequenceField = ComponentUtils.copy(collectionGroup.getAddLineLabelField(), idSuffix); 250 } 251 sequenceField.setRowSpan(rowSpan); 252 253 if (sequenceField instanceof DataBinding) { 254 ((DataBinding) sequenceField).getBindingInfo().setBindByNamePrefix(bindingPath); 255 } 256 257 ComponentUtils.updateContextForLine(sequenceField, currentLine, lineIndex); 258 dataFields.add(sequenceField); 259 } 260 261 // select field will come after sequence field (if enabled) or be first column 262 if (collectionGroup.isRenderSelectField()) { 263 Field selectField = ComponentUtils.copy(selectFieldPrototype, idSuffix); 264 CollectionLayoutUtils.prepareSelectFieldForLine(selectField, collectionGroup, bindingPath, currentLine); 265 266 ComponentUtils.updateContextForLine(selectField, currentLine, lineIndex); 267 dataFields.add(selectField); 268 } 269 270 // now add the fields in the correct position 271 int cellPosition = 0; 272 for (Field lineField : lineFields) { 273 dataFields.add(lineField); 274 275 cellPosition += lineField.getColSpan(); 276 277 // action field should be in last column 278 if ((cellPosition == getNumberOfDataColumns()) && collectionGroup.isRenderLineActions() 279 && !collectionGroup.isReadOnly()) { 280 FieldGroup lineActionsField = ComponentUtils.copy(actionFieldPrototype, idSuffix); 281 282 ComponentUtils.updateContextForLine(lineActionsField, currentLine, lineIndex); 283 lineActionsField.setRowSpan(rowSpan); 284 lineActionsField.setItems(actions); 285 286 dataFields.add(lineActionsField); 287 } 288 } 289 290 // update colspan on sub-collection fields 291 for (FieldGroup subCollectionField : subCollectionFields) { 292 subCollectionField.setColSpan(numberOfDataColumns); 293 } 294 295 // add sub-collection fields to end of data fields 296 dataFields.addAll(subCollectionFields); 297 } 298 299 /** 300 * Create the <code>LabelField</code> instances that will be used to render 301 * the table header 302 * 303 * <p> 304 * For each column, a copy of headerFieldPrototype is made that determines 305 * the label configuration. The actual label text comes from the field for 306 * which the header applies to. The first column is always the sequence (if 307 * enabled) and the last column contains the actions. Both the sequence and 308 * action header fields will span all rows for the header. 309 * </p> 310 * 311 * <p> 312 * The headerFields list will contain the final list of header fields built 313 * </p> 314 * 315 * @param collectionGroup 316 * - CollectionGroup container the table applies to 317 * @param lineFields - fields for the data columns from which the headers are pulled 318 */ 319 protected void buildTableHeaderRows(CollectionGroup collectionGroup, List<Field> lineFields) { 320 // row count needed to determine the row span for the sequence and 321 // action fields, since they should span all rows for the line 322 int rowCount = calculateNumberOfRows(lineFields); 323 324 // first column is sequence label 325 if (renderSequenceField) { 326 sequenceFieldPrototype.setLabelFieldRendered(true); 327 sequenceFieldPrototype.setRowSpan(rowCount); 328 addHeaderField(sequenceFieldPrototype, 1); 329 } 330 331 // next is select field 332 if (collectionGroup.isRenderSelectField()) { 333 selectFieldPrototype.setLabelFieldRendered(true); 334 selectFieldPrototype.setRowSpan(rowCount); 335 addHeaderField(selectFieldPrototype, 1); 336 } 337 338 // pull out label fields from the container's items 339 int cellPosition = 0; 340 for (Field field : lineFields) { 341 if (!field.isRender() && StringUtils.isEmpty(field.getProgressiveRender())) { 342 continue; 343 } 344 345 cellPosition += field.getColSpan(); 346 addHeaderField(field, cellPosition); 347 348 // add action header as last column in row 349 if ((cellPosition == getNumberOfDataColumns()) && collectionGroup.isRenderLineActions() 350 && !collectionGroup.isReadOnly()) { 351 actionFieldPrototype.setLabelFieldRendered(true); 352 actionFieldPrototype.setRowSpan(rowCount); 353 addHeaderField(actionFieldPrototype, cellPosition); 354 } 355 } 356 } 357 358 /** 359 * Creates a new instance of the header field prototype and then sets the 360 * label to the short (if useShortLabels is set to true) or long label of 361 * the given component. After created the header field is added to the list 362 * making up the table header 363 * 364 * @param field 365 * - field instance the header field is being created for 366 * @param column 367 * - column number for the header, used for setting the id 368 */ 369 protected void addHeaderField(Field field, int column) { 370 LabelField headerField = ComponentUtils.copy(headerFieldPrototype, "_c" + column); 371 if (useShortLabels) { 372 headerField.setLabelText(field.getLabel()); 373 } 374 else { 375 headerField.setLabelText(field.getLabel()); 376 } 377 378 headerField.setRowSpan(field.getRowSpan()); 379 headerField.setColSpan(field.getColSpan()); 380 381 if ((field.getRequired() != null) && field.getRequired().booleanValue()) { 382 headerField.getRequiredMessageField().setRender(true); 383 } 384 else { 385 headerField.getRequiredMessageField().setRender(false); 386 } 387 388 headerFields.add(headerField); 389 } 390 391 /** 392 * Calculates how many rows will be needed per collection line to display 393 * the list of fields. Assumption is made that the total number of cells the 394 * fields take up is evenly divisible by the configured number of columns 395 * 396 * @param items 397 * - list of items that make up one collection line 398 * @return int number of rows 399 */ 400 protected int calculateNumberOfRows(List<? extends Field> items) { 401 int rowCount = 0; 402 403 // check flag that indicates only one row should be created 404 if (isSuppressLineWrapping()) { 405 return 1; 406 } 407 408 int cellCount = 0; 409 for (Field field : items) { 410 cellCount += field.getColSpan() + field.getRowSpan() - 1; 411 } 412 413 if (cellCount != 0) { 414 rowCount = cellCount / getNumberOfDataColumns(); 415 } 416 417 return rowCount; 418 } 419 420 /** 421 * @see org.kuali.rice.krad.uif.layout.ContainerAware#getSupportedContainer() 422 */ 423 @Override 424 public Class<? extends Container> getSupportedContainer() { 425 return CollectionGroup.class; 426 } 427 428 /** 429 * @see org.kuali.rice.krad.uif.layout.LayoutManagerBase#getComponentsForLifecycle() 430 */ 431 @Override 432 public List<Component> getComponentsForLifecycle() { 433 List<Component> components = super.getComponentsForLifecycle(); 434 435 components.add(richTable); 436 components.add(addLineGroup); 437 components.addAll(headerFields); 438 components.addAll(dataFields); 439 440 return components; 441 } 442 443 /** 444 * @see org.kuali.rice.krad.uif.layout.LayoutManager#getComponentPrototypes() 445 */ 446 @Override 447 public List<Component> getComponentPrototypes() { 448 List<Component> components = super.getComponentPrototypes(); 449 450 components.add(headerFieldPrototype); 451 components.add(sequenceFieldPrototype); 452 components.add(actionFieldPrototype); 453 components.add(subCollectionFieldGroupPrototype); 454 components.add(selectFieldPrototype); 455 456 return components; 457 } 458 459 /** 460 * Indicates whether the short label for the collection field should be used 461 * as the table header or the regular label 462 * 463 * @return boolean true if short label should be used, false if long label 464 * should be used 465 */ 466 public boolean isUseShortLabels() { 467 return this.useShortLabels; 468 } 469 470 /** 471 * Setter for the use short label indicator 472 * 473 * @param useShortLabels 474 */ 475 public void setUseShortLabels(boolean useShortLabels) { 476 this.useShortLabels = useShortLabels; 477 } 478 479 /** 480 * Indicates whether the header should be repeated before each collection 481 * row. If false the header is only rendered at the beginning of the table 482 * 483 * @return boolean true if header should be repeated, false if it should 484 * only be rendered once 485 */ 486 public boolean isRepeatHeader() { 487 return this.repeatHeader; 488 } 489 490 /** 491 * Setter for the repeat header indicator 492 * 493 * @param repeatHeader 494 */ 495 public void setRepeatHeader(boolean repeatHeader) { 496 this.repeatHeader = repeatHeader; 497 } 498 499 /** 500 * <code>LabelField</code> instance to use as a prototype for creating the 501 * tables header fields. For each header field the prototype will be copied 502 * and adjusted as necessary 503 * 504 * @return LabelField instance to serve as prototype 505 */ 506 public LabelField getHeaderFieldPrototype() { 507 return this.headerFieldPrototype; 508 } 509 510 /** 511 * Setter for the header field prototype 512 * 513 * @param headerFieldPrototype 514 */ 515 public void setHeaderFieldPrototype(LabelField headerFieldPrototype) { 516 this.headerFieldPrototype = headerFieldPrototype; 517 } 518 519 /** 520 * List of <code>LabelField</code> instances that should be rendered to make 521 * up the tables header 522 * 523 * @return List of label field instances 524 */ 525 public List<LabelField> getHeaderFields() { 526 return this.headerFields; 527 } 528 529 /** 530 * Indicates whether the sequence field should be rendered for the 531 * collection 532 * 533 * @return boolean true if sequence field should be rendered, false if not 534 */ 535 public boolean isRenderSequenceField() { 536 return this.renderSequenceField; 537 } 538 539 /** 540 * Setter for the render sequence field indicator 541 * 542 * @param renderSequenceField 543 */ 544 public void setRenderSequenceField(boolean renderSequenceField) { 545 this.renderSequenceField = renderSequenceField; 546 } 547 548 /** 549 * Attribute name to use as sequence value. For each collection line the 550 * value of this field on the line will be retrieved and used as the 551 * sequence value 552 * 553 * @return String sequence property name 554 */ 555 public String getSequencePropertyName() { 556 if ((sequenceFieldPrototype != null) && (sequenceFieldPrototype instanceof DataField)) { 557 return ((DataField) sequenceFieldPrototype).getPropertyName(); 558 } 559 560 return null; 561 } 562 563 /** 564 * Setter for the sequence property name 565 * 566 * @param sequencePropertyName 567 */ 568 public void setSequencePropertyName(String sequencePropertyName) { 569 if ((sequenceFieldPrototype != null) && (sequenceFieldPrototype instanceof DataField)) { 570 ((DataField) sequenceFieldPrototype).setPropertyName(sequencePropertyName); 571 } 572 } 573 574 /** 575 * Indicates whether the sequence field should be generated with the current 576 * line number 577 * 578 * <p> 579 * If set to true the sequence field prototype will be changed to a message 580 * field (if not already a message field) and the text will be set to the 581 * current line number 582 * </p> 583 * 584 * @return boolean true if the sequence field should be generated from the 585 * line number, false if not 586 */ 587 public boolean isGenerateAutoSequence() { 588 return this.generateAutoSequence; 589 } 590 591 /** 592 * Setter for the generate auto sequence field 593 * 594 * @param generateAutoSequence 595 */ 596 public void setGenerateAutoSequence(boolean generateAutoSequence) { 597 this.generateAutoSequence = generateAutoSequence; 598 } 599 600 /** 601 * <code>Field</code> instance to serve as a prototype for the 602 * sequence field. For each collection line this instance is copied and 603 * adjusted as necessary 604 * 605 * @return Attribute field instance 606 */ 607 public Field getSequenceFieldPrototype() { 608 return this.sequenceFieldPrototype; 609 } 610 611 /** 612 * Setter for the sequence field prototype 613 * 614 * @param sequenceFieldPrototype 615 */ 616 public void setSequenceFieldPrototype(Field sequenceFieldPrototype) { 617 this.sequenceFieldPrototype = sequenceFieldPrototype; 618 } 619 620 /** 621 * <code>FieldGroup</code> instance to serve as a prototype for the actions 622 * column. For each collection line this instance is copied and adjusted as 623 * necessary. Note the actual actions for the group come from the collection 624 * groups actions List 625 * (org.kuali.rice.krad.uif.container.CollectionGroup.getActionFields()). The 626 * FieldGroup prototype is useful for setting styling of the actions column 627 * and for the layout of the action fields. Note also the label associated 628 * with the prototype is used for the action column header 629 * 630 * @return GroupField instance 631 */ 632 public FieldGroup getActionFieldPrototype() { 633 return this.actionFieldPrototype; 634 } 635 636 /** 637 * Setter for the action field prototype 638 * 639 * @param actionFieldPrototype 640 */ 641 public void setActionFieldPrototype(FieldGroup actionFieldPrototype) { 642 this.actionFieldPrototype = actionFieldPrototype; 643 } 644 645 /** 646 * @see org.kuali.rice.krad.uif.layout.CollectionLayoutManager#getSubCollectionFieldGroupPrototype() 647 */ 648 public FieldGroup getSubCollectionFieldGroupPrototype() { 649 return this.subCollectionFieldGroupPrototype; 650 } 651 652 /** 653 * Setter for the sub-collection field group prototype 654 * 655 * @param subCollectionFieldGroupPrototype 656 */ 657 public void setSubCollectionFieldGroupPrototype(FieldGroup subCollectionFieldGroupPrototype) { 658 this.subCollectionFieldGroupPrototype = subCollectionFieldGroupPrototype; 659 } 660 661 /** 662 * Field instance that serves as a prototype for creating the select field on each line when 663 * {@link org.kuali.rice.krad.uif.container.CollectionGroup#isRenderSelectField()} is true 664 * 665 * <p> 666 * This prototype can be used to set the control used for the select field (generally will be a checkbox control) 667 * in addition to styling and other setting. The binding path will be formed with using the 668 * {@link org.kuali.rice.krad.uif.container.CollectionGroup#getSelectPropertyName()} or if not set the framework 669 * will use {@link org.kuali.rice.krad.web.form.UifFormBase#getSelectedCollectionLines()} 670 * </p> 671 * 672 * @return Field select field prototype instance 673 */ 674 public Field getSelectFieldPrototype() { 675 return selectFieldPrototype; 676 } 677 678 /** 679 * Setter for the prototype instance for select fields 680 * 681 * @param selectFieldPrototype 682 */ 683 public void setSelectFieldPrototype(Field selectFieldPrototype) { 684 this.selectFieldPrototype = selectFieldPrototype; 685 } 686 687 /** 688 * Indicates whether the add line should be rendered in a separate group, or as part of the table (first line) 689 * 690 * <p> 691 * When separate add line is enabled, the fields for the add line will be placed in the {@link #getAddLineGroup()}. 692 * This group can be used to configure the add line presentation. In addition to the fields, the header on the 693 * group (unless already set) will be set to 694 * {@link org.kuali.rice.krad.uif.container.CollectionGroup#getAddLineLabel()} and the add line actions will 695 * be placed into the group's footer. 696 * </p> 697 * 698 * @return boolean true if add line should be separated, false if it should be placed into the table 699 */ 700 public boolean isSeparateAddLine() { 701 return separateAddLine; 702 } 703 704 /** 705 * Setter for the separate add line indicator 706 * 707 * @param separateAddLine 708 */ 709 public void setSeparateAddLine(boolean separateAddLine) { 710 this.separateAddLine = separateAddLine; 711 } 712 713 /** 714 * When {@link #isSeparateAddLine()} is true, this group will be used to render the add line 715 * 716 * <p> 717 * This group can be used to configure how the add line will be rendered. For example the layout manager configured 718 * on the group will be used to rendered the add line fields. If the header (title) is not set on the group, it 719 * will be set from 720 * {@link org.kuali.rice.krad.uif.container.CollectionGroup#getAddLineLabel()}. In addition, 721 * {@link org.kuali.rice.krad.uif.container.CollectionGroup#getAddLineActionFields()} will be added to the group 722 * footer items. 723 * </p> 724 * 725 * @return Group instance for the collection add line 726 */ 727 public Group getAddLineGroup() { 728 return addLineGroup; 729 } 730 731 /** 732 * Setter for the add line Group 733 * 734 * @param addLineGroup 735 */ 736 public void setAddLineGroup(Group addLineGroup) { 737 this.addLineGroup = addLineGroup; 738 } 739 740 /** 741 * List of <code>Field</code> instances that make up the tables body. Pulled 742 * by the layout manager template to send through the Grid layout 743 * 744 * @return List<Field> table body fields 745 */ 746 public List<Field> getDataFields() { 747 return this.dataFields; 748 } 749 750 /** 751 * Widget associated with the table to add functionality such as sorting, 752 * paging, and export 753 * 754 * @return TableTools instance 755 */ 756 public RichTable getRichTable() { 757 return this.richTable; 758 } 759 760 /** 761 * Setter for the table tools widget 762 * 763 * @param richTable 764 */ 765 public void setRichTable(RichTable richTable) { 766 this.richTable = richTable; 767 } 768 769 /** 770 * @return the numberOfDataColumns 771 */ 772 public int getNumberOfDataColumns() { 773 return this.numberOfDataColumns; 774 } 775 776 /** 777 * @param numberOfDataColumns the numberOfDataColumns to set 778 */ 779 public void setNumberOfDataColumns(int numberOfDataColumns) { 780 this.numberOfDataColumns = numberOfDataColumns; 781 } 782 783 /** since columns are visible by default, this set holds propertyNames for the ones meant to be hidden*/ 784 public Set<String> getHiddenColumns() { 785 return hiddenColumns; 786 } 787 788 public void setHiddenColumns(Set<String> hiddenColumns) { 789 this.hiddenColumns = hiddenColumns; 790 } 791 792 /**holds the propertyNames for columns that are to be sorted*/ 793 public Set<String> getSortableColumns() { 794 return sortableColumns; 795 } 796 797 public void setSortableColumns(Set<String> sortableColumns) { 798 this.sortableColumns = sortableColumns; 799 } 800}