beginnings of excel export

This commit is contained in:
Greg DiCristofaro 2021-02-24 15:44:41 -05:00
parent 882c0a0635
commit fd0838f4b4
7 changed files with 574 additions and 0 deletions

View File

@ -0,0 +1,66 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.sleuthkit.autopsy.datasourcesummary.uiutils;
import javax.swing.JLabel;
/**
* Basic interface for a cell model.
*/
public interface CellModel {
/**
* Describes the horizontal alignment.
*/
public enum HorizontalAlign {
LEFT(JLabel.LEFT),
CENTER(JLabel.CENTER),
RIGHT(JLabel.RIGHT);
private final int jlabelAlignment;
/**
* Constructor for a HorizontalAlign enum.
*
* @param jlabelAlignment The corresponding JLabel horizontal alignment
* number.
*/
HorizontalAlign(int jlabelAlignment) {
this.jlabelAlignment = jlabelAlignment;
}
/**
* @return The corresponding JLabel horizontal alignment (i.e.
* JLabel.LEFT).
*/
int getJLabelAlignment() {
return this.jlabelAlignment;
}
}
/**
* @return The root data object.
*/
Object getData();
/**
* @return The text to be shown in the cell.
*/
default String getText() {
Object data = getData();
return (data == null) ? null : data.toString();
}
/**
* @return The tooltip (if any) to be displayed in the cell.
*/
String getTooltip();
/**
* @return The horizontal alignment for the text in the cell.
*/
HorizontalAlign getHorizontalAlignment();
}

View File

@ -0,0 +1,71 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.sleuthkit.autopsy.datasourcesummary.uiutils;
import java.util.function.Function;
/**
*
* @author gregd
*/
/**
* Describes aspects of a column which can be used with getTableModel or
* getJTablePanel. 'T' represents the object that will represent rows in the
* table.
*/
public class ColumnModel<T, C extends CellModel> {
private final String headerTitle;
private final Function<T, ? extends C> cellRenderer;
private final Integer width;
/**
* Constructor for a DataResultColumnModel.
*
* @param headerTitle The title for the column.
* @param cellRenderer The method that generates a CellModel for the column
* based on the data.
*/
public ColumnModel(String headerTitle, Function<T, ? extends C> cellRenderer) {
this(headerTitle, cellRenderer, null);
}
/**
* Constructor for a DataResultColumnModel.
*
* @param headerTitle The title for the column.
* @param cellRenderer The method that generates a CellModel for the column
* based on the data.
* @param width The preferred width of the column.
*/
public ColumnModel(String headerTitle, Function<T, ? extends C> cellRenderer, Integer width) {
this.headerTitle = headerTitle;
this.cellRenderer = cellRenderer;
this.width = width;
}
/**
* @return The title for the column.
*/
public String getHeaderTitle() {
return headerTitle;
}
/**
* @return The method that generates a CellModel for the column based on the
* data.
*/
public Function<T, ? extends C> getCellRenderer() {
return cellRenderer;
}
/**
* @return The preferred width of the column (can be null).
*/
public Integer getWidth() {
return width;
}
}

View File

@ -0,0 +1,159 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.sleuthkit.autopsy.datasourcesummary.uiutils;
import java.awt.Insets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.function.Supplier;
/**
*
* @author gregd
*/
/**
* The default cell model.
*/
public class DefaultCellModel<T> implements GuiCellModel, ExcelCellModel {
private final T data;
private final Function<T, String> stringConverter;
String tooltip;
CellModel.HorizontalAlign horizontalAlignment;
Insets insets;
List<MenuItem> popupMenu;
Supplier<List<MenuItem>> menuItemSupplier;
private final String excelFormatString;
/**
* Main constructor.
*
* @param text The text to be displayed in the cell.
*/
public DefaultCellModel(T data) {
this(data, null, null);
}
public DefaultCellModel(T data, Function<T, String> stringConverter, String excelFormatString) {
this.data = data;
this.stringConverter = stringConverter;
this.excelFormatString = excelFormatString;
}
@Override
public T getData() {
return this.data;
}
@Override
public String getExcelFormatString() {
return this.excelFormatString;
}
@Override
public String getText() {
if (this.stringConverter == null) {
return this.data == null ? "" : this.data.toString();
} else {
return this.stringConverter.apply(this.data);
}
}
@Override
public String getTooltip() {
return tooltip;
}
/**
* Sets the tooltip for this cell model.
*
* @param tooltip The tooltip for the cell model.
*
* @return As a utility, returns this.
*/
public DefaultCellModel setTooltip(String tooltip) {
this.tooltip = tooltip;
return this;
}
@Override
public HorizontalAlign getHorizontalAlignment() {
return horizontalAlignment;
}
/**
* Sets the horizontal alignment for this cell model.
*
* @param alignment The horizontal alignment for the cell model.
*
* @return As a utility, returns this.
*/
public DefaultCellModel setHorizontalAlignment(CellModel.HorizontalAlign alignment) {
this.horizontalAlignment = alignment;
return this;
}
@Override
public Insets getInsets() {
return insets;
}
/**
* Sets the insets for the text within the cell
*
* @param insets The insets.
*
* @return As a utility, returns this.
*/
public DefaultCellModel setInsets(Insets insets) {
this.insets = insets;
return this;
}
@Override
public List<MenuItem> getPopupMenu() {
if (popupMenu != null) {
return Collections.unmodifiableList(popupMenu);
}
if (menuItemSupplier != null) {
return this.menuItemSupplier.get();
}
return null;
}
/**
* Sets a function to lazy load the popup menu items.
*
* @param menuItemSupplier The lazy load function for popup items.
* @return
*/
public DefaultCellModel setPopupMenuRetriever(Supplier<List<MenuItem>> menuItemSupplier) {
this.menuItemSupplier = menuItemSupplier;
return this;
}
/**
* Sets the list of items for a popup menu
*
* @param popupMenu
* @return As a utility, returns this.
*/
public DefaultCellModel setPopupMenu(List<MenuItem> popupMenu) {
this.popupMenu = popupMenu == null ? null : new ArrayList<>(popupMenu);
return this;
}
@Override
public String toString() {
return getText();
}
}

View File

@ -0,0 +1,18 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.sleuthkit.autopsy.datasourcesummary.uiutils;
/**
* Basic interface for a cell model.
*/
public interface ExcelCellModel extends CellModel {
/**
* @return The format string to be used with Apache POI during excel export
* or null if none necessary.
*/
String getExcelFormatString();
}

View File

@ -0,0 +1,156 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.sleuthkit.autopsy.datasourcesummary.uiutils;
import java.io.FileOutputStream;
import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.logging.Logger;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
/**
*
* @author gregd
*/
public class ExcelExport {
private static final Logger logger = Logger.getLogger(ExcelExport.class.getName());
public static void main(String[] args) throws IOException {
// Create a Workbook
Workbook workbook = new XSSFWorkbook(); // new HSSFWorkbook() for generating `.xls` file
// Create a Font for styling header cells
Font headerFont = workbook.createFont();
headerFont.setBold(true);
//headerFont.setFontHeightInPoints((short) 14);
// Create a CellStyle with the font
CellStyle headerCellStyle = workbook.createCellStyle();
headerCellStyle.setFont(headerFont);
createSheet(workbook, headerCellStyle, GeolocationDTO.TEMPLATE_1, dtos1);
createSheet(workbook, headerCellStyle, GeolocationDTO.TEMPLATE_2, dtos2);
// Write the output to a file
FileOutputStream fileOut = new FileOutputStream("C:\\Users\\gregd\\Desktop\\datasourcesummary-export.xlsx");
workbook.write(fileOut);
fileOut.close();
// Closing the workbook
workbook.close();
}
public static <T, C extends ExcelCellModel> Sheet createSheet(
Workbook workbook, CellStyle headerCellStyle, TableTemplate<T, C> tableTemplate, List<T> data)
throws IllegalArgumentException {
if (workbook == null || tableTemplate == null) {
throw new IllegalArgumentException("workbook and tableTemplate parameters cannot be null");
}
List<ColumnModel<T, C>> columns = tableTemplate.getColumns() != null
? tableTemplate.getColumns()
: Collections.emptyList();
List<T> safeData = data == null ? Collections.emptyList() : data;
Sheet sheet = workbook.createSheet(tableTemplate.getTabName());
// Create a header row
Row headerRow = sheet.createRow(0);
// Create header cells
for (int i = 0; i < columns.size(); i++) {
Cell cell = headerRow.createCell(i);
cell.setCellValue(columns.get(i).getHeaderTitle());
cell.setCellStyle(headerCellStyle);
}
// freeze header row
sheet.createFreezePane(0, 1);
// Create Cell Style for each column (if one is needed)
Map<String, CellStyle> cellStyles = new HashMap<>();
for (int rowNum = 0; rowNum < safeData.size(); rowNum++) {
T rowData = safeData.get(rowNum);
Row row = sheet.createRow(rowNum + 1);
for (int colNum = 0; colNum < columns.size(); colNum++) {
ColumnModel<T, ? extends ExcelCellModel> colModel = columns.get(colNum);
ExcelCellModel cellModel = colModel.getCellRenderer().apply(rowData);
String formatString = cellModel.getExcelFormatString();
Optional<CellStyle> cellStyle = (formatString == null)
? Optional.empty()
: Optional.of(cellStyles.computeIfAbsent(formatString, (k) -> getCellStyles(workbook, formatString)));
createCell(row, colNum, cellModel, cellStyle);
}
}
// Resize all columns to fit the content size
for (int i = 0; i < columns.size(); i++) {
sheet.autoSizeColumn(i);
}
return sheet;
}
private static Cell createCell(Row row, int colNum, ExcelCellModel cellModel, Optional<CellStyle> cellStyle) {
Object cellData = cellModel.getData();
Cell cell = row.createCell(colNum);
if (cellData instanceof Calendar) {
cell.setCellValue((Calendar) cellData);
} else if (cellData instanceof Date) {
cell.setCellValue((Date) cellData);
} else if (cellData instanceof Double) {
cell.setCellValue((Double) cellData);
} else if (cellData instanceof LocalDate) {
cell.setCellValue((LocalDate) cellData);
} else if (cellData instanceof LocalDateTime) {
cell.setCellValue((LocalDateTime) cellData);
} else if (cellData instanceof String) {
cell.setCellValue((String) cellData);
} else if (cellData instanceof Short) {
cell.setCellValue((Short) cellData);
} else if (cellData instanceof Integer) {
cell.setCellValue((Integer) cellData);
} else if (cellData instanceof Long) {
cell.setCellValue((Long) cellData);
} else if (cellData instanceof Float) {
cell.setCellValue((Float) cellData);
} else {
cell.setCellValue(cellModel.getText());
}
cellStyle.ifPresent((cs) -> cell.setCellStyle(cs));
return cell;
}
private static <T> CellStyle getCellStyles(Workbook workbook, String formatString) {
CellStyle cellStyle = workbook.createCellStyle();
cellStyle.setDataFormat(workbook.getCreationHelper().createDataFormat().getFormat(formatString));
return cellStyle;
}
}

View File

@ -0,0 +1,73 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.sleuthkit.autopsy.datasourcesummary.uiutils;
import java.awt.Insets;
import java.util.List;
/**
* Basic interface for a cell model.
*/
public interface GuiCellModel extends CellModel {
/**
* A menu item to be used within a popup menu.
*/
public interface MenuItem {
/**
* @return The title for that popup menu item.
*/
String getTitle();
/**
* @return The action if that popup menu item is clicked.
*/
Runnable getAction();
}
/**
* Default implementation of a menu item.
*/
public static class DefaultMenuItem implements MenuItem {
private final String title;
private final Runnable action;
/**
* Main constructor.
*
* @param title The title for the menu item.
* @param action The action should the menu item be clicked.
*/
public DefaultMenuItem(String title, Runnable action) {
this.title = title;
this.action = action;
}
@Override
public String getTitle() {
return title;
}
@Override
public Runnable getAction() {
return action;
}
}
/**
* @return The insets for the cell text.
*/
Insets getInsets();
/**
* @return The popup menu associated with this cell or null if no popup menu
* should be shown for this cell.
*/
List<MenuItem> getPopupMenu();
}

View File

@ -0,0 +1,31 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.sleuthkit.autopsy.datasourcesummary.uiutils;
import java.util.List;
/**
*
* @author gregd
*/
public class TableTemplate<T, C extends CellModel> {
private final List<ColumnModel<T, C>> columns;
private final String tabName;
public TableTemplate(List<ColumnModel<T, C>> columns, String tabName) {
this.columns = columns;
this.tabName = tabName;
}
public List<ColumnModel<T, C>> getColumns() {
return columns;
}
public String getTabName() {
return tabName;
}
}