Use ModelMenuContributor for context menu on the RecordedModelsTab
This commit is contained in:
parent
ebc8d4b321
commit
31c9a38d06
|
@ -30,13 +30,13 @@ import javafx.scene.layout.Region;
|
|||
public class AddToGroupAction {
|
||||
|
||||
private Node source;
|
||||
private Model model;
|
||||
private List<Model> models;
|
||||
private Recorder recorder;
|
||||
|
||||
public AddToGroupAction(Node source, Recorder recorder, Model model) {
|
||||
public AddToGroupAction(Node source, Recorder recorder, List<Model> models) {
|
||||
this.source = source;
|
||||
this.recorder = recorder;
|
||||
this.model = model;
|
||||
this.models = models;
|
||||
}
|
||||
|
||||
public void execute() {
|
||||
|
@ -56,13 +56,17 @@ public class AddToGroupAction {
|
|||
Set<ModelGroup> modelGroups = recorder.getModelGroups();
|
||||
Optional<ModelGroup> existingGroup = modelGroups.stream().filter(mg -> mg.getName().equalsIgnoreCase(text)).findFirst();
|
||||
if (existingGroup.isPresent()) {
|
||||
existingGroup.get().add(model);
|
||||
for (Model model : models) {
|
||||
existingGroup.get().add(model);
|
||||
}
|
||||
recorder.saveModelGroup(existingGroup.get());
|
||||
} else {
|
||||
var group = new ModelGroup();
|
||||
group.setId(UUID.randomUUID());
|
||||
group.setName(text);
|
||||
group.add(model);
|
||||
for (Model model : models) {
|
||||
group.add(model);
|
||||
}
|
||||
modelGroups.add(group);
|
||||
recorder.saveModelGroup(group);
|
||||
}
|
||||
|
@ -122,7 +126,7 @@ public class AddToGroupAction {
|
|||
}
|
||||
|
||||
private void suggestInitialName(Set<ModelGroup> modelGroups) {
|
||||
String bestName = model.getDisplayName();
|
||||
String bestName = models.get(0).getDisplayName();
|
||||
for (ModelGroup modelGroup : modelGroups) {
|
||||
if (StringUtil.percentageOfEquality(bestName, modelGroup.getName()) > 70) {
|
||||
bestName = modelGroup.getName();
|
||||
|
|
|
@ -8,23 +8,21 @@ import org.slf4j.LoggerFactory;
|
|||
|
||||
import ctbrec.Config;
|
||||
import ctbrec.Model;
|
||||
import ctbrec.ui.JavaFxModel;
|
||||
import ctbrec.ui.controls.Dialogs;
|
||||
import javafx.scene.Cursor;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.TableView;
|
||||
|
||||
public class EditNotesAction {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(EditNotesAction.class);
|
||||
|
||||
private Node source;
|
||||
private Model model;
|
||||
private TableView<JavaFxModel> table;
|
||||
private Runnable callback;
|
||||
|
||||
public EditNotesAction(Node source, Model selectedModel, TableView<JavaFxModel> table) {
|
||||
public EditNotesAction(Node source, Model selectedModel, Runnable callback) {
|
||||
this.source = source;
|
||||
this.model = selectedModel;
|
||||
this.table = table;
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
public void execute() {
|
||||
|
@ -43,7 +41,13 @@ public class EditNotesAction {
|
|||
LOG.warn("Couldn't save config", e);
|
||||
}
|
||||
});
|
||||
table.refresh();
|
||||
if (callback != null) {
|
||||
try {
|
||||
callback.run();
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error while executing callback", e);
|
||||
}
|
||||
}
|
||||
source.setCursor(Cursor.DEFAULT);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,6 +77,12 @@ public class SetStopDateAction {
|
|||
model.setRecordUntil(stopAt);
|
||||
model.setRecordUntilSubsequentAction(action);
|
||||
try {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e1) {
|
||||
// TODO Auto-generated catch block
|
||||
e1.printStackTrace();
|
||||
}
|
||||
recorder.stopRecordingAt(model);
|
||||
} catch (InvalidKeyException | NoSuchAlgorithmException | IOException e) {
|
||||
Dialogs.showError(source.getScene(), "Error", "Couln't set stop date", e);
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
package ctbrec.ui.menu;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
|
@ -18,9 +22,11 @@ import ctbrec.ui.DesktopIntegration;
|
|||
import ctbrec.ui.SiteUiFactory;
|
||||
import ctbrec.ui.StreamSourceSelectionDialog;
|
||||
import ctbrec.ui.action.AddToGroupAction;
|
||||
import ctbrec.ui.action.EditNotesAction;
|
||||
import ctbrec.ui.action.IgnoreModelsAction;
|
||||
import ctbrec.ui.action.OpenRecordingsDir;
|
||||
import ctbrec.ui.action.PlayAction;
|
||||
import ctbrec.ui.action.RemoveTimeLimitAction;
|
||||
import ctbrec.ui.action.SetStopDateAction;
|
||||
import ctbrec.ui.action.StartRecordingAction;
|
||||
import ctbrec.ui.action.StopRecordingAction;
|
||||
|
@ -35,6 +41,7 @@ import javafx.scene.control.Alert;
|
|||
import javafx.scene.control.ContextMenu;
|
||||
import javafx.scene.control.MenuItem;
|
||||
import javafx.scene.control.SeparatorMenuItem;
|
||||
import javafx.scene.control.TabPane;
|
||||
import javafx.scene.input.Clipboard;
|
||||
import javafx.scene.input.ClipboardContent;
|
||||
|
||||
|
@ -52,6 +59,7 @@ public class ModelMenuContributor {
|
|||
private TriConsumer<Model, Boolean, Boolean> followCallback;
|
||||
private Consumer<Model> ignoreCallback;
|
||||
private boolean removeWithIgnore = false;
|
||||
private Runnable callback;
|
||||
|
||||
private ModelMenuContributor(Node source, Config config, Recorder recorder) {
|
||||
this.source = source;
|
||||
|
@ -87,21 +95,39 @@ public class ModelMenuContributor {
|
|||
startStopCallback = Optional.ofNullable(startStopCallback).orElse(m -> {});
|
||||
followCallback = Optional.ofNullable(followCallback).orElse((m, f, s) -> {});
|
||||
ignoreCallback = Optional.ofNullable(ignoreCallback).orElse(m -> {});
|
||||
callback = Optional.ofNullable(callback).orElse(() -> {});
|
||||
addOpenInPlayer(menu, selectedModels);
|
||||
addOpenInBrowser(menu, selectedModels);
|
||||
addCopyUrl(menu, selectedModels);
|
||||
menu.getItems().add(new SeparatorMenuItem());
|
||||
|
||||
addStartOrStop(menu, selectedModels);
|
||||
addStartRecordingWithTimeLimit(menu, selectedModels);
|
||||
addRemoveTimeLimit(menu, selectedModels);
|
||||
addSwitchStreamSource(menu, selectedModels);
|
||||
addStartPaused(menu, selectedModels);
|
||||
addRecordLater(menu, selectedModels);
|
||||
addPauseResume(menu, selectedModels);
|
||||
addGroupMenu(menu, selectedModels);
|
||||
menu.getItems().add(new SeparatorMenuItem());
|
||||
|
||||
addFollowUnfollow(menu, selectedModels);
|
||||
addSendTip(menu, selectedModels);
|
||||
addIgnore(menu, selectedModels);
|
||||
addOpenRecDir(menu, selectedModels);
|
||||
addNotes(menu, selectedModels);
|
||||
}
|
||||
|
||||
public ModelMenuContributor afterwards(Runnable callback) {
|
||||
this.callback = callback;
|
||||
return this;
|
||||
}
|
||||
|
||||
private void addNotes(ContextMenu menu, List<Model> selectedModels) {
|
||||
var notes = new MenuItem("Notes");
|
||||
notes.setDisable(selectedModels.size() != 1);
|
||||
notes.setOnAction(e -> new EditNotesAction(source, selectedModels.get(0), callback).execute());
|
||||
menu.getItems().add(notes);
|
||||
}
|
||||
|
||||
private void addOpenRecDir(ContextMenu menu, List<Model> selectedModels) {
|
||||
|
@ -110,7 +136,11 @@ public class ModelMenuContributor {
|
|||
}
|
||||
var model = selectedModels.get(0);
|
||||
var openRecDir = new MenuItem("Open recording directory");
|
||||
openRecDir.setOnAction(e -> new OpenRecordingsDir(source, model).execute());
|
||||
openRecDir.setDisable(selectedModels.size() != 1);
|
||||
openRecDir.setOnAction(e -> {
|
||||
new OpenRecordingsDir(source, model).execute();
|
||||
executeCallback();
|
||||
});
|
||||
menu.getItems().add(openRecDir);
|
||||
}
|
||||
|
||||
|
@ -124,26 +154,28 @@ public class ModelMenuContributor {
|
|||
if (selectedModels == null || selectedModels.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
var model = selectedModels.get(0);
|
||||
var copyUrl = new MenuItem("Copy URL");
|
||||
copyUrl.setOnAction(e -> {
|
||||
var sb = new StringBuilder();
|
||||
for (Model model : selectedModels) {
|
||||
sb.append(model.getUrl()).append('\n');
|
||||
}
|
||||
sb.deleteCharAt(sb.length() - 1);
|
||||
final var content = new ClipboardContent();
|
||||
content.putString(model.getUrl());
|
||||
content.putString(sb.toString());
|
||||
Clipboard.getSystemClipboard().setContent(content);
|
||||
});
|
||||
menu.getItems().add(copyUrl);
|
||||
}
|
||||
|
||||
private void addSendTip(ContextMenu menu, List<Model> selectedModels) {
|
||||
if (selectedModels == null || selectedModels.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
var model = selectedModels.get(0);
|
||||
var site = model.getSite();
|
||||
if (site.supportsTips()) {
|
||||
var sendTip = new MenuItem("Send Tip");
|
||||
sendTip.setOnAction(e -> new TipAction(model, source).execute());
|
||||
sendTip.setDisable(!site.credentialsAvailable());
|
||||
sendTip.setDisable(selectedModels.size() != 1);
|
||||
menu.getItems().add(sendTip);
|
||||
}
|
||||
}
|
||||
|
@ -166,13 +198,21 @@ public class ModelMenuContributor {
|
|||
var unfollow = new MenuItem("Unfollow");
|
||||
unfollow.setOnAction(e -> follow(selectedModels, false));
|
||||
|
||||
var followOrUnFollow = (source instanceof FollowedTab) ? unfollow : follow; // TODO source instanceof FollowedTab does not work
|
||||
var followOrUnFollow = isFollowedTab() ? unfollow : follow;
|
||||
followOrUnFollow.setDisable(!site.credentialsAvailable());
|
||||
menu.getItems().add(followOrUnFollow);
|
||||
followOrUnFollow.setDisable(!site.credentialsAvailable());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isFollowedTab() {
|
||||
if (source instanceof TabPane) {
|
||||
var tabPane = (TabPane) source;
|
||||
return tabPane.getSelectionModel().getSelectedItem() instanceof FollowedTab;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void follow(List<Model> selectedModels, boolean follow) {
|
||||
for (Model model : selectedModels) {
|
||||
follow(model, follow);
|
||||
|
@ -219,11 +259,71 @@ public class ModelMenuContributor {
|
|||
}, GlobalThreadPool.get());
|
||||
}
|
||||
|
||||
private void addSwitchStreamSource(ContextMenu menu, List<Model> selectedModels) {
|
||||
var model = selectedModels.get(0);
|
||||
if (!recorder.isTracked(model)) {
|
||||
return;
|
||||
}
|
||||
var switchStreamSource = new MenuItem("Switch resolution");
|
||||
switchStreamSource.setOnAction(e -> switchStreamSource(selectedModels.get(0)));
|
||||
menu.getItems().add(switchStreamSource);
|
||||
switchStreamSource.setDisable(selectedModels.size() != 1);
|
||||
}
|
||||
|
||||
private void switchStreamSource(Model selectedModel) {
|
||||
var couldntSwitchHeaderText = "Couldn't switch stream resolution";
|
||||
|
||||
try {
|
||||
if (!selectedModel.isOnline(true)) {
|
||||
Dialogs.showError(source.getScene(), couldntSwitchHeaderText, "The resolution can only be changed, when the model is online", null);
|
||||
return;
|
||||
}
|
||||
} catch (InterruptedException e1) {
|
||||
Thread.currentThread().interrupt();
|
||||
Dialogs.showError(source.getScene(), couldntSwitchHeaderText, "An error occured while checking, if the model is online", null);
|
||||
return;
|
||||
} catch (IOException | ExecutionException e1) {
|
||||
Dialogs.showError(source.getScene(), couldntSwitchHeaderText, "An error occured while checking, if the model is online", null);
|
||||
return;
|
||||
}
|
||||
|
||||
Consumer<Model> onSuccess = m -> {
|
||||
try {
|
||||
recorder.switchStreamSource(m);
|
||||
} catch (InvalidKeyException | NoSuchAlgorithmException | IllegalStateException | IOException e) {
|
||||
LOG.error(couldntSwitchHeaderText, e);
|
||||
showStreamSwitchErrorDialog(e);
|
||||
}
|
||||
};
|
||||
Consumer<Throwable> onFail = t -> {
|
||||
LOG.error(couldntSwitchHeaderText, t);
|
||||
showStreamSwitchErrorDialog(t);
|
||||
};
|
||||
StreamSourceSelectionDialog.show(source.getScene(), selectedModel, onSuccess, onFail);
|
||||
}
|
||||
|
||||
private void showStreamSwitchErrorDialog(Throwable throwable) {
|
||||
showErrorDialog(throwable, "Couldn't switch stream resolution", "Error while switching stream resolution");
|
||||
}
|
||||
|
||||
private void showErrorDialog(Throwable throwable, String header, String msg) {
|
||||
Alert alert = new AutosizeAlert(Alert.AlertType.ERROR, source.getScene());
|
||||
alert.setTitle("Error");
|
||||
alert.setHeaderText(header);
|
||||
alert.setContentText(msg + ": " + throwable.getLocalizedMessage());
|
||||
alert.showAndWait();
|
||||
}
|
||||
|
||||
private void addGroupMenu(ContextMenu menu, List<Model> selectedModels) {
|
||||
var model = selectedModels.get(0);
|
||||
var addToGroup = new MenuItem("Add to group");
|
||||
addToGroup.setOnAction(e -> new AddToGroupAction(source, recorder, model).execute());
|
||||
var groupSubMenu = new ModelGroupMenuBuilder().model(model).recorder(recorder).node(source).build();
|
||||
addToGroup.setOnAction(e -> new AddToGroupAction(source, recorder, selectedModels).execute(callback));
|
||||
var groupSubMenu = new ModelGroupMenuBuilder() // @formatter:off
|
||||
.model(model)
|
||||
.recorder(recorder)
|
||||
.node(source)
|
||||
.callback(m -> callback.run())
|
||||
.build(); // @formatter:on
|
||||
Optional<ModelGroup> modelGroup = recorder.getModelGroup(model);
|
||||
menu.getItems().add(modelGroup.isEmpty() ? addToGroup : groupSubMenu);
|
||||
}
|
||||
|
@ -279,15 +379,33 @@ public class ModelMenuContributor {
|
|||
}
|
||||
|
||||
private void addStartRecordingWithTimeLimit(ContextMenu menu, List<Model> selectedModels) {
|
||||
var text = recorder.isTracked(selectedModels.get(0)) ? "Record Until" : "Start Recording Until";
|
||||
var model = selectedModels.get(0);
|
||||
var text = recorder.isTracked(model) ? "Record Until" : "Start Recording Until";
|
||||
var start = new MenuItem(text);
|
||||
menu.getItems().add(start);
|
||||
start.setOnAction(e -> {
|
||||
startStopAction(selectedModels, true);
|
||||
selectedModels.forEach(m -> new SetStopDateAction(source, m, recorder).execute());
|
||||
selectedModels.forEach(m -> new SetStopDateAction(source, m, recorder).execute() //
|
||||
.thenAccept(b -> executeCallback()));
|
||||
});
|
||||
}
|
||||
|
||||
private void addRemoveTimeLimit(ContextMenu menu, List<Model> selectedModels) {
|
||||
var model = selectedModels.get(0);
|
||||
if (!model.isRecordingTimeLimited()) {
|
||||
return;
|
||||
}
|
||||
var removeTimeLimit = new MenuItem("Remove Time Limit");
|
||||
removeTimeLimit.setOnAction(e -> removeTimeLimit(model));
|
||||
menu.getItems().add(removeTimeLimit);
|
||||
}
|
||||
|
||||
private void removeTimeLimit(Model selectedModel) {
|
||||
new RemoveTimeLimitAction(source, selectedModel, recorder) //
|
||||
.execute() //
|
||||
.whenComplete((result, exception) -> executeCallback());
|
||||
}
|
||||
|
||||
private void addOpenInPlayer(ContextMenu menu, List<Model> selectedModels) {
|
||||
var openInPlayer = new MenuItem("Open in Player");
|
||||
openInPlayer.setOnAction(e -> selectedModels.forEach(m -> new PlayAction(source, m).execute()));
|
||||
|
@ -343,4 +461,12 @@ public class ModelMenuContributor {
|
|||
private void stopRecording(List<Model> models) {
|
||||
new StopRecordingAction(source, models, recorder).execute(startStopCallback);
|
||||
}
|
||||
|
||||
private void executeCallback() {
|
||||
try {
|
||||
callback.run();
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error while executing menu callback", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@ import ctbrec.ui.DesktopIntegration;
|
|||
import ctbrec.ui.JavaFxModel;
|
||||
import ctbrec.ui.PreviewPopupHandler;
|
||||
import ctbrec.ui.action.CheckModelAccountAction;
|
||||
import ctbrec.ui.action.EditNotesAction;
|
||||
import ctbrec.ui.action.FollowAction;
|
||||
import ctbrec.ui.action.IgnoreModelsAction;
|
||||
import ctbrec.ui.action.PlayAction;
|
||||
|
@ -501,16 +500,13 @@ public class RecordLaterTab extends Tab implements TabSelectionListener {
|
|||
follow.setDisable(!selectedModels.stream().allMatch(m -> m.getSite().supportsFollow() && m.getSite().credentialsAvailable()));
|
||||
var ignore = new MenuItem("Ignore");
|
||||
ignore.setOnAction(e -> ignore(selectedModels));
|
||||
var notes = new MenuItem("Notes");
|
||||
notes.setOnAction(e -> notes(selectedModels));
|
||||
|
||||
ContextMenu menu = new CustomMouseBehaviorContextMenu(start, stop, copyUrl, openInPlayer, openInBrowser, follow, notes, ignore);
|
||||
ContextMenu menu = new CustomMouseBehaviorContextMenu(start, stop, copyUrl, openInPlayer, openInBrowser, follow, ignore);
|
||||
|
||||
if (selectedModels.size() > 1) {
|
||||
copyUrl.setDisable(true);
|
||||
openInPlayer.setDisable(true);
|
||||
openInBrowser.setDisable(true);
|
||||
notes.setDisable(true);
|
||||
}
|
||||
|
||||
return menu;
|
||||
|
@ -524,10 +520,6 @@ public class RecordLaterTab extends Tab implements TabSelectionListener {
|
|||
new FollowAction(getTabPane(), new ArrayList<>(selectedModels)).execute();
|
||||
}
|
||||
|
||||
private void notes(ObservableList<JavaFxModel> selectedModels) {
|
||||
new EditNotesAction(getTabPane(), selectedModels.get(0), table).execute();
|
||||
}
|
||||
|
||||
private void openInPlayer(JavaFxModel selectedModel) {
|
||||
new PlayAction(getTabPane(), selectedModel).execute();
|
||||
}
|
||||
|
|
|
@ -6,18 +6,15 @@ 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;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -34,20 +31,10 @@ import ctbrec.sites.Site;
|
|||
import ctbrec.ui.AutosizeAlert;
|
||||
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.EditNotesAction;
|
||||
import ctbrec.ui.action.FollowAction;
|
||||
import ctbrec.ui.action.IgnoreModelsAction;
|
||||
import ctbrec.ui.action.OpenRecordingsDir;
|
||||
import ctbrec.ui.action.OpenUrlAction;
|
||||
import ctbrec.ui.action.PauseAction;
|
||||
import ctbrec.ui.action.PlayAction;
|
||||
import ctbrec.ui.action.RemoveTimeLimitAction;
|
||||
import ctbrec.ui.action.ResumeAction;
|
||||
import ctbrec.ui.action.SetStopDateAction;
|
||||
import ctbrec.ui.action.StartRecordingAction;
|
||||
import ctbrec.ui.action.StopRecordingAction;
|
||||
import ctbrec.ui.action.ToggleRecordingAction;
|
||||
import ctbrec.ui.controls.CustomMouseBehaviorContextMenu;
|
||||
|
@ -56,7 +43,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.menu.ModelGroupMenuBuilder;
|
||||
import ctbrec.ui.menu.ModelMenuContributor;
|
||||
import ctbrec.ui.tabs.TabSelectionListener;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
|
@ -71,12 +58,11 @@ import javafx.concurrent.WorkerStateEvent;
|
|||
import javafx.event.ActionEvent;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.Cursor;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.ContextMenu;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.Menu;
|
||||
import javafx.scene.control.MenuItem;
|
||||
import javafx.scene.control.ScrollPane;
|
||||
import javafx.scene.control.SelectionMode;
|
||||
import javafx.scene.control.Tab;
|
||||
|
@ -92,8 +78,6 @@ import javafx.scene.control.Tooltip;
|
|||
import javafx.scene.control.cell.CheckBoxTableCell;
|
||||
import javafx.scene.control.cell.PropertyValueFactory;
|
||||
import javafx.scene.control.cell.TextFieldTableCell;
|
||||
import javafx.scene.input.Clipboard;
|
||||
import javafx.scene.input.ClipboardContent;
|
||||
import javafx.scene.input.ContextMenuEvent;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.input.KeyEvent;
|
||||
|
@ -505,6 +489,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
|||
filteredModels.clear();
|
||||
filter(filter.getText());
|
||||
table.sort();
|
||||
table.refresh();
|
||||
}
|
||||
|
||||
private void addOrUpdateModels(List<JavaFxModel> updatedModels) {
|
||||
|
@ -635,162 +620,21 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
|||
}
|
||||
|
||||
private ContextMenu createContextMenu() {
|
||||
ObservableList<JavaFxModel> selectedModels = table.getSelectionModel().getSelectedItems();
|
||||
List<Model> selectedModels = table.getSelectionModel().getSelectedItems().stream().map(JavaFxModel::getDelegate).collect(Collectors.toList());
|
||||
if (selectedModels.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
var stop = new MenuItem("Remove Model");
|
||||
stop.setOnAction(e -> stopAction(selectedModels));
|
||||
var recordLater = new MenuItem("Record Later");
|
||||
recordLater.setOnAction(e -> recordLater(selectedModels));
|
||||
|
||||
var copyUrl = new MenuItem("Copy URL");
|
||||
copyUrl.setOnAction(e -> {
|
||||
Model selected = selectedModels.get(0);
|
||||
final var clipboard = Clipboard.getSystemClipboard();
|
||||
final var content = new ClipboardContent();
|
||||
content.putString(selected.getUrl());
|
||||
clipboard.setContent(content);
|
||||
});
|
||||
ContextMenu menu = new CustomMouseBehaviorContextMenu();
|
||||
|
||||
var pauseRecording = new MenuItem("Pause Recording");
|
||||
pauseRecording.setOnAction(e -> pauseRecording(selectedModels));
|
||||
var resumeRecording = new MenuItem("Resume Recording");
|
||||
resumeRecording.setOnAction(e -> resumeRecording(selectedModels));
|
||||
var stopRecordingAt = new MenuItem("Stop Recording at Date");
|
||||
stopRecordingAt.setOnAction(e -> setStopDate(selectedModels.get(0)));
|
||||
var removeTimeLimit = new MenuItem("Remove Time Limit");
|
||||
removeTimeLimit.setOnAction(e -> removeTimeLimit(selectedModels.get(0)));
|
||||
var openInBrowser = new MenuItem("Open in Browser");
|
||||
openInBrowser.setOnAction(e -> openInBrowser(selectedModels));
|
||||
var openInPlayer = new MenuItem("Open in Player");
|
||||
openInPlayer.setOnAction(e -> openInPlayer(selectedModels.get(0)));
|
||||
var switchStreamSource = new MenuItem("Switch resolution");
|
||||
switchStreamSource.setOnAction(e -> switchStreamSource(selectedModels.get(0)));
|
||||
var follow = new MenuItem("Follow");
|
||||
follow.setOnAction(e -> follow(selectedModels));
|
||||
follow.setDisable(!selectedModels.stream().allMatch(m -> m.getSite().supportsFollow() && m.getSite().credentialsAvailable()));
|
||||
var ignore = new MenuItem("Ignore");
|
||||
ignore.setOnAction(e -> ignore(selectedModels));
|
||||
var notes = new MenuItem("Notes");
|
||||
notes.setOnAction(e -> notes(selectedModels));
|
||||
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 -> new AddToGroupAction(this.getContent(), recorder, selectedModels.get(0)).execute(() -> table.refresh()));
|
||||
var groupSubMenu = createModelGroupMenu(selectedModels);
|
||||
|
||||
ContextMenu menu = new CustomMouseBehaviorContextMenu(stop, recordLater);
|
||||
if (selectedModels.size() == 1) {
|
||||
menu.getItems().add(selectedModels.get(0).isSuspended() ? resumeRecording : pauseRecording);
|
||||
menu.getItems().add(stopRecordingAt);
|
||||
if (selectedModels.get(0).isRecordingTimeLimited()) {
|
||||
menu.getItems().add(removeTimeLimit);
|
||||
}
|
||||
} else {
|
||||
menu.getItems().addAll(resumeRecording, pauseRecording);
|
||||
}
|
||||
Optional<ModelGroup> modelGroup = recorder.getModelGroup(selectedModels.get(0));
|
||||
menu.getItems().add(modelGroup.isEmpty() ? addToGroup : groupSubMenu);
|
||||
menu.getItems().addAll(copyUrl, openInPlayer, openInBrowser, openRecDir, switchStreamSource, follow, notes, ignore);
|
||||
|
||||
if (selectedModels.size() > 1) {
|
||||
copyUrl.setDisable(true);
|
||||
openInPlayer.setDisable(true);
|
||||
switchStreamSource.setDisable(true);
|
||||
notes.setDisable(true);
|
||||
}
|
||||
ModelMenuContributor.newContributor(getTabPane(), Config.getInstance(), recorder) //
|
||||
.withStartStopCallback(m -> getTabPane().setCursor(Cursor.DEFAULT)) //
|
||||
.afterwards(table::refresh)
|
||||
.contributeToMenu(selectedModels, menu);
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
private void openInBrowser(ObservableList<JavaFxModel> selectedModels) {
|
||||
List<Model> models = selectedModels.stream().map(JavaFxModel::getDelegate).collect(Collectors.toList());
|
||||
new OpenUrlAction(getTabPane(), models).execute();
|
||||
}
|
||||
|
||||
private Menu createModelGroupMenu(ObservableList<JavaFxModel> selectedModels) {
|
||||
return new ModelGroupMenuBuilder() //
|
||||
.model(selectedModels.get(0)) //
|
||||
.recorder(recorder) //
|
||||
.node(table) //
|
||||
.callback(m -> table.refresh()) //
|
||||
.build();
|
||||
}
|
||||
|
||||
private void setStopDate(JavaFxModel model) {
|
||||
new SetStopDateAction(table, model.getDelegate(), recorder) //
|
||||
.execute() //
|
||||
.whenComplete((result, exception) -> table.refresh());
|
||||
}
|
||||
|
||||
private void removeTimeLimit(JavaFxModel selectedModel) {
|
||||
new RemoveTimeLimitAction(table, selectedModel.getDelegate(), recorder) //
|
||||
.execute() //
|
||||
.whenComplete((result, exception) -> table.refresh());
|
||||
}
|
||||
|
||||
private void ignore(ObservableList<JavaFxModel> selectedModels) {
|
||||
new IgnoreModelsAction(table, selectedModels, recorder, true).execute();
|
||||
}
|
||||
|
||||
private void follow(ObservableList<JavaFxModel> selectedModels) {
|
||||
new FollowAction(getTabPane(), new ArrayList<>(selectedModels)).execute();
|
||||
}
|
||||
|
||||
private void notes(ObservableList<JavaFxModel> selectedModels) {
|
||||
new EditNotesAction(getTabPane(), selectedModels.get(0), table).execute();
|
||||
}
|
||||
|
||||
private void openInPlayer(JavaFxModel selectedModel) {
|
||||
new PlayAction(getTabPane(), selectedModel).execute();
|
||||
}
|
||||
|
||||
private void switchStreamSource(JavaFxModel fxModel) {
|
||||
var couldntSwitchHeaderText = "Couldn't switch stream resolution";
|
||||
|
||||
try {
|
||||
if (!fxModel.isOnline(true)) {
|
||||
Dialogs.showError(getTabPane().getScene(), couldntSwitchHeaderText, "The resolution can only be changed, when the model is online", null);
|
||||
return;
|
||||
}
|
||||
} catch (InterruptedException e1) {
|
||||
Thread.currentThread().interrupt();
|
||||
Dialogs.showError(getTabPane().getScene(), couldntSwitchHeaderText, "An error occured while checking, if the model is online", null);
|
||||
return;
|
||||
} catch (IOException | ExecutionException e1) {
|
||||
Dialogs.showError(getTabPane().getScene(), couldntSwitchHeaderText, "An error occured while checking, if the model is online", null);
|
||||
return;
|
||||
}
|
||||
|
||||
Consumer<Model> onSuccess = m -> {
|
||||
try {
|
||||
recorder.switchStreamSource(m);
|
||||
} catch (InvalidKeyException | NoSuchAlgorithmException | IllegalStateException | IOException e) {
|
||||
LOG.error(couldntSwitchHeaderText, e);
|
||||
showStreamSwitchErrorDialog(e);
|
||||
}
|
||||
};
|
||||
Consumer<Throwable> onFail = t -> {
|
||||
LOG.error(couldntSwitchHeaderText, t);
|
||||
showStreamSwitchErrorDialog(t);
|
||||
};
|
||||
StreamSourceSelectionDialog.show(getTabPane().getScene(), fxModel.getDelegate(), onSuccess, onFail);
|
||||
}
|
||||
|
||||
private void showStreamSwitchErrorDialog(Throwable throwable) {
|
||||
showErrorDialog(throwable, "Couldn't switch stream resolution", "Error while switching stream resolution");
|
||||
}
|
||||
|
||||
private void showErrorDialog(Throwable throwable, String header, String msg) {
|
||||
Alert alert = new AutosizeAlert(Alert.AlertType.ERROR, getTabPane().getScene());
|
||||
alert.setTitle("Error");
|
||||
alert.setHeaderText(header);
|
||||
alert.setContentText(msg + ": " + throwable.getLocalizedMessage());
|
||||
alert.showAndWait();
|
||||
}
|
||||
|
||||
private boolean stopAction(List<JavaFxModel> selectedModels) {
|
||||
var confirmed = true;
|
||||
if (Config.getInstance().getSettings().confirmationForDangerousActions) {
|
||||
|
@ -809,17 +653,6 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
|||
return confirmed;
|
||||
}
|
||||
|
||||
private void recordLater(List<JavaFxModel> selectedModels) {
|
||||
boolean confirmed = stopAction(selectedModels);
|
||||
if (confirmed) {
|
||||
List<Model> models = selectedModels.stream().map(JavaFxModel::getDelegate).map(m -> {
|
||||
m.setMarkedForLaterRecording(true);
|
||||
return m;
|
||||
}).collect(Collectors.toList());
|
||||
new StartRecordingAction(table, models, recorder).execute();
|
||||
}
|
||||
}
|
||||
|
||||
private void pauseRecording(List<JavaFxModel> selectedModels) {
|
||||
List<Model> models = selectedModels.stream().map(JavaFxModel::getDelegate).collect(Collectors.toList());
|
||||
new PauseAction(getTabPane(), models, recorder).execute();
|
||||
|
|
Loading…
Reference in New Issue