Make columns of RecordingsTable configurable
This commit is contained in:
parent
fd51527f75
commit
abf65b1cc2
|
@ -0,0 +1,109 @@
|
|||
package ctbrec.ui.controls.table;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import ctbrec.Config;
|
||||
import ctbrec.Settings;
|
||||
import javafx.scene.control.TableColumn.SortType;
|
||||
|
||||
public class SettingTableViewStateStore implements TableViewStateStore {
|
||||
|
||||
private final Config config;
|
||||
private final String settingPrefix;
|
||||
private final String columnOrderSetting;
|
||||
private final String columnWidthSetting;
|
||||
private final String columnVisibilitySetting;
|
||||
private final String sortColumnSetting;
|
||||
private final String sortTypeSetting;
|
||||
|
||||
public SettingTableViewStateStore(Config config, String settingPrefix) {
|
||||
this.config = config;
|
||||
this.settingPrefix = settingPrefix;
|
||||
columnOrderSetting = settingPrefix + "ColumnOrder";
|
||||
columnWidthSetting = settingPrefix + "ColumnWidth";
|
||||
columnVisibilitySetting = settingPrefix + "ColumnVisibility";
|
||||
sortColumnSetting = settingPrefix + "SortColumn";
|
||||
sortTypeSetting = settingPrefix + "SortType";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> loadColumnOrder() {
|
||||
return loadSetting(columnOrderSetting);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Double> loadColumnWidths() {
|
||||
return loadSetting(columnWidthSetting);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Boolean> loadColumnVisibility() {
|
||||
return loadSetting(columnVisibilitySetting);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String loadSortColumn() {
|
||||
return loadSetting(sortColumnSetting);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortType loadSortType() {
|
||||
return SortType.valueOf(loadSetting(sortTypeSetting));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T loadSetting(String name) {
|
||||
try {
|
||||
Field field = Settings.class.getDeclaredField(name);
|
||||
return (T) field.get(config.getSettings());
|
||||
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
|
||||
throw new TableViewStateStoreException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void setSetting(String name, Object value) {
|
||||
try {
|
||||
Field field = Settings.class.getDeclaredField(name);
|
||||
field.set(config.getSettings(), value); // NOSONAR
|
||||
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
|
||||
throw new TableViewStateStoreException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveColumnOrder(List<String> columnIds) throws IOException {
|
||||
setSetting(columnOrderSetting, columnIds);
|
||||
save();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveColumnWidths(Map<String, Double> columnIdsToWidth) throws IOException {
|
||||
setSetting(columnWidthSetting, columnIdsToWidth);
|
||||
save();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveColumnVisibility(Map<String, Boolean> columnIdsToVisibility) throws IOException {
|
||||
setSetting(columnVisibilitySetting, columnIdsToVisibility);
|
||||
save();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveSorting(String columnId, SortType sortType) throws IOException {
|
||||
setSetting(sortColumnSetting, columnId);
|
||||
setSetting(sortTypeSetting, sortType.name());
|
||||
save();
|
||||
}
|
||||
|
||||
private void save() throws IOException {
|
||||
config.save();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return settingPrefix;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
package ctbrec.ui.controls.table;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ctbrec.StringUtil;
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.scene.control.TableView;
|
||||
|
||||
public class StatePersistingTableView<T> extends TableView<T> {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(StatePersistingTableView.class);
|
||||
|
||||
private Instant initialized;
|
||||
private TableViewStateStore stateStore;
|
||||
|
||||
public StatePersistingTableView(TableViewStateStore stateStore) {
|
||||
super();
|
||||
this.stateStore = stateStore;
|
||||
setTableMenuButtonVisible(true);
|
||||
initialized = Instant.now();
|
||||
}
|
||||
|
||||
public void restoreState() {
|
||||
restoreColumnOrder();
|
||||
restoreColumnWidths();
|
||||
restoreColumnVisibility();
|
||||
restoreSorting();
|
||||
|
||||
addStateListeners();
|
||||
}
|
||||
|
||||
private void addStateListeners() {
|
||||
// column order
|
||||
getColumns().addListener((ListChangeListener<? super TableColumn<T, ?>>) c -> saveColumnOrder());
|
||||
// column visibility
|
||||
getColumns().forEach(tc -> tc.visibleProperty().addListener((obs, oldV, newV) -> saveColumnVisibility()));
|
||||
// column width
|
||||
getColumns().forEach(tc -> tc.widthProperty().addListener((obs, oldV, newV) -> saveColumnWidths()));
|
||||
// sort order
|
||||
getSortOrder().addListener((ListChangeListener<? super TableColumn<T, ?>>) c -> saveSorting());
|
||||
getColumns().forEach(tc -> tc.sortTypeProperty().addListener((obs, oldV, newV) -> saveSorting()));
|
||||
}
|
||||
|
||||
protected void restoreColumnVisibility() {
|
||||
Map<String, Boolean> visibility = stateStore.loadColumnVisibility();
|
||||
for (TableColumn<T, ?> tc : getColumns()) {
|
||||
tc.setVisible(visibility.getOrDefault(tc.getId(), true));
|
||||
}
|
||||
}
|
||||
|
||||
protected void restoreColumnWidths() {
|
||||
Map<String, Double> widths = stateStore.loadColumnWidths();
|
||||
for (TableColumn<T, ?> tc : getColumns()) {
|
||||
tc.setPrefWidth(widths.getOrDefault(tc.getId(), tc.getWidth()));
|
||||
}
|
||||
}
|
||||
|
||||
protected void restoreColumnOrder() {
|
||||
List<String> order = stateStore.loadColumnOrder();
|
||||
ObservableList<TableColumn<T, ?>> tableColumns = getColumns();
|
||||
for (var i = 0; i < order.size(); i++) {
|
||||
for (var j = 0; j < getColumns().size(); j++) {
|
||||
if (Objects.equals(order.get(i), tableColumns.get(j).getId())) {
|
||||
TableColumn<T, ?> col = tableColumns.get(j);
|
||||
tableColumns.remove(j);
|
||||
tableColumns.add(Math.min(i, tableColumns.size()), col);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void restoreSorting() {
|
||||
String sortCol = stateStore.loadSortColumn();
|
||||
if (StringUtil.isNotBlank(sortCol)) {
|
||||
for (TableColumn<T, ?> col : getColumns()) {
|
||||
if (Objects.equals(sortCol, col.getId())) {
|
||||
col.setSortType(stateStore.loadSortType());
|
||||
getSortOrder().clear();
|
||||
getSortOrder().add(col);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void saveState() {
|
||||
saveColumnOrder();
|
||||
saveColumnWidths();
|
||||
saveColumnVisibility();
|
||||
saveSorting();
|
||||
}
|
||||
|
||||
protected void saveSorting() {
|
||||
if (!getSortOrder().isEmpty()) {
|
||||
TableColumn<T, ?> col = getSortOrder().get(0);
|
||||
saveSetting(() -> stateStore.saveSorting(col.getId(), col.getSortType()));
|
||||
} else {
|
||||
saveSetting(() -> stateStore.saveSorting(null, stateStore.loadSortType()));
|
||||
}
|
||||
}
|
||||
|
||||
protected void saveColumnVisibility() {
|
||||
saveSetting(() -> {
|
||||
Map<String, Boolean> columnIdToVisible = getColumns().stream().collect(Collectors.toMap(TableColumn::getId, TableColumn::isVisible));
|
||||
stateStore.saveColumnVisibility(columnIdToVisible);
|
||||
});
|
||||
}
|
||||
|
||||
protected void saveColumnWidths() {
|
||||
saveSetting(() -> {
|
||||
Map<String, Double> columnIdToWidth = getColumns().stream().collect(Collectors.toMap(TableColumn::getId, TableColumn::getWidth));
|
||||
stateStore.saveColumnWidths(columnIdToWidth);
|
||||
});
|
||||
}
|
||||
|
||||
protected void saveColumnOrder() {
|
||||
saveSetting(() -> {
|
||||
List<String> tableIds = getColumns().stream().map(TableColumn::getId).collect(Collectors.toList());
|
||||
stateStore.saveColumnOrder(tableIds);
|
||||
});
|
||||
}
|
||||
|
||||
private void saveSetting(ThrowingRunnable r) {
|
||||
if (Duration.between(initialized, Instant.now()).getSeconds() > 1) {
|
||||
try {
|
||||
r.run();
|
||||
} catch (Exception e) {
|
||||
LOG.error("Couldn't safe table view state with prefix {}", stateStore.getName(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
private interface ThrowingRunnable {
|
||||
void run() throws Exception; // NOSONAR
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package ctbrec.ui.controls.table;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javafx.scene.control.TableColumn.SortType;
|
||||
|
||||
public interface TableViewStateStore {
|
||||
List<String> loadColumnOrder();
|
||||
Map<String, Double> loadColumnWidths();
|
||||
Map<String, Boolean> loadColumnVisibility();
|
||||
String loadSortColumn();
|
||||
SortType loadSortType();
|
||||
|
||||
void saveColumnOrder(List<String> columnIds) throws IOException;
|
||||
void saveColumnWidths(Map<String, Double> columnIdsToWidth) throws IOException;
|
||||
void saveColumnVisibility(Map<String, Boolean> columnIdsToVisibility) throws IOException;
|
||||
void saveSorting(String columnId, SortType sortType) throws IOException;
|
||||
String getName();
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package ctbrec.ui.controls.table;
|
||||
|
||||
public class TableViewStateStoreException extends RuntimeException {
|
||||
|
||||
public TableViewStateStoreException(Exception e) {
|
||||
super(e);
|
||||
}
|
||||
|
||||
}
|
|
@ -55,6 +55,8 @@ import ctbrec.ui.controls.CustomMouseBehaviorContextMenu;
|
|||
import ctbrec.ui.controls.DateTimeCellFactory;
|
||||
import ctbrec.ui.controls.Dialogs;
|
||||
import ctbrec.ui.controls.Toast;
|
||||
import ctbrec.ui.controls.table.SettingTableViewStateStore;
|
||||
import ctbrec.ui.controls.table.StatePersistingTableView;
|
||||
import ctbrec.ui.menu.ModelMenuContributor;
|
||||
import ctbrec.ui.tabs.recorded.ModelName;
|
||||
import javafx.application.Platform;
|
||||
|
@ -80,8 +82,6 @@ import javafx.scene.control.SelectionMode;
|
|||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TableCell;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.scene.control.TableColumn.SortType;
|
||||
import javafx.scene.control.TableView;
|
||||
import javafx.scene.control.Tooltip;
|
||||
import javafx.scene.input.ContextMenuEvent;
|
||||
import javafx.scene.input.KeyCode;
|
||||
|
@ -109,7 +109,8 @@ public class RecordingsTab extends Tab implements TabSelectionListener, Shutdown
|
|||
|
||||
FlowPane grid = new FlowPane();
|
||||
ScrollPane scrollPane = new ScrollPane();
|
||||
TableView<JavaFxRecording> table = new TableView<>();
|
||||
SettingTableViewStateStore tableStateStore = new SettingTableViewStateStore(Config.getInstance(), "recordingsTable");
|
||||
StatePersistingTableView<JavaFxRecording> table = new StatePersistingTableView<>(tableStateStore);
|
||||
ObservableList<JavaFxRecording> observableRecordings = FXCollections.observableArrayList();
|
||||
ContextMenu popup;
|
||||
ProgressBar spaceLeft;
|
||||
|
@ -216,7 +217,7 @@ public class RecordingsTab extends Tab implements TabSelectionListener, Shutdown
|
|||
root.setCenter(scrollPane);
|
||||
setContent(root);
|
||||
|
||||
restoreState();
|
||||
table.restoreState();
|
||||
}
|
||||
|
||||
public boolean isDownloadRunning() {
|
||||
|
@ -855,62 +856,6 @@ public class RecordingsTab extends Tab implements TabSelectionListener, Shutdown
|
|||
|
||||
@Override
|
||||
public void onShutdown() {
|
||||
if (!table.getSortOrder().isEmpty()) {
|
||||
TableColumn<JavaFxRecording, ?> col = table.getSortOrder().get(0);
|
||||
Config.getInstance().getSettings().recordingsSortColumn = col.getText();
|
||||
Config.getInstance().getSettings().recordingsSortType = col.getSortType().toString();
|
||||
}
|
||||
int columns = table.getColumns().size();
|
||||
var columnWidths = new double[columns];
|
||||
var columnIds = new String[columns];
|
||||
for (var i = 0; i < columnWidths.length; i++) {
|
||||
columnWidths[i] = table.getColumns().get(i).getWidth();
|
||||
columnIds[i] = table.getColumns().get(i).getId();
|
||||
}
|
||||
Config.getInstance().getSettings().recordingsColumnWidths = columnWidths;
|
||||
Config.getInstance().getSettings().recordingsColumnIds = columnIds;
|
||||
}
|
||||
|
||||
private void restoreState() {
|
||||
restoreColumnOrder();
|
||||
restoreColumnWidths();
|
||||
restoreSorting();
|
||||
}
|
||||
|
||||
private void restoreSorting() {
|
||||
String sortCol = Config.getInstance().getSettings().recordingsSortColumn;
|
||||
if (StringUtil.isNotBlank(sortCol)) {
|
||||
for (TableColumn<JavaFxRecording, ?> col : table.getColumns()) {
|
||||
if (Objects.equals(sortCol, col.getText())) {
|
||||
col.setSortType(SortType.valueOf(Config.getInstance().getSettings().recordingsSortType));
|
||||
table.getSortOrder().clear();
|
||||
table.getSortOrder().add(col);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void restoreColumnOrder() {
|
||||
String[] columnIds = Config.getInstance().getSettings().recordingsColumnIds;
|
||||
ObservableList<TableColumn<JavaFxRecording, ?>> columns = table.getColumns();
|
||||
for (var i = 0; i < columnIds.length; i++) {
|
||||
for (var j = 0; j < table.getColumns().size(); j++) {
|
||||
if (Objects.equals(columnIds[i], columns.get(j).getId())) {
|
||||
TableColumn<JavaFxRecording, ?> col = columns.get(j);
|
||||
columns.remove(j); // NOSONAR
|
||||
columns.add(i, col);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void restoreColumnWidths() {
|
||||
double[] columnWidths = Config.getInstance().getSettings().recordingsColumnWidths;
|
||||
if (columnWidths != null && columnWidths.length == table.getColumns().size()) {
|
||||
for (var i = 0; i < columnWidths.length; i++) {
|
||||
table.getColumns().get(i).setPrefWidth(columnWidths[i]);
|
||||
}
|
||||
}
|
||||
table.saveState();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -148,12 +148,13 @@ public class Settings {
|
|||
public List<String> recordedModelsDisabledTableColumns = new ArrayList<>();
|
||||
public String recordedModelsSortColumn = "";
|
||||
public String recordedModelsSortType = "";
|
||||
public double[] recordingsColumnWidths = new double[0];
|
||||
public String[] recordingsColumnIds = new String[0];
|
||||
public List<String> recordingsTableColumnOrder = new ArrayList<>();
|
||||
public Map<String, Boolean> recordingsTableColumnVisibility = new HashMap<>();
|
||||
public Map<String, Double> recordingsTableColumnWidth = new HashMap<>();
|
||||
public String recordingsTableSortColumn = "";
|
||||
public String recordingsTableSortType = "";
|
||||
public String recordingsDir = System.getProperty("user.home") + File.separator + "ctbrec";
|
||||
public DirectoryStructure recordingsDirStructure = DirectoryStructure.FLAT;
|
||||
public String recordingsSortColumn = "";
|
||||
public String recordingsSortType = "";
|
||||
public List<Model> recordLater = new ArrayList<>();
|
||||
public boolean recordSingleFile = false;
|
||||
public boolean removeRecordingAfterPostProcessing = false;
|
||||
|
|
Loading…
Reference in New Issue