
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 String s = fixSheetNameChars(name); 104 if (sheetNames.containsKey(s)) { 105 int i = 1; 106 do { 107 i++; 108 s = name+" "+Integer.toString(i); 109 } while (sheetNames.containsKey(s)); 110 } 111 Sheet res = wb.createSheet(s); 112 sheetNames.put(s, res); 113 return res; 114 } 115 116 private String fixSheetNameChars(String name) { 117 StringBuilder b = new StringBuilder(); 118 for (char ch : name.toCharArray()) { 119 switch (ch) { 120 case '/': 121 case '\\': 122 case '?': 123 case '*': 124 case ']': 125 case '[': 126 case ':': 127 b.append('_'); 128 break; 129 default: 130 b.append(ch); 131 } 132 } 133 return b.toString(); 134 } 135 136 private static Map<String, CellStyle> createStyles(Workbook wb){ 137 Map<String, CellStyle> styles = new HashMap<>(); 138 139 CellStyle style; 140 Font headerFont = wb.createFont(); 141 headerFont.setBold(true); 142 style = createBorderedStyle(wb); 143 style.setFillForegroundColor(IndexedColors.LIGHT_CORNFLOWER_BLUE.getIndex()); 144 style.setFillPattern(FillPatternType.SOLID_FOREGROUND); 145 style.setVerticalAlignment(VerticalAlignment.TOP); 146 style.setWrapText(true); 147 style.setFont(headerFont); 148 styles.put("header", style); 149 150 style = createBorderedStyle(wb); 151 style.setVerticalAlignment(VerticalAlignment.TOP); 152 style.setWrapText(true); 153 styles.put("body", style); 154 155 return styles; 156 } 157 158 private static CellStyle createBorderedStyle(Workbook wb){ 159 BorderStyle thin = BorderStyle.THIN; 160 short black = IndexedColors.GREY_50_PERCENT.getIndex(); 161 162 CellStyle style = wb.createCellStyle(); 163 style.setBorderRight(thin); 164 style.setRightBorderColor(black); 165 style.setBorderBottom(thin); 166 style.setBottomBorderColor(black); 167 style.setBorderLeft(thin); 168 style.setLeftBorderColor(black); 169 style.setBorderTop(thin); 170 style.setTopBorderColor(black); 171 return style; 172 } 173 174 protected void addCell(Row row, int pos, String content) { 175 addCell(row, pos, content, styles.get("body")); 176 } 177 178 protected void addCell(Row row, int pos, boolean b) { 179 addCell(row, pos, b ? "Y" : ""); 180 } 181 182 protected void addCell(Row row, int pos, int content) { 183 addCell(row, pos, Integer.toString(content)); 184 } 185 186 protected void addCell(Row row, int pos, String content, CellStyle style) { 187 Cell cell = row.createCell(pos); 188 cell.setCellValue(content); 189 cell.setCellStyle(style); 190 } 191 192 protected int columnPixels(double columns) { 193 double WIDTH_FACTOR = 256; 194 double PADDING = 180; 195 return (int)Math.floor(columns*WIDTH_FACTOR + PADDING); 196 } 197 198 protected void addHeaders(Sheet sheet, String... titles) { 199 Row headerRow = sheet.createRow(sheet.getRow(0) == null ? 0 : sheet.getLastRowNum()+1); 200 for (int i = 0; i < titles.length; i++) { 201 addCell(headerRow, i, titles[i], styles.get("header")); 202 } 203 } 204 205 protected void addRow(Sheet sheet, String... values) { 206 Row row = sheet.createRow(sheet.getLastRowNum()+1); 207 208 for (int i = 0; i < values.length; i++) { 209 addCell(row, i, values[i], styles.get("body")); 210 } 211 } 212 213}