Skip to content

Commit 80fcf4f

Browse files
committed
Switch to Apache POI for XLSX support. Fixes yarl#136
This has only received VERY LIMITED testing. It now writes .xlsx files and reads either .xls or .xlsx In addition to testing, packaging should also be reviewed. It may be possible to remove some of the bundled JARs (or better yet, switch to Maven for dependency management).
1 parent ae10043 commit 80fcf4f

19 files changed

+103
-67
lines changed

lib/SparseBitSet-1.2.jar

23.9 KB
Binary file not shown.

lib/commons-codec-1.15.jar

346 KB
Binary file not shown.

lib/commons-collections4-4.4.jar

734 KB
Binary file not shown.

lib/commons-compress-1.21.jar

994 KB
Binary file not shown.

lib/commons-io-2.11.0.jar

319 KB
Binary file not shown.

lib/commons-logging-1.2.jar

60.4 KB
Binary file not shown.

lib/commons-math3-3.6.1.jar

2.11 MB
Binary file not shown.

lib/curvesapi-1.07.jar

109 KB
Binary file not shown.

lib/jakarta.activation-2.0.1.jar

60.7 KB
Binary file not shown.

lib/jakarta.xml.bind-api-3.0.1.jar

126 KB
Binary file not shown.

lib/jxl.jar

-709 KB
Binary file not shown.

lib/log4j-api-2.18.0.jar

308 KB
Binary file not shown.

lib/poi-5.2.3.jar

2.83 MB
Binary file not shown.

lib/poi-ooxml-5.2.3.jar

1.92 MB
Binary file not shown.

lib/poi-ooxml-lite-5.2.3.jar

5.63 MB
Binary file not shown.

lib/slf4j-api-1.7.36.jar

40.2 KB
Binary file not shown.

lib/xmlbeans-5.1.1.jar

2.09 MB
Binary file not shown.

src/pattypan/panes/CreateFilePane.java

+43-31
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@
3030
import com.drew.metadata.exif.ExifSubIFDDirectory;
3131
import java.awt.Desktop;
3232
import java.io.File;
33+
import java.io.FileOutputStream;
3334
import java.io.IOException;
35+
import java.io.OutputStream;
3436
import java.text.SimpleDateFormat;
3537
import java.util.Date;
3638
import java.util.TimeZone;
@@ -40,13 +42,12 @@
4042
import javafx.scene.text.TextAlignment;
4143
import javafx.scene.text.TextFlow;
4244
import javafx.stage.Stage;
43-
import jxl.CellView;
44-
import jxl.Workbook;
45-
import jxl.read.biff.BiffException;
46-
import jxl.write.Label;
47-
import jxl.write.WritableSheet;
48-
import jxl.write.WritableWorkbook;
49-
import jxl.write.WriteException;
45+
import org.apache.poi.ss.usermodel.Cell;
46+
import org.apache.poi.ss.usermodel.CellType;
47+
import org.apache.poi.ss.usermodel.Row;
48+
import org.apache.poi.ss.usermodel.Sheet;
49+
import org.apache.poi.xssf.streaming.SXSSFSheet;
50+
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
5051
import pattypan.Session;
5152
import pattypan.Settings;
5253
import pattypan.Template;
@@ -103,7 +104,7 @@ private WikiPane setActions() {
103104
createSpreadsheet();
104105
showOpenFileButton();
105106
Settings.saveProperties();
106-
} catch (IOException | BiffException | WriteException ex) {
107+
} catch (IOException ex) {
107108
addElement(new WikiLabel("create-file-error"));
108109
Session.LOGGER.log(Level.WARNING,
109110
"Error occurred during creation of spreadsheet file: {0}",
@@ -135,43 +136,49 @@ private void showOpenFileButton() {
135136
nextButton.setVisible(true);
136137
}
137138

138-
private void autoSizeColumn(int column, WritableSheet sheet) {
139-
CellView cell = sheet.getColumnView(column);
140-
cell.setAutosize(true);
141-
sheet.setColumnView(column, cell);
139+
private void autoSizeColumn(int column, Sheet sheet) {
140+
sheet.autoSizeColumn(column);
142141
}
143142

144-
private void createSpreadsheet() throws IOException, BiffException, WriteException {
145-
File f = new File(Session.DIRECTORY, fileName.getText() + ".xls");
146-
WritableWorkbook workbook = Workbook.createWorkbook(f);
143+
private void createSpreadsheet() throws IOException {
144+
File f = new File(Session.DIRECTORY, fileName.getText() + ".xlsx");
145+
// Autosize appears to only be supported for OOXML workbooks, so making this specific instead of generic
146+
// boolean xml = true;
147+
// final Workbook workbook = xml ? new SXSSFWorkbook() : new HSSFWorkbook();
148+
final SXSSFWorkbook workbook = new SXSSFWorkbook();
147149

148150
createDataSheet(workbook);
149151
createTemplateSheet(workbook);
150152

151-
workbook.write();
153+
try (OutputStream os = new FileOutputStream(f)){
154+
workbook.write(os);
155+
os.flush();
156+
}
152157
workbook.close();
153158
Session.FILE = f;
154159
}
155160

156161
/**
157162
*
158163
* @param workbook
159-
* @throws WriteException
160164
*/
161-
private void createDataSheet(WritableWorkbook workbook) throws WriteException {
162-
WritableSheet sheet = workbook.createSheet("Data", 0);
165+
private void createDataSheet(SXSSFWorkbook workbook) {
166+
SXSSFSheet sheet = workbook.createSheet("Data");
163167

164168
// first row (header)
169+
Row header = sheet.createRow(0);
165170
int column = 0;
166171
for (String variable : Session.VARIABLES) {
167-
sheet.addCell(new Label(column++, 0, variable));
172+
Cell c = header.createCell(column++);
173+
c.setCellValue(variable);
168174
}
169175

170176
// next rows with path and name
171177
int row = 1;
172178
for (File file : Session.FILES) {
173-
sheet.addCell(new Label(0, row, file.getAbsolutePath()));
174-
sheet.addCell(new Label(1, row++, Util.getNameFromFilename(file.getName())));
179+
Row cells = sheet.createRow(row++);
180+
cells.createCell(0, CellType.STRING).setCellValue(file.getAbsolutePath());
181+
cells.createCell(1, CellType.STRING).setCellValue(Util.getNameFromFilename(file.getName()));
175182
}
176183

177184
if (Session.METHOD.equals("template")) {
@@ -181,7 +188,8 @@ private void createDataSheet(WritableWorkbook workbook) throws WriteException {
181188
column = Session.VARIABLES.indexOf(tf.name);
182189
row = 1;
183190
for (File file : Session.FILES) {
184-
sheet.addCell(new Label(column, row++, tf.value));
191+
// TODO: We may not have the cells created yet here. Let's see what happens
192+
sheet.getRow(row++).getCell(column).setCellValue(tf.value);
185193
}
186194
}
187195
}
@@ -191,32 +199,36 @@ private void createDataSheet(WritableWorkbook workbook) throws WriteException {
191199
if (column >= 0 && !Settings.getSetting("exifDate").isEmpty()) {
192200
row = 1;
193201
for (File file : Session.FILES) {
194-
sheet.addCell(new Label(column, row++, getExifDate(file)));
202+
// TODO: We may not have the cells created yet here. Let's see what happens
203+
sheet.getRow(row++).getCell(column).setCellValue(getExifDate(file));
195204
}
196205
}
197206

198-
for (int num = 0; num < sheet.getColumns(); num++) {
207+
sheet.trackAllColumnsForAutoSizing();
208+
for (int num = 0; num < sheet.getRow(0).getLastCellNum(); num++) {
199209
autoSizeColumn(num, sheet);
200210
}
201211
}
202212

203213
/**
204214
*
205215
* @param workbook
206-
* @throws WriteException
207216
*/
208-
private void createTemplateSheet(WritableWorkbook workbook) throws WriteException {
209-
WritableSheet templateSheet = workbook.createSheet("Template", 1);
210-
templateSheet.addCell(new Label(0, 0, "'" + Session.WIKICODE));
211-
// ^^
217+
private void createTemplateSheet(SXSSFWorkbook workbook) {
218+
SXSSFSheet templateSheet = workbook.createSheet("Template");
219+
Row row = templateSheet.createRow(0);
220+
Cell cell = row.createCell(0);
221+
cell.setCellValue("'" + Session.WIKICODE);
222+
// ^^
212223
// leading apostrophe prevents turning wikitext into formula in Excel
213224

225+
templateSheet.trackAllColumnsForAutoSizing();
214226
autoSizeColumn(0, templateSheet);
215227
}
216228

217229
/**
218230
*
219-
* @param filePath
231+
* @param file
220232
* @return
221233
*/
222234
private String getExifDate(File file) {

src/pattypan/panes/LoadPane.java

+60-36
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,22 @@
2323
*/
2424
package pattypan.panes;
2525

26-
import freemarker.core.InvalidReferenceException;
2726
import freemarker.template.Configuration;
2827
import freemarker.template.Template;
2928
import freemarker.template.TemplateException;
3029
import freemarker.template.TemplateExceptionHandler;
30+
import java.io.BufferedInputStream;
3131
import java.io.File;
32+
import java.io.FileInputStream;
3233
import java.io.IOException;
34+
import java.io.InputStream;
3335
import java.io.StringReader;
3436
import java.io.StringWriter;
3537
import java.text.SimpleDateFormat;
3638
import java.util.ArrayList;
39+
import java.util.Date;
3740
import java.util.HashMap;
41+
import java.util.List;
3842
import java.util.Map;
3943
import java.util.Set;
4044
import java.util.TimeZone;
@@ -43,13 +47,17 @@
4347
import javafx.scene.layout.VBox;
4448
import javafx.stage.FileChooser;
4549
import javafx.stage.Stage;
46-
import jxl.Cell;
47-
import jxl.CellType;
48-
import jxl.DateCell;
49-
import jxl.Sheet;
50-
import jxl.Workbook;
51-
import jxl.WorkbookSettings;
52-
import jxl.read.biff.BiffException;
50+
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
51+
import org.apache.poi.poifs.filesystem.FileMagic;
52+
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
53+
import org.apache.poi.ss.usermodel.Cell;
54+
import org.apache.poi.ss.usermodel.CellType;
55+
import org.apache.poi.ss.usermodel.DateUtil;
56+
import org.apache.poi.ss.usermodel.Row;
57+
import org.apache.poi.ss.usermodel.Sheet;
58+
import org.apache.poi.ss.usermodel.Workbook;
59+
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
60+
5361
import pattypan.Session;
5462
import pattypan.Settings;
5563
import pattypan.UploadElement;
@@ -236,10 +244,9 @@ private void addInfo(String text, String cssClass) {
236244
* @throws Exception when essential headers are missing
237245
*/
238246
private void readHeaders(Sheet sheet) throws Exception {
239-
int columns = sheet.getColumns();
240-
ArrayList<String> cols = new ArrayList<>();
241-
for (int col = 0; col < columns; col++) {
242-
cols.add(sheet.getCell(col, 0).getContents());
247+
List<String> cols = new ArrayList<>();
248+
for (Cell c : sheet.getRow(0)) {
249+
cols.add(c.getStringCellValue());
243250
}
244251

245252
if (cols.isEmpty()) {
@@ -264,18 +271,22 @@ private String getCellValue(Sheet sheet, int column, int row) {
264271
formatDate.setTimeZone(TimeZone.getTimeZone("UTC"));
265272
formatDateHour.setTimeZone(TimeZone.getTimeZone("UTC"));
266273

267-
Cell valueCell = sheet.getCell(column, row);
268-
String value;
274+
Cell valueCell = sheet.getRow(row).getCell(column);
275+
String value = null;
269276

270-
if (valueCell.getType() == CellType.DATE) {
271-
DateCell dateCell = (DateCell) valueCell;
277+
if (valueCell != null) {
278+
if (valueCell.getCellType() == CellType.NUMERIC && DateUtil.isCellDateFormatted(valueCell)) {
279+
Date date = DateUtil.getJavaDate(valueCell.getNumericCellValue());
280+
// FIXME: Restore more sophisticated date handling
281+
value = formatDate.format(date);
272282
//@TODO: more elegant hour detection
273-
value = dateCell.getContents().contains(":")
274-
? formatDateHour.format(dateCell.getDate())
275-
: formatDate.format(dateCell.getDate());
276-
} else {
277-
value = sheet.getCell(column, row).getContents().trim();
278-
}
283+
// value = dateCell.getContents().contains(":")
284+
// ? formatDateHour.format(dateCell.getDate())
285+
// : formatDate.format(dateCell.getDate());
286+
} else {
287+
value = valueCell.getStringCellValue().trim();
288+
}
289+
}
279290
return value;
280291
}
281292

@@ -294,9 +305,7 @@ private void loadSpreadsheet(File file) {
294305
readSpreadSheet();
295306
} catch (IOException ex) {
296307
addInfo("File error: there are problems opening file. It may be corrupted.");
297-
} catch (BiffException ex) {
298-
addInfo("File error: file needs to be saved in binnary format. Please save your file in \"Excel 97-2003 format\"");
299-
} catch (InvalidReferenceException ex) {
308+
} catch (TemplateException ex) {
300309
addInfo("File error: variables mismatch. Column headers variables must match wikitemplate variables.");
301310
} catch (Exception ex) {
302311
addInfo(ex.getMessage());
@@ -312,14 +321,27 @@ private void loadSpreadsheet(File file) {
312321
*/
313322
private ArrayList<Map<String, String>> readDescriptions(Sheet sheet) {
314323
ArrayList<Map<String, String>> descriptions = new ArrayList<>();
315-
int rows = sheet.getRows();
316-
int columns = sheet.getColumns();
324+
int rows = sheet.getLastRowNum();
325+
int columns = sheet.getRow(0).getLastCellNum();
317326

327+
// Collect header labels
328+
String[] labels = new String[columns];
329+
Row cells = sheet.getRow(0);
330+
for (int col = 0; col < columns; col++) {
331+
Cell cell = cells.getCell(col);
332+
if (cell != null) {
333+
String value = cell.getStringCellValue();
334+
labels[col] = value;
335+
} else {
336+
labels[col] = null;
337+
}
338+
}
318339
for (int row = 1; row < rows; row++) {
319340
Map<String, String> description = new HashMap();
341+
cells = sheet.getRow(row);
320342
for (int column = 0; column < columns; column++) {
321-
String label = sheet.getCell(column, 0).getContents().trim();
322-
if (label.isEmpty()) {
343+
String label = labels[column];
344+
if (label == null || label.isEmpty()) {
323345
continue;
324346
}
325347
String value = getCellValue(sheet, column, row);
@@ -333,17 +355,19 @@ private ArrayList<Map<String, String>> readDescriptions(Sheet sheet) {
333355
/**
334356
* Reads spreadsheet stored in Session.FILE.
335357
*/
336-
private void readSpreadSheet() throws BiffException, IOException, Exception {
358+
private void readSpreadSheet() throws IOException, TemplateException, Exception {
337359
infoContainer.getChildren().clear();
338360
Session.SCENES.remove("CheckPane");
339361

340-
WorkbookSettings ws = new WorkbookSettings();
341-
ws.setEncoding("Cp1252");
362+
InputStream inputStream = new BufferedInputStream(new FileInputStream(Session.FILE));
363+
Workbook wb = FileMagic.valueOf(inputStream) == FileMagic.OOXML ? new XSSFWorkbook(inputStream)
364+
: new HSSFWorkbook(new POIFSFileSystem(inputStream));
365+
366+
// ws.setEncoding("Cp1252"); // FIXME
342367

343368
try {
344-
Workbook workbook = Workbook.getWorkbook(Session.FILE, ws);
345-
Sheet dataSheet = workbook.getSheet(0);
346-
Sheet templateSheet = workbook.getSheet(1);
369+
Sheet dataSheet = wb.getSheetAt(0);
370+
Sheet templateSheet = wb.getSheetAt(1);
347371
readHeaders(dataSheet);
348372
addFilesToUpload(readDescriptions(dataSheet), readTemplate(templateSheet));
349373
} catch (IndexOutOfBoundsException ex) {
@@ -362,7 +386,7 @@ private void readSpreadSheet() throws BiffException, IOException, Exception {
362386
*/
363387
private Template readTemplate(Sheet sheet) throws Exception {
364388
try {
365-
String text = sheet.getCell(0, 0).getContents();
389+
String text = sheet.getRow(0).getCell(0).getStringCellValue();
366390
return new Template("wikitemplate", new StringReader(text), cfg);
367391
} catch (ArrayIndexOutOfBoundsException ex) {
368392
throw new Exception("Error: template in spreadsheet looks empty. Check if wikitemplate is present in second tab of your spreadsheet (first row and first column).");

0 commit comments

Comments
 (0)