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