
001package org.hl7.fhir.r5.renderers.spreadsheets; 002 003import java.io.IOException; 004import java.io.OutputStream; 005import java.util.ArrayList; 006import java.util.HashMap; 007import java.util.List; 008import java.util.Map; 009 010import org.apache.poi.ss.usermodel.BorderStyle; 011import org.apache.poi.ss.usermodel.Cell; 012import org.apache.poi.ss.usermodel.CellStyle; 013import org.apache.poi.ss.usermodel.FillPatternType; 014import org.apache.poi.ss.usermodel.Font; 015import org.apache.poi.ss.usermodel.IndexedColors; 016import org.apache.poi.ss.usermodel.Row; 017import org.apache.poi.ss.usermodel.Sheet; 018import org.apache.poi.ss.usermodel.VerticalAlignment; 019import org.apache.poi.ss.usermodel.Workbook; 020import org.apache.poi.xssf.usermodel.XSSFWorkbook; 021import org.hl7.fhir.exceptions.FHIRException; 022import org.hl7.fhir.r5.context.IWorkerContext; 023import org.hl7.fhir.r5.renderers.DataRenderer; 024import org.hl7.fhir.utilities.MarkedToMoveToAdjunctPackage; 025 026import com.microsoft.schemas.office.visio.x2012.main.ShapeSheetType; 027 028/* 029 Copyright (c) 2011+, HL7, Inc. 030 All rights reserved. 031 032 Redistribution and use in source and binary forms, with or without modification, 033 are permitted provided that the following conditions are met: 034 035 * Redistributions of source code must retain the above copyright notice, this 036 list of conditions and the following disclaimer. 037 * Redistributions in binary form must reproduce the above copyright notice, 038 this list of conditions and the following disclaimer in the documentation 039 and/or other materials provided with the distribution. 040 * Neither the name of HL7 nor the names of its contributors may be used to 041 endorse or promote products derived from this software without specific 042 prior written permission. 043 044 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 045 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 046 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 047 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 048 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 049 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 050 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 051 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 052 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 053 POSSIBILITY OF SUCH DAMAGE. 054 055 */ 056 057 058 059@MarkedToMoveToAdjunctPackage 060public class SpreadsheetGenerator { 061 062 private static final int MAX_SENSITIVE_SHEET_NAME_LEN = 31; 063 064 protected IWorkerContext context; 065 066 protected XSSFWorkbook wb = new XSSFWorkbook(); 067 protected Map<String, CellStyle> styles; 068 069 protected DataRenderer dr; 070 private Map<String, Sheet> sheetNames = new HashMap<>(); 071 072 public SpreadsheetGenerator(IWorkerContext context) { 073 super(); 074 this.context = context; 075 styles = createStyles(wb); 076 dr = new DataRenderer(context); 077 } 078 079 public void finish(OutputStream outStream) throws IOException { 080 wb.write(outStream); 081 outStream.flush(); 082 outStream.close(); 083 } 084 085 protected boolean hasSheet(String name) { 086 if (name.length() > MAX_SENSITIVE_SHEET_NAME_LEN - 2) { 087 name = name.substring(0, MAX_SENSITIVE_SHEET_NAME_LEN - 2); 088 } 089 String s = fixSheetNameChars(name); 090 return sheetNames.containsKey(s); 091 } 092 093 protected Sheet getSheet(String name) { 094 if (name.length() > MAX_SENSITIVE_SHEET_NAME_LEN - 2) { 095 name = name.substring(0, MAX_SENSITIVE_SHEET_NAME_LEN - 2); 096 } 097 String s = fixSheetNameChars(name); 098 return sheetNames.get(s); 099 } 100 101 protected Sheet makeSheet(String name) { 102 if (name.length() > MAX_SENSITIVE_SHEET_NAME_LEN - 2) { 103 name = name.substring(0, MAX_SENSITIVE_SHEET_NAME_LEN - 2); 104 } 105 name = fixSheetNameChars(name); 106 String s = name; 107 if (sheetNames.containsKey(s)) { 108 int i = 1; 109 do { 110 i++; 111 s = name+" "+Integer.toString(i); 112 } while (sheetNames.containsKey(s)); 113 } 114 Sheet res = wb.createSheet(s); 115 sheetNames.put(s, res); 116 return res; 117 } 118 119 private String fixSheetNameChars(String name) { 120 StringBuilder b = new StringBuilder(); 121 for (char ch : name.toCharArray()) { 122 switch (ch) { 123 case '/': 124 case '\\': 125 case '?': 126 case '*': 127 case ']': 128 case '[': 129 case ':': 130 b.append('_'); 131 break; 132 default: 133 b.append(ch); 134 } 135 } 136 return b.toString(); 137 } 138 139 private static Map<String, CellStyle> createStyles(Workbook wb){ 140 Map<String, CellStyle> styles = new HashMap<>(); 141 142 CellStyle style; 143 Font headerFont = wb.createFont(); 144 headerFont.setBold(true); 145 style = createBorderedStyle(wb); 146 style.setFillForegroundColor(IndexedColors.LIGHT_CORNFLOWER_BLUE.getIndex()); 147 style.setFillPattern(FillPatternType.SOLID_FOREGROUND); 148 style.setVerticalAlignment(VerticalAlignment.TOP); 149 style.setWrapText(true); 150 style.setFont(headerFont); 151 styles.put("header", style); 152 153 style = createBorderedStyle(wb); 154 style.setVerticalAlignment(VerticalAlignment.TOP); 155 style.setWrapText(true); 156 styles.put("body", style); 157 158 return styles; 159 } 160 161 private static CellStyle createBorderedStyle(Workbook wb){ 162 BorderStyle thin = BorderStyle.THIN; 163 short black = IndexedColors.GREY_50_PERCENT.getIndex(); 164 165 CellStyle style = wb.createCellStyle(); 166 style.setBorderRight(thin); 167 style.setRightBorderColor(black); 168 style.setBorderBottom(thin); 169 style.setBottomBorderColor(black); 170 style.setBorderLeft(thin); 171 style.setLeftBorderColor(black); 172 style.setBorderTop(thin); 173 style.setTopBorderColor(black); 174 return style; 175 } 176 177 protected void addCell(Row row, int pos, String content) { 178 addCell(row, pos, content, styles.get("body")); 179 } 180 181 protected void addCell(Row row, int pos, boolean b) { 182 addCell(row, pos, b ? "Y" : ""); 183 } 184 185 protected void addCell(Row row, int pos, int content) { 186 addCell(row, pos, Integer.toString(content)); 187 } 188 189 protected void addCell(Row row, int pos, String content, CellStyle style) { 190 Cell cell = row.createCell(pos); 191 cell.setCellValue(content); 192 cell.setCellStyle(style); 193 } 194 195 protected int columnPixels(double columns) { 196 double WIDTH_FACTOR = 256; 197 double PADDING = 180; 198 return (int)Math.floor(columns*WIDTH_FACTOR + PADDING); 199 } 200 201 protected void addHeaders(Sheet sheet, String... titles) { 202 Row headerRow = sheet.createRow(sheet.getRow(0) == null ? 0 : sheet.getLastRowNum()+1); 203 for (int i = 0; i < titles.length; i++) { 204 addCell(headerRow, i, titles[i], styles.get("header")); 205 } 206 } 207 208 protected void addRow(Sheet sheet, String... values) { 209 Row row = sheet.createRow(sheet.getLastRowNum()+1); 210 211 for (int i = 0; i < values.length; i++) { 212 addCell(row, i, values[i], styles.get("body")); 213 } 214 } 215 216 public void dump() { 217 wb = null; 218 styles = null; 219 dr = null; 220 sheetNames = null; 221 } 222}