View Javadoc

1   /**
2    * Copyright 2005-2011 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.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/ecl2.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.krad.uif.widget;
17  
18  import org.apache.commons.lang.ClassUtils;
19  import org.apache.commons.lang.StringUtils;
20  import org.kuali.rice.core.api.util.type.KualiDecimal;
21  import org.kuali.rice.core.api.util.type.KualiInteger;
22  import org.kuali.rice.core.api.util.type.KualiPercent;
23  import org.kuali.rice.krad.uif.UifConstants;
24  import org.kuali.rice.krad.uif.container.CollectionGroup;
25  import org.kuali.rice.krad.uif.control.Control;
26  import org.kuali.rice.krad.uif.field.DataField;
27  import org.kuali.rice.krad.uif.field.InputField;
28  import org.kuali.rice.krad.uif.view.View;
29  import org.kuali.rice.krad.uif.control.CheckboxControl;
30  import org.kuali.rice.krad.uif.control.CheckboxGroupControl;
31  import org.kuali.rice.krad.uif.control.RadioGroupControl;
32  import org.kuali.rice.krad.uif.control.SelectControl;
33  import org.kuali.rice.krad.uif.component.Component;
34  import org.kuali.rice.krad.uif.field.FieldGroup;
35  import org.kuali.rice.krad.uif.layout.LayoutManager;
36  import org.kuali.rice.krad.uif.layout.TableLayoutManager;
37  import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
38  import org.kuali.rice.krad.web.form.UifFormBase;
39  
40  import java.sql.Timestamp;
41  import java.util.Set;
42  
43  /**
44   * Decorates a HTML Table client side with various tools
45   *
46   * <p>
47   * Decorations implemented depend on widget implementation. Examples are
48   * sorting, paging and skinning.
49   * </p>
50   *
51   * @author Kuali Rice Team (rice.collab@kuali.org)
52   */
53  public class RichTable extends WidgetBase {
54      private static final long serialVersionUID = 4671589690877390070L;
55  
56      private String emptyTableMessage;
57      private boolean disableTableSort;
58      /** since columns are visible by default, this set holds propertyNames for the ones meant to be hidden*/
59      private Set<String> hiddenColumns;
60      /**holds the propertyNames for columns that are to be sorted*/
61      private Set<String> sortableColumns;
62  
63  
64      private boolean showSearchAndExportOptions = true;
65  
66      public RichTable() {
67          super();
68      }
69  
70      /**
71       * The following initialization is performed:
72       *
73       * <ul>
74       * <li>Initializes component options for empty table message</li>
75       * </ul>
76       */
77      @Override
78      public void performFinalize(View view, Object model, Component component) {
79          super.performFinalize(view, model, component);
80  
81          UifFormBase formBase = (UifFormBase) model;
82  
83          if (isRender()) {
84              if (StringUtils.isNotBlank(getEmptyTableMessage())) {
85                  getComponentOptions().put(UifConstants.TableToolsKeys.LANGUAGE,
86                          "{\"" + UifConstants.TableToolsKeys.EMPTY_TABLE + "\" : \"" + getEmptyTableMessage() + "\"}");
87              }
88  
89              if (!isShowSearchAndExportOptions()) {
90                  Object domOption = getComponentOptions().get(UifConstants.TableToolsKeys.SDOM);
91                  if (domOption instanceof String) {
92                      String sDomOption = (String) domOption;
93                      if (StringUtils.isNotBlank(sDomOption)) {
94                          sDomOption = StringUtils.remove(sDomOption, "T"); //Removes Export option
95                          sDomOption = StringUtils.remove(sDomOption, "f"); //Removes search option
96                          getComponentOptions().put(UifConstants.TableToolsKeys.SDOM, sDomOption);
97                      }
98                  }
99  
100             }
101 
102             // for add events, disable initial sorting
103             if (UifConstants.ActionEvents.ADD_LINE.equals(formBase.getActionEvent())) {
104                 getComponentOptions().put(UifConstants.TableToolsKeys.AASORTING, "[]");
105             }
106 
107             if (component instanceof CollectionGroup) {
108                 buildTableOptions((CollectionGroup) component);
109             }
110 
111             if (isDisableTableSort()) {
112                 getComponentOptions().put(UifConstants.TableToolsKeys.TABLE_SORT, "false");
113             }
114         }
115     }
116 
117     /**
118      * Builds column options for sorting
119      *
120      * @param collectionGroup
121      */
122     protected void buildTableOptions(CollectionGroup collectionGroup) {
123         LayoutManager layoutManager = collectionGroup.getLayoutManager();
124 
125         // if sub collection exists, don't allow the table sortable
126         if (!collectionGroup.getSubCollections().isEmpty()) {
127             setDisableTableSort(true);
128         }
129 
130        if (!isDisableTableSort()) {
131             // if rendering add line, skip that row from col sorting
132             if (collectionGroup.isRenderAddLine()
133                     && !collectionGroup.isReadOnly()
134                     && !((layoutManager instanceof TableLayoutManager) && ((TableLayoutManager) layoutManager)
135                     .isSeparateAddLine())) {
136                 getComponentOptions().put(UifConstants.TableToolsKeys.SORT_SKIP_ROWS,
137                         "[" + UifConstants.TableToolsValues.ADD_ROW_DEFAULT_INDEX + "]");
138             }
139 
140             StringBuffer tableToolsColumnOptions = new StringBuffer("[");
141 
142             if (layoutManager instanceof TableLayoutManager && ((TableLayoutManager) layoutManager)
143                     .isRenderSequenceField()) {
144                 tableToolsColumnOptions.append(" null ,");
145             }
146 
147             // skip select field if enabled
148             if (collectionGroup.isRenderSelectField()) {
149                 String colOptions = constructTableColumnOptions(false, null, null);
150                 tableToolsColumnOptions.append(colOptions + " , ");
151             }
152 
153             //if data dictionary defines aoColumns, copy here and skip default sorting/visibility behaviour
154             if (!StringUtils.isEmpty(getComponentOptions().get(UifConstants.TableToolsKeys.AO_COLUMNS))) {
155                 //get the contents of the JS array string
156                 String jsArray = getComponentOptions().get(UifConstants.TableToolsKeys.AO_COLUMNS);
157                 int startBrace = StringUtils.indexOf(jsArray,"[");
158                 int endBrace = StringUtils.lastIndexOf(jsArray, "]");
159                 tableToolsColumnOptions.append(StringUtils.substring(jsArray, startBrace + 1, endBrace) + " , ");
160             } else {
161                     //use layout manager sortableColumns and hiddenColumns if set
162                     Set<String> currentSortableColumns =  getSortableColumns();
163                     Set<String> currentHiddenColumns =  getHiddenColumns();
164                     if (layoutManager instanceof TableLayoutManager) {
165                         TableLayoutManager tableLayoutMgr = (TableLayoutManager) layoutManager;
166                         if (tableLayoutMgr.getSortableColumns() != null && !tableLayoutMgr.getSortableColumns().isEmpty()) {
167                             currentSortableColumns = tableLayoutMgr.getSortableColumns();
168                         }
169                         if (tableLayoutMgr.getHiddenColumns() != null && !tableLayoutMgr.getHiddenColumns().isEmpty()) {
170                             currentHiddenColumns = tableLayoutMgr.getHiddenColumns();
171                         }
172                     }
173                 // TODO: does this handle multiple rows correctly?
174                 for (Component component : collectionGroup.getItems()) {
175                     // For FieldGroup, get the first field from that group
176                     if (component instanceof FieldGroup) {
177                         component = ((FieldGroup) component).getItems().get(0);
178                     }
179 
180                     if (component instanceof DataField) {
181                         DataField field = (DataField) component;
182                         //if a field is marked as invisible in hiddenColumns, append options and skip sorting
183                         if (currentHiddenColumns != null && currentHiddenColumns.contains(field.getPropertyName())) {
184                             tableToolsColumnOptions.append("{" + UifConstants.TableToolsKeys.VISIBLE + ": " + UifConstants.TableToolsValues.FALSE + "}, ");
185                         //if sortableColumns is present and a field is marked as sortable or unspecified
186                         } else if (currentSortableColumns != null && !currentSortableColumns.isEmpty()) {
187                             if (currentSortableColumns.contains(field.getPropertyName())) {
188                                 tableToolsColumnOptions.append(getDataFieldColumnOptions(collectionGroup, field) + ", ");
189                             } else {
190                                 tableToolsColumnOptions.append("{'" + UifConstants.TableToolsKeys.SORTABLE + "': " + UifConstants.TableToolsValues.FALSE + "}, ");
191                             }
192                         } else {//sortable columns not defined
193                             String colOptions = getDataFieldColumnOptions(collectionGroup, field);
194                             tableToolsColumnOptions.append(colOptions + " , ");
195                         }
196                     } else {
197                         String colOptions = constructTableColumnOptions(false, null, null);
198                         tableToolsColumnOptions.append(colOptions + " , ");
199                     }
200                 }
201             }
202 
203             if (collectionGroup.isRenderLineActions() && !collectionGroup.isReadOnly()) {
204                 String colOptions = constructTableColumnOptions(false, null, null);
205                 tableToolsColumnOptions.append(colOptions);
206             } else {
207                 tableToolsColumnOptions = new StringBuffer(StringUtils.removeEnd(tableToolsColumnOptions.toString(),
208                         ", "));
209             }
210 
211             tableToolsColumnOptions.append("]");
212 
213             getComponentOptions().put(UifConstants.TableToolsKeys.AO_COLUMNS, tableToolsColumnOptions.toString());
214        }
215     }
216 
217     /**
218      * construct the column options for a data field
219      * @param collectionGroup - the collectionGroup in which the data field is defined
220      * @param field - the field to construction options for
221      * @return - options as valid for datatable
222      */
223     private String getDataFieldColumnOptions(CollectionGroup collectionGroup, DataField field) {
224         String sortType = null;
225         if (!collectionGroup.isReadOnly() && (field instanceof InputField)
226                 && ((InputField) field).getControl() != null) {
227             Control control = ((InputField) field).getControl();
228             if (control instanceof SelectControl) {
229                 sortType = UifConstants.TableToolsValues.DOM_SELECT;
230             } else if (control instanceof CheckboxControl || control instanceof CheckboxGroupControl) {
231                 sortType = UifConstants.TableToolsValues.DOM_CHECK;
232             } else if (control instanceof RadioGroupControl) {
233                 sortType = UifConstants.TableToolsValues.DOM_RADIO;
234             } else {
235                 sortType = UifConstants.TableToolsValues.DOM_TEXT;
236             }
237         } else {
238             sortType = UifConstants.TableToolsValues.DOM_TEXT;
239         }
240 
241         Class dataTypeClass = ObjectPropertyUtils.getPropertyType(collectionGroup.getCollectionObjectClass(),
242                 field.getPropertyName());
243         return constructTableColumnOptions(true, dataTypeClass, sortType);
244     }
245 
246     /**
247      * Constructs the sort data type for each datatable columns.
248      */
249     protected String constructTableColumnOptions(boolean isSortable, Class dataTypeClass, String sortDataType) {
250         String colOptions = "null";
251 
252         String sortType = "";
253         if (!isSortable || dataTypeClass == null || sortType == null) {
254             colOptions = "\"" + UifConstants.TableToolsKeys.SORTABLE + "\" : false, \"sType\" : \"string\"";
255         } else {
256             if (ClassUtils.isAssignable(dataTypeClass, KualiPercent.class)) {
257                 sortType = UifConstants.TableToolsValues.PERCENT;
258             } else if (ClassUtils.isAssignable(dataTypeClass, KualiInteger.class) || ClassUtils.isAssignable(
259                     dataTypeClass, KualiDecimal.class)) {
260                 sortType = UifConstants.TableToolsValues.CURRENCY;
261             } else if (ClassUtils.isAssignable(dataTypeClass, Timestamp.class)) {
262                 sortType = "date";
263             } else if (ClassUtils.isAssignable(dataTypeClass, java.sql.Date.class) || ClassUtils.isAssignable(
264                     dataTypeClass, java.util.Date.class)) {
265                 sortType = UifConstants.TableToolsValues.DATE;
266             } else if (ClassUtils.isAssignable(dataTypeClass, Number.class)) {
267                 sortType = UifConstants.TableToolsValues.NUMERIC;
268             }
269             else {
270                 sortType = UifConstants.TableToolsValues.STRING;
271             }
272 
273             colOptions = "\"" + UifConstants.TableToolsKeys.SORT_DATA_TYPE + "\" : \"" + sortDataType + "\"";
274             colOptions += " , \"" + UifConstants.TableToolsKeys.SORT_TYPE + "\" : \"" + sortType + "\"";
275         }
276 
277         colOptions = "{" + colOptions + "}";
278 
279         return colOptions;
280     }
281 
282     /**
283      * Returns the text which is used to display text when the table is empty
284      *
285      * @return empty table message
286      */
287     public String getEmptyTableMessage() {
288         return emptyTableMessage;
289     }
290 
291     /**
292      * Setter for a text to be displayed when the table is empty
293      *
294      * @param emptyTableMessage
295      */
296     public void setEmptyTableMessage(String emptyTableMessage) {
297         this.emptyTableMessage = emptyTableMessage;
298     }
299 
300     /**
301      * Returns true if sorting is disabled
302      *
303      * @return the disableTableSort
304      */
305     public boolean isDisableTableSort() {
306         return this.disableTableSort;
307     }
308 
309     /**
310      * Enables/disables the table sorting
311      *
312      * @param disableTableSort the disableTableSort to set
313      */
314     public void setDisableTableSort(boolean disableTableSort) {
315         this.disableTableSort = disableTableSort;
316     }
317 
318     /**
319      * Returns true if search and export options are enabled
320      *
321      * @return the showSearchAndExportOptions
322      */
323     public boolean isShowSearchAndExportOptions() {
324         return this.showSearchAndExportOptions;
325     }
326 
327     /**
328      * Show/Hide the search and export options in tabletools
329      *
330      * @param showSearchAndExportOptions the showSearchAndExportOptions to set
331      */
332     public void setShowSearchAndExportOptions(boolean showSearchAndExportOptions) {
333         this.showSearchAndExportOptions = showSearchAndExportOptions;
334     }
335 
336     public Set<String> getHiddenColumns() {
337         return hiddenColumns;
338     }
339 
340     public void setHiddenColumns(Set<String> hiddenColumns) {
341         this.hiddenColumns = hiddenColumns;
342     }
343 
344     public Set<String> getSortableColumns() {
345         return sortableColumns;
346     }
347 
348     public void setSortableColumns(Set<String> sortableColumns) {
349         this.sortableColumns = sortableColumns;
350     }
351 }