lawless-legends/OutlawEditor/src/main/java/org/badvision/outlaweditor/ui/impl/SheetEditorControllerImpl.java

304 lines
12 KiB
Java

/*
* Copyright 2016 org.badvision.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.badvision.outlaweditor.ui.impl;
import static org.badvision.outlaweditor.data.DataUtilities.getValue;
import static org.badvision.outlaweditor.data.DataUtilities.setValue;
import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import org.badvision.outlaweditor.SheetEditor;
import org.badvision.outlaweditor.TransferHelper;
import org.badvision.outlaweditor.data.DataUtilities;
import org.badvision.outlaweditor.data.xml.Columns;
import org.badvision.outlaweditor.data.xml.Rows;
import org.badvision.outlaweditor.data.xml.Rows.Row;
import org.badvision.outlaweditor.data.xml.UserType;
import org.badvision.outlaweditor.ui.ApplicationUIController;
import org.badvision.outlaweditor.ui.SheetEditorController;
import org.badvision.outlaweditor.ui.UIAction;
import org.controlsfx.control.spreadsheet.GridBase;
import org.controlsfx.control.spreadsheet.SpreadsheetCell;
import org.controlsfx.control.spreadsheet.SpreadsheetCellBase;
import jakarta.xml.bind.JAXBException;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.scene.control.MenuItem;
import javafx.stage.FileChooser;
public class SheetEditorControllerImpl extends SheetEditorController {
private SheetEditor editor;
private ObservableList<ObservableList<SpreadsheetCell>> tableData;
private static Object getCellFromRow(ObservableList<SpreadsheetCell> row, int sortCol) {
if (row.size() > sortCol) {
return row.get(sortCol).getItem();
} else {
return null;
}
}
/**
* Initializes the controller class.
*/
@Override
public void initialize(URL url, ResourceBundle rb) {
super.initialize();
tableData = table.getGrid().getRows();
table.setEditable(true);
table.getContextMenu().getItems().addAll(
createMenuItem("Insert Row", () -> insertRow(new Row(), getSelectedRow())),
createMenuItem("Clone Row", () -> cloneRow(editor.getSheet().getRows().getRow().get(getSelectedRow()))),
createMenuItem("Delete Row", () -> deleteRowWithConfirmation(editor.getSheet().getRows().getRow().get(getSelectedRow()))),
createMenuItem("Delete Column", () -> deleteColumnWithConfirmation(editor.getSheet().getColumns().getColumn().get(getSelectedColumn()))),
createMenuItem("Rename Column", () -> renameColumn(editor.getSheet().getColumns().getColumn().get(getSelectedColumn()))),
createMenuItem("Sort ascending", () -> {
int sortCol = table.getSelectionModel().getFocusedCell().getColumn();
table.setComparator((a,b)->compare(getCellFromRow(a, sortCol), getCellFromRow(b, sortCol)));
}),
createMenuItem("Sort descending", () -> {
int sortCol = table.getSelectionModel().getFocusedCell().getColumn();
table.setComparator((a,b)->compare(getCellFromRow(b, sortCol), getCellFromRow(a, sortCol)));
})
);
}
public int compare(Object a, Object b) {
if (a == null) return -1;
if (b == null) return 1;
String aStr = String.valueOf(a);
String bStr = String.valueOf(b);
try {
return (Double.compare(Double.parseDouble(aStr), Double.parseDouble(bStr)));
} catch (NumberFormatException ex) {
return aStr.compareTo(bStr);
}
}
private int getSelectedRow() {
return table.getSelectionModel().getFocusedCell().getRow();
}
private int getSelectedColumn() {
return table.getSelectionModel().getFocusedCell().getColumn();
}
@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<List<String>> 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());
List<String> header = data.get(0);
data.stream().skip(1)
.map(cols -> {
Row r = new Row();
for (int i = 0; i < cols.size(); i++) {
if (cols.get(i) != null && header.size() > i && header.get(i) != null) {
setValue(r.getOtherAttributes(), header.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;
buildTableFromSheet();
}
@Override
public void addColumnAction(ActionEvent event) {
String newColName = UIAction.getText("Enter new column name", "new");
if (newColName != null && !newColName.isEmpty()) {
UserType col = new UserType();
col.setName(newColName);
if (editor.getSheet().getColumns() == null) {
editor.getSheet().setColumns(new Columns());
}
insertColumn(col);
rebuildGridUI();
}
}
@Override
public void addRowAction(ActionEvent event) {
insertRow(new Row(), -1);
}
//--------
private void buildTableFromSheet() {
if (editor.getSheet().getRows() != null) {
rebuildGridUI();
}
sheetNameField.textProperty().set(editor.getSheet().getName());
sheetNameField.textProperty().addListener((value, oldValue, newValue) -> {
editor.getSheet().setName(newValue);
ApplicationUIController.getController().updateSelectors();
});
}
private void insertColumn(UserType col) {
insertColumn(col, -1);
}
private void insertColumn(UserType col, int pos) {
table.getGrid().getColumnHeaders().clear();
if (pos < 0 || pos >= editor.getSheet().getColumns().getColumn().size()) {
editor.getSheet().getColumns().getColumn().add(col);
} else {
editor.getSheet().getColumns().getColumn().add(pos, col);
}
rebuildColumnHeaders();
}
private void insertRow(Row row, int pos) {
if (editor.getSheet().getRows() == null) {
editor.getSheet().setRows(new Rows());
}
if (pos < 0 || pos >= editor.getSheet().getRows().getRow().size()) {
editor.getSheet().getRows().getRow().add(row);
} else {
editor.getSheet().getRows().getRow().add(pos, row);
}
rebuildGridUI();
}
private MenuItem createMenuItem(String text, Runnable action) {
MenuItem menuItem = new MenuItem(text);
menuItem.setOnAction((evt) -> action.run());
return menuItem;
}
private void deleteColumnWithConfirmation(UserType col) {
UIAction.confirm("Are you sure you want to delete column " + col.getName() + "?",
() -> deleteColumn(col),
null);
}
private void renameColumn(UserType col) {
String newColName = UIAction.getText("Enter new column name", col.getName());
if (newColName != null && !newColName.isEmpty() && !col.getName().equals(newColName)) {
UserType newCol = new UserType();
newCol.setName(newColName);
editor.getSheet().getColumns().getColumn().add(newCol);
editor.getSheet().getRows().getRow()
.forEach(row -> {
setValue(row.getOtherAttributes(), newColName, getValue(row.getOtherAttributes(), col.getName()));
});
deleteColumn(col);
}
}
private void deleteColumn(UserType col) {
editor.getSheet().getColumns().getColumn().remove(col);
editor.getSheet().getRows().getRow().stream()
.map(Row::getOtherAttributes)
.forEach(
m -> m.keySet().removeIf(n -> n.getLocalPart().equals(col.getName()))
);
rebuildGridUI();
}
private void deleteRowWithConfirmation(Row row) {
UIAction.confirm("Delete row, are you sure?", () -> {
editor.getSheet().getRows().getRow().remove(row);
rebuildGridUI();
}, () -> {
});
}
private void cloneRow(Row row) {
try {
Row newRow = TransferHelper.cloneObject(row, Row.class, "row");
int pos = editor.getSheet().getRows().getRow().indexOf(row);
insertRow(newRow, pos);
} catch (JAXBException ex) {
Logger.getLogger(SheetEditorControllerImpl.class.getName()).log(Level.SEVERE, null, ex);
}
}
private void rebuildGridUI() {
int numCols = editor.getSheet().getColumns().getColumn().size();
int numRows = editor.getSheet().getRows() == null ? 0 : editor.getSheet().getRows().getRow().size();
table.setGrid(new GridBase(numRows, numCols));
rebuildColumnHeaders();
tableData = FXCollections.observableList(new ArrayList<>(numRows));
if (editor.getSheet().getRows() != null) {
int rowNum = 0;
for (Row row : editor.getSheet().getRows().getRow()) {
int colNum = 0;
ObservableList<SpreadsheetCell> rowUi = FXCollections.observableList(new ArrayList<>(numCols));
tableData.add(rowUi);
for (UserType col : editor.getSheet().getColumns().getColumn()) {
String value = getValue(row.getOtherAttributes(), col.getName());
SpreadsheetCellBase cell = new SpreadsheetCellBase(rowNum, colNum, 1, 1);
cell.setItem(value);
cell.itemProperty().addListener((ObservableValue<? extends Object> val, Object oldVal, Object newVal) -> {
setValue(row.getOtherAttributes(), col.getName(), String.valueOf(newVal));
});
rowUi.add(cell);
colNum++;
}
rowNum++;
}
}
table.getGrid().setRows(tableData);
}
private void rebuildColumnHeaders() {
int numCols = editor.getSheet().getColumns().getColumn().size();
table.getGrid().getColumnHeaders().addAll(
editor.getSheet().getColumns().getColumn().stream()
.map(UserType::getName)
.collect(Collectors.toCollection(
() -> FXCollections.observableList(new ArrayList<>(numCols))
))
);
}
}