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