forked from j62/ctbrec
1
0
Fork 0

Add CSV export for model table

Also cache the data in a file to bootstrap the table on startup
This commit is contained in:
0xboobface 2018-12-19 17:44:10 +01:00
parent db5b6bdf5b
commit f05d9b32e2
1 changed files with 153 additions and 18 deletions

View File

@ -1,6 +1,13 @@
package ctbrec.ui.sites.myfreecams; package ctbrec.ui.sites.myfreecams;
import static java.nio.file.StandardOpenOption.*;
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.URLDecoder; import java.net.URLDecoder;
import java.nio.file.Files;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
@ -12,6 +19,8 @@ import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
import org.json.JSONArray;
import org.json.JSONObject;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -28,6 +37,7 @@ import ctbrec.ui.action.PlayAction;
import ctbrec.ui.action.StartRecordingAction; import ctbrec.ui.action.StartRecordingAction;
import ctbrec.ui.controls.SearchBox; import ctbrec.ui.controls.SearchBox;
import javafx.beans.property.DoubleProperty; import javafx.beans.property.DoubleProperty;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleDoubleProperty; import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty; import javafx.beans.property.StringProperty;
@ -51,6 +61,7 @@ import javafx.scene.control.Tab;
import javafx.scene.control.TableColumn; import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.SortType; import javafx.scene.control.TableColumn.SortType;
import javafx.scene.control.TableView; import javafx.scene.control.TableView;
import javafx.scene.control.Tooltip;
import javafx.scene.input.Clipboard; import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent; import javafx.scene.input.ClipboardContent;
import javafx.scene.input.ContextMenuEvent; import javafx.scene.input.ContextMenuEvent;
@ -58,6 +69,7 @@ import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane; import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox; import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority; import javafx.scene.layout.Priority;
import javafx.stage.FileChooser;
import javafx.util.Duration; import javafx.util.Duration;
public class MyFreeCamsTableTab extends Tab implements TabSelectionListener { public class MyFreeCamsTableTab extends Tab implements TabSelectionListener {
@ -73,13 +85,15 @@ public class MyFreeCamsTableTab extends Tab implements TabSelectionListener {
private Label count = new Label("models"); private Label count = new Label("models");
private List<TableColumn<ModelTableRow, ?>> columns = new ArrayList<>(); private List<TableColumn<ModelTableRow, ?>> columns = new ArrayList<>();
private ContextMenu popup; private ContextMenu popup;
private long lastJsonWrite = 0;
public MyFreeCamsTableTab(MyFreeCams mfc) { public MyFreeCamsTableTab(MyFreeCams mfc) {
this.mfc = mfc; this.mfc = mfc;
setText("Tabular"); setText("Tabular");
setClosable(false); setClosable(false);
initUpdateService();
createGui(); createGui();
loadData();
initUpdateService();
restoreState(); restoreState();
filter(filterInput.getText()); filter(filterInput.getText());
} }
@ -131,6 +145,12 @@ public class MyFreeCamsTableTab extends Tab implements TabSelectionListener {
filteredModels.clear(); filteredModels.clear();
filter(filterInput.getText()); filter(filterInput.getText());
table.sort(); table.sort();
long now = System.currentTimeMillis();
if( (now - lastJsonWrite) > TimeUnit.SECONDS.toMillis(30)) {
lastJsonWrite = now;
saveData();
}
} }
private void createGui() { private void createGui() {
@ -151,11 +171,15 @@ public class MyFreeCamsTableTab extends Tab implements TabSelectionListener {
}); });
filterInput.getStyleClass().remove("search-box-icon"); filterInput.getStyleClass().remove("search-box-icon");
HBox.setHgrow(filterInput, Priority.ALWAYS); HBox.setHgrow(filterInput, Priority.ALWAYS);
Button export = new Button("");
export.setOnAction(this::export);
export.setTooltip(new Tooltip("Export data"));
Button columnSelection = new Button(""); Button columnSelection = new Button("");
//Button columnSelection = new Button("");
columnSelection.setOnAction(this::showColumnSelection); columnSelection.setOnAction(this::showColumnSelection);
columnSelection.setTooltip(new Tooltip("Select columns"));
HBox topBar = new HBox(5); HBox topBar = new HBox(5);
topBar.getChildren().addAll(filterInput, count, columnSelection); topBar.getChildren().addAll(filterInput, count, export, columnSelection);
count.prefHeightProperty().bind(filterInput.heightProperty()); count.prefHeightProperty().bind(filterInput.heightProperty());
count.setAlignment(Pos.CENTER); count.setAlignment(Pos.CENTER);
layout.setTop(topBar); layout.setTop(topBar);
@ -312,8 +336,11 @@ public class MyFreeCamsTableTab extends Tab implements TabSelectionListener {
for (int i = 0; i < table.getItems().size(); i++) { for (int i = 0; i < table.getItems().size(); i++) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
for (TableColumn<ModelTableRow, ?> tc : table.getColumns()) { for (TableColumn<ModelTableRow, ?> tc : table.getColumns()) {
String cellData = tc.getCellData(i).toString(); Object cellData = tc.getCellData(i);
sb.append(cellData).append(' '); if(cellData != null) {
String content = cellData.toString();
sb.append(content).append(' ');
}
} }
String searchText = sb.toString(); String searchText = sb.toString();
@ -339,6 +366,43 @@ public class MyFreeCamsTableTab extends Tab implements TabSelectionListener {
} }
} }
private void export(ActionEvent evt) {
FileChooser chooser = new FileChooser();
File file = chooser.showSaveDialog(getTabPane().getScene().getWindow());
if(file != null) {
try(FileOutputStream fout = new FileOutputStream(file)) {
PrintStream ps = new PrintStream(fout);
List<ModelTableRow> union = new ArrayList<>();
union.addAll(filteredModels);
union.addAll(observableModels);
ps.println("\"uid\",\"blurp\",\"camScore\",\"continent\",\"country\",\"ethnic\",\"name\",\"new\",\"occupation\",\"state\",\"tags\",\"topic\"");
for (ModelTableRow row : union) {
ps.print("\"" + row.uid + "\""); ps.print(',');
ps.print(escape(row.blurp)); ps.print(',');
ps.print(escape(row.camScore)); ps.print(',');
ps.print(escape(row.continent)); ps.print(',');
ps.print(escape(row.country)); ps.print(',');
ps.print(escape(row.ethnic)); ps.print(',');
ps.print(escape(row.name)); ps.print(',');
ps.print(escape(row.newModel)); ps.print(',');
ps.print(escape(row.occupation)); ps.print(',');
ps.print(escape(row.state)); ps.print(',');
ps.print(escape(row.tags)); ps.print(',');
ps.print(escape(row.topic));
ps.println();
}
} catch (Exception e) {
LOG.debug("Couldn't write mfc models table data: {}", e.getMessage());
e.printStackTrace();
}
}
}
private String escape(Property<?> prop) {
String value = prop.getValue() != null ? prop.getValue().toString() : "";
return "\"" + value.replaceAll("\"", "\"\"") + "\"";
}
private void showColumnSelection(ActionEvent evt) { private void showColumnSelection(ActionEvent evt) {
ContextMenu menu = new ContextMenu(); ContextMenu menu = new ContextMenu();
for (TableColumn<ModelTableRow, ?> tc : columns) { for (TableColumn<ModelTableRow, ?> tc : columns) {
@ -398,6 +462,68 @@ public class MyFreeCamsTableTab extends Tab implements TabSelectionListener {
if(updateService != null) { if(updateService != null) {
updateService.cancel(); updateService.cancel();
} }
saveData();
}
private void saveData() {
try {
List<ModelTableRow> union = new ArrayList<>();
union.addAll(filteredModels);
union.addAll(observableModels);
JSONArray data = new JSONArray();
for (ModelTableRow row : union) {
JSONObject model = new JSONObject();
model.put("uid", row.uid);
model.put("blurp", row.blurp.get());
model.put("camScore", row.camScore.get());
model.put("continent", row.continent.get());
model.put("country", row.country.get());
model.put("ethnic", row.ethnic.get());
model.put("name", row.name.get());
model.put("newModel", row.newModel.get());
model.put("occupation", row.occupation.get());
model.put("state", row.state.get());
model.put("tags", row.tags.get());
model.put("topic", row.topic.get());
data.put(model);
}
File file = new File(Config.getInstance().getConfigDir(), "mfc-models.json");
Files.write(file.toPath(), data.toString(2).getBytes("utf-8"), CREATE, WRITE);
} catch (Exception e) {
LOG.debug("Couldn't write mfc models table data: {}", e.getMessage());
}
}
private void loadData() {
try {
File file = new File(Config.getInstance().getConfigDir(), "mfc-models.json");
if(!file.exists()) {
return;
}
String json = new String(Files.readAllBytes(file.toPath()), "utf-8");
JSONArray data = new JSONArray(json);
for (int i = 0; i < data.length(); i++) {
try {
ModelTableRow row = new ModelTableRow();
JSONObject model = data.getJSONObject(i);
row.uid = model.getInt("uid");
row.blurp.set(model.optString("blurp"));
row.camScore.set(model.optDouble("camScore"));
row.continent.set(model.optString("continent"));
row.country.set(model.optString("country"));
row.ethnic.set(model.optString("ethnic"));
row.name.set(model.optString("name"));
row.newModel.set(model.optString("newModel"));
row.occupation.set(model.optString("occupation"));
row.state.set(model.optString("state"));
row.tags.set(model.optString("tags"));
row.topic.set(model.optString("topic"));
observableModels.add(row);
} catch (Exception e) {}
}
} catch (Exception e) {
LOG.debug("Couldn't read mfc models table data: {}", e.getMessage());
}
} }
private void saveState() { private void saveState() {
@ -463,28 +589,31 @@ public class MyFreeCamsTableTab extends Tab implements TabSelectionListener {
update(st); update(st);
} }
private ModelTableRow() {
}
public void update(SessionState st) { public void update(SessionState st) {
uid = st.getUid(); uid = st.getUid();
name.set(Optional.ofNullable(st.getNm()).orElse("n/a")); setProperty(name, Optional.ofNullable(st.getNm()));
state.set(Optional.ofNullable(st.getVs()).map(vs -> ctbrec.sites.mfc.State.of(vs).toString()).orElse("n/a")); setProperty(state, Optional.ofNullable(st.getVs()).map(vs -> ctbrec.sites.mfc.State.of(vs).toString()));
camScore.set(Optional.ofNullable(st.getM()).map(m -> m.getCamscore()).orElse(0d)); setProperty(camScore, Optional.ofNullable(st.getM()).map(m -> m.getCamscore()));
Integer nu = Optional.ofNullable(st.getM()).map(m -> m.getNewModel()).orElse(0); Optional<Integer> isNew = Optional.ofNullable(st.getM()).map(m -> m.getNewModel());
newModel.set(nu == 1 ? "new" : ""); if(isNew.isPresent()) {
ethnic.set(Optional.ofNullable(st.getU()).map(u -> u.getEthnic()).orElse("n/a")); newModel.set(isNew.get() == 1 ? "new" : "");
country.set(Optional.ofNullable(st.getU()).map(u -> u.getCountry()).orElse("n/a")); }
continent.set(Optional.ofNullable(st.getM()).map(m -> m.getContinent()).orElse("n/a")); setProperty(ethnic, Optional.ofNullable(st.getU()).map(u -> u.getEthnic()));
occupation.set(Optional.ofNullable(st.getU()).map(u -> u.getOccupation()).orElse("n/a")); setProperty(country, Optional.ofNullable(st.getU()).map(u -> u.getCountry()));
setProperty(continent, Optional.ofNullable(st.getM()).map(m -> m.getContinent()));
setProperty(occupation, Optional.ofNullable(st.getU()).map(u -> u.getOccupation()));
Set<String> tagSet = Optional.ofNullable(st.getM()).map(m -> m.getTags()).orElse(Collections.emptySet()); Set<String> tagSet = Optional.ofNullable(st.getM()).map(m -> m.getTags()).orElse(Collections.emptySet());
if(tagSet.isEmpty()) { if(!tagSet.isEmpty()) {
tags.set("");
} else {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
for (String t : tagSet) { for (String t : tagSet) {
sb.append(t).append(',').append(' '); sb.append(t).append(',').append(' ');
} }
tags.set(sb.substring(0, sb.length()-2)); tags.set(sb.substring(0, sb.length()-2));
} }
blurp.set(Optional.ofNullable(st.getU()).map(u -> u.getBlurb()).orElse("n/a")); setProperty(blurp, Optional.ofNullable(st.getU()).map(u -> u.getBlurb()));
String tpc = Optional.ofNullable(st.getM()).map(m -> m.getTopic()).orElse("n/a"); String tpc = Optional.ofNullable(st.getM()).map(m -> m.getTopic()).orElse("n/a");
try { try {
tpc = URLDecoder.decode(tpc, "utf-8"); tpc = URLDecoder.decode(tpc, "utf-8");
@ -494,6 +623,12 @@ public class MyFreeCamsTableTab extends Tab implements TabSelectionListener {
topic.set(tpc); topic.set(tpc);
} }
private <T> void setProperty(Property<T> prop, Optional<T> value) {
if(value.isPresent() && !Objects.equals(value.get(), prop.getValue())) {
prop.setValue(value.get());
}
}
public StringProperty nameProperty() { public StringProperty nameProperty() {
return name; return name;
}; };