diff --git a/OutlawEditor/pom.xml b/OutlawEditor/pom.xml
index dfb98eaa..a09f2107 100644
--- a/OutlawEditor/pom.xml
+++ b/OutlawEditor/pom.xml
@@ -182,5 +182,15 @@
org.apache.felix.scr
2.0.2
+
+ org.apache.poi
+ poi
+ 3.14
+
+
+ org.apache.poi
+ poi-ooxml
+ 3.14
+
diff --git a/OutlawEditor/src/main/java/org/badvision/outlaweditor/data/DataUtilities.java b/OutlawEditor/src/main/java/org/badvision/outlaweditor/data/DataUtilities.java
index c02d28aa..dddbef0e 100644
--- a/OutlawEditor/src/main/java/org/badvision/outlaweditor/data/DataUtilities.java
+++ b/OutlawEditor/src/main/java/org/badvision/outlaweditor/data/DataUtilities.java
@@ -9,14 +9,30 @@
*/
package org.badvision.outlaweditor.data;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.xml.namespace.QName;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.badvision.outlaweditor.api.ApplicationState;
import org.badvision.outlaweditor.data.xml.Block;
import org.badvision.outlaweditor.data.xml.Field;
@@ -25,6 +41,7 @@ import org.badvision.outlaweditor.data.xml.Map;
import org.badvision.outlaweditor.data.xml.NamedEntity;
import org.badvision.outlaweditor.data.xml.Scope;
import org.badvision.outlaweditor.data.xml.Script;
+import org.badvision.outlaweditor.ui.UIAction;
public class DataUtilities {
@@ -140,7 +157,65 @@ public class DataUtilities {
map.put(new QName(name), newValue);
}
}
-
+
+ public static List> readFromFile(File file) {
+ try {
+ if (file.getName().toLowerCase().endsWith("txt") ||
+ file.getName().toLowerCase().endsWith("tsv")) {
+ return readTextFile(file);
+ } else if (file.getName().toLowerCase().endsWith("xls")) {
+ return readLegacyExcel(file);
+ } else if (file.getName().toLowerCase().endsWith("xlsx")) {
+ return readExcel(file);
+ }
+ } catch (IOException | InvalidFormatException ex) {
+ Logger.getLogger(DataUtilities.class.getName()).log(Level.SEVERE, null, ex);
+ }
+ UIAction.alert("Couldn't figure out how to import file "+file.getName());
+ return Collections.EMPTY_LIST;
+ }
+
+ public static List> readTextFile(File file) throws FileNotFoundException {
+ BufferedReader reader = new BufferedReader(new FileReader(file));
+ return reader.lines().map(line -> Arrays.asList(line.split("\\t"))).collect(Collectors.toList());
+ }
+
+ public static List> readLegacyExcel(File file) throws FileNotFoundException, IOException {
+ return readSheet(new HSSFWorkbook(new FileInputStream(file)));
+ }
+
+ public static List> readExcel(File file) throws FileNotFoundException, IOException, InvalidFormatException {
+ return readSheet(new XSSFWorkbook(file));
+ }
+
+ public static List> readSheet(Workbook workbook) {
+ Sheet sheet = workbook.getSheetAt(0);
+ List> data = new ArrayList<>();
+ sheet.forEach(row -> {
+ List rowData = new ArrayList<>();
+ row.forEach(cell -> {
+ String col = getStringValueFromCell(cell);
+ rowData.add(col);
+ });
+ data.add(rowData);
+ });
+ return data;
+ }
+
+ public static String getStringValueFromCell(Cell cell) {
+ switch (cell.getCellType()) {
+ case Cell.CELL_TYPE_BOOLEAN:
+ return Boolean.toString(cell.getBooleanCellValue());
+ case Cell.CELL_TYPE_BLANK:
+ return null;
+ case Cell.CELL_TYPE_NUMERIC:
+ return Double.toString(cell.getNumericCellValue());
+ case Cell.CELL_TYPE_STRING:
+ return cell.getStringCellValue();
+ default:
+ return "???";
+ }
+ }
//------------------------------ String comparators
/**
* Rank two strings similarity in terms of distance The lower the number,
diff --git a/OutlawEditor/src/main/java/org/badvision/outlaweditor/ui/SheetEditorController.java b/OutlawEditor/src/main/java/org/badvision/outlaweditor/ui/SheetEditorController.java
index 9056212d..4429736d 100644
--- a/OutlawEditor/src/main/java/org/badvision/outlaweditor/ui/SheetEditorController.java
+++ b/OutlawEditor/src/main/java/org/badvision/outlaweditor/ui/SheetEditorController.java
@@ -14,7 +14,6 @@
package org.badvision.outlaweditor.ui;
import java.net.URL;
-import java.util.Map;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
@@ -50,6 +49,9 @@ public abstract class SheetEditorController implements Initializable {
@FXML
abstract public void addRowAction(ActionEvent event);
+ @FXML
+ abstract public void doImport(ActionEvent event);
+
@FXML
protected void initialize() {
assert addColumn != null : "fx:id=\"addColumn\" was not injected: check your FXML file 'SheetEditor.fxml'.";
diff --git a/OutlawEditor/src/main/java/org/badvision/outlaweditor/ui/impl/SheetEditorControllerImpl.java b/OutlawEditor/src/main/java/org/badvision/outlaweditor/ui/impl/SheetEditorControllerImpl.java
index e3e169e1..9f7b392c 100644
--- a/OutlawEditor/src/main/java/org/badvision/outlaweditor/ui/impl/SheetEditorControllerImpl.java
+++ b/OutlawEditor/src/main/java/org/badvision/outlaweditor/ui/impl/SheetEditorControllerImpl.java
@@ -15,8 +15,11 @@
*/
package org.badvision.outlaweditor.ui.impl;
+import java.io.File;
import java.net.URL;
+import java.util.List;
import java.util.ResourceBundle;
+import java.util.stream.Collectors;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
@@ -24,13 +27,14 @@ import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
-import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.TextFieldTableCell;
-import javafx.util.Callback;
+import javafx.stage.FileChooser;
import javafx.util.converter.DefaultStringConverter;
+import javax.xml.namespace.QName;
import org.badvision.outlaweditor.SheetEditor;
+import org.badvision.outlaweditor.data.DataUtilities;
import static org.badvision.outlaweditor.data.DataUtilities.getValue;
import static org.badvision.outlaweditor.data.DataUtilities.setValue;
import org.badvision.outlaweditor.data.xml.Columns;
@@ -45,6 +49,7 @@ public class SheetEditorControllerImpl extends SheetEditorController {
private SheetEditor editor;
private ObservableList tableData;
+ private ListChangeListener columnChangeListener = c -> syncData();
/**
* Initializes the controller class.
@@ -57,21 +62,45 @@ public class SheetEditorControllerImpl extends SheetEditorController {
table.setEditable(true);
}
+ @Override
+ public void doImport(ActionEvent event) {
+ FileChooser openFileDialog = new FileChooser();
+ openFileDialog.setTitle("Select either a text or an Excel file");
+ File selected = openFileDialog.showOpenDialog(null);
+ if (selected != null && selected.exists() && selected.isFile()) {
+ List> data = DataUtilities.readFromFile(selected);
+ if (data != null && data.size() > 1) {
+ tableData.clear();
+ editor.getSheet().setColumns(new Columns());
+ data.get(0).stream().map(s -> s != null && !s.isEmpty() ? s : "---").map(name -> {
+ UserType type = new UserType();
+ type.setName(name);
+ return type;
+ }).collect(Collectors.toCollection(editor.getSheet().getColumns()::getColumn));
+
+ editor.getSheet().setRows(new Rows());
+ data.stream().skip(1)
+ .map(cols -> {
+ Row r = new Row();
+ for (int i = 0; i < cols.size(); i++) {
+ if (cols.get(i) != null) {
+ setValue(r.getOtherAttributes(), data.get(0).get(i), cols.get(i));
+ }
+ }
+ return r;
+ })
+ .filter(r -> !r.getOtherAttributes().isEmpty())
+ .collect(Collectors.toCollection(editor.getSheet().getRows()::getRow));
+
+ buildTableFromSheet();
+ }
+ }
+ }
+
public void setEditor(SheetEditor editor) {
tableData.clear();
this.editor = editor;
- if (editor.getSheet().getColumns() != null) {
- editor.getSheet().getColumns().getColumn().stream().forEach(this::insertViewColumn);
- }
- if (editor.getSheet().getRows() != null) {
- tableData.setAll(editor.getSheet().getRows().getRow());
- }
- sheetNameField.textProperty().set(editor.getSheet().getName());
- sheetNameField.textProperty().addListener((value, oldValue, newValue) -> {
- editor.getSheet().setName(newValue);
- ApplicationUIController.getController().updateSelectors();
- });
- table.getColumns().addListener((ListChangeListener.Change extends TableColumn> c) -> syncData());
+ buildTableFromSheet();
}
@Override
@@ -93,6 +122,23 @@ public class SheetEditorControllerImpl extends SheetEditorController {
insertViewRow(new Row());
}
+ //--------
+ private void buildTableFromSheet() {
+ table.getColumns().removeListener(columnChangeListener);
+ if (editor.getSheet().getColumns() != null) {
+ editor.getSheet().getColumns().getColumn().stream().forEach(this::insertViewColumn);
+ }
+ if (editor.getSheet().getRows() != null) {
+ tableData.setAll(editor.getSheet().getRows().getRow());
+ }
+ sheetNameField.textProperty().set(editor.getSheet().getName());
+ sheetNameField.textProperty().addListener((value, oldValue, newValue) -> {
+ editor.getSheet().setName(newValue);
+ ApplicationUIController.getController().updateSelectors();
+ });
+ table.getColumns().addListener(columnChangeListener);
+ }
+
private void insertViewColumn(UserType col) {
insertViewColumn(col, -1);
}
@@ -114,12 +160,13 @@ public class SheetEditorControllerImpl extends SheetEditorController {
TextFieldTableCell myCell = new TextFieldTableCell(new DefaultStringConverter()) {
@Override
/**
- * Patch behavior so that any change is immediately persisted, enter is not required.
+ * Patch behavior so that any change is immediately persisted,
+ * enter is not required.
*/
public void startEdit() {
super.startEdit();
TextField textField = (TextField) getGraphic();
- textField.textProperty().addListener((p,o,n)->{
+ textField.textProperty().addListener((p, o, n) -> {
setItem(n);
int index = this.getTableRow().getIndex();
Row row = tableData.get(index);
@@ -129,7 +176,7 @@ public class SheetEditorControllerImpl extends SheetEditorController {
};
return myCell;
});
-
+
tableCol.setOnEditCommit((event) -> {
table.requestFocus();
table.getSelectionModel().clearSelection();
diff --git a/OutlawEditor/src/main/resources/SheetEditor.fxml b/OutlawEditor/src/main/resources/SheetEditor.fxml
index 0ff21552..13333a94 100644
--- a/OutlawEditor/src/main/resources/SheetEditor.fxml
+++ b/OutlawEditor/src/main/resources/SheetEditor.fxml
@@ -24,7 +24,7 @@