Add a lot of model groups tweaks

This commit is contained in:
0xb00bface 2021-05-13 16:28:06 +02:00
parent e78ae2685a
commit 0c4f37f950
15 changed files with 210 additions and 112 deletions

View File

@ -2,6 +2,7 @@ package ctbrec.ui;
public enum Icon {
BLANK_16(Icon.class.getResource("/16/blank.png").toExternalForm()),
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());

View File

@ -43,8 +43,7 @@ public class AddToGroupAction {
source.setCursor(Cursor.WAIT);
try {
var dialog = new AddModelGroupDialog();
boolean ok = Dialogs.showCustomInput(source.getScene(), "Add model to group", dialog.getMainPane());
dialog.requestFocus();
boolean ok = Dialogs.showCustomInput(source.getScene(), "Add model to group", dialog.getMainPane(), (obs, ov, nv) -> dialog.requestFocus());
if (ok) {
String text = dialog.getText();
if (StringUtil.isBlank(text)) {
@ -80,18 +79,19 @@ public class AddToGroupAction {
return comboBox.getEditor().getText();
}
public void requestFocus() {
comboBox.requestFocus();
void requestFocus() {
System.err.println("request focus");
editor.requestFocus();
editor.positionCaret(0);
editor.selectAll();
}
Region getMainPane() throws InvalidKeyException, NoSuchAlgorithmException, IOException {
Region getMainPane() {
var dialogPane = new GridPane();
Set<ModelGroup> modelGroups;
modelGroups = recorder.getModelGroups();
List<ModelGroupListItem> comboBoxItems = modelGroups.stream().map(ModelGroupListItem::new).sorted().collect(Collectors.toList());
ObservableList<ModelGroupListItem> comboBoxModel = FXCollections.observableArrayList(comboBoxItems);
suggester = new ObservableListSuggester(comboBoxModel);
comboBox = new ComboBox<>(comboBoxModel);
comboBox.setEditable(true);
editor = comboBox.getEditor();
@ -112,9 +112,22 @@ public class AddToGroupAction {
comboBox.setPlaceholder(new Label(" type in a name to a add a new group "));
dialogPane.add(new Label("Model group "), 0, 0);
dialogPane.add(comboBox, 1, 0);
suggestInitialName(modelGroups);
suggester = new ObservableListSuggester(comboBoxModel);
return dialogPane;
}
private void suggestInitialName(Set<ModelGroup> modelGroups) {
String bestName = model.getDisplayName();
for (ModelGroup modelGroup : modelGroups) {
if (StringUtil.percentageOfEquality(bestName, modelGroup.getName()) > 70) {
bestName = modelGroup.getName();
break;
}
}
editor.setText(bestName);
}
private void autocomplete(boolean fulltextSearch) {
String oldtext = getOldText();
if(oldtext.isEmpty()) {

View File

@ -1,8 +1,5 @@
package ctbrec.ui.action;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@ -71,18 +68,13 @@ public class EditGroupAction {
private List<String> urls;
public EditModelGroupDialog(Model model) {
Optional<ModelGroup> optionalModelGroup;
try {
optionalModelGroup = recorder.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);
}
} catch (InvalidKeyException | NoSuchAlgorithmException | IOException e) {
Dialogs.showError(getScene(), DIALOG_TITLE, "Couldn't edit model group", e);
Optional<ModelGroup> optionalModelGroup = recorder.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);
}
}
@ -103,14 +95,12 @@ public class EditGroupAction {
vgapProperty().bind(hgapProperty());
groupName = new TextField(modelGroup.getName());
Button up = createUpButton();
Button down = createDownButton();
Button remove = createRemoveButton();
var up = createUpButton();
var down = createDownButton();
var remove = createRemoveButton();
var buttons = new VBox(3, up, down, remove);
urlList = FXCollections.observableList(modelGroup.getModelUrls());
urlList.addListener((ListChangeListener<String>) change -> {
urls = new ArrayList<>(urlList);
});
urlList.addListener((ListChangeListener<String>) change -> urls = new ArrayList<>(urlList));
urlListView = new ListView<>(urlList);
GridPane.setHgrow(urlListView, Priority.ALWAYS);

View File

@ -10,5 +10,8 @@ public class CustomMouseBehaviorContextMenu extends ContextMenu {
super(items);
UiUtils.disableRightClickFor(this);
UiUtils.ignoreMouseReleasedIfMouseExited(this);
setAutoHide(true);
setHideOnEscape(true);
setAutoFix(true);
}
}

View File

@ -13,6 +13,7 @@ import ctbrec.ModelGroup;
import ctbrec.StringUtil;
import ctbrec.ui.AutosizeAlert;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
@ -105,7 +106,8 @@ public class Dialogs {
return dialog.showAndWait();
}
public static Boolean showCustomInput(Scene parent, String title, Region region) {
@SafeVarargs
public static Boolean showCustomInput(Scene parent, String title, Region region, ChangeListener<Boolean> ...showingListener) {
Dialog<?> dialog = new Dialog<>();
dialog.setTitle(title);
dialog.getDialogPane().getButtonTypes().addAll(OK, CANCEL);
@ -118,6 +120,9 @@ public class Dialogs {
stage.getScene().getStylesheets().addAll(parent.getStylesheets());
}
dialog.getDialogPane().setContent(region);
for (ChangeListener<Boolean> changeListener : showingListener) {
dialog.showingProperty().addListener(changeListener);
}
dialog.showAndWait();
return dialog.getResult() == OK;
}

View File

@ -4,8 +4,6 @@ import static ctbrec.ui.controls.Dialogs.*;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;
@ -48,7 +46,6 @@ import ctbrec.ui.action.IgnoreModelsAction;
import ctbrec.ui.action.OpenRecordingsDir;
import ctbrec.ui.action.SetStopDateAction;
import ctbrec.ui.controls.CustomMouseBehaviorContextMenu;
import ctbrec.ui.controls.Dialogs;
import ctbrec.ui.controls.FasterVerticalScrollPaneSkin;
import ctbrec.ui.controls.SearchBox;
import ctbrec.ui.controls.SearchPopover;
@ -472,6 +469,14 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
return newCell;
}
// private ContextMenu createContextMenu(ThumbCell cell) {
// return new ModelContextMenu.Builder()
// .model(cell.getModel())
// .node(grid)
// .recorder(recorder)
// .build();
// }
private ContextMenu createContextMenu(ThumbCell cell) {
var model = cell.getModel();
boolean modelIsTrackedByRecorder = recorder.isTracked(model);
@ -546,7 +551,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
if (site.supportsTips()) {
contextMenu.getItems().add(sendTip);
}
Optional<ModelGroup> modelGroup = getModelGroup(model);
Optional<ModelGroup> modelGroup = recorder.getModelGroup(model);
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")) {
@ -558,15 +563,6 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
return contextMenu;
}
private Optional<ModelGroup> getModelGroup(Model model) {
try {
return recorder.getModelGroup(model);
} catch (InvalidKeyException | NoSuchAlgorithmException | IOException e) {
Dialogs.showError(grid.getScene(), "Error", "Couldn't get model group for model " + model, e);
return Optional.empty();
}
}
private void editGroup(Model model) {
new EditGroupAction(this.getContent(), recorder, model).execute();
}
@ -900,14 +896,14 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
private boolean modelPropertiesMatchToken(String token, Model m) throws IOException, ExecutionException {
int[] resolution = Optional.ofNullable(ThumbCell.resolutionCache.getIfPresent(m)).orElse(new int[2]);
String searchText = createSearchText(m);
boolean tokensMissing = false;
var tokensMissing = false;
if (token.matches(">\\d+")) {
int res = Integer.parseInt(token.substring(1));
var res = Integer.parseInt(token.substring(1));
if (resolution[1] < res) {
tokensMissing = true;
}
} else if (token.matches("<\\d+")) {
int res = Integer.parseInt(token.substring(1));
var res = Integer.parseInt(token.substring(1));
if (resolution[1] > res) {
tokensMissing = true;
}
@ -916,7 +912,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
tokensMissing = true;
}
} else {
boolean negated = false;
var negated = false;
if(token.startsWith("!")) {
negated = true;
token = token.substring(1);
@ -928,7 +924,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
}
private String createSearchText(Model m) {
StringBuilder searchTextBuilder = new StringBuilder(m.getName());
var searchTextBuilder = new StringBuilder(m.getName());
searchTextBuilder.append(' ');
searchTextBuilder.append(m.getDisplayName());
searchTextBuilder.append(' ');
@ -939,6 +935,8 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
searchTextBuilder.append(resolution[1]);
searchTextBuilder.append(' ');
searchTextBuilder.append(Optional.ofNullable(m.getDescription()).orElse(""));
searchTextBuilder.append(' ');
searchTextBuilder.append(recorder.getModelGroup(m).map(ModelGroup::getName).orElse(""));
return searchTextBuilder.toString().trim();
}

View File

@ -2,55 +2,42 @@ package ctbrec.ui.tabs.recorded;
import static ctbrec.ui.Icon.*;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import ctbrec.Model;
import ctbrec.ModelGroup;
import ctbrec.recorder.Recorder;
import ctbrec.ui.controls.Dialogs;
import ctbrec.ui.tabs.recorded.RecordedModelsTab.ModelName;
import javafx.scene.image.ImageView;
public class ModelNameTableCell extends IconTableCell<String> {
public class ModelNameTableCell extends IconTableCell<ModelName> {
private Recorder recorder;
public ModelNameTableCell(Recorder recorder) {
super(Map.of(GROUP_16, new ImageView(GROUP_16.url())));
super(Map.of( //
GROUP_16, new ImageView(GROUP_16.url()), //
BLANK_16, new ImageView(BLANK_16.url())));
this.recorder = recorder;
}
@Override
protected void updateItem(String item, boolean empty) {
protected void updateItem(ModelName modelName, boolean empty) {
setText(null);
tooltip = null;
show(BLANK_16);
hide(GROUP_16);
if (item != null && !empty) {
setText(item);
if (modelName != null && !empty) {
setText(modelName.toString());
Model m = getTableView().getItems().get(getTableRow().getIndex());
Optional<ModelGroup> optionalGroup = getModelGroup(m);
if (optionalGroup.isPresent()) {
ModelGroup group = optionalGroup.get();
setText(group.getName() + " (aka " + item + ')');
recorder.getModelGroup(m).ifPresent(group -> {
hide(BLANK_16);
show(GROUP_16);
tooltip = group.getModelUrls().size() + " models:\n";
tooltip += group.getModelUrls().stream().collect(Collectors.joining("\n"));
}
}
super.updateItem(item, empty);
}
private Optional<ModelGroup> getModelGroup(Model model) {
try {
return recorder.getModelGroup(model);
} catch (InvalidKeyException | NoSuchAlgorithmException | IOException e) {
Dialogs.showError(getScene(), "Error", "Couldn't get model group for model " + model, e);
return Optional.empty();
});
}
super.updateItem(modelName, empty);
}
}

View File

@ -16,16 +16,11 @@ public class OnlineTableCell extends IconTableCell<Boolean> {
@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;
hide(CHECK_16);
tooltip = null;
if (!empty && Objects.equal(value, Boolean.TRUE)) {
show(CHECK_16);
tooltip = "Online";
}
super.updateItem(value, empty);
}

View File

@ -59,6 +59,7 @@ 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.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringPropertyBase;
import javafx.beans.value.ChangeListener;
@ -170,9 +171,12 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
if(!Config.getInstance().getSettings().livePreviews) {
preview.setVisible(false);
}
TableColumn<JavaFxModel, String> name = new TableColumn<>("Model");
TableColumn<JavaFxModel, ModelName> name = new TableColumn<>("Model");
name.setPrefWidth(200);
name.setCellValueFactory(new PropertyValueFactory<>("displayName"));
name.setCellValueFactory(param -> {
ModelName modelName = new ModelName(param.getValue(), recorder);
return new SimpleObjectProperty<>(modelName);
});
name.setCellFactory(param -> new ModelNameTableCell(recorder));
name.setEditable(false);
name.setId("name");
@ -694,7 +698,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
} else {
menu.getItems().addAll(resumeRecording, pauseRecording);
}
Optional<ModelGroup> modelGroup = getModelGroup(selectedModels.get(0));
Optional<ModelGroup> modelGroup = recorder.getModelGroup(selectedModels.get(0));
menu.getItems().add(modelGroup.isEmpty() ? addToGroup : editGroup);
menu.getItems().addAll(copyUrl, openInPlayer, openInBrowser, openRecDir, switchStreamSource, follow, notes, ignore);
@ -709,15 +713,6 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
return menu;
}
private Optional<ModelGroup> getModelGroup(Model model) {
try {
return recorder.getModelGroup(model);
} catch (InvalidKeyException | NoSuchAlgorithmException | IOException e) {
Dialogs.showError(grid.getScene(), "Error", "Couldn't get model group for model " + model, e);
return Optional.empty();
}
}
private void addToGroup(Model model) {
new AddToGroupAction(this.getContent(), recorder, model).execute();
table.refresh();
@ -952,4 +947,26 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
return tableCell;
}
}
public static class ModelName {
private Model mdl;
private Recorder rec;
public ModelName(Model model, Recorder recorder) {
mdl = model;
rec = recorder;
}
@Override
public String toString() {
Optional<ModelGroup> modelGroup = rec.getModelGroup(mdl);
String s;
if (modelGroup.isPresent()) {
s = modelGroup.get().getName() + " (aka " + mdl.getDisplayName() + ')';
} else {
return mdl.toString();
}
return s;
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 533 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 541 B

View File

@ -88,4 +88,107 @@ public class StringUtil {
}
return result.toString();
}
public static int percentageOfEquality(String s, String t) {
// check if strings are empty
if (s == null || t == null || s.length() == 0 || t.length() == 0) {
return 0;
}
// check if the strings are equal
if (s.equals(t)) {
return 100;
}
// check if one string is a substring of the other
String shorter;
String longer;
if (s.length() > t.length()) {
shorter = t;
longer = s;
} else {
shorter = s;
longer = t;
}
if (longer.startsWith(shorter) && longer.length() > shorter.length()) {
if (longer.charAt(shorter.length()) == ' ') {
return 99;
} else {
return 98;
}
}
s = s.toLowerCase();
s = s.replaceAll("-", " ");
s = s.replaceAll(":", " ");
s = s.replaceAll(";", " ");
s = s.replaceAll("\\|", " ");
s = s.replaceAll("_", " ");
s = s.replaceAll("\\.", "\\. ");
s = s.trim();
t = t.toLowerCase();
t = t.replaceAll("-", " ");
t = t.replaceAll(":", " ");
t = t.replaceAll(";", " ");
t = t.replaceAll("\\|", " ");
t = t.replaceAll("_", " ");
t = t.replaceAll("\\.", "\\. ");
t = t.trim();
// calculate levenshteinDistance
int levenshteinDistance = StringUtil.getLevenshteinDistance(s, t);
int length = Math.max(s.length(), t.length());
// calculate the percentage of equality
int percentage = 100 - (int) ((double) levenshteinDistance * 100 / length);
return percentage;
}
public static int getLevenshteinDistance(String s, String t) {
int n = s.length();
int m = t.length();
int d[][] = new int[n + 1][m + 1];
int i;
int j;
int cost;
if (n == 0) {
return m;
}
if (m == 0) {
return n;
}
for (i = 0; i <= n; i++) {
d[i][0] = i;
}
for (j = 0; j <= m; j++) {
d[0][j] = j;
}
for (i = 1; i <= n; i++) {
for (j = 1; j <= m; j++) {
if (s.charAt(i - 1) == t.charAt(j - 1)) {
cost = 0;
} else {
cost = 1;
}
d[i][j] = min(d[i - 1][j] + 1, // insertion
d[i][j - 1] + 1, // deletion
d[i - 1][j - 1] + cost); // substitution
}
}
return d[n][m];
}
private static int min(int a, int b, int c) {
if (b < a) {
a = b;
}
if (c < a) {
a = c;
}
return a;
}
}

View File

@ -152,7 +152,7 @@ public interface Recorder {
*/
public int getModelCount();
public Set<ModelGroup> getModelGroups() throws InvalidKeyException, NoSuchAlgorithmException, IOException;
public Set<ModelGroup> getModelGroups();
/**
* Saves a model group. If the group already exists, it will be overwritten. Otherwise it will
@ -166,7 +166,7 @@ public interface Recorder {
public void deleteModelGroup(ModelGroup group) throws IOException, InvalidKeyException, NoSuchAlgorithmException;
default Optional<ModelGroup> getModelGroup(Model model) throws InvalidKeyException, NoSuchAlgorithmException, IOException {
default Optional<ModelGroup> getModelGroup(Model model) {
return getModelGroups().stream()
.filter(mg -> mg.getModelUrls().contains(model.getUrl()))
.findFirst();

View File

@ -690,7 +690,7 @@ public class RemoteRecorder implements Recorder {
}
@Override
public Set<ModelGroup> getModelGroups() throws InvalidKeyException, NoSuchAlgorithmException, IOException {
public Set<ModelGroup> getModelGroups() {
return modelGroups;
}

View File

@ -3,9 +3,6 @@ package ctbrec.recorder.postprocessing;
import static ctbrec.StringUtil.*;
import static java.util.Optional.*;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;
@ -18,9 +15,6 @@ import java.util.Optional;
import java.util.UUID;
import java.util.function.Function;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ctbrec.Config;
import ctbrec.Model;
import ctbrec.ModelGroup;
@ -30,18 +24,10 @@ import ctbrec.sites.Site;
public abstract class AbstractPlaceholderAwarePostProcessor extends AbstractPostProcessor {
private static final Logger LOG = LoggerFactory.getLogger(AbstractPlaceholderAwarePostProcessor.class);
public String fillInPlaceHolders(String input, PostProcessingContext ctx) {
Recording rec = ctx.getRecording();
Config config = ctx.getConfig();
Optional<ModelGroup> modelGroup;
try {
modelGroup = ctx.getRecorder().getModelGroup(rec.getModel());
} catch (InvalidKeyException | NoSuchAlgorithmException | IOException e) {
LOG.error("Couldn't get model group for {}", rec.getModel(), e);
return input;
}
Optional<ModelGroup> modelGroup = ctx.getRecorder().getModelGroup(rec.getModel());
Map<String, Function<String, Optional<String>>> placeholderValueSuppliers = new HashMap<>();
placeholderValueSuppliers.put("modelName", r -> ofNullable(rec.getModel().getName()));