Add dialog to edit model groups
|
@ -63,12 +63,12 @@ import ctbrec.ui.settings.SettingsTab;
|
|||
import ctbrec.ui.tabs.DonateTabFx;
|
||||
import ctbrec.ui.tabs.HelpTab;
|
||||
import ctbrec.ui.tabs.RecentlyWatchedTab;
|
||||
import ctbrec.ui.tabs.RecordedTab;
|
||||
import ctbrec.ui.tabs.RecordingsTab;
|
||||
import ctbrec.ui.tabs.SiteTab;
|
||||
import ctbrec.ui.tabs.TabSelectionListener;
|
||||
import ctbrec.ui.tabs.UpdateTab;
|
||||
import ctbrec.ui.tabs.logging.LoggingTab;
|
||||
import ctbrec.ui.tabs.recorded.RecordedTab;
|
||||
import javafx.application.Application;
|
||||
import javafx.application.HostServices;
|
||||
import javafx.application.Platform;
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
package ctbrec.ui;
|
||||
|
||||
public enum Icon {
|
||||
|
||||
GROUP_16(Icon.class.getResource("/16/users.png").toExternalForm()),
|
||||
CHECK_16(Icon.class.getResource("/16/check-small.png").toExternalForm()),
|
||||
CLOCK_16(Icon.class.getResource("/16/clock.png").toExternalForm());
|
||||
|
||||
private String url;
|
||||
|
||||
private Icon(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String url() {
|
||||
return url;
|
||||
}
|
||||
}
|
|
@ -22,15 +22,13 @@ import javafx.beans.property.BooleanProperty;
|
|||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.beans.property.SimpleIntegerProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
|
||||
/**
|
||||
* Just a wrapper for Model, which augments it with JavaFX value binding properties, so that UI widgets get updated proeprly
|
||||
*/
|
||||
public class JavaFxModel implements Model {
|
||||
private transient StringProperty onlineProperty = new SimpleStringProperty();
|
||||
private transient StringProperty recordingProperty = new SimpleStringProperty();
|
||||
private transient BooleanProperty onlineProperty = new SimpleBooleanProperty();
|
||||
private transient BooleanProperty recordingProperty = new SimpleBooleanProperty();
|
||||
private transient BooleanProperty pausedProperty = new SimpleBooleanProperty();
|
||||
private transient SimpleIntegerProperty priorityProperty = new SimpleIntegerProperty();
|
||||
private transient SimpleObjectProperty<Instant> lastSeenProperty = new SimpleObjectProperty<>();
|
||||
|
@ -105,14 +103,22 @@ public class JavaFxModel implements Model {
|
|||
return delegate.toString();
|
||||
}
|
||||
|
||||
public StringProperty getOnlineProperty() {
|
||||
public BooleanProperty getOnlineProperty() {
|
||||
return onlineProperty;
|
||||
}
|
||||
|
||||
public StringProperty getRecordingProperty() {
|
||||
public void setOnlineProperty(boolean online) {
|
||||
this.onlineProperty.set(online);
|
||||
}
|
||||
|
||||
public BooleanProperty getRecordingProperty() {
|
||||
return recordingProperty;
|
||||
}
|
||||
|
||||
public void setRecordingProperty(boolean recording) {
|
||||
this.recordingProperty.setValue(recording);
|
||||
}
|
||||
|
||||
public BooleanProperty getPausedProperty() {
|
||||
return pausedProperty;
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ public class AddToGroupAction {
|
|||
public void execute() {
|
||||
source.setCursor(Cursor.WAIT);
|
||||
try {
|
||||
var dialog = new ModelGroupDialog();
|
||||
var dialog = new AddModelGroupDialog();
|
||||
boolean ok = Dialogs.showCustomInput(source.getScene(), "Add model to group", dialog.getMainPane());
|
||||
dialog.requestFocus();
|
||||
if (ok) {
|
||||
|
@ -70,7 +70,7 @@ public class AddToGroupAction {
|
|||
}
|
||||
}
|
||||
|
||||
private static class ModelGroupDialog {
|
||||
private static class AddModelGroupDialog {
|
||||
private ComboBox<ModelGroupListItem> comboBox;
|
||||
private TextField editor;
|
||||
private ObservableListSuggester suggester;
|
||||
|
|
|
@ -0,0 +1,161 @@
|
|||
package ctbrec.ui.action;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import ctbrec.Config;
|
||||
import ctbrec.Model;
|
||||
import ctbrec.ModelGroup;
|
||||
import ctbrec.recorder.Recorder;
|
||||
import ctbrec.ui.controls.Dialogs;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.scene.Cursor;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.ListView;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.control.Tooltip;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
public class EditGroupAction {
|
||||
|
||||
private static final String DIALOG_TITLE = "Edit model group";
|
||||
|
||||
private Node source;
|
||||
private Model model;
|
||||
private Recorder recorder;
|
||||
|
||||
public EditGroupAction(Node source, Recorder recorder, Model model) {
|
||||
this.source = source;
|
||||
this.recorder = recorder;
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
public void execute() {
|
||||
source.setCursor(Cursor.WAIT);
|
||||
try {
|
||||
var dialog = new EditModelGroupDialog(model);
|
||||
boolean ok = Dialogs.showCustomInput(source.getScene(), DIALOG_TITLE, dialog);
|
||||
if (ok) {
|
||||
var group = dialog.getModelGroup();
|
||||
group.setName(dialog.getGroupName());
|
||||
group.getModelUrls().clear();
|
||||
group.getModelUrls().addAll(dialog.getUrls());
|
||||
recorder.saveModelGroup(group);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Dialogs.showError(source.getScene(), DIALOG_TITLE, "Editing model group failed", e);
|
||||
} finally {
|
||||
source.setCursor(Cursor.DEFAULT);
|
||||
}
|
||||
}
|
||||
|
||||
private static class EditModelGroupDialog extends GridPane {
|
||||
private TextField groupName;
|
||||
private ListView<String> urlListView;
|
||||
private ObservableList<String> urlList;
|
||||
private ModelGroup modelGroup;
|
||||
private List<String> urls;
|
||||
|
||||
public EditModelGroupDialog(Model model) {
|
||||
Optional<ModelGroup> optionalModelGroup = Config.getInstance().getModelGroup(model);
|
||||
if (optionalModelGroup.isPresent()) {
|
||||
modelGroup = optionalModelGroup.get();
|
||||
urls = new ArrayList<>(modelGroup.getModelUrls());
|
||||
createGui(modelGroup);
|
||||
} else {
|
||||
Dialogs.showError(getScene(), DIALOG_TITLE, "No group found for model", null);
|
||||
}
|
||||
}
|
||||
|
||||
public ModelGroup getModelGroup() {
|
||||
return modelGroup;
|
||||
}
|
||||
|
||||
public List<String> getUrls() {
|
||||
return urls;
|
||||
}
|
||||
|
||||
public String getGroupName() {
|
||||
return groupName.getText();
|
||||
}
|
||||
|
||||
void createGui(ModelGroup modelGroup) {
|
||||
setHgap(5);
|
||||
vgapProperty().bind(hgapProperty());
|
||||
|
||||
groupName = new TextField(modelGroup.getName());
|
||||
Button up = createUpButton();
|
||||
Button down = createDownButton();
|
||||
Button remove = createRemoveButton();
|
||||
var buttons = new VBox(3, up, down, remove);
|
||||
urlList = FXCollections.observableList(modelGroup.getModelUrls());
|
||||
urlList.addListener((ListChangeListener<String>) change -> {
|
||||
urls = new ArrayList<>(urlList);
|
||||
});
|
||||
urlListView = new ListView<>(urlList);
|
||||
GridPane.setHgrow(urlListView, Priority.ALWAYS);
|
||||
|
||||
var row = 0;
|
||||
add(groupName, 0, row++);
|
||||
add(urlListView, 0, row);
|
||||
add(buttons, 1, row);
|
||||
|
||||
urlListView.getSelectionModel().selectedIndexProperty().addListener((obs, oldV, newV) -> {
|
||||
var idx = newV.intValue();
|
||||
boolean noSelection = idx == -1;
|
||||
up.setDisable(noSelection || idx == 0);
|
||||
down.setDisable(noSelection || idx == urlList.size() - 1);
|
||||
remove.setDisable(noSelection);
|
||||
});
|
||||
}
|
||||
|
||||
private Button createUpButton() {
|
||||
var button = createButton("\u25B4", "Move step up");
|
||||
button.setOnAction(evt -> {
|
||||
int idx = urlListView.getSelectionModel().getSelectedIndex();
|
||||
String selectedItem = urlListView.getSelectionModel().getSelectedItem();
|
||||
urlList.remove(idx);
|
||||
urlList.add(idx - 1, selectedItem);
|
||||
urlListView.getSelectionModel().select(idx - 1);
|
||||
});
|
||||
return button;
|
||||
}
|
||||
|
||||
private Button createDownButton() {
|
||||
var button = createButton("\u25BE", "Move step down");
|
||||
button.setOnAction(evt -> {
|
||||
int idx = urlListView.getSelectionModel().getSelectedIndex();
|
||||
String selectedItem = urlListView.getSelectionModel().getSelectedItem();
|
||||
urlList.remove(idx);
|
||||
urlList.add(idx + 1, selectedItem);
|
||||
urlListView.getSelectionModel().select(idx + 1);
|
||||
});
|
||||
return button;
|
||||
}
|
||||
|
||||
private Button createRemoveButton() {
|
||||
var button = createButton("-", "Remove selected step");
|
||||
button.setOnAction(evt -> {
|
||||
String selectedItem = urlListView.getSelectionModel().getSelectedItem();
|
||||
if (selectedItem != null) {
|
||||
urlList.remove(selectedItem);
|
||||
}
|
||||
});
|
||||
return button;
|
||||
}
|
||||
|
||||
private Button createButton(String text, String tooltip) {
|
||||
var b = new Button(text);
|
||||
b.setTooltip(new Tooltip(tooltip));
|
||||
b.setDisable(true);
|
||||
b.setPrefSize(32, 32);
|
||||
return b;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -56,7 +56,7 @@ public class Dialogs {
|
|||
}
|
||||
alert.setContentText(content);
|
||||
if (parent != null) {
|
||||
Stage stage = (Stage) alert.getDialogPane().getScene().getWindow();
|
||||
var stage = (Stage) alert.getDialogPane().getScene().getWindow();
|
||||
stage.getScene().getStylesheets().addAll(parent.getStylesheets());
|
||||
}
|
||||
alert.showAndWait();
|
||||
|
@ -77,18 +77,18 @@ public class Dialogs {
|
|||
dialog.initModality(Modality.APPLICATION_MODAL);
|
||||
dialog.setResizable(true);
|
||||
InputStream icon = Dialogs.class.getResourceAsStream("/icon.png");
|
||||
Stage stage = (Stage) dialog.getDialogPane().getScene().getWindow();
|
||||
var stage = (Stage) dialog.getDialogPane().getScene().getWindow();
|
||||
stage.getIcons().add(new Image(icon));
|
||||
if (parent != null) {
|
||||
stage.getScene().getStylesheets().addAll(parent.getStylesheets());
|
||||
}
|
||||
|
||||
GridPane grid = new GridPane();
|
||||
var grid = new GridPane();
|
||||
grid.setHgap(10);
|
||||
grid.setVgap(10);
|
||||
grid.setPadding(new Insets(20, 150, 10, 10));
|
||||
|
||||
TextArea notes = new TextArea(text);
|
||||
var notes = new TextArea(text);
|
||||
notes.setPrefRowCount(3);
|
||||
grid.add(notes, 0, 0);
|
||||
dialog.getDialogPane().setContent(grid);
|
||||
|
@ -112,7 +112,7 @@ public class Dialogs {
|
|||
dialog.initModality(Modality.APPLICATION_MODAL);
|
||||
dialog.setResizable(true);
|
||||
InputStream icon = Dialogs.class.getResourceAsStream("/icon.png");
|
||||
Stage stage = (Stage) dialog.getDialogPane().getScene().getWindow();
|
||||
var stage = (Stage) dialog.getDialogPane().getScene().getWindow();
|
||||
stage.getIcons().add(new Image(icon));
|
||||
if (parent != null) {
|
||||
stage.getScene().getStylesheets().addAll(parent.getStylesheets());
|
||||
|
@ -123,7 +123,7 @@ public class Dialogs {
|
|||
}
|
||||
|
||||
public static boolean showConfirmDialog(String title, String message, String header, Scene parent) {
|
||||
AutosizeAlert confirm = new AutosizeAlert(AlertType.CONFIRMATION, message, parent, YES, NO);
|
||||
var confirm = new AutosizeAlert(AlertType.CONFIRMATION, message, parent, YES, NO);
|
||||
confirm.setTitle(title);
|
||||
confirm.setHeaderText(header);
|
||||
confirm.showAndWait();
|
||||
|
@ -131,8 +131,8 @@ public class Dialogs {
|
|||
}
|
||||
|
||||
public static ButtonType showShutdownDialog(Scene parent) {
|
||||
String message = "There are recordings in progress";
|
||||
AutosizeAlert confirm = new AutosizeAlert(AlertType.CONFIRMATION, "", parent, YES, FINISH, NO);
|
||||
var message = "There are recordings in progress";
|
||||
var confirm = new AutosizeAlert(AlertType.CONFIRMATION, "", parent, YES, FINISH, NO);
|
||||
confirm.setTitle("Shutdown");
|
||||
confirm.setHeaderText(message);
|
||||
((Button) confirm.getDialogPane().lookupButton(ButtonType.YES)).setText("Shutdown Now");
|
||||
|
@ -146,7 +146,7 @@ public class Dialogs {
|
|||
}
|
||||
|
||||
public static Optional<ModelGroup> showModelGroupSelectionDialog(Scene parent, Model model) {
|
||||
GridPane dialogPane = new GridPane();
|
||||
var dialogPane = new GridPane();
|
||||
Set<ModelGroup> modelGroups = Config.getInstance().getSettings().modelGroups;
|
||||
ObservableList<ModelGroup> comboBoxModel = FXCollections.observableArrayList(modelGroups);
|
||||
ComboBox<ModelGroup> comboBox = new ComboBox<>(comboBoxModel);
|
||||
|
@ -165,7 +165,7 @@ public class Dialogs {
|
|||
existingGroup.get().add(model);
|
||||
return existingGroup;
|
||||
} else {
|
||||
ModelGroup group = new ModelGroup();
|
||||
var group = new ModelGroup();
|
||||
group.setId(UUID.randomUUID());
|
||||
group.setName(text);
|
||||
group.add(model);
|
||||
|
|
|
@ -41,6 +41,7 @@ import ctbrec.ui.SiteUiFactory;
|
|||
import ctbrec.ui.TipDialog;
|
||||
import ctbrec.ui.TokenLabel;
|
||||
import ctbrec.ui.action.AddToGroupAction;
|
||||
import ctbrec.ui.action.EditGroupAction;
|
||||
import ctbrec.ui.action.IgnoreModelsAction;
|
||||
import ctbrec.ui.action.OpenRecordingsDir;
|
||||
import ctbrec.ui.action.SetStopDateAction;
|
||||
|
@ -469,57 +470,57 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
|||
}
|
||||
|
||||
private ContextMenu createContextMenu(ThumbCell cell) {
|
||||
Model model = cell.getModel();
|
||||
var model = cell.getModel();
|
||||
boolean modelIsTrackedByRecorder = recorder.isTracked(model);
|
||||
|
||||
MenuItem openInPlayer = new MenuItem("Open in Player");
|
||||
var openInPlayer = new MenuItem("Open in Player");
|
||||
openInPlayer.setOnAction(e -> startPlayer(getSelectedThumbCells(cell)));
|
||||
|
||||
MenuItem start = new MenuItem("Start Recording");
|
||||
var start = new MenuItem("Start Recording");
|
||||
start.setOnAction(e -> startStopAction(getSelectedThumbCells(cell), true));
|
||||
|
||||
MenuItem stop = new MenuItem("Stop Recording");
|
||||
var stop = new MenuItem("Stop Recording");
|
||||
stop.setOnAction(e -> startStopAction(getSelectedThumbCells(cell), false));
|
||||
MenuItem startStop = recorder.isTracked(model) ? stop : start;
|
||||
var startStop = recorder.isTracked(model) ? stop : start;
|
||||
|
||||
MenuItem recordUntil = new MenuItem("Start Recording Until");
|
||||
var recordUntil = new MenuItem("Start Recording Until");
|
||||
recordUntil.setOnAction(e -> startRecordingWithTimeLimit(getSelectedThumbCells(cell)));
|
||||
MenuItem addPaused = new MenuItem("Add in paused state");
|
||||
var addPaused = new MenuItem("Add in paused state");
|
||||
addPaused.setOnAction(e -> addPaused(getSelectedThumbCells(cell)));
|
||||
MenuItem recordLater = new MenuItem("Record Later");
|
||||
var recordLater = new MenuItem("Record Later");
|
||||
recordLater.setOnAction(e -> recordLater(getSelectedThumbCells(cell), true));
|
||||
MenuItem removeRecordLater = new MenuItem("Forget Model");
|
||||
var removeRecordLater = new MenuItem("Forget Model");
|
||||
removeRecordLater.setOnAction(e -> recordLater(getSelectedThumbCells(cell), false));
|
||||
MenuItem addRemoveBookmark = recorder.isMarkedForLaterRecording(model) ? removeRecordLater : recordLater;
|
||||
var addRemoveBookmark = recorder.isMarkedForLaterRecording(model) ? removeRecordLater : recordLater;
|
||||
|
||||
MenuItem pause = new MenuItem("Pause Recording");
|
||||
var pause = new MenuItem("Pause Recording");
|
||||
pause.setOnAction(e -> pauseResumeAction(getSelectedThumbCells(cell), true));
|
||||
MenuItem resume = new MenuItem("Resume Recording");
|
||||
var resume = new MenuItem("Resume Recording");
|
||||
resume.setOnAction(e -> pauseResumeAction(getSelectedThumbCells(cell), false));
|
||||
MenuItem pauseResume = recorder.isSuspended(model) ? resume : pause;
|
||||
var pauseResume = recorder.isSuspended(model) ? resume : pause;
|
||||
|
||||
MenuItem follow = new MenuItem("Follow");
|
||||
var follow = new MenuItem("Follow");
|
||||
follow.setOnAction(e -> follow(getSelectedThumbCells(cell), true));
|
||||
MenuItem unfollow = new MenuItem("Unfollow");
|
||||
var unfollow = new MenuItem("Unfollow");
|
||||
unfollow.setOnAction(e -> follow(getSelectedThumbCells(cell), false));
|
||||
|
||||
MenuItem addToGroup = new MenuItem("Add to group");
|
||||
var addToGroup = new MenuItem("Add to group");
|
||||
addToGroup.setOnAction(e -> addToGroup(model));
|
||||
MenuItem editGroup = new MenuItem("Edit group");
|
||||
var editGroup = new MenuItem("Edit group");
|
||||
editGroup.setOnAction(e -> editGroup(model));
|
||||
|
||||
MenuItem ignore = new MenuItem("Ignore");
|
||||
var ignore = new MenuItem("Ignore");
|
||||
ignore.setOnAction(e -> ignore(getSelectedThumbCells(cell)));
|
||||
|
||||
MenuItem refresh = new MenuItem("Refresh Overview");
|
||||
var refresh = new MenuItem("Refresh Overview");
|
||||
refresh.setOnAction(e -> refresh());
|
||||
|
||||
MenuItem openRecDir = new MenuItem("Open recording directory");
|
||||
var openRecDir = new MenuItem("Open recording directory");
|
||||
openRecDir.setOnAction(e -> new OpenRecordingsDir(cell, model).execute());
|
||||
|
||||
MenuItem copyUrl = createCopyUrlMenuItem(cell);
|
||||
MenuItem openInBrowser = createOpenInBrowser(cell);
|
||||
MenuItem sendTip = createTipMenuItem(cell);
|
||||
var copyUrl = createCopyUrlMenuItem(cell);
|
||||
var openInBrowser = createOpenInBrowser(cell);
|
||||
var sendTip = createTipMenuItem(cell);
|
||||
|
||||
configureItemsForSelection(cell, openInPlayer, copyUrl, sendTip);
|
||||
|
||||
|
@ -535,7 +536,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
|||
}
|
||||
contextMenu.getItems().add(new SeparatorMenuItem());
|
||||
if (site.supportsFollow()) {
|
||||
MenuItem followOrUnFollow = (this instanceof FollowedTab) ? unfollow : follow;
|
||||
var followOrUnFollow = (this instanceof FollowedTab) ? unfollow : follow;
|
||||
followOrUnFollow.setDisable(!site.credentialsAvailable());
|
||||
contextMenu.getItems().add(followOrUnFollow);
|
||||
}
|
||||
|
@ -546,7 +547,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
|||
contextMenu.getItems().add(modelGroup.isEmpty() ? addToGroup : editGroup);
|
||||
contextMenu.getItems().addAll(copyUrl, openInBrowser, ignore, refresh, openRecDir);
|
||||
if (model instanceof MyFreeCamsModel && Objects.equals(System.getenv("CTBREC_DEV"), "1")) {
|
||||
MenuItem debug = new MenuItem("debug");
|
||||
var debug = new MenuItem("debug");
|
||||
debug.setOnAction(e -> MyFreeCamsClient.getInstance().getSessionState(model));
|
||||
contextMenu.getItems().add(debug);
|
||||
}
|
||||
|
@ -555,6 +556,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
|||
}
|
||||
|
||||
private void editGroup(Model model) {
|
||||
new EditGroupAction(this.getContent(), recorder, model).execute();
|
||||
}
|
||||
|
||||
private void addToGroup(Model model) {
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
package ctbrec.ui.tabs.recorded;
|
||||
|
||||
import ctbrec.ui.JavaFxModel;
|
||||
import ctbrec.ui.action.PlayAction;
|
||||
import javafx.scene.control.TableCell;
|
||||
import javafx.scene.input.MouseButton;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
|
||||
public class ClickableTableCell<T> extends TableCell<JavaFxModel, T> {
|
||||
|
||||
public ClickableTableCell() {
|
||||
addEventFilter(MouseEvent.MOUSE_CLICKED, event -> {
|
||||
if (event.getButton() == MouseButton.PRIMARY && event.getClickCount() == 2) {
|
||||
JavaFxModel selectedModel = getTableView().getSelectionModel().getSelectedItem();
|
||||
if(selectedModel != null) {
|
||||
new PlayAction(getTableView(), selectedModel).execute();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package ctbrec.ui.tabs.recorded;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import ctbrec.ui.Icon;
|
||||
import javafx.scene.control.Tooltip;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.layout.HBox;
|
||||
|
||||
public class IconTableCell<T> extends ClickableTableCell<T> {
|
||||
|
||||
protected String tooltip;
|
||||
protected HBox iconRow;
|
||||
private Map<Icon, ImageView> icons;
|
||||
|
||||
public IconTableCell(Map<Icon, ImageView> icons) {
|
||||
this.icons = Objects.requireNonNullElse(icons, new HashMap<>());
|
||||
iconRow = new HBox(3);
|
||||
}
|
||||
|
||||
protected void show(Icon iconName) {
|
||||
var imageView = icons.get(iconName);
|
||||
if (imageView != null) {
|
||||
iconRow.getChildren().remove(imageView);
|
||||
iconRow.getChildren().add(imageView);
|
||||
}
|
||||
}
|
||||
|
||||
protected void hide(Icon iconName) {
|
||||
var imageView = icons.get(iconName);
|
||||
if (imageView != null) {
|
||||
iconRow.getChildren().remove(imageView);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateItem(T value, boolean empty) {
|
||||
if (tooltip != null) {
|
||||
setTooltip(new Tooltip(tooltip));
|
||||
} else {
|
||||
setTooltip(null);
|
||||
}
|
||||
setGraphic(iconRow);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package ctbrec.ui.tabs.recorded;
|
||||
|
||||
import static ctbrec.ui.Icon.*;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import ctbrec.Config;
|
||||
import ctbrec.Model;
|
||||
import ctbrec.ModelGroup;
|
||||
import javafx.scene.image.ImageView;
|
||||
|
||||
public class ModelNameTableCell extends IconTableCell<String> {
|
||||
|
||||
public ModelNameTableCell() {
|
||||
super(Map.of(GROUP_16, new ImageView(GROUP_16.url())));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateItem(String item, boolean empty) {
|
||||
setText(null);
|
||||
tooltip = null;
|
||||
hide(GROUP_16);
|
||||
|
||||
if (item != null && !empty) {
|
||||
setText(item);
|
||||
Model m = getTableView().getItems().get(getTableRow().getIndex());
|
||||
Optional<ModelGroup> optionalGroup = Config.getInstance().getModelGroup(m);
|
||||
if (optionalGroup.isPresent()) {
|
||||
ModelGroup group = optionalGroup.get();
|
||||
setText(group.getName() + " (aka " + item + ')');
|
||||
show(GROUP_16);
|
||||
tooltip = group.getModelUrls().size() + " models:\n";
|
||||
tooltip += group.getModelUrls().stream().collect(Collectors.joining("\n"));
|
||||
}
|
||||
}
|
||||
super.updateItem(item, empty);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package ctbrec.ui.tabs.recorded;
|
||||
|
||||
import static ctbrec.ui.Icon.*;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
|
||||
import javafx.scene.image.ImageView;
|
||||
|
||||
public class OnlineTableCell extends IconTableCell<Boolean> {
|
||||
|
||||
public OnlineTableCell() {
|
||||
super(Map.of(CHECK_16, new ImageView(CHECK_16.url())));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateItem(Boolean value, boolean empty) {
|
||||
if (!empty) {
|
||||
if (Objects.equal(value, Boolean.TRUE)) {
|
||||
show(CHECK_16);
|
||||
tooltip = "Online";
|
||||
} else {
|
||||
hide(CHECK_16);
|
||||
tooltip = null;
|
||||
}
|
||||
} else {
|
||||
tooltip = null;
|
||||
}
|
||||
super.updateItem(value, empty);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package ctbrec.ui.tabs;
|
||||
package ctbrec.ui.tabs.recorded;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.InvalidKeyException;
|
||||
|
@ -37,6 +37,7 @@ import ctbrec.ui.controls.Dialogs;
|
|||
import ctbrec.ui.controls.SearchBox;
|
||||
import ctbrec.ui.controls.autocomplete.AutoFillTextField;
|
||||
import ctbrec.ui.controls.autocomplete.ObservableListSuggester;
|
||||
import ctbrec.ui.tabs.TabSelectionListener;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringPropertyBase;
|
|
@ -1,16 +1,11 @@
|
|||
package ctbrec.ui.tabs;
|
||||
package ctbrec.ui.tabs.recorded;
|
||||
|
||||
import static ctbrec.Recording.State.*;
|
||||
import static ctbrec.ui.UnicodeEmoji.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.FormatStyle;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
|
@ -31,6 +26,7 @@ import org.slf4j.LoggerFactory;
|
|||
|
||||
import ctbrec.Config;
|
||||
import ctbrec.Model;
|
||||
import ctbrec.ModelGroup;
|
||||
import ctbrec.Recording;
|
||||
import ctbrec.StringUtil;
|
||||
import ctbrec.recorder.Recorder;
|
||||
|
@ -40,7 +36,9 @@ import ctbrec.ui.DesktopIntegration;
|
|||
import ctbrec.ui.JavaFxModel;
|
||||
import ctbrec.ui.PreviewPopupHandler;
|
||||
import ctbrec.ui.StreamSourceSelectionDialog;
|
||||
import ctbrec.ui.action.AddToGroupAction;
|
||||
import ctbrec.ui.action.CheckModelAccountAction;
|
||||
import ctbrec.ui.action.EditGroupAction;
|
||||
import ctbrec.ui.action.EditNotesAction;
|
||||
import ctbrec.ui.action.FollowAction;
|
||||
import ctbrec.ui.action.IgnoreModelsAction;
|
||||
|
@ -59,6 +57,7 @@ import ctbrec.ui.controls.Dialogs;
|
|||
import ctbrec.ui.controls.SearchBox;
|
||||
import ctbrec.ui.controls.autocomplete.AutoFillTextField;
|
||||
import ctbrec.ui.controls.autocomplete.ObservableListSuggester;
|
||||
import ctbrec.ui.tabs.TabSelectionListener;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringPropertyBase;
|
||||
|
@ -157,7 +156,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
|||
|
||||
table.setEditable(true);
|
||||
table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
|
||||
PreviewPopupHandler previewPopupHandler = new PreviewPopupHandler(table);
|
||||
var previewPopupHandler = new PreviewPopupHandler(table);
|
||||
table.setRowFactory(tableview -> {
|
||||
TableRow<JavaFxModel> row = new TableRow<>();
|
||||
row.addEventHandler(MouseEvent.ANY, previewPopupHandler);
|
||||
|
@ -174,7 +173,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
|||
TableColumn<JavaFxModel, String> name = new TableColumn<>("Model");
|
||||
name.setPrefWidth(200);
|
||||
name.setCellValueFactory(new PropertyValueFactory<>("displayName"));
|
||||
name.setCellFactory(new ClickableCellFactory<>());
|
||||
name.setCellFactory(param -> new ModelNameTableCell());
|
||||
name.setEditable(false);
|
||||
name.setId("name");
|
||||
TableColumn<JavaFxModel, String> url = new TableColumn<>("URL");
|
||||
|
@ -183,15 +182,16 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
|||
url.setPrefWidth(400);
|
||||
url.setEditable(false);
|
||||
url.setId("url");
|
||||
TableColumn<JavaFxModel, String> online = new TableColumn<>("Online");
|
||||
TableColumn<JavaFxModel, Boolean> 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.setStyle(STYLE_ALIGN_CENTER);
|
||||
TableColumn<JavaFxModel, String> recording = new TableColumn<>("Recording");
|
||||
TableColumn<JavaFxModel, Boolean> recording = new TableColumn<>("Recording");
|
||||
recording.setCellValueFactory(cdf -> cdf.getValue().getRecordingProperty());
|
||||
recording.setCellFactory(tc -> new RecordingCell());
|
||||
recording.setCellFactory(tc -> new RecordingTableCell());
|
||||
recording.setPrefWidth(100);
|
||||
recording.setEditable(false);
|
||||
recording.setId("recording");
|
||||
|
@ -272,7 +272,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
|||
|
||||
scrollPane.setContent(table);
|
||||
|
||||
HBox addModelBox = new HBox(5);
|
||||
var addModelBox = new HBox(5);
|
||||
modelLabel.setPadding(new Insets(5, 0, 0, 0));
|
||||
ObservableList<String> suggestions = FXCollections.observableArrayList();
|
||||
sites.forEach(site -> suggestions.add(site.getClass().getSimpleName()));
|
||||
|
@ -302,7 +302,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
|||
checkModelAccountExistance.setOnAction(evt -> new CheckModelAccountAction(checkModelAccountExistance, recorder)
|
||||
.execute(Predicate.not(Model::isMarkedForLaterRecording)));
|
||||
|
||||
HBox filterContainer = new HBox();
|
||||
var filterContainer = new HBox();
|
||||
filterContainer.setSpacing(0);
|
||||
filterContainer.setPadding(new Insets(0));
|
||||
filterContainer.setAlignment(Pos.CENTER_RIGHT);
|
||||
|
@ -326,7 +326,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
|||
filterContainer.getChildren().add(filter);
|
||||
addModelBox.getChildren().add(filterContainer);
|
||||
|
||||
BorderPane root = new BorderPane();
|
||||
var root = new BorderPane();
|
||||
root.setPadding(new Insets(5));
|
||||
root.setTop(addModelBox);
|
||||
root.setCenter(scrollPane);
|
||||
|
@ -338,7 +338,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
|||
private void jumpToNextModel(KeyCode code) {
|
||||
if (!table.getItems().isEmpty() && (code.isLetterKey() || code.isDigitKey())) {
|
||||
// determine where to start looking for the next model
|
||||
int startAt = 0;
|
||||
var startAt = 0;
|
||||
if (table.getSelectionModel().getSelectedIndex() >= 0) {
|
||||
startAt = table.getSelectionModel().getSelectedIndex() + 1;
|
||||
if (startAt >= table.getItems().size()) {
|
||||
|
@ -346,7 +346,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
|||
}
|
||||
}
|
||||
|
||||
String c = code.getChar().toLowerCase();
|
||||
var c = code.getChar().toLowerCase();
|
||||
int i = startAt;
|
||||
do {
|
||||
JavaFxModel current = table.getItems().get(i);
|
||||
|
@ -378,7 +378,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
|||
private void updatePriority(JavaFxModel model, int priority) {
|
||||
try {
|
||||
if (priority < 0 || priority > 100) {
|
||||
String msg = "Priority has to be between 0 and 100";
|
||||
var msg = "Priority has to be between 0 and 100";
|
||||
Dialogs.showError(table.getScene(), "Invalid value", msg, null);
|
||||
} else {
|
||||
model.setPriority(priority);
|
||||
|
@ -404,7 +404,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
|||
|
||||
private void addModelByUrl(String url) {
|
||||
for (Site site : sites) {
|
||||
Model newModel = site.createModelFromUrl(url);
|
||||
var newModel = site.createModelFromUrl(url);
|
||||
if (newModel != null) {
|
||||
try {
|
||||
recorder.addModel(newModel);
|
||||
|
@ -431,7 +431,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
|||
for (Site site : sites) {
|
||||
if (Objects.equals(siteName.toLowerCase(), site.getClass().getSimpleName().toLowerCase())) {
|
||||
try {
|
||||
Model m = site.createModel(modelName);
|
||||
var m = site.createModel(modelName);
|
||||
recorder.addModel(m);
|
||||
} catch (IOException | InvalidKeyException | NoSuchAlgorithmException | IllegalStateException e1) {
|
||||
Dialogs.showError(getTabPane().getScene(), "Couldn't add model", "The model " + modelName + " could not be added:", e1);
|
||||
|
@ -548,18 +548,18 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
|||
String[] tokens = filter.split(" ");
|
||||
observableModels.addAll(filteredModels);
|
||||
filteredModels.clear();
|
||||
for (int i = 0; i < table.getItems().size(); i++) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (var i = 0; i < table.getItems().size(); i++) {
|
||||
var sb = new StringBuilder();
|
||||
for (TableColumn<JavaFxModel, ?> tc : table.getColumns()) {
|
||||
Object cellData = tc.getCellData(i);
|
||||
if (cellData != null) {
|
||||
String content = cellData.toString();
|
||||
var content = cellData.toString();
|
||||
sb.append(content).append(' ');
|
||||
}
|
||||
}
|
||||
String searchText = sb.toString();
|
||||
var searchText = sb.toString();
|
||||
|
||||
boolean tokensMissing = false;
|
||||
var tokensMissing = false;
|
||||
for (String token : tokens) {
|
||||
if (!searchText.toLowerCase().contains(token.toLowerCase())) {
|
||||
tokensMissing = true;
|
||||
|
@ -594,18 +594,14 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
|||
.peek(fxm -> { // NOSONAR
|
||||
for (Recording recording : recordings) {
|
||||
if(recording.getStatus() == RECORDING && Objects.equals(recording.getModel(), fxm)){
|
||||
String recordingValue = HEAVY_CHECK_MARK;
|
||||
if(!Objects.equals(recording.getModel().getRecordUntil(), Instant.ofEpochMilli(Model.RECORD_INDEFINITELY))) {
|
||||
recordingValue += ' ' + CLOCK;
|
||||
}
|
||||
fxm.getRecordingProperty().set(recordingValue);
|
||||
fxm.setRecordingProperty(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (Model onlineModel : onlineModels) {
|
||||
if(Objects.equals(onlineModel, fxm)) {
|
||||
fxm.getOnlineProperty().set(HEAVY_CHECK_MARK);
|
||||
fxm.setOnlineProperty(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -616,7 +612,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
|||
}
|
||||
};
|
||||
ExecutorService executor = Executors.newSingleThreadExecutor(r -> {
|
||||
Thread t = new Thread(r);
|
||||
var t = new Thread(r);
|
||||
t.setDaemon(true);
|
||||
t.setName("RecordedModelsTab UpdateService");
|
||||
return t;
|
||||
|
@ -645,44 +641,49 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
|||
if (selectedModels.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
MenuItem stop = new MenuItem("Remove Model");
|
||||
var stop = new MenuItem("Remove Model");
|
||||
stop.setOnAction(e -> stopAction(selectedModels));
|
||||
MenuItem recordLater = new MenuItem("Record Later");
|
||||
var recordLater = new MenuItem("Record Later");
|
||||
recordLater.setOnAction(e -> recordLater(selectedModels));
|
||||
|
||||
MenuItem copyUrl = new MenuItem("Copy URL");
|
||||
var copyUrl = new MenuItem("Copy URL");
|
||||
copyUrl.setOnAction(e -> {
|
||||
Model selected = selectedModels.get(0);
|
||||
final Clipboard clipboard = Clipboard.getSystemClipboard();
|
||||
final ClipboardContent content = new ClipboardContent();
|
||||
final var clipboard = Clipboard.getSystemClipboard();
|
||||
final var content = new ClipboardContent();
|
||||
content.putString(selected.getUrl());
|
||||
clipboard.setContent(content);
|
||||
});
|
||||
|
||||
MenuItem pauseRecording = new MenuItem("Pause Recording");
|
||||
var pauseRecording = new MenuItem("Pause Recording");
|
||||
pauseRecording.setOnAction(e -> pauseRecording(selectedModels));
|
||||
MenuItem resumeRecording = new MenuItem("Resume Recording");
|
||||
var resumeRecording = new MenuItem("Resume Recording");
|
||||
resumeRecording.setOnAction(e -> resumeRecording(selectedModels));
|
||||
MenuItem stopRecordingAt = new MenuItem("Stop Recording at Date");
|
||||
var stopRecordingAt = new MenuItem("Stop Recording at Date");
|
||||
stopRecordingAt.setOnAction(e -> setStopDate(selectedModels.get(0)));
|
||||
MenuItem removeTimeLimit = new MenuItem("Remove Time Limit");
|
||||
var removeTimeLimit = new MenuItem("Remove Time Limit");
|
||||
removeTimeLimit.setOnAction(e -> removeTimeLimit(selectedModels.get(0)));
|
||||
MenuItem openInBrowser = new MenuItem("Open in Browser");
|
||||
var openInBrowser = new MenuItem("Open in Browser");
|
||||
openInBrowser.setOnAction(e -> DesktopIntegration.open(selectedModels.get(0).getUrl()));
|
||||
MenuItem openInPlayer = new MenuItem("Open in Player");
|
||||
var openInPlayer = new MenuItem("Open in Player");
|
||||
openInPlayer.setOnAction(e -> openInPlayer(selectedModels.get(0)));
|
||||
MenuItem switchStreamSource = new MenuItem("Switch resolution");
|
||||
var switchStreamSource = new MenuItem("Switch resolution");
|
||||
switchStreamSource.setOnAction(e -> switchStreamSource(selectedModels.get(0)));
|
||||
MenuItem follow = new MenuItem("Follow");
|
||||
var follow = new MenuItem("Follow");
|
||||
follow.setOnAction(e -> follow(selectedModels));
|
||||
follow.setDisable(!selectedModels.stream().allMatch(m -> m.getSite().supportsFollow() && m.getSite().credentialsAvailable()));
|
||||
MenuItem ignore = new MenuItem("Ignore");
|
||||
var ignore = new MenuItem("Ignore");
|
||||
ignore.setOnAction(e -> ignore(selectedModels));
|
||||
MenuItem notes = new MenuItem("Notes");
|
||||
var notes = new MenuItem("Notes");
|
||||
notes.setOnAction(e -> notes(selectedModels));
|
||||
MenuItem openRecDir = new MenuItem("Open recording directory");
|
||||
var openRecDir = new MenuItem("Open recording directory");
|
||||
openRecDir.setOnAction(e -> new OpenRecordingsDir(table, selectedModels.get(0)).execute());
|
||||
|
||||
var addToGroup = new MenuItem("Add to group");
|
||||
addToGroup.setOnAction(e -> addToGroup(selectedModels.get(0)));
|
||||
var editGroup = new MenuItem("Edit group");
|
||||
editGroup.setOnAction(e -> editGroup(selectedModels.get(0)));
|
||||
|
||||
ContextMenu menu = new CustomMouseBehaviorContextMenu(stop, recordLater);
|
||||
if (selectedModels.size() == 1) {
|
||||
menu.getItems().add(selectedModels.get(0).isSuspended() ? resumeRecording : pauseRecording);
|
||||
|
@ -693,6 +694,8 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
|||
} else {
|
||||
menu.getItems().addAll(resumeRecording, pauseRecording);
|
||||
}
|
||||
Optional<ModelGroup> modelGroup = Config.getInstance().getModelGroup(selectedModels.get(0));
|
||||
menu.getItems().add(modelGroup.isEmpty() ? addToGroup : editGroup);
|
||||
menu.getItems().addAll(copyUrl, openInPlayer, openInBrowser, openRecDir, switchStreamSource, follow, notes, ignore);
|
||||
|
||||
if (selectedModels.size() > 1) {
|
||||
|
@ -706,6 +709,16 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
|||
return menu;
|
||||
}
|
||||
|
||||
private void addToGroup(Model model) {
|
||||
new AddToGroupAction(this.getContent(), recorder, model).execute();
|
||||
table.refresh();
|
||||
}
|
||||
|
||||
private void editGroup(Model model) {
|
||||
new EditGroupAction(this.getContent(), recorder, model).execute();
|
||||
table.refresh();
|
||||
}
|
||||
|
||||
private void setStopDate(JavaFxModel model) {
|
||||
new SetStopDateAction(table, model.getDelegate(), recorder) //
|
||||
.execute() //
|
||||
|
@ -735,7 +748,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
|||
}
|
||||
|
||||
private void switchStreamSource(JavaFxModel fxModel) {
|
||||
String couldntSwitchHeaderText = "Couldn't switch stream resolution";
|
||||
var couldntSwitchHeaderText = "Couldn't switch stream resolution";
|
||||
|
||||
try {
|
||||
if (!fxModel.isOnline(true)) {
|
||||
|
@ -781,7 +794,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
|||
}
|
||||
|
||||
private boolean stopAction(List<JavaFxModel> selectedModels) {
|
||||
boolean confirmed = true;
|
||||
var confirmed = true;
|
||||
if (Config.getInstance().getSettings().confirmationForDangerousActions) {
|
||||
int n = selectedModels.size();
|
||||
String plural = n > 1 ? "s" : "";
|
||||
|
@ -829,9 +842,9 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
|||
Config.getInstance().getSettings().recordedModelsSortType = col.getSortType().toString();
|
||||
}
|
||||
int columns = table.getColumns().size();
|
||||
double[] columnWidths = new double[columns];
|
||||
String[] columnIds = new String[columns];
|
||||
for (int i = 0; i < columnWidths.length; i++) {
|
||||
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();
|
||||
}
|
||||
|
@ -862,8 +875,8 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
|||
private void restoreColumnOrder() {
|
||||
String[] columnIds = Config.getInstance().getSettings().recordedModelsColumnIds;
|
||||
ObservableList<TableColumn<JavaFxModel,?>> columns = table.getColumns();
|
||||
for (int i = 0; i < columnIds.length; i++) {
|
||||
for (int j = 0; j < table.getColumns().size(); j++) {
|
||||
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<JavaFxModel, ?> col = columns.get(j);
|
||||
columns.remove(j); // NOSONAR
|
||||
|
@ -876,7 +889,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
|||
private void restoreColumnWidths() {
|
||||
double[] columnWidths = Config.getInstance().getSettings().recordedModelsColumnWidths;
|
||||
if (columnWidths != null && columnWidths.length == table.getColumns().size()) {
|
||||
for (int i = 0; i < columnWidths.length; i++) {
|
||||
for (var i = 0; i < columnWidths.length; i++) {
|
||||
table.getColumns().get(i).setPrefWidth(columnWidths[i]);
|
||||
}
|
||||
}
|
||||
|
@ -930,25 +943,4 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
|||
return tableCell;
|
||||
}
|
||||
}
|
||||
|
||||
private class RecordingCell extends TableCell<JavaFxModel, String> {
|
||||
@Override
|
||||
protected void updateItem(String value, boolean empty) {
|
||||
super.updateItem(value, empty);
|
||||
if (value == null) {
|
||||
setTooltip(null);
|
||||
setText(null);
|
||||
} else {
|
||||
Model m = getTableView().getItems().get(getTableRow().getIndex());
|
||||
if (m.isRecordingTimeLimited()) {
|
||||
Tooltip tooltip = new Tooltip();
|
||||
DateTimeFormatter dtf = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT);
|
||||
ZonedDateTime zonedDateTime = m.getRecordUntil().atZone(ZoneId.systemDefault());
|
||||
tooltip.setText("Recording until " + dtf.format(zonedDateTime));
|
||||
setTooltip(tooltip);
|
||||
}
|
||||
setText(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +1,11 @@
|
|||
package ctbrec.ui.tabs;
|
||||
package ctbrec.ui.tabs.recorded;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import ctbrec.recorder.Recorder;
|
||||
import ctbrec.sites.Site;
|
||||
import ctbrec.ui.ShutdownListener;
|
||||
import ctbrec.ui.tabs.TabSelectionListener;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.geometry.Side;
|
||||
import javafx.scene.control.Tab;
|
|
@ -0,0 +1,47 @@
|
|||
package ctbrec.ui.tabs.recorded;
|
||||
|
||||
import static ctbrec.ui.Icon.*;
|
||||
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.FormatStyle;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import ctbrec.Model;
|
||||
import ctbrec.SubsequentAction;
|
||||
import javafx.scene.image.ImageView;
|
||||
|
||||
public class RecordingTableCell extends IconTableCell<Boolean> {
|
||||
|
||||
public RecordingTableCell() {
|
||||
super(Map.of( //
|
||||
CHECK_16, new ImageView(CHECK_16.url()), //
|
||||
CLOCK_16, new ImageView(CLOCK_16.url())));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateItem(Boolean value, boolean empty) {
|
||||
tooltip = null;
|
||||
hide(CHECK_16);
|
||||
hide(CLOCK_16);
|
||||
if (value == null || empty) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Objects.equals(value, Boolean.TRUE)) {
|
||||
show(CHECK_16);
|
||||
tooltip = "Recording";
|
||||
}
|
||||
|
||||
Model m = getTableView().getItems().get(getTableRow().getIndex());
|
||||
if (m.isRecordingTimeLimited()) {
|
||||
show(CLOCK_16);
|
||||
var dtf = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT);
|
||||
var zonedDateTime = m.getRecordUntil().atZone(ZoneId.systemDefault());
|
||||
String action = m.getRecordUntilSubsequentAction() == SubsequentAction.PAUSE ? "Pause" : "Remove";
|
||||
tooltip = action + " at " + dtf.format(zonedDateTime);
|
||||
}
|
||||
super.updateItem(value, empty);
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 4.8 KiB |
After Width: | Height: | Size: 4.7 KiB |
After Width: | Height: | Size: 4.7 KiB |
After Width: | Height: | Size: 4.8 KiB |
After Width: | Height: | Size: 4.8 KiB |
After Width: | Height: | Size: 822 B |
After Width: | Height: | Size: 317 B |
|
@ -0,0 +1,57 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
viewBox="0 0 512 512"
|
||||
version="1.1"
|
||||
id="svg4"
|
||||
sodipodi:docname="check-small.svg"
|
||||
inkscape:version="1.0.2 (e86c870879, 2021-01-15, custom)"
|
||||
inkscape:export-filename="/tmp/check-small.png"
|
||||
inkscape:export-xdpi="6.1875"
|
||||
inkscape:export-ydpi="6.1875">
|
||||
<metadata
|
||||
id="metadata10">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs8" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1692"
|
||||
inkscape:window-height="996"
|
||||
id="namedview6"
|
||||
showgrid="false"
|
||||
inkscape:zoom="0.86731066"
|
||||
inkscape:cx="195.31674"
|
||||
inkscape:cy="250.01464"
|
||||
inkscape:window-x="492"
|
||||
inkscape:window-y="126"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg4" />
|
||||
<!-- Font Awesome Free 5.15.3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) -->
|
||||
<path
|
||||
id="path2"
|
||||
d="m 381.39691,131.00011 c -3.5266,-0.0142 -7.05951,1.31523 -9.76101,3.9928 L 209.31438,295.84932 140.6532,226.69926 c -5.35937,-5.39755 -14.08537,-5.43238 -19.48837,-0.0784 l -26.089151,25.85232 c -5.402999,5.35397 -5.439003,14.07004 -0.07851,19.46875 L 199.24608,376.92842 c 5.35938,5.39756 14.08538,5.43354 19.48837,0.0784 L 416.9263,180.60297 c 5.40184,-5.35511 5.43567,-14.07117 0.0762,-19.46875 l -25.87831,-26.0629 c -2.67968,-2.69878 -6.20076,-4.05702 -9.72735,-4.07121 z"
|
||||
style="stroke-width:1.14778" />
|
||||
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 291 B |
After Width: | Height: | Size: 757 B |
After Width: | Height: | Size: 603 B |
Before Width: | Height: | Size: 9.6 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 7.6 KiB |
Before Width: | Height: | Size: 8.6 KiB |
|
@ -106,6 +106,7 @@ public class Settings {
|
|||
public String mfcPassword = "";
|
||||
public String mfcUsername = "";
|
||||
public boolean minimizeToTray = false;
|
||||
@Deprecated
|
||||
public int minimumLengthInSeconds = 0;
|
||||
public long minimumSpaceLeftInBytes = 0;
|
||||
public Map<String, String> modelNotes = new HashMap<>();
|
||||
|
|