Rework to avoid using preferences object to retrieve options

This commit is contained in:
Guillaume Tâche
2024-09-22 21:59:10 +02:00
parent 7f99c48e2c
commit c59619da2d
115 changed files with 2294 additions and 765 deletions

View File

@@ -1,5 +1,6 @@
package com.github.gtache.autosubtitle.gui.parameters;
import com.github.gtache.autosubtitle.subtitle.Font;
import com.github.gtache.autosubtitle.subtitle.OutputFormat;
import com.github.gtache.autosubtitle.subtitle.extractor.ExtractionModel;
@@ -65,6 +66,11 @@ public interface ParametersModel {
*/
void setFontSize(int fontSize);
/**
* @return The current font
*/
Font font();
/**
* @return The current max line length setting
*/

View File

@@ -1,7 +1,6 @@
package com.github.gtache.autosubtitle.gui.subtitles;
import com.github.gtache.autosubtitle.Language;
import com.github.gtache.autosubtitle.VideoInfo;
import com.github.gtache.autosubtitle.subtitle.Subtitle;
import com.github.gtache.autosubtitle.subtitle.SubtitleCollection;
@@ -33,18 +32,6 @@ public interface SubtitlesModel<T extends Subtitle, U extends SubtitleCollection
*/
void setVideoLanguage(Language language);
/**
* @return The video info
*/
VideoInfo videoInfo();
/**
* Sets the video info
*
* @param videoInfo The new video info
*/
void setVideoInfo(VideoInfo videoInfo);
/**
* @return The list of available translations languages
*/

View File

@@ -1,8 +1,9 @@
package com.github.gtache.autosubtitle.gui.work;
import com.github.gtache.autosubtitle.Video;
import com.github.gtache.autosubtitle.subtitle.ExportOptions;
import com.github.gtache.autosubtitle.subtitle.SubtitleCollection;
import com.github.gtache.autosubtitle.subtitle.extractor.ExtractionModel;
import com.github.gtache.autosubtitle.subtitle.extractor.ExtractOptions;
/**
* Model for the main view
@@ -19,16 +20,6 @@ public interface WorkModel {
*/
void setVideo(Video video);
/**
* @return The current extraction model
*/
ExtractionModel extractionModel();
/**
* @param model The new extraction model
*/
void setExtractionModel(ExtractionModel model);
/**
* @return The current status
*/
@@ -80,4 +71,28 @@ public interface WorkModel {
* @param collection The last extracted collection
*/
void setExtractedCollection(SubtitleCollection<?> collection);
/**
* @return The current export options
*/
ExportOptions exportOptions();
/**
* Sets the export options
*
* @param options The options
*/
void setExportOptions(ExportOptions options);
/**
* @return The current extract options
*/
ExtractOptions extractOptions();
/**
* Sets the extract options
*
* @param options The options
*/
void setExtractOptions(ExtractOptions options);
}

View File

@@ -14,13 +14,13 @@ public class CombinedResourceBundle extends ResourceBundle {
private final Map<String, String> resources;
private final Locale locale;
public CombinedResourceBundle(final ResourceBundle... resourceBundles) {
this(Arrays.asList(resourceBundles));
public CombinedResourceBundle(final ResourceBundle... bundles) {
this(Arrays.asList(bundles));
}
public CombinedResourceBundle(final List<ResourceBundle> resourceBundles) {
final var filteredBundles = resourceBundles.stream().filter(Objects::nonNull).toList();
if (filteredBundles.size() != resourceBundles.size()) {
public CombinedResourceBundle(final Collection<ResourceBundle> bundles) {
final var filteredBundles = bundles.stream().filter(Objects::nonNull).toList();
if (filteredBundles.size() != bundles.size()) {
logger.warn("There was one or more null bundles in the inner bundles");
}
if (filteredBundles.isEmpty()) {

View File

@@ -5,5 +5,6 @@ import java.util.spi.ResourceBundleProvider;
/**
* Provider for MainBundle
*/
@FunctionalInterface
public interface MainBundleProvider extends ResourceBundleProvider {
}

View File

@@ -5,5 +5,6 @@ import java.util.spi.ResourceBundleProvider;
/**
* Provider for ParametersBundle
*/
@FunctionalInterface
public interface ParametersBundleProvider extends ResourceBundleProvider {
}

View File

@@ -5,5 +5,6 @@ import java.util.spi.ResourceBundleProvider;
/**
* Provider for SetupBundle
*/
@FunctionalInterface
public interface SetupBundleProvider extends ResourceBundleProvider {
}

View File

@@ -5,5 +5,6 @@ import java.util.spi.ResourceBundleProvider;
/**
* Provider for SubtitlesBundle
*/
@FunctionalInterface
public interface SubtitlesBundleProvider extends ResourceBundleProvider {
}

View File

@@ -5,5 +5,6 @@ import java.util.spi.ResourceBundleProvider;
/**
* Provider for WorkBundle
*/
@FunctionalInterface
public interface WorkBundleProvider extends ResourceBundleProvider {
}

View File

@@ -31,6 +31,9 @@ public final class GuiCoreModule {
@Play
static byte[] providesPlayImage() {
try (final var in = GuiCoreModule.class.getResourceAsStream("/com/github/gtache/autosubtitle/gui/impl/play_64.png")) {
if (in == null) {
throw new UncheckedIOException(new IOException("Resource not found : /com/github/gtache/autosubtitle/gui/impl/play_64.png"));
}
return in.readAllBytes();
} catch (final IOException e) {
throw new UncheckedIOException(e);
@@ -41,6 +44,9 @@ public final class GuiCoreModule {
@Pause
static byte[] providesPauseImage() {
try (final var in = GuiCoreModule.class.getResourceAsStream("/com/github/gtache/autosubtitle/gui/impl/pause_64.png")) {
if (in == null) {
throw new UncheckedIOException(new IOException("Resource not found : /com/github/gtache/autosubtitle/gui/impl/pause_64.png"));
}
return in.readAllBytes();
} catch (final IOException e) {
throw new UncheckedIOException(e);

View File

@@ -20,6 +20,7 @@ import javax.inject.Singleton;
import java.util.function.UnaryOperator;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;
import java.util.regex.Pattern;
import static java.util.Objects.requireNonNull;
@@ -30,6 +31,7 @@ import static java.util.Objects.requireNonNull;
public class FXParametersController extends AbstractFXController implements ParametersController {
private static final Logger logger = LogManager.getLogger(FXParametersController.class);
private static final Pattern INTEGER_PATTERN = Pattern.compile("[1-9]\\d*");
@FXML
private PrefixSelectionComboBox<ExtractionModel> extractionModelCombobox;
@FXML
@@ -67,7 +69,7 @@ public class FXParametersController extends AbstractFXController implements Para
final UnaryOperator<TextFormatter.Change> integerFilter = change -> {
final var newText = change.getControlNewText();
if (newText.matches("[1-9]\\d*")) {
if (INTEGER_PATTERN.matcher(newText).matches()) {
return change;
}
return null;

View File

@@ -5,11 +5,16 @@ import com.github.gtache.autosubtitle.modules.impl.FontName;
import com.github.gtache.autosubtitle.modules.impl.FontSize;
import com.github.gtache.autosubtitle.modules.impl.MaxLineLength;
import com.github.gtache.autosubtitle.modules.impl.MaxLines;
import com.github.gtache.autosubtitle.subtitle.Font;
import com.github.gtache.autosubtitle.subtitle.OutputFormat;
import com.github.gtache.autosubtitle.subtitle.extractor.ExtractionModel;
import com.github.gtache.autosubtitle.subtitle.extractor.ExtractionModelProvider;
import com.github.gtache.autosubtitle.subtitle.impl.FontImpl;
import javafx.beans.binding.Bindings;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
@@ -33,6 +38,7 @@ public class FXParametersModel implements ParametersModel {
private final ObservableList<String> availableFontFamilies;
private final StringProperty fontName;
private final IntegerProperty fontSize;
private final ReadOnlyObjectWrapper<Font> font;
private final IntegerProperty maxLineLength;
private final IntegerProperty maxLines;
@@ -46,8 +52,11 @@ public class FXParametersModel implements ParametersModel {
this.availableFontFamilies = FXCollections.unmodifiableObservableList(FXCollections.observableArrayList("Arial"));
this.fontName = new SimpleStringProperty(defaultFontFamily);
this.fontSize = new SimpleIntegerProperty(defaultFontSize);
this.font = new ReadOnlyObjectWrapper<>();
this.maxLineLength = new SimpleIntegerProperty(defaultMaxLineLength);
this.maxLines = new SimpleIntegerProperty(defaultMaxLines);
font.bind(Bindings.createObjectBinding(() -> new FontImpl(fontName(), fontSize()), fontName, fontSize));
}
@Override
@@ -84,7 +93,7 @@ public class FXParametersModel implements ParametersModel {
outputFormat.set(format);
}
ObjectProperty<OutputFormat> outputFormatProperty() {
public ObjectProperty<OutputFormat> outputFormatProperty() {
return outputFormat;
}
@@ -121,6 +130,15 @@ public class FXParametersModel implements ParametersModel {
return fontSize;
}
@Override
public Font font() {
return font.get();
}
public ReadOnlyObjectProperty<Font> fontProperty() {
return font.getReadOnlyProperty();
}
@Override
public int maxLineLength() {
return maxLineLength.get();
@@ -131,7 +149,7 @@ public class FXParametersModel implements ParametersModel {
this.maxLineLength.set(maxLineLength);
}
IntegerProperty maxLineLengthProperty() {
public IntegerProperty maxLineLengthProperty() {
return maxLineLength;
}
@@ -145,7 +163,7 @@ public class FXParametersModel implements ParametersModel {
this.maxLines.set(maxLines);
}
IntegerProperty maxLinesProperty() {
public IntegerProperty maxLinesProperty() {
return maxLines;
}
}

View File

@@ -1,11 +1,15 @@
package com.github.gtache.autosubtitle.gui.subtitles.fx;
import com.github.gtache.autosubtitle.Language;
import com.github.gtache.autosubtitle.Video;
import com.github.gtache.autosubtitle.gui.fx.FXBinder;
import com.github.gtache.autosubtitle.gui.work.fx.FXWorkModel;
import com.github.gtache.autosubtitle.gui.parameters.fx.FXParametersModel;
import com.github.gtache.autosubtitle.gui.work.WorkStatus;
import com.github.gtache.autosubtitle.gui.work.fx.FXWorkModel;
import com.github.gtache.autosubtitle.subtitle.converter.impl.FormatOptionsImpl;
import com.github.gtache.autosubtitle.subtitle.converter.impl.ParseOptionsImpl;
import com.github.gtache.autosubtitle.subtitle.gui.fx.ObservableSubtitleCollectionImpl;
import com.github.gtache.autosubtitle.subtitle.impl.ExportOptionsImpl;
import com.github.gtache.autosubtitle.subtitle.impl.ImportOptionsImpl;
import javafx.beans.binding.Bindings;
import javax.inject.Inject;
@@ -19,11 +23,13 @@ import java.util.Objects;
public class FXSubtitlesBinder implements FXBinder {
private final FXWorkModel workModel;
private final FXParametersModel parametersModel;
private final FXSubtitlesModel subtitlesModel;
@Inject
FXSubtitlesBinder(final FXWorkModel workModel, final FXSubtitlesModel subtitlesModel) {
FXSubtitlesBinder(final FXWorkModel workModel, final FXParametersModel parametersModel, final FXSubtitlesModel subtitlesModel) {
this.workModel = Objects.requireNonNull(workModel);
this.parametersModel = Objects.requireNonNull(parametersModel);
this.subtitlesModel = Objects.requireNonNull(subtitlesModel);
}
@@ -36,11 +42,9 @@ public class FXSubtitlesBinder implements FXBinder {
workModel.selectedSubtitleProperty().bind(subtitlesModel.selectedSubtitleProperty());
workModel.canExportProperty().bind(Bindings.isNotEmpty(subtitlesModel.collections()).and(workModel.statusProperty().isEqualTo(WorkStatus.IDLE)));
workModel.videoLanguageProperty().bind(subtitlesModel.videoLanguageProperty());
subtitlesModel.videoInfoProperty().bind(workModel.videoProperty().map(Video::info));
subtitlesModel.translatingProperty().addListener((observable, oldValue, newValue) -> {
if (newValue) {
if (Boolean.TRUE.equals(newValue)) {
workModel.statusProperty().set(WorkStatus.TRANSLATING);
} else {
workModel.statusProperty().set(WorkStatus.IDLE);
@@ -55,5 +59,20 @@ public class FXSubtitlesBinder implements FXBinder {
Bindings.bindContent(workModel.collections(), subtitlesModel.collections());
Bindings.bindContent(workModel.subtitles(), subtitlesModel.selectedSubtitles());
subtitlesModel.exportOptionsProperty().bind(Bindings.createObjectBinding(() -> {
if (workModel.video() == null) {
return null;
} else {
final var format = parametersModel.outputFormat();
final var formatOptions = new FormatOptionsImpl(workModel.video().info(), parametersModel.font());
return new ExportOptionsImpl(format, formatOptions);
}
}, parametersModel.outputFormatProperty(), workModel.videoProperty(), parametersModel.fontProperty()));
subtitlesModel.importOptionsProperty().bind(Bindings.createObjectBinding(() -> {
final var parseOptions = new ParseOptionsImpl(parametersModel.maxLineLength(), parametersModel.maxLines(), parametersModel.font());
return new ImportOptionsImpl(parseOptions);
}, parametersModel.maxLineLengthProperty(), parametersModel.maxLinesProperty(), parametersModel.fontProperty()));
}
}

View File

@@ -114,9 +114,7 @@ public class FXSubtitlesController extends AbstractFXController implements Subti
bindComboboxes();
bindTable();
mainSubtitlesTab.textProperty().bind(Bindings.createStringBinding(() -> model.videoLanguage().iso2(), model.videoLanguageProperty()));
model.collections().addListener((MapChangeListener<Language, ObservableSubtitleCollectionImpl>) change -> {
manageTabs();
});
model.collections().addListener((MapChangeListener<Language, ObservableSubtitleCollectionImpl>) change -> manageTabs());
tabPane.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
if (newValue != null) {
model.setSelectedCollection(model.collections().get(Language.getLanguage(newValue.getText())));
@@ -293,10 +291,11 @@ public class FXSubtitlesController extends AbstractFXController implements Subti
try {
final var filename = file.getFileName().toString();
final var extension = filename.substring(filename.lastIndexOf('.') + 1);
final var options = model.exportOptions();
if (subtitleExtensions.contains(extension)) {
importerExporter.exportSubtitles(model.selectedCollection(), model.videoInfo(), file);
importerExporter.exportSubtitles(model.selectedCollection(), options, file);
} else {
importerExporter.exportSubtitles(model.collections().values(), model.videoInfo(), file);
importerExporter.exportSubtitles(model.collections().values(), options, file);
}
} catch (final IOException e) {
logger.error("Error saving subtitles {}", file, e);
@@ -307,7 +306,8 @@ public class FXSubtitlesController extends AbstractFXController implements Subti
@Override
public void loadSubtitles(final Path file) {
try {
final var map = importerExporter.importSubtitles(file);
final var importOptions = model.importOptions();
final var map = importerExporter.importSubtitles(file, importOptions);
if (model.videoLanguage() == Language.AUTO) {
model.setVideoLanguage(map.keySet().stream().findFirst().orElse(Language.AUTO));
}

View File

@@ -1,8 +1,9 @@
package com.github.gtache.autosubtitle.gui.subtitles.fx;
import com.github.gtache.autosubtitle.Language;
import com.github.gtache.autosubtitle.VideoInfo;
import com.github.gtache.autosubtitle.gui.subtitles.SubtitlesModel;
import com.github.gtache.autosubtitle.subtitle.ExportOptions;
import com.github.gtache.autosubtitle.subtitle.ImportOptions;
import com.github.gtache.autosubtitle.subtitle.gui.fx.ObservableSubtitleCollectionImpl;
import com.github.gtache.autosubtitle.subtitle.gui.fx.ObservableSubtitleImpl;
import javafx.beans.binding.Bindings;
@@ -30,7 +31,6 @@ public class FXSubtitlesModel implements SubtitlesModel<ObservableSubtitleImpl,
private final ObservableList<Language> availableVideoLanguages;
private final ObjectProperty<Language> videoLanguage;
private final ObjectProperty<VideoInfo> videoInfo;
private final ObservableList<Language> availableTranslationLanguages;
private final ObservableList<Language> selectedTranslationsLanguages;
private final ObjectProperty<Language> selectedLanguage;
@@ -46,6 +46,8 @@ public class FXSubtitlesModel implements SubtitlesModel<ObservableSubtitleImpl,
private final BooleanProperty canEditTable;
private final ReadOnlyBooleanWrapper canSaveSubtitles;
private final BooleanProperty isTranslating;
private final ObjectProperty<ExportOptions> exportOptions;
private final ObjectProperty<ImportOptions> importOptions;
@Inject
FXSubtitlesModel() {
@@ -61,7 +63,6 @@ public class FXSubtitlesModel implements SubtitlesModel<ObservableSubtitleImpl,
}).toList()));
this.availableTranslationLanguages = FXCollections.observableArrayList(Arrays.stream(Language.values()).filter(l -> l != Language.AUTO).toList());
this.videoLanguage = new SimpleObjectProperty<>(Language.AUTO);
this.videoInfo = new SimpleObjectProperty<>();
this.selectedTranslationsLanguages = FXCollections.observableArrayList();
this.selectedLanguage = new SimpleObjectProperty<>(Language.AUTO);
this.collections = FXCollections.observableHashMap();
@@ -75,6 +76,8 @@ public class FXSubtitlesModel implements SubtitlesModel<ObservableSubtitleImpl,
this.canSaveSubtitles = new ReadOnlyBooleanWrapper(false);
this.canEditTable = new SimpleBooleanProperty(false);
this.isTranslating = new SimpleBooleanProperty(false);
this.exportOptions = new SimpleObjectProperty<>();
this.importOptions = new SimpleObjectProperty<>();
canSaveSubtitles.bind(Bindings.isNotEmpty(collections));
collections.addListener((MapChangeListener<Language, ObservableSubtitleCollectionImpl>) change ->
@@ -107,24 +110,10 @@ public class FXSubtitlesModel implements SubtitlesModel<ObservableSubtitleImpl,
videoLanguage.set(language);
}
ObjectProperty<Language> videoLanguageProperty() {
public ObjectProperty<Language> videoLanguageProperty() {
return videoLanguage;
}
@Override
public VideoInfo videoInfo() {
return videoInfo.get();
}
@Override
public void setVideoInfo(final VideoInfo videoInfo) {
this.videoInfo.set(videoInfo);
}
ObjectProperty<VideoInfo> videoInfoProperty() {
return videoInfo;
}
@Override
public ObservableList<Language> availableTranslationsLanguage() {
return FXCollections.unmodifiableObservableList(availableTranslationLanguages);
@@ -270,4 +259,20 @@ public class FXSubtitlesModel implements SubtitlesModel<ObservableSubtitleImpl,
public BooleanProperty canEditTableProperty() {
return canEditTable;
}
ExportOptions exportOptions() {
return exportOptions.get();
}
public ObjectProperty<ExportOptions> exportOptionsProperty() {
return exportOptions;
}
ImportOptions importOptions() {
return importOptions.get();
}
public ObjectProperty<ImportOptions> importOptionsProperty() {
return importOptions;
}
}

View File

@@ -2,10 +2,17 @@ package com.github.gtache.autosubtitle.gui.work.fx;
import com.github.gtache.autosubtitle.gui.fx.FXBinder;
import com.github.gtache.autosubtitle.gui.parameters.fx.FXParametersModel;
import com.github.gtache.autosubtitle.gui.subtitles.fx.FXSubtitlesModel;
import com.github.gtache.autosubtitle.subtitle.converter.impl.FormatOptionsImpl;
import com.github.gtache.autosubtitle.subtitle.converter.impl.ParseOptionsImpl;
import com.github.gtache.autosubtitle.subtitle.extractor.impl.ExtractOptionsImpl;
import com.github.gtache.autosubtitle.subtitle.impl.ExportOptionsImpl;
import javafx.beans.binding.Bindings;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.Objects;
import static java.util.Objects.requireNonNull;
/**
* {@link FXBinder} for {@link FXWorkModel}
@@ -15,15 +22,29 @@ public class FXWorkBinder implements FXBinder {
private final FXWorkModel workModel;
private final FXParametersModel parametersModel;
private final FXSubtitlesModel subtitlesModel;
@Inject
FXWorkBinder(final FXWorkModel workModel, final FXParametersModel parametersModel) {
this.workModel = Objects.requireNonNull(workModel);
this.parametersModel = Objects.requireNonNull(parametersModel);
FXWorkBinder(final FXWorkModel workModel, final FXParametersModel parametersModel, final FXSubtitlesModel subtitlesModel) {
this.workModel = requireNonNull(workModel);
this.parametersModel = requireNonNull(parametersModel);
this.subtitlesModel = requireNonNull(subtitlesModel);
}
@Override
public void createBindings() {
workModel.extractionModelProperty().bind(parametersModel.extractionModelProperty());
workModel.exportOptionsProperty().bind(Bindings.createObjectBinding(() -> {
if (workModel.video() == null) {
return null;
} else {
return new ExportOptionsImpl(parametersModel.outputFormat(), new FormatOptionsImpl(workModel.video().info(), parametersModel.font()));
}
}, workModel.videoProperty(), parametersModel.outputFormatProperty(), parametersModel.fontProperty()));
workModel.extractOptionsProperty().bind(Bindings.createObjectBinding(() ->
new ExtractOptionsImpl(subtitlesModel.videoLanguage(), parametersModel.extractionModel(),
new ParseOptionsImpl(parametersModel.maxLineLength(), parametersModel.maxLines(), parametersModel.font())),
subtitlesModel.videoLanguageProperty(), parametersModel.extractionModelProperty(),
parametersModel.maxLineLengthProperty(), parametersModel.maxLinesProperty(), parametersModel.fontProperty()));
}
}

View File

@@ -75,7 +75,7 @@ public class FXWorkController extends AbstractFXController implements WorkContro
private final FXWorkModel model;
private final FXWorkBinder binder;
private final SubtitleExtractor subtitleExtractor;
private final SubtitleExtractor<?> subtitleExtractor;
private final VideoConverter videoConverter;
private final VideoLoader videoLoader;
@@ -142,7 +142,7 @@ public class FXWorkController extends AbstractFXController implements WorkContro
private SubtitleCollection<?> extractAsync() {
try {
return subtitleExtractor.extract(model.video(), model.videoLanguageProperty().get(), model.extractionModel());
return subtitleExtractor.extract(model.video(), model.extractOptions());
} catch (final ExtractException e) {
throw new CompletionException(e);
}
@@ -182,7 +182,7 @@ public class FXWorkController extends AbstractFXController implements WorkContro
model.setStatus(WorkStatus.EXPORTING);
CompletableFuture.runAsync(() -> {
try {
videoConverter.addSoftSubtitles(model.video(), model.collections().values(), file.toPath());
videoConverter.addSoftSubtitles(model.video(), model.collections().values(), model.exportOptions(), file.toPath());
} catch (final IOException e) {
throw new CompletionException(e);
}
@@ -207,7 +207,7 @@ public class FXWorkController extends AbstractFXController implements WorkContro
model.setStatus(WorkStatus.EXPORTING);
CompletableFuture.runAsync(() -> {
try {
videoConverter.addHardSubtitles(model.video(), model.collections().get(model.videoLanguageProperty().get()), file.toPath());
videoConverter.addHardSubtitles(model.video(), model.collections().get(model.extractOptions().language()), model.exportOptions(), file.toPath());
} catch (final IOException e) {
throw new CompletionException(e);
}

View File

@@ -5,8 +5,9 @@ import com.github.gtache.autosubtitle.Video;
import com.github.gtache.autosubtitle.gui.work.WorkModel;
import com.github.gtache.autosubtitle.gui.work.WorkStatus;
import com.github.gtache.autosubtitle.subtitle.EditableSubtitle;
import com.github.gtache.autosubtitle.subtitle.ExportOptions;
import com.github.gtache.autosubtitle.subtitle.SubtitleCollection;
import com.github.gtache.autosubtitle.subtitle.extractor.ExtractionModel;
import com.github.gtache.autosubtitle.subtitle.extractor.ExtractOptions;
import com.github.gtache.autosubtitle.subtitle.gui.fx.ObservableSubtitleCollectionImpl;
import com.github.gtache.autosubtitle.subtitle.gui.fx.ObservableSubtitleImpl;
import javafx.beans.property.BooleanProperty;
@@ -31,7 +32,6 @@ import javax.inject.Singleton;
public class FXWorkModel implements WorkModel {
private final ObjectProperty<Video> video;
private final ObjectProperty<ExtractionModel> extractionModel;
private final ObjectProperty<WorkStatus> workStatus;
private final DoubleProperty progress;
private final ObjectProperty<EditableSubtitle> selectedSubtitle;
@@ -42,12 +42,13 @@ public class FXWorkModel implements WorkModel {
private final BooleanProperty canExport;
private final ReadOnlyBooleanWrapper isProgressVisible;
private final ObjectProperty<SubtitleCollection<?>> extractedCollection;
private final ObjectProperty<ExportOptions> exportOptions;
private final ObjectProperty<ExtractOptions> extractOptions;
@Inject
FXWorkModel() {
this.video = new SimpleObjectProperty<>();
this.workStatus = new SimpleObjectProperty<>(WorkStatus.IDLE);
this.extractionModel = new SimpleObjectProperty<>();
this.progress = new SimpleDoubleProperty(-1);
this.selectedSubtitle = new SimpleObjectProperty<>();
this.subtitles = FXCollections.observableArrayList();
@@ -57,6 +58,8 @@ public class FXWorkModel implements WorkModel {
this.canExport = new SimpleBooleanProperty(false);
this.isProgressVisible = new ReadOnlyBooleanWrapper(false);
this.extractedCollection = new SimpleObjectProperty<>();
this.exportOptions = new SimpleObjectProperty<>();
this.extractOptions = new SimpleObjectProperty<>();
isProgressVisible.bind(workStatus.isNotEqualTo(WorkStatus.IDLE));
canExtract.bind(video.isNotNull().and(workStatus.isEqualTo(WorkStatus.IDLE)));
@@ -76,20 +79,6 @@ public class FXWorkModel implements WorkModel {
return video;
}
@Override
public ExtractionModel extractionModel() {
return extractionModel.get();
}
@Override
public void setExtractionModel(final ExtractionModel model) {
extractionModel.set(model);
}
ObjectProperty<ExtractionModel> extractionModelProperty() {
return extractionModel;
}
@Override
public WorkStatus status() {
return workStatus.get();
@@ -176,7 +165,31 @@ public class FXWorkModel implements WorkModel {
return collections;
}
public ObjectProperty<Language> videoLanguageProperty() {
return videoLanguage;
@Override
public ExportOptions exportOptions() {
return exportOptions.get();
}
@Override
public void setExportOptions(final ExportOptions options) {
exportOptions.set(options);
}
public ObjectProperty<ExportOptions> exportOptionsProperty() {
return exportOptions;
}
@Override
public ExtractOptions extractOptions() {
return extractOptions.get();
}
@Override
public void setExtractOptions(final ExtractOptions options) {
extractOptions.set(options);
}
public ObjectProperty<ExtractOptions> extractOptionsProperty() {
return extractOptions;
}
}

View File

@@ -9,7 +9,6 @@ module com.github.gtache.autosubtitle.gui.fx {
requires transitive javafx.fxml;
requires org.controlsfx.controls;
requires org.apache.logging.log4j;
requires java.desktop;
requires transitive java.prefs;
exports com.github.gtache.autosubtitle.gui.fx;

View File

@@ -3,6 +3,7 @@ package com.github.gtache.autosubtitle.gui.parameters.fx;
import com.github.gtache.autosubtitle.subtitle.OutputFormat;
import com.github.gtache.autosubtitle.subtitle.extractor.ExtractionModel;
import com.github.gtache.autosubtitle.subtitle.extractor.ExtractionModelProvider;
import com.github.gtache.autosubtitle.subtitle.impl.FontImpl;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -101,6 +102,18 @@ class TestFXParametersModel {
assertEquals(fontSize, model.fontSizeProperty().get());
}
@Test
void testFont() {
assertEquals(new FontImpl(DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE), model.font());
assertEquals(new FontImpl(DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE), model.fontProperty().get());
model.setFontName("TT");
assertEquals(new FontImpl("TT", DEFAULT_FONT_SIZE), model.font());
assertEquals(new FontImpl("TT", DEFAULT_FONT_SIZE), model.fontProperty().get());
model.setFontSize(1);
assertEquals(new FontImpl("TT", 1), model.font());
assertEquals(new FontImpl("TT", 1), model.fontProperty().get());
}
@Test
void testMaxLineLength() {
assertEquals(DEFAULT_MAX_LINE_LENGTH, model.maxLineLength());

View File

@@ -3,15 +3,26 @@ package com.github.gtache.autosubtitle.gui.subtitles.fx;
import com.github.gtache.autosubtitle.Language;
import com.github.gtache.autosubtitle.Video;
import com.github.gtache.autosubtitle.VideoInfo;
import com.github.gtache.autosubtitle.gui.parameters.fx.FXParametersModel;
import com.github.gtache.autosubtitle.gui.work.WorkStatus;
import com.github.gtache.autosubtitle.gui.work.fx.FXWorkModel;
import com.github.gtache.autosubtitle.subtitle.OutputFormat;
import com.github.gtache.autosubtitle.subtitle.converter.impl.FormatOptionsImpl;
import com.github.gtache.autosubtitle.subtitle.converter.impl.ParseOptionsImpl;
import com.github.gtache.autosubtitle.subtitle.extractor.ExtractionModelProvider;
import com.github.gtache.autosubtitle.subtitle.gui.fx.ObservableSubtitleCollectionImpl;
import com.github.gtache.autosubtitle.subtitle.gui.fx.ObservableSubtitleImpl;
import com.github.gtache.autosubtitle.subtitle.impl.ExportOptionsImpl;
import com.github.gtache.autosubtitle.subtitle.impl.FontImpl;
import com.github.gtache.autosubtitle.subtitle.impl.ImportOptionsImpl;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.List;
import java.util.Map;
@@ -19,16 +30,28 @@ import java.util.Map;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class)
class TestFXSubtitlesBinder {
private final FXWorkModel workModel;
private final FXSubtitlesModel subtitlesModel;
private final FXParametersModel parametersModel;
private final FXSubtitlesBinder binder;
private final String defaultFontFamily;
private final int defaultFontSize;
private final int defaultMaxLineLength;
private final int defaultMaxLines;
TestFXSubtitlesBinder() {
TestFXSubtitlesBinder(@Mock final ExtractionModelProvider extractionModelProvider) {
this.workModel = spy(FXWorkModel.class);
this.defaultFontFamily = "Arial";
this.defaultFontSize = 12;
this.defaultMaxLineLength = 40;
this.defaultMaxLines = 2;
this.parametersModel = mock(FXParametersModel.class, withSettings().defaultAnswer(CALLS_REAL_METHODS)
.useConstructor(extractionModelProvider, defaultFontFamily, defaultFontSize, defaultMaxLineLength, defaultMaxLines));
this.subtitlesModel = new FXSubtitlesModel();
this.binder = new FXSubtitlesBinder(workModel, subtitlesModel);
this.binder = new FXSubtitlesBinder(workModel, parametersModel, subtitlesModel);
}
@BeforeEach
@@ -93,23 +116,6 @@ class TestFXSubtitlesBinder {
assertFalse(workModel.canExport());
}
@Test
void testVideoLanguageBinding() {
assertEquals(Language.AUTO, workModel.videoLanguageProperty().get());
subtitlesModel.setVideoLanguage(Language.EN);
assertEquals(Language.EN, workModel.videoLanguageProperty().get());
}
@Test
void testVideoInfoBinding() {
assertNull(subtitlesModel.videoInfo());
final var video = mock(Video.class);
final var info = mock(VideoInfo.class);
when(video.info()).thenReturn(info);
workModel.setVideo(video);
assertEquals(info, subtitlesModel.videoInfo());
}
@Test
void testTranslatingBinding() {
assertEquals(WorkStatus.IDLE, workModel.status());
@@ -145,4 +151,33 @@ class TestFXSubtitlesBinder {
subtitlesModel.selectedSubtitles().add(subtitle);
assertEquals(List.of(subtitle), workModel.subtitles());
}
@Test
void testExportOptionsBinding() {
assertNull(subtitlesModel.exportOptions());
final var video = mock(Video.class);
final var info = mock(VideoInfo.class);
when(video.info()).thenReturn(info);
workModel.setVideo(video);
assertEquals(new ExportOptionsImpl(OutputFormat.SRT, new FormatOptionsImpl(info, new FontImpl(defaultFontFamily, defaultFontSize))), subtitlesModel.exportOptions());
parametersModel.setFontSize(14);
parametersModel.setFontName("TT");
assertEquals(new ExportOptionsImpl(OutputFormat.SRT, new FormatOptionsImpl(info, new FontImpl("TT", 14))), subtitlesModel.exportOptions());
parametersModel.setOutputFormat(OutputFormat.ASS);
assertEquals(new ExportOptionsImpl(OutputFormat.ASS, new FormatOptionsImpl(info, new FontImpl("TT", 14))), subtitlesModel.exportOptions());
workModel.setVideo(null);
assertNull(subtitlesModel.exportOptions());
}
@Test
void testImportOptionsBinding() {
assertEquals(new ImportOptionsImpl(new ParseOptionsImpl(defaultMaxLineLength, defaultMaxLines, new FontImpl(defaultFontFamily, defaultFontSize))), subtitlesModel.importOptions());
parametersModel.setFontSize(14);
parametersModel.setFontName("TT");
assertEquals(new ImportOptionsImpl(new ParseOptionsImpl(defaultMaxLineLength, defaultMaxLines, new FontImpl("TT", 14))), subtitlesModel.importOptions());
parametersModel.setMaxLineLength(1);
assertEquals(new ImportOptionsImpl(new ParseOptionsImpl(1, defaultMaxLines, new FontImpl("TT", 14))), subtitlesModel.importOptions());
parametersModel.setMaxLines(4);
assertEquals(new ImportOptionsImpl(new ParseOptionsImpl(1, 4, new FontImpl("TT", 14))), subtitlesModel.importOptions());
}
}

View File

@@ -1,7 +1,8 @@
package com.github.gtache.autosubtitle.gui.subtitles.fx;
import com.github.gtache.autosubtitle.Language;
import com.github.gtache.autosubtitle.VideoInfo;
import com.github.gtache.autosubtitle.subtitle.ExportOptions;
import com.github.gtache.autosubtitle.subtitle.ImportOptions;
import com.github.gtache.autosubtitle.subtitle.gui.fx.ObservableSubtitleCollectionImpl;
import com.github.gtache.autosubtitle.subtitle.gui.fx.ObservableSubtitleImpl;
import javafx.collections.FXCollections;
@@ -56,16 +57,6 @@ class TestFXSubtitlesModel {
assertEquals(Language.DE, model.videoLanguageProperty().get());
}
@Test
void testVideoInfo() {
assertNull(model.videoInfo());
assertNull(model.videoInfoProperty().get());
final var videoInfo = mock(VideoInfo.class);
model.setVideoInfo(videoInfo);
assertEquals(videoInfo, model.videoInfo());
assertEquals(videoInfo, model.videoInfoProperty().get());
}
@Test
void testSelectedTranslationsLanguages() {
assertEquals(List.of(), model.selectedTranslationsLanguages());
@@ -197,4 +188,18 @@ class TestFXSubtitlesModel {
assertTrue(model.isTranslating());
assertTrue(model.translatingProperty().get());
}
@Test
void testExportOptions() {
assertNull(model.exportOptionsProperty().get());
final var options = mock(ExportOptions.class);
assertDoesNotThrow(() -> model.exportOptionsProperty().set(options));
}
@Test
void testImportOptions() {
assertNull(model.importOptionsProperty().get());
final var options = mock(ImportOptions.class);
assertDoesNotThrow(() -> model.importOptionsProperty().set(options));
}
}

View File

@@ -1,24 +1,56 @@
package com.github.gtache.autosubtitle.gui.work.fx;
import com.github.gtache.autosubtitle.Language;
import com.github.gtache.autosubtitle.Video;
import com.github.gtache.autosubtitle.VideoInfo;
import com.github.gtache.autosubtitle.gui.parameters.fx.FXParametersModel;
import com.github.gtache.autosubtitle.gui.subtitles.fx.FXSubtitlesModel;
import com.github.gtache.autosubtitle.subtitle.OutputFormat;
import com.github.gtache.autosubtitle.subtitle.converter.impl.FormatOptionsImpl;
import com.github.gtache.autosubtitle.subtitle.converter.impl.ParseOptionsImpl;
import com.github.gtache.autosubtitle.subtitle.extractor.ExtractionModel;
import com.github.gtache.autosubtitle.subtitle.extractor.ExtractionModelProvider;
import com.github.gtache.autosubtitle.subtitle.extractor.impl.ExtractOptionsImpl;
import com.github.gtache.autosubtitle.subtitle.impl.ExportOptionsImpl;
import com.github.gtache.autosubtitle.subtitle.impl.FontImpl;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.junit.jupiter.api.Assertions.*;
import java.util.Objects;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class)
class TestFXWorkBinder {
private final FXWorkModel workModel;
private final FXParametersModel parametersModel;
private final FXSubtitlesModel subtitlesModel;
private final FXWorkBinder binder;
private final String defaultFontFamily;
private final int defaultFontSize;
private final int defaultMaxLineLength;
private final int defaultMaxLines;
private final ExtractionModelProvider extractionModelProvider;
private final ExtractionModel extractionModel;
TestFXWorkBinder() {
TestFXWorkBinder(@Mock final ExtractionModelProvider extractionModelProvider, @Mock final ExtractionModel extractionModel) {
this.extractionModelProvider = Objects.requireNonNull(extractionModelProvider);
this.extractionModel = Objects.requireNonNull(extractionModel);
when(extractionModelProvider.getDefaultExtractionModel()).thenReturn(extractionModel);
this.defaultFontFamily = "Arial";
this.defaultFontSize = 12;
this.defaultMaxLineLength = 40;
this.defaultMaxLines = 1;
this.parametersModel = mock(FXParametersModel.class, withSettings().defaultAnswer(CALLS_REAL_METHODS).useConstructor(extractionModelProvider, defaultFontFamily, defaultFontSize, defaultMaxLineLength, defaultMaxLines));
this.subtitlesModel = spy(FXSubtitlesModel.class);
this.workModel = new FXWorkModel();
this.parametersModel = mock(FXParametersModel.class, withSettings().defaultAnswer(CALLS_REAL_METHODS).useConstructor(mock(ExtractionModelProvider.class), "Arial", 12, 40, 1));
this.binder = new FXWorkBinder(workModel, parametersModel);
this.binder = new FXWorkBinder(workModel, parametersModel, subtitlesModel);
}
@BeforeEach
@@ -27,14 +59,36 @@ class TestFXWorkBinder {
}
@Test
void testBindings() {
assertNull(workModel.extractionModel());
assertNull(parametersModel.extractionModel());
void testExportOptionsBinding() {
assertNull(workModel.exportOptions());
final var video = mock(Video.class);
final var info = mock(VideoInfo.class);
when(video.info()).thenReturn(info);
workModel.setVideo(video);
assertEquals(new ExportOptionsImpl(OutputFormat.SRT, new FormatOptionsImpl(info, new FontImpl(defaultFontFamily, defaultFontSize))), workModel.exportOptions());
parametersModel.setFontSize(14);
parametersModel.setFontName("TT");
assertEquals(new ExportOptionsImpl(OutputFormat.SRT, new FormatOptionsImpl(info, new FontImpl("TT", 14))), workModel.exportOptions());
parametersModel.setOutputFormat(OutputFormat.ASS);
assertEquals(new ExportOptionsImpl(OutputFormat.ASS, new FormatOptionsImpl(info, new FontImpl("TT", 14))), workModel.exportOptions());
workModel.setVideo(null);
assertNull(workModel.exportOptions());
}
final var extractionModel = mock(ExtractionModel.class);
parametersModel.setExtractionModel(extractionModel);
assertEquals(extractionModel, workModel.extractionModel());
assertThrows(RuntimeException.class, () -> workModel.setExtractionModel(mock(ExtractionModel.class)));
@Test
void testExtractOptionsBinding() {
assertEquals(new ExtractOptionsImpl(Language.AUTO, extractionModel, new ParseOptionsImpl(defaultMaxLineLength, defaultMaxLines, new FontImpl(defaultFontFamily, defaultFontSize))), workModel.extractOptions());
parametersModel.setFontSize(14);
parametersModel.setFontName("TT");
assertEquals(new ExtractOptionsImpl(Language.AUTO, extractionModel, new ParseOptionsImpl(defaultMaxLineLength, defaultMaxLines, new FontImpl("TT", 14))), workModel.extractOptions());
parametersModel.setMaxLineLength(1);
assertEquals(new ExtractOptionsImpl(Language.AUTO, extractionModel, new ParseOptionsImpl(1, defaultMaxLines, new FontImpl("TT", 14))), workModel.extractOptions());
parametersModel.setMaxLines(4);
assertEquals(new ExtractOptionsImpl(Language.AUTO, extractionModel, new ParseOptionsImpl(1, 4, new FontImpl("TT", 14))), workModel.extractOptions());
final var newModel = mock(ExtractionModel.class);
parametersModel.setExtractionModel(newModel);
assertEquals(new ExtractOptionsImpl(Language.AUTO, newModel, new ParseOptionsImpl(1, 4, new FontImpl("TT", 14))), workModel.extractOptions());
subtitlesModel.setVideoLanguage(Language.EN);
assertEquals(new ExtractOptionsImpl(Language.EN, newModel, new ParseOptionsImpl(1, 4, new FontImpl("TT", 14))), workModel.extractOptions());
}
}

View File

@@ -4,8 +4,9 @@ import com.github.gtache.autosubtitle.Language;
import com.github.gtache.autosubtitle.Video;
import com.github.gtache.autosubtitle.gui.work.WorkStatus;
import com.github.gtache.autosubtitle.subtitle.EditableSubtitle;
import com.github.gtache.autosubtitle.subtitle.ExportOptions;
import com.github.gtache.autosubtitle.subtitle.SubtitleCollection;
import com.github.gtache.autosubtitle.subtitle.extractor.ExtractionModel;
import com.github.gtache.autosubtitle.subtitle.extractor.ExtractOptions;
import com.github.gtache.autosubtitle.subtitle.gui.fx.ObservableSubtitleCollectionImpl;
import com.github.gtache.autosubtitle.subtitle.gui.fx.ObservableSubtitleImpl;
import org.junit.jupiter.api.Test;
@@ -43,16 +44,6 @@ class TestFXWorkModel {
assertEquals(WorkStatus.TRANSLATING, model.statusProperty().get());
}
@Test
void testExtractionModel() {
assertNull(model.extractionModel());
assertNull(model.extractionModelProperty().get());
final var extractionModel = mock(ExtractionModel.class);
model.setExtractionModel(extractionModel);
assertEquals(extractionModel, model.extractionModel());
assertEquals(extractionModel, model.extractionModelProperty().get());
}
@Test
void testProgress() {
assertEquals(-1.0, model.progress());
@@ -80,12 +71,6 @@ class TestFXWorkModel {
assertDoesNotThrow(() -> model.collections().put(Language.FR, mock(ObservableSubtitleCollectionImpl.class)));
}
@Test
void testVideoLanguage() {
assertEquals(Language.AUTO, model.videoLanguageProperty().get());
assertDoesNotThrow(() -> model.videoLanguageProperty().set(Language.FR));
}
@Test
void testCanExtract() {
assertFalse(model.canExtract());
@@ -123,4 +108,24 @@ class TestFXWorkModel {
assertNotNull(model.extractedCollection());
assertNotNull(model.extractedCollectionProperty().get());
}
@Test
void testExportOptions() {
assertNull(model.exportOptions());
assertNull(model.exportOptionsProperty().get());
final var options = mock(ExportOptions.class);
model.setExportOptions(options);
assertEquals(options, model.exportOptions());
assertEquals(options, model.exportOptionsProperty().get());
}
@Test
void testExtractOptions() {
assertNull(model.extractOptions());
assertNull(model.extractOptionsProperty().get());
final var options = mock(ExtractOptions.class);
model.setExtractOptions(options);
assertEquals(options, model.extractOptions());
assertEquals(options, model.extractOptionsProperty().get());
}
}

View File

@@ -30,10 +30,10 @@ class TestObservableSubtitleCollectionImpl {
@Test
void testEmptyConstructor() {
final var collection = new ObservableSubtitleCollectionImpl();
assertEquals("", collection.text());
assertEquals(List.of(), collection.subtitles());
assertEquals(Language.AUTO, collection.language());
final var emptyCollection = new ObservableSubtitleCollectionImpl();
assertEquals("", emptyCollection.text());
assertEquals(List.of(), emptyCollection.subtitles());
assertEquals(Language.AUTO, emptyCollection.language());
}
@Test

View File

@@ -79,28 +79,28 @@ class TestObservableSubtitleImpl {
@Test
void testStringConstructor() {
final var subtitle = new ObservableSubtitleImpl(content);
assertEquals(content, subtitle.content());
final var observable = new ObservableSubtitleImpl(content);
assertEquals(content, observable.content());
}
@Test
void testWholeConstructor() {
final var subtitle = new ObservableSubtitleImpl(content, start, end, font, bounds);
assertEquals(content, subtitle.content());
assertEquals(start, subtitle.start());
assertEquals(end, subtitle.end());
assertEquals(font, subtitle.font());
assertEquals(bounds, subtitle.bounds());
final var observable = new ObservableSubtitleImpl(content, start, end, font, bounds);
assertEquals(content, observable.content());
assertEquals(start, observable.start());
assertEquals(end, observable.end());
assertEquals(font, observable.font());
assertEquals(bounds, observable.bounds());
}
@Test
void testCopyConstructor() {
final var originalSubtitle = new SubtitleImpl(content, start, end, font, bounds);
final var subtitle = new ObservableSubtitleImpl(originalSubtitle);
assertEquals(content, subtitle.content());
assertEquals(start, subtitle.start());
assertEquals(end, subtitle.end());
assertEquals(font, subtitle.font());
assertEquals(bounds, subtitle.bounds());
final var observable = new ObservableSubtitleImpl(originalSubtitle);
assertEquals(content, observable.content());
assertEquals(start, observable.start());
assertEquals(end, observable.end());
assertEquals(font, observable.font());
assertEquals(bounds, observable.bounds());
}
}

View File

@@ -24,6 +24,6 @@ public final class Main extends Application {
}
public static void main(final String[] args) {
Application.launch(args);
launch(args);
}
}

View File

@@ -14,6 +14,7 @@ import javax.inject.Singleton;
/**
* Main component
*/
@FunctionalInterface
@Singleton
@Component(modules = {CoreModule.class, GuiCoreModule.class, FXModule.class, FFmpegModule.class,
WhisperXModule.class, DeepLModule.class})