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> 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 @@ - +