diff --git a/client/src/main/java/ctbrec/ui/sites/myfreecams/MyFreeCamsTableTab.java b/client/src/main/java/ctbrec/ui/sites/myfreecams/MyFreeCamsTableTab.java index c420c5eb..e4c6d784 100644 --- a/client/src/main/java/ctbrec/ui/sites/myfreecams/MyFreeCamsTableTab.java +++ b/client/src/main/java/ctbrec/ui/sites/myfreecams/MyFreeCamsTableTab.java @@ -459,15 +459,21 @@ public class MyFreeCamsTableTab extends Tab implements TabSelectionListener { item.setOnAction(e -> { if (item.isSelected()) { Config.getInstance().getSettings().mfcDisabledModelsTableColumns.remove(tc.getText()); + boolean added = false; for (int i = table.getColumns().size() - 1; i >= 0; i--) { TableColumn other = table.getColumns().get(i); + LOG.debug("Adding column {}", tc.getText()); int idx = (int) tc.getUserData(); int otherIdx = (int) other.getUserData(); if (otherIdx < idx) { table.getColumns().add(i + 1, tc); + added = true; break; } } + if (!added) { + table.getColumns().add(0, tc); + } } else { Config.getInstance().getSettings().mfcDisabledModelsTableColumns.add(tc.getText()); table.getColumns().remove(tc); diff --git a/client/src/main/java/ctbrec/ui/tabs/recorded/RecordedModelsTab.java b/client/src/main/java/ctbrec/ui/tabs/recorded/RecordedModelsTab.java index 30bf30a8..99f65314 100644 --- a/client/src/main/java/ctbrec/ui/tabs/recorded/RecordedModelsTab.java +++ b/client/src/main/java/ctbrec/ui/tabs/recorded/RecordedModelsTab.java @@ -9,6 +9,7 @@ import java.io.IOException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.time.Instant; +import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; @@ -66,10 +67,12 @@ import javafx.concurrent.Task; import javafx.concurrent.WorkerStateEvent; import javafx.event.ActionEvent; import javafx.geometry.Insets; +import javafx.geometry.Point2D; import javafx.geometry.Pos; import javafx.scene.Cursor; import javafx.scene.control.Alert; import javafx.scene.control.Button; +import javafx.scene.control.CheckMenuItem; import javafx.scene.control.ContextMenu; import javafx.scene.control.Label; import javafx.scene.control.ScrollPane; @@ -116,6 +119,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { FlowPane grid = new FlowPane(); ScrollPane scrollPane = new ScrollPane(); TableView table = new TableView<>(); + private List> columns = new ArrayList<>(); ObservableList observableModels = FXCollections.observableArrayList(); ObservableList filteredModels = FXCollections.observableArrayList(); ContextMenu popup; @@ -143,7 +147,6 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { initializeUpdateService(); } - @SuppressWarnings("unchecked") private void createGui() { grid.setPadding(new Insets(5)); grid.setHgap(5); @@ -154,6 +157,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { scrollPane.setFitToWidth(true); BorderPane.setMargin(scrollPane, new Insets(5)); + int idx = 0; table.setEditable(true); table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); var previewPopupHandler = new PreviewPopupHandler(table); @@ -167,6 +171,9 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { preview.setCellValueFactory(cdf -> new SimpleStringProperty(" ▶ ")); preview.setEditable(false); preview.setId("preview"); + preview.setUserData(idx++); + columns.add(preview); + addTableColumnIfEnabled(preview); if (!Config.getInstance().getSettings().livePreviews) { preview.setVisible(false); } @@ -186,6 +193,9 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { portrait.setCellFactory(param -> new ImageTableCell()); portrait.setEditable(false); portrait.setId("portrait"); + portrait.setUserData(idx++); + columns.add(portrait); + addTableColumnIfEnabled(portrait); TableColumn name = new TableColumn<>("Model"); name.setPrefWidth(200); @@ -196,32 +206,47 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { name.setCellFactory(param -> new ModelNameTableCell(recorder)); name.setEditable(false); name.setId("name"); + name.setUserData(idx++); + columns.add(name); + addTableColumnIfEnabled(name); TableColumn url = new TableColumn<>("URL"); url.setCellValueFactory(new PropertyValueFactory<>("url")); url.setCellFactory(new ClickableCellFactory<>()); url.setPrefWidth(400); url.setEditable(false); url.setId("url"); + url.setUserData(idx++); + columns.add(url); + addTableColumnIfEnabled(url); TableColumn online = new TableColumn<>("Online"); online.setCellValueFactory(cdf -> cdf.getValue().getOnlineProperty()); online.setCellFactory(param -> new OnlineTableCell()); online.setPrefWidth(100); online.setEditable(false); online.setId("online"); + online.setUserData(idx++); online.setStyle(STYLE_ALIGN_CENTER); + columns.add(online); + addTableColumnIfEnabled(online); TableColumn recording = new TableColumn<>("Recording"); recording.setCellValueFactory(cdf -> cdf.getValue().getRecordingProperty()); recording.setCellFactory(tc -> new RecordingTableCell()); recording.setPrefWidth(100); recording.setEditable(false); recording.setId("recording"); + recording.setUserData(idx++); recording.setStyle(STYLE_ALIGN_CENTER); + columns.add(recording); + addTableColumnIfEnabled(recording); TableColumn paused = new TableColumn<>("Paused"); paused.setCellValueFactory(cdf -> cdf.getValue().getPausedProperty()); paused.setCellFactory(CheckBoxTableCell.forTableColumn(paused)); paused.setPrefWidth(100); paused.setEditable(true); paused.setId("paused"); + paused.setUserData(idx++); + columns.add(paused); + addTableColumnIfEnabled(paused); TableColumn priority = new TableColumn<>("Priority"); priority.setCellValueFactory(param -> param.getValue().getPriorityProperty()); priority.setCellFactory(new PriorityCellFactory()); @@ -231,18 +256,27 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { priority.setOnEditCommit(this::onUpdatePriority); priority.setOnEditCancel(e -> cellEditing = false); priority.setId("priority"); + priority.setUserData(idx++); + columns.add(priority); + addTableColumnIfEnabled(priority); TableColumn lastSeen = new TableColumn<>("last seen"); lastSeen.setCellValueFactory(cdf -> cdf.getValue().lastSeenProperty()); lastSeen.setCellFactory(new DateTimeCellFactory<>()); lastSeen.setPrefWidth(150); lastSeen.setEditable(false); lastSeen.setId("lastSeen"); + lastSeen.setUserData(idx++); + columns.add(lastSeen); + addTableColumnIfEnabled(lastSeen); TableColumn lastRecorded = new TableColumn<>("last recorded"); lastRecorded.setCellValueFactory(cdf -> cdf.getValue().lastRecordedProperty()); lastRecorded.setCellFactory(new DateTimeCellFactory<>()); lastRecorded.setPrefWidth(150); lastRecorded.setEditable(false); lastRecorded.setId("lastRecorded"); + lastRecorded.setUserData(idx++); + columns.add(lastRecorded); + addTableColumnIfEnabled(lastRecorded); TableColumn notes = new TableColumn<>("Notes"); notes.setCellValueFactory(cdf -> { JavaFxModel m = cdf.getValue(); @@ -267,7 +301,10 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { notes.setPrefWidth(400); notes.setEditable(false); notes.setId("notes"); - table.getColumns().addAll(preview, portrait, name, url, online, recording, paused, priority, lastSeen, lastRecorded, notes); + notes.setUserData(idx); + columns.add(notes); + addTableColumnIfEnabled(notes); + table.setItems(observableModels); table.addEventHandler(ContextMenuEvent.CONTEXT_MENU_REQUESTED, event -> { popup = createContextMenu(); @@ -321,8 +358,9 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { checkModelAccountExistance .setOnAction(evt -> new CheckModelAccountAction(checkModelAccountExistance, recorder).execute(Predicate.not(Model::isMarkedForLaterRecording))); + var filterContainer = new HBox(); - filterContainer.setSpacing(0); + filterContainer.setSpacing(5); filterContainer.setPadding(new Insets(0)); filterContainer.setAlignment(Pos.CENTER_RIGHT); filterContainer.minWidth(100); @@ -342,7 +380,14 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { } }); filter.getStyleClass().remove("search-box-icon"); - filterContainer.getChildren().add(filter); + + var columnSelection = new Button("⚙"); + columnSelection.setOnAction(this::showColumnSelection); + columnSelection.setTooltip(new Tooltip("Select columns")); + columnSelection.prefHeightProperty().bind(filter.prefHeightProperty()); + columnSelection.prefWidthProperty().bind(columnSelection.prefHeightProperty()); + + filterContainer.getChildren().addAll(columnSelection, filter); addModelBox.getChildren().add(filterContainer); var root = new BorderPane(); @@ -354,6 +399,12 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { restoreState(); } + private void addTableColumnIfEnabled(TableColumn tc) { + if(isColumnEnabled(tc)) { + table.getColumns().add(tc); + } + } + private void jumpToNextModel(KeyCode code) { if (!table.getItems().isEmpty() && (code.isLetterKey() || code.isDigitKey())) { // determine where to start looking for the next model @@ -847,4 +898,50 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { } return new Image(RecordedModelsTab.class.getResourceAsStream("/silhouette_256.png")); } + + private void showColumnSelection(ActionEvent evt) { + ContextMenu menu = new CustomMouseBehaviorContextMenu(); + for (TableColumn tc : columns) { + var item = new CheckMenuItem(tc.getText()); + item.setSelected(isColumnEnabled(tc)); + menu.getItems().add(item); + item.setOnAction(e -> { + try { + if (item.isSelected()) { + Config.getInstance().getSettings().disabledRecordedModelsTableColumns.remove(tc.getText()); + boolean added = false; + for (int i = table.getColumns().size() - 1; i >= 0; i--) { + TableColumn other = table.getColumns().get(i); + if (!other.isVisible()) { + continue; + } + int idx = (int) tc.getUserData(); + LOG.debug("otherIdx {}", other.getText()); + int otherIdx = (int) other.getUserData(); + if (otherIdx < idx) { + table.getColumns().add(i + 1, tc); + added = true; + break; + } + } + if (!added) { + table.getColumns().add(0, tc); + } + } else { + Config.getInstance().getSettings().disabledRecordedModelsTableColumns.add(tc.getText()); + table.getColumns().remove(tc); + } + } catch (Exception ex) { + LOG.error("Couldn't activate column {}", tc, ex); + } + }); + } + Button src = (Button) evt.getSource(); + Point2D location = src.localToScreen(src.getTranslateX(), src.getTranslateY()); + menu.show(getTabPane().getScene().getWindow(), location.getX(), location.getY() + src.getHeight() + 5); + } + + private boolean isColumnEnabled(TableColumn tc) { + return !Config.getInstance().getSettings().disabledRecordedModelsTableColumns.contains(tc.getText()); + } } diff --git a/common/src/main/java/ctbrec/Settings.java b/common/src/main/java/ctbrec/Settings.java index f2af3d49..2bf3aa39 100644 --- a/common/src/main/java/ctbrec/Settings.java +++ b/common/src/main/java/ctbrec/Settings.java @@ -64,6 +64,7 @@ public class Settings { public boolean confirmationForDangerousActions = false; public String contactsheetTimestampLook = "font=sans-serif:fontcolor=white:fontsize=60:box=1:boxcolor=black@0.5:boxborderw=5"; public boolean determineResolution = false; + public List disabledRecordedModelsTableColumns = new ArrayList<>(); public List disabledSites = new ArrayList<>(); public String downloadFilename = "${modelSanitizedName}-${localDateTime}"; public List eventHandlers = new ArrayList<>();