001/** 002 * Copyright 2005-2018 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.collections; 017 018import org.kuali.rice.krad.uif.container.CollectionGroup; 019import org.kuali.rice.krad.uif.element.Label; 020import org.kuali.rice.krad.uif.field.Field; 021import org.kuali.rice.krad.uif.layout.TableLayoutManager; 022import org.kuali.rice.krad.util.KRADUtils; 023 024import java.util.ArrayList; 025import java.util.HashMap; 026import java.util.List; 027import java.util.Map; 028 029/** 030 * @author Kuali Rice Team (rice.collab@kuali.org) 031 */ 032public class TableExporter { 033 034 /** 035 * Generates formatted table data based on the posted view results and format type. 036 * 037 * @param collectionGroup collection group instance that should be exported 038 * @param model top level object containing the data 039 * @param formatType format which the table should be generated in 040 * @return generated table data 041 */ 042 public static String buildExportTableData(CollectionGroup collectionGroup, Object model, String formatType) { 043 // load table format elements used for generated particular style 044 Map<String, String> exportTableFormatOptions = getExportTableFormatOptions(formatType); 045 String startTable = exportTableFormatOptions.get("startTable"); 046 String endTable = exportTableFormatOptions.get("endTable"); 047 048 StringBuilder tableRows = new StringBuilder(""); 049 050 TableLayoutManager layoutManager = (TableLayoutManager) collectionGroup.getLayoutManager(); 051 052 List<Label> headerLabels = layoutManager.getHeaderLabels(); 053 List<Field> rowFields = layoutManager.getAllRowFields(); 054 int numberOfColumns = layoutManager.getNumberOfColumns(); 055 056 List<Integer> ignoredColumns = findIgnoredColumns(layoutManager, collectionGroup); 057 058 // append table header data as first row 059 if (!headerLabels.isEmpty()) { 060 List<String> labels = new ArrayList<String>(); 061 062 for (Label label : headerLabels) { 063 labels.add(label.getLabelText()); 064 } 065 066 tableRows.append(buildExportTableRow(labels, exportTableFormatOptions, ignoredColumns)); 067 } 068 069 // load all subsequent rows to the table 070 if (!rowFields.isEmpty()) { 071 List<String> columnData = new ArrayList<String>(); 072 073 for (Field field : rowFields) { 074 columnData.add(KRADUtils.getSimpleFieldValue(model, field)); 075 076 if (columnData.size() >= numberOfColumns) { 077 tableRows.append(buildExportTableRow(columnData, exportTableFormatOptions, ignoredColumns)); 078 columnData.clear(); 079 } 080 } 081 } 082 083 return startTable + tableRows.toString() + endTable; 084 } 085 086 /** 087 * Helper function to determine whether if column should be displayed. Used to help extract 088 * columns used in screen format such as action or select that is not needed for export. 089 * 090 * @param layoutManager The layout manager. 091 * @param collectionGroup The collection group. 092 * @return Index numbers for all columns that should be ignored. 093 */ 094 protected static List<Integer> findIgnoredColumns(TableLayoutManager layoutManager, 095 CollectionGroup collectionGroup) { 096 List<Integer> ignoreColumns = new ArrayList<Integer>(); 097 098 int actionColumnIndex = layoutManager.getActionColumnIndex(); 099 int numberOfColumns = layoutManager.getNumberOfColumns(); 100 boolean renderActions = collectionGroup.isRenderLineActions() && !Boolean.TRUE.equals(collectionGroup.getReadOnly()); 101 boolean renderSelectField = collectionGroup.isIncludeLineSelectionField(); 102 boolean renderSequenceField = layoutManager.isRenderSequenceField(); 103 104 if (renderActions || renderSelectField || renderSequenceField) { 105 int shiftColumn = 0; 106 107 if (renderSelectField) { 108 ignoreColumns.add(shiftColumn); 109 shiftColumn++; 110 } 111 if (renderSequenceField) { 112 ignoreColumns.add(shiftColumn); 113 shiftColumn++; 114 } 115 if (renderActions) { 116 if (actionColumnIndex == 1) { 117 ignoreColumns.add(shiftColumn); 118 } else if (actionColumnIndex == -1) { 119 ignoreColumns.add(numberOfColumns - 1); 120 } else if (actionColumnIndex > 1) { 121 ignoreColumns.add(actionColumnIndex); 122 } 123 } 124 } 125 126 return ignoreColumns; 127 } 128 129 /** 130 * Helper method used to build formatted table row data for export. 131 * 132 * @param columnData Formatted column data. 133 * @param tableFormatOptions Format options: startRow and endRow are added to the row, 134 * startColumn and endColumn are added to each column. 135 * @param ignoredColumns Index numbers of columns to ignore. 136 * @return Formatted table data for one row. 137 */ 138 protected static String buildExportTableRow(List<String> columnData, Map<String, String> tableFormatOptions, 139 List<Integer> ignoredColumns) { 140 String startRow = tableFormatOptions.get("startRow"); 141 String endRow = tableFormatOptions.get("endRow"); 142 String startColumn = tableFormatOptions.get("startColumn"); 143 String endColumn = tableFormatOptions.get("endColumn"); 144 boolean appendLastColumn = Boolean.valueOf(tableFormatOptions.get("appendLastColumn")); 145 int columnIndex = 0; 146 147 StringBuilder builder = new StringBuilder(); 148 for (String columnItem : columnData) { 149 boolean displayColumn = !ignoredColumns.contains(columnIndex); 150 if (displayColumn) { 151 builder.append(startColumn + columnItem + endColumn); 152 } 153 if (columnIndex >= columnData.size() - 1 && !appendLastColumn) { 154 builder.delete(builder.length() - endColumn.length(), builder.length()); 155 } 156 columnIndex++; 157 } 158 159 return startRow + builder.toString() + endRow; 160 } 161 162 /** 163 * Identify table formatting elements based on formatType. Defaults to txt format if not found 164 * 165 * @param formatType The format type: csv, xls, or xml. 166 * @return The format options for to use with the indicated format type. 167 */ 168 protected static Map<String, String> getExportTableFormatOptions(String formatType) { 169 HashMap<String, String> map = new HashMap<String, String>(); 170 171 map.put("contentType", "text/plain"); 172 map.put("formatType", "txt"); 173 map.put("startTable", ""); 174 map.put("endTable", ""); 175 map.put("startRow", ""); 176 map.put("endRow", "\n"); 177 map.put("startColumn", ""); 178 map.put("endColumn", ", "); 179 map.put("appendLastColumn", "false"); 180 181 if ("csv".equals(formatType)) { 182 map.put("contentType", "text/csv"); 183 map.put("formatType", "csv"); 184 map.put("startTable", ""); 185 map.put("endTable", ""); 186 map.put("startRow", ""); 187 map.put("endRow", "\n"); 188 map.put("startColumn", ""); 189 map.put("endColumn", ", "); 190 map.put("appendLastColumn", "false"); 191 192 } else if ("xls".equals(formatType)) { 193 map.put("contentType", "application/vnd.ms-excel"); 194 map.put("formatType", "xls"); 195 map.put("startTable", ""); 196 map.put("endTable", ""); 197 map.put("startRow", ""); 198 map.put("endRow", "\n"); 199 map.put("startColumn", "\""); 200 map.put("endColumn", "\"\t"); 201 map.put("appendLastColumn", "true"); 202 203 } else if ("xml".equals(formatType)) { 204 map.put("contentType", "application/xml"); 205 map.put("formatType", "xml"); 206 map.put("startTable", "<table>\n"); 207 map.put("endTable", "</table>\n"); 208 map.put("startRow", " <row>\n"); 209 map.put("endRow", " </row>\n"); 210 map.put("startColumn", " <column>"); 211 map.put("endColumn", "</column>\n"); 212 map.put("appendLastColumn", "true"); 213 214 } 215 216 return map; 217 } 218}