import java.util.*;
import java.io.*;
import java.text.*;
import java.math.BigDecimal;
import javafx.application.*;
import javafx.stage.*;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.control.TableColumn.*;
import javafx.scene.layout.*;
import javafx.collections.*;
import javafx.beans.property.*;
import javafx.geometry.*;
import javafx.scene.input.*;
public class DbfEdit extends Application {
Stage stage;
Label label;
SmDBF dbf;
String dStFormat = "yyyy/MM/dd";
String tStFormat = "yyyy/MM/dd-HH:mm:ss";
@Override
public void start(Stage stage) {
this.stage = stage;
BorderPane layout = new BorderPane();
stage.setScene(new Scene(layout, 700, 400));
TableView<IntVal> tableView = new TableView<>();
label = new Label();
File file;
List<String> p = getParameters().getRaw();
if (!p.isEmpty()) {
file = new File(p.get(0));
if (!file.isFile()) throw new RuntimeException(file.getName() + " file not found");
} else file = new File("demo.dbf");
try {
if (file.exists())
dbf = new SmDBF(file);
else {
dbf = new SmDBF(file, new Object[][] {
{"FIELD1_C", 'C', 20, 0},
{"FIELD2_L", 'L', 1, 0},
{"FIELD3_D", 'D', 8, 0},
{"FIELD4_T", 'T', 14, 0},
{"FIELD5_N", 'N', 15, 0},
{"FIELD6_F", 'F', 7, 2}
});
//dbf.setCharset("cp437");
for (int i = 0; i < 20; i++) {
dbf.append();
dbf.set(1, "Record " + i);
dbf.set(2, true);
dbf.set(3, new Date());
dbf.set(4, new Date());
dbf.set(5, new BigDecimal(i));
dbf.set(6, new BigDecimal(i));
}
}
} catch (Exception e) { throw new RuntimeException(e); }
try {
tableView.setItems(new VirtObservableList());
for (int i = 1; i <= dbf.getFieldCount(); i++) {
final int f = i;
TableColumn<IntVal, IntVal> column = new TableColumn<>(dbf.getFieldName(f));
column.setCellValueFactory(cd -> new ReadOnlyObjectWrapper<IntVal>(cd.getValue()));
column.setCellFactory(c -> {
TableCell<IntVal, IntVal> cell = new TableCell<IntVal, IntVal>() {
@Override
protected void updateItem(IntVal item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setText(null);
setStyle("");
} else {
String s;
Object obj = null;
dbf.goToRec(item.get() + 1);
char type = dbf.getFieldType(f);
if (type == 'M') s = SmDBF.typeToString(type);
else {
try {
obj = dbf.get(f);
if (obj == null) {
s = "null";
} else if (obj instanceof Boolean) {
s = (Boolean)obj ? "T" : "F";
} else if (obj instanceof Date) {
s = new SimpleDateFormat(type == 'D' ? dStFormat : tStFormat).format((Date)obj);
} else if (obj instanceof String) {
s = SmDBF.rtrim((String)obj);
} else s = obj.toString();
} catch (Exception e) { s = "error"; }
}
if (type == 'N' || type == 'F') setAlignment(Pos.CENTER_RIGHT);
try {
String style = dbf.isDeleted() ? "-fx-accent" : "-fx-text-base-color";
setStyle("-fx-text-fill: " + style);
} catch (Exception e) { }
setText(s);
}
}
};
return cell;
});
if (dbf.getFieldLength(f) > 30) column.setPrefWidth(200);
tableView.getColumns().add(column);
}
} catch (Exception e) { e.printStackTrace(); }
tableView.setOnKeyPressed(ke -> {
try {
VirtObservableList items = (VirtObservableList)tableView.getItems();
if (ke.getCode() == KeyCode.INSERT) {
Alert alert = new Alert(Alert.AlertType.CONFIRMATION, "Append record?");
alert.initOwner(stage);
alert.setHeaderText(null);
Optional<ButtonType> result = alert.showAndWait();
if (result.get() == ButtonType.OK){
dbf.append();
items.insert(items.size());
tableView.getSelectionModel().selectLast();
tableView.scrollTo(tableView.getSelectionModel().getSelectedIndices().get(0));
}
} else if (ke.getCode() == KeyCode.DELETE) {
IntVal item = tableView.getSelectionModel().getSelectedItems().get(0);
if (item != null) {
dbf.goToRec(item.get() + 1);
Alert alert = new Alert(Alert.AlertType.CONFIRMATION, (dbf.isDeleted() ? "Recall" : "Delete") + " record?");
alert.initOwner(stage);
alert.setHeaderText(null);
Optional<ButtonType> result = alert.showAndWait();
if (result.get() == ButtonType.OK){
dbf.setDeleted(!dbf.isDeleted());
@SuppressWarnings("unchecked") TablePosition<IntVal,?> oldPos = tableView.getSelectionModel().getSelectedCells().get(0);
items.update(item.get());
tableView.getSelectionModel().select(oldPos.getRow(), oldPos.getTableColumn());
}
}
} else if (ke.getCode() == KeyCode.ENTER) {
IntVal item = tableView.getSelectionModel().getSelectedItems().get(0);
if (item != null) {
dbf.goToRec(item.get() + 1);
int c = tableView.getSelectionModel().getSelectedCells().get(0).getColumn() + 1;
char t = dbf.getFieldType(c);
if (t != 'M') {
Object obj = dbf.get(c);
String s = "", l = "";
int len;
if (t == 'C') {
s = SmDBF.rtrim(obj.toString());
len = dbf.getFieldLength(c);
l = "Length: " + len;
} else if (t == 'L') {
s = obj == null ? "F" : (Boolean)obj ? "T" : "F";
len = 1;
l = "Value: T or F";
} else if (t == 'D' || t == 'T') {
String stFormat = t == 'D' ? dStFormat : tStFormat;
s = new SimpleDateFormat(stFormat).format(obj == null ? new Date() : (Date)obj);
len = stFormat.length();
l = "Format: " + stFormat.toUpperCase();
} else if (t == 'N' || t == 'F') {
s = obj == null ? "0" : obj.toString();
len = dbf.getFieldLength(c);
l = "Length: " + len + (dbf.getFieldLengthDecimal(c) > 0 ? "." + dbf.getFieldLengthDecimal(c) : "");
} else len = 0;
TextInputDialog dialog = new TextInputDialog(s);
dialog.initOwner(stage);
dialog.setHeaderText(null);
dialog.setContentText(dbf.getFieldName(c));
dialog.getDialogPane().setExpandableContent(new Label("Type: " + SmDBF.typeToString(t) + ", " + l));
dialog.getDialogPane().setExpanded(true);
TextField tf = dialog.getEditor();
tf.textProperty().addListener((observable, oldValue, newValue) -> {
if (tf.getText().length() > len) tf.setText(tf.getText().substring(0, len));
});
//if (t == 'N' || t == 'F') tf.setAlignment(Pos.CENTER_RIGHT);
Optional<String> result = dialog.showAndWait();
if (result.isPresent()) {
obj = null;
try {
if (t == 'C') {
obj = result.get();
} else if (t == 'L') {
if (result.get().equalsIgnoreCase("T")) obj = Boolean.valueOf(true);
else if (result.get().equalsIgnoreCase("F")) obj = Boolean.valueOf(false);
} else if (t == 'D' || t == 'T') {
obj = new SimpleDateFormat(t == 'D' ? dStFormat : tStFormat).parse(result.get());
} else if (t == 'N' || t == 'F') {
obj = new BigDecimal(result.get());
}
} catch (Exception e) { }
try { dbf.set(c, obj); } catch (Exception e) {
Alert alert = new Alert(Alert.AlertType.ERROR, e.toString(), ButtonType.OK);
alert.initOwner(stage);
alert.setHeaderText(null);
alert.showAndWait();
}
@SuppressWarnings("unchecked") TablePosition<IntVal,?> oldPos = tableView.getSelectionModel().getSelectedCells().get(0);
items.update(item.get());
tableView.getSelectionModel().select(oldPos.getRow(), oldPos.getTableColumn());
}
}
}
}
} catch (Exception e) { }
});
tableView.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
tableView.getSelectionModel().setCellSelectionEnabled(true);
tableView.sortPolicyProperty().set(t -> false);
@SuppressWarnings("rawtypes") ObservableList<TablePosition> selectedCells = tableView.getSelectionModel().getSelectedCells();
selectedCells.addListener((@SuppressWarnings("rawtypes") ListChangeListener.Change<? extends TablePosition> change) -> {
if (selectedCells.size() > 0) {
TablePosition<?,?> pos = (TablePosition<?,?>)selectedCells.get(0);
label.setText(String.format("Field: %5d / %d Record: %7d / %d", pos.getColumn() + 1, dbf.getFieldCount(), pos.getRow() + 1, dbf.getRecCount()));
} else {
label.setText("");
}
});
tableView.getSelectionModel().select(0, tableView.getColumns().get(0));
layout.setCenter(tableView);
layout.setBottom(label);
stage.setOnCloseRequest(event -> { try { dbf.close(); } catch (Exception e) { } });
stage.show();
}
public class IntVal {
private int value;
public IntVal(int value) { this.value = value; }
public void set(int value) { this.value = value; }
public int get() { return value; }
} // End of class IntVal
public class VirtObservableList extends ObservableListBase<IntVal> {
IntVal value = new IntVal(-1);
@Override
public int size() {
return dbf.getRecCount();
}
@Override
public IntVal get(int index) {
if (index < 0 || index >= size()) throw new IndexOutOfBoundsException();
if (index != value.get()) {
value = new IntVal(index);
}
return value;
}
void update(int index) {
beginChange();
nextUpdate(index);
endChange();
value.set(-1);
}
void insert(int index) {
beginChange();
nextAdd(index, index + 1);
endChange();
value.set(-1);
}
} // End of class VirtObservableList
} // End of class DbfEdit