diff --git a/CHANGELOG.md b/CHANGELOG.md index 0cc588d5f64..50053b9c270 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv - We fixed an issue where in the merge dialog the file field of entries was not correctly merged when the first and second entry both contained values inside the file field. [#10572](https://github.com/JabRef/jabref/issues/10572) - We fixed some small inconsistencies in the user interface. [#10507](https://github.com/JabRef/jabref/issues/10507) [#10458](https://github.com/JabRef/jabref/issues/10458) [#10660](https://github.com/JabRef/jabref/issues/10660) - We fixed the issue where the Hayagriva YAML exporter would not include a parent field for the publisher/series. [#10596](https://github.com/JabRef/jabref/issues/10596) +- We fixed issues in the external file type dialog w.r.t. duplicate entries in the case of a language switch. [#10271](https://github.com/JabRef/jabref/issues/10271) ### Removed diff --git a/src/main/java/org/jabref/gui/exporter/CreateModifyExporterDialogViewModel.java b/src/main/java/org/jabref/gui/exporter/CreateModifyExporterDialogViewModel.java index 78c808dad3c..d9e0c1bc69c 100644 --- a/src/main/java/org/jabref/gui/exporter/CreateModifyExporterDialogViewModel.java +++ b/src/main/java/org/jabref/gui/exporter/CreateModifyExporterDialogViewModel.java @@ -57,7 +57,7 @@ public ExporterViewModel saveExporter() { // Check that there are no empty strings. if (layoutFile.get().isEmpty() || name.get().isEmpty() || extension.get().isEmpty() || !layoutFile.get().endsWith(".layout")) { - LOGGER.info("One of the fields is empty or invalid!"); + LOGGER.info("One of the fields is empty or invalid."); return null; } diff --git a/src/main/java/org/jabref/gui/externalfiletype/ExternalFileTypes.java b/src/main/java/org/jabref/gui/externalfiletype/ExternalFileTypes.java index c3a7ebf3d46..25e2bfaa088 100644 --- a/src/main/java/org/jabref/gui/externalfiletype/ExternalFileTypes.java +++ b/src/main/java/org/jabref/gui/externalfiletype/ExternalFileTypes.java @@ -148,10 +148,10 @@ public static String toStringList(Collection fileTypes) { for (ExternalFileType type : fileTypes) { results.add(type); - // See if we can find a type with matching name in the default type list: + // See if we can find a type with matching extension in the default type list: ExternalFileType found = null; for (ExternalFileType defType : defTypes) { - if (defType.getName().equals(type.getName())) { + if (defType.getExtension().equals(type.getExtension())) { found = defType; break; } @@ -221,11 +221,11 @@ public static Set fromString(String storedFileTypes) { } else { // A new or modified entry type. Construct it from the string array: ExternalFileType type = CustomExternalFileType.buildFromArgs(val); - // Check if there is a default type with the same name. If so, this is a + // Check if there is a default type with the same extension. If so, this is a // modification of that type, so remove the default one: ExternalFileType toRemove = null; for (ExternalFileType defType : types) { - if (type.getName().equals(defType.getName())) { + if (type.getExtension().equals(defType.getExtension())) { toRemove = defType; break; } diff --git a/src/main/java/org/jabref/gui/preferences/externalfiletypes/EditExternalFileTypeEntryDialog.java b/src/main/java/org/jabref/gui/preferences/externalfiletypes/EditExternalFileTypeEntryDialog.java index e5aa3e55c03..d0dc110b581 100644 --- a/src/main/java/org/jabref/gui/preferences/externalfiletypes/EditExternalFileTypeEntryDialog.java +++ b/src/main/java/org/jabref/gui/preferences/externalfiletypes/EditExternalFileTypeEntryDialog.java @@ -1,5 +1,7 @@ package org.jabref.gui.preferences.externalfiletypes; +import javafx.application.Platform; +import javafx.collections.ObservableList; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.scene.control.Button; @@ -13,9 +15,11 @@ import org.jabref.gui.desktop.os.NativeDesktop; import org.jabref.gui.util.BaseDialog; import org.jabref.gui.util.FileDialogConfiguration; +import org.jabref.gui.util.IconValidationDecorator; import org.jabref.logic.util.OS; import com.airhacks.afterburner.views.ViewLoader; +import de.saxsys.mvvmfx.utils.validation.visualization.ControlsFxVisualizer; import jakarta.inject.Inject; public class EditExternalFileTypeEntryDialog extends BaseDialog { @@ -33,20 +37,26 @@ public class EditExternalFileTypeEntryDialog extends BaseDialog { private final NativeDesktop nativeDesktop = OS.getNativeDesktop(); private final FileDialogConfiguration fileDialogConfiguration = new FileDialogConfiguration.Builder().withInitialDirectory(nativeDesktop.getApplicationDirectory()).build(); - private final ExternalFileTypeItemViewModel item; + private final ObservableList fileTypes; private EditExternalFileTypeViewModel viewModel; - public EditExternalFileTypeEntryDialog(ExternalFileTypeItemViewModel item, String dialogTitle) { - this.item = item; + private final ControlsFxVisualizer visualizer = new ControlsFxVisualizer(); + public EditExternalFileTypeEntryDialog(ExternalFileTypeItemViewModel item, String dialogTitle, ObservableList fileTypes) { + this.item = item; + this.fileTypes = fileTypes; this.setTitle(dialogTitle); ViewLoader.view(this) .load() .setAsDialogPane(this); + getDialogPane().getButtonTypes().setAll(ButtonType.OK, ButtonType.CANCEL); + + final Button confirmDialogButton = (Button) getDialogPane().lookupButton(ButtonType.OK); + confirmDialogButton.disableProperty().bind(viewModel.validationStatus().validProperty().not()); this.setResultConverter(button -> { if (button == ButtonType.OK) { viewModel.storeSettings(); @@ -57,7 +67,9 @@ public EditExternalFileTypeEntryDialog(ExternalFileTypeItemViewModel item, Strin @FXML public void initialize() { - viewModel = new EditExternalFileTypeViewModel(item); + visualizer.setDecoration(new IconValidationDecorator()); + + viewModel = new EditExternalFileTypeViewModel(item, fileTypes); icon.setGraphic(viewModel.getIcon()); @@ -65,11 +77,16 @@ public void initialize() { customApplication.selectedProperty().bindBidirectional(viewModel.customApplicationSelectedProperty()); selectedApplication.disableProperty().bind(viewModel.defaultApplicationSelectedProperty()); btnBrowse.disableProperty().bind(viewModel.defaultApplicationSelectedProperty()); - extension.textProperty().bindBidirectional(viewModel.extensionProperty()); name.textProperty().bindBidirectional(viewModel.nameProperty()); mimeType.textProperty().bindBidirectional(viewModel.mimeTypeProperty()); selectedApplication.textProperty().bindBidirectional(viewModel.selectedApplicationProperty()); + + Platform.runLater(() -> { + visualizer.initVisualization(viewModel.extensionValidation(), extension, true); + visualizer.initVisualization(viewModel.nameValidation(), name, true); + visualizer.initVisualization(viewModel.mimeTypeValidation(), mimeType, true); + }); } @FXML diff --git a/src/main/java/org/jabref/gui/preferences/externalfiletypes/EditExternalFileTypeViewModel.java b/src/main/java/org/jabref/gui/preferences/externalfiletypes/EditExternalFileTypeViewModel.java index 7a095e76b94..e56aa5e5114 100644 --- a/src/main/java/org/jabref/gui/preferences/externalfiletypes/EditExternalFileTypeViewModel.java +++ b/src/main/java/org/jabref/gui/preferences/externalfiletypes/EditExternalFileTypeViewModel.java @@ -4,21 +4,41 @@ import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; +import javafx.collections.ObservableList; import javafx.scene.Node; +import org.jabref.logic.l10n.Localization; +import org.jabref.model.strings.StringUtil; + +import de.saxsys.mvvmfx.utils.validation.CompositeValidator; +import de.saxsys.mvvmfx.utils.validation.FunctionBasedValidator; +import de.saxsys.mvvmfx.utils.validation.ValidationMessage; +import de.saxsys.mvvmfx.utils.validation.ValidationStatus; +import de.saxsys.mvvmfx.utils.validation.Validator; + public class EditExternalFileTypeViewModel { private final ExternalFileTypeItemViewModel fileTypeViewModel; - private final StringProperty nameProperty = new SimpleStringProperty(""); private final StringProperty mimeTypeProperty = new SimpleStringProperty(""); private final StringProperty extensionProperty = new SimpleStringProperty(""); private final StringProperty selectedApplicationProperty = new SimpleStringProperty(""); private final BooleanProperty defaultApplicationSelectedProperty = new SimpleBooleanProperty(false); private final BooleanProperty customApplicationSelectedProperty = new SimpleBooleanProperty(false); - - public EditExternalFileTypeViewModel(ExternalFileTypeItemViewModel fileTypeViewModel) { + private final ObservableList fileTypes; + private final String originalExtension; + private final String originalName; + private final String originalMimeType; + private CompositeValidator extensionValidator; + private CompositeValidator nameValidator; + private CompositeValidator mimeTypeValidator; + private CompositeValidator validator; + + public EditExternalFileTypeViewModel(ExternalFileTypeItemViewModel fileTypeViewModel, ObservableList fileTypes) { this.fileTypeViewModel = fileTypeViewModel; - + this.fileTypes = fileTypes; + this.originalExtension = fileTypeViewModel.extensionProperty().getValue(); + this.originalName = fileTypeViewModel.nameProperty().getValue(); + this.originalMimeType = fileTypeViewModel.mimetypeProperty().getValue(); extensionProperty.setValue(fileTypeViewModel.extensionProperty().getValue()); nameProperty.setValue(fileTypeViewModel.nameProperty().getValue()); mimeTypeProperty.setValue(fileTypeViewModel.mimetypeProperty().getValue()); @@ -29,6 +49,92 @@ public EditExternalFileTypeViewModel(ExternalFileTypeItemViewModel fileTypeViewM customApplicationSelectedProperty.setValue(true); selectedApplicationProperty.setValue(fileTypeViewModel.applicationProperty().getValue()); } + + setupValidation(); + } + + private void setupValidation() { + validator = new CompositeValidator(); + extensionValidator = new CompositeValidator(); + + Validator extensionisNotBlankValidator = new FunctionBasedValidator<>( + extensionProperty, + StringUtil::isNotBlank, + ValidationMessage.error(Localization.lang("Please enter a name for the extension.")) + ); + Validator sameExtensionValidator = new FunctionBasedValidator<>( + extensionProperty, + extension -> { + for (ExternalFileTypeItemViewModel fileTypeItem : fileTypes) { + if (extension.equalsIgnoreCase(fileTypeItem.extensionProperty().get()) && !extension.equalsIgnoreCase(originalExtension)) { + return false; + } + } + return true; + }, + ValidationMessage.error(Localization.lang("There already exists an external file type with the same extension")) + ); + extensionValidator.addValidators(sameExtensionValidator, extensionisNotBlankValidator); + + nameValidator = new CompositeValidator(); + Validator sameNameValidator = new FunctionBasedValidator<>( + nameProperty, + name -> { + for (ExternalFileTypeItemViewModel fileTypeItem : fileTypes) { + if (name.equalsIgnoreCase(fileTypeItem.nameProperty().get()) && !name.equalsIgnoreCase(originalName)) { + return false; + } + } + return true; + }, + ValidationMessage.error(Localization.lang("There already exists an external file type with the same name")) + ); + + Validator nameIsNotBlankValidator = new FunctionBasedValidator<>( + nameProperty, + StringUtil::isNotBlank, + ValidationMessage.error(Localization.lang("Please enter a name.")) + ); + nameValidator.addValidators(sameNameValidator, nameIsNotBlankValidator); + + mimeTypeValidator = new CompositeValidator(); + Validator mimeTypeIsNotBlankValidator = new FunctionBasedValidator<>( + mimeTypeProperty, + StringUtil::isNotBlank, + ValidationMessage.error(Localization.lang("Please enter a name for the MIME type.")) + ); + + Validator sameMimeTypeValidator = new FunctionBasedValidator<>( + mimeTypeProperty, + mimeType -> { + for (ExternalFileTypeItemViewModel fileTypeItem : fileTypes) { + if (mimeType.equalsIgnoreCase(fileTypeItem.mimetypeProperty().get()) && !mimeType.equalsIgnoreCase(originalMimeType)) { + return false; + } + } + return true; + }, + ValidationMessage.error(Localization.lang("There already exists an external file type with the same MIME type")) + ); + mimeTypeValidator.addValidators(sameMimeTypeValidator, mimeTypeIsNotBlankValidator); + + validator.addValidators(extensionValidator, sameExtensionValidator, nameValidator, sameNameValidator, mimeTypeValidator, sameMimeTypeValidator); + } + + public ValidationStatus validationStatus() { + return validator.getValidationStatus(); + } + + public ValidationStatus extensionValidation() { + return extensionValidator.getValidationStatus(); + } + + public ValidationStatus mimeTypeValidation() { + return mimeTypeValidator.getValidationStatus(); + } + + public ValidationStatus nameValidation() { + return nameValidator.getValidationStatus(); } public Node getIcon() { @@ -59,6 +165,10 @@ public BooleanProperty customApplicationSelectedProperty() { return customApplicationSelectedProperty; } + public BooleanProperty validExtensionTypeProperty() { + return defaultApplicationSelectedProperty; + } + public void storeSettings() { fileTypeViewModel.nameProperty().setValue(nameProperty.getValue().trim()); fileTypeViewModel.mimetypeProperty().setValue(mimeTypeProperty.getValue().trim()); diff --git a/src/main/java/org/jabref/gui/preferences/externalfiletypes/ExternalFileTypesTab.java b/src/main/java/org/jabref/gui/preferences/externalfiletypes/ExternalFileTypesTab.java index b131484ddc3..4e5913c6d2a 100644 --- a/src/main/java/org/jabref/gui/preferences/externalfiletypes/ExternalFileTypesTab.java +++ b/src/main/java/org/jabref/gui/preferences/externalfiletypes/ExternalFileTypesTab.java @@ -78,7 +78,7 @@ public void initialize() { .install(fileTypesTableIconColumn); new ValueTableCellFactory() .withGraphic(none -> IconTheme.JabRefIcons.EDIT.getGraphicNode()) - .withOnMouseClickedEvent((type, none) -> event -> viewModel.edit(type)) + .withOnMouseClickedEvent((type, none) -> event -> editType(type)) .install(fileTypesTableEditColumn); new ValueTableCellFactory() .withGraphic(none -> IconTheme.JabRefIcons.DELETE_ENTRY.getGraphicNode()) @@ -86,11 +86,19 @@ public void initialize() { .install(fileTypesTableDeleteColumn); } + private void editType(ExternalFileTypeItemViewModel type) { + if (viewModel.edit(type)) { + fileTypesTable.getSelectionModel().selectLast(); + fileTypesTable.scrollTo(viewModel.getFileTypes().size() - 1); + } + } + @FXML private void addNewType() { - viewModel.addNewType(); - fileTypesTable.getSelectionModel().selectLast(); - fileTypesTable.scrollTo(viewModel.getFileTypes().size() - 1); + if (viewModel.addNewType()) { + fileTypesTable.getSelectionModel().selectLast(); + fileTypesTable.scrollTo(viewModel.getFileTypes().size() - 1); + } } @FXML diff --git a/src/main/java/org/jabref/gui/preferences/externalfiletypes/ExternalFileTypesTabViewModel.java b/src/main/java/org/jabref/gui/preferences/externalfiletypes/ExternalFileTypesTabViewModel.java index b61818105f0..faacc66b978 100644 --- a/src/main/java/org/jabref/gui/preferences/externalfiletypes/ExternalFileTypesTabViewModel.java +++ b/src/main/java/org/jabref/gui/preferences/externalfiletypes/ExternalFileTypesTabViewModel.java @@ -8,14 +8,19 @@ import javafx.collections.ObservableList; import org.jabref.gui.DialogService; +import org.jabref.gui.exporter.CreateModifyExporterDialogViewModel; import org.jabref.gui.externalfiletype.ExternalFileType; import org.jabref.gui.externalfiletype.ExternalFileTypes; import org.jabref.gui.preferences.PreferenceTabViewModel; import org.jabref.logic.l10n.Localization; import org.jabref.preferences.FilePreferences; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + public class ExternalFileTypesTabViewModel implements PreferenceTabViewModel { + private static final Logger LOGGER = LoggerFactory.getLogger(CreateModifyExporterDialogViewModel.class); private final ObservableList fileTypes = FXCollections.observableArrayList(); private final FilePreferences filePreferences; @@ -54,25 +59,69 @@ public void resetToDefaults() { fileTypes.sort(Comparator.comparing(ExternalFileTypeItemViewModel::getName)); } - public void addNewType() { + public boolean addNewType() { ExternalFileTypeItemViewModel item = new ExternalFileTypeItemViewModel(); - fileTypes.add(item); showEditDialog(item, Localization.lang("Add new file type")); + + if (!isValidExternalFileType(item)) { + return false; + } + + fileTypes.add(item); + return true; } public ObservableList getFileTypes() { return fileTypes; } - private void showEditDialog(ExternalFileTypeItemViewModel item, String dialogTitle) { - dialogService.showCustomDialogAndWait(new EditExternalFileTypeEntryDialog(item, dialogTitle)); + protected void showEditDialog(ExternalFileTypeItemViewModel item, String dialogTitle) { + dialogService.showCustomDialogAndWait(new EditExternalFileTypeEntryDialog(item, dialogTitle, fileTypes)); } - public void edit(ExternalFileTypeItemViewModel type) { - showEditDialog(type, Localization.lang("Edit file type")); + public boolean edit(ExternalFileTypeItemViewModel type) { + ExternalFileTypeItemViewModel typeToModify = new ExternalFileTypeItemViewModel(type.toExternalFileType()); + showEditDialog(typeToModify, Localization.lang("Edit file type")); + + if (!isValidExternalFileType(typeToModify)) { + return false; + } + + fileTypes.remove(type); + fileTypes.add(typeToModify); + return true; } public void remove(ExternalFileTypeItemViewModel type) { fileTypes.remove(type); } + + public boolean isValidExternalFileType(ExternalFileTypeItemViewModel item) { + if (withEmptyValue(item)) { + LOGGER.debug("One of the fields is empty or invalid."); + return false; + } + + if (!isUniqueExtension(item)) { + LOGGER.debug("File Extension exists already."); + return false; + } + + return true; + } + + private boolean withEmptyValue(ExternalFileTypeItemViewModel item) { + return item.getName().isEmpty() || item.extensionProperty().get().isEmpty() || item.mimetypeProperty().get().isEmpty(); + } + + private boolean isUniqueExtension(ExternalFileTypeItemViewModel item) { + // check extension need to be unique in the list + String newExt = item.extensionProperty().get(); + for (ExternalFileTypeItemViewModel fileTypeItem : fileTypes) { + if (newExt.equalsIgnoreCase(fileTypeItem.extensionProperty().get())) { + return false; + } + } + return true; + } } diff --git a/src/main/resources/csl-styles b/src/main/resources/csl-styles index a3d9a63426d..42f54b22d80 160000 --- a/src/main/resources/csl-styles +++ b/src/main/resources/csl-styles @@ -1 +1 @@ -Subproject commit a3d9a63426d2390068b4c98da6f48bd4ce73b257 +Subproject commit 42f54b22d8058c957404945b7dca5cc59c1fc68d diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index ea1e11f80ae..019dcfcd8ae 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -2040,6 +2040,15 @@ Matching=Matching Same\ as\ --import,\ but\ will\ be\ imported\ to\ the\ opened\ tab=Same as --import, but will be imported to the opened tab Allow\ integers\ in\ 'edition'\ field\ in\ BibTeX\ mode=Allow integers in 'edition' field in BibTeX mode +Please\ enter\ a\ name\ for\ the\ MIME\ type.=Please enter a name for the MIME type. +Please\ enter\ a\ name\ for\ the\ extension.=Please enter a name for the extension. +Please\ enter\ a\ name.=Please enter a name. + +There\ already\ exists\ an\ external\ file\ type\ with\ the\ same\ MIME\ type=There already exists an external file type with the same MIME type +There\ already\ exists\ an\ external\ file\ type\ with\ the\ same\ extension=There already exists an external file type with the same extension +There\ already\ exists\ an\ external\ file\ type\ with\ the\ same\ name=There already exists an external file type with the same name + + Search\ for\ citations\ in\ LaTeX\ files...=Search for citations in LaTeX files... LaTeX\ Citations\ Search\ Results=LaTeX Citations Search Results LaTeX\ files\ directory\:=LaTeX files directory: @@ -2622,7 +2631,7 @@ Enable=Enable Keep\ disabled=Keep disabled Predatory\ journal\ %0\ found=Predatory journal %0 found - + Hide\ user\ comments=Hide user comments Show\ user\ comments\ field=Show user comments field diff --git a/src/test/java/org/jabref/gui/preferences/externalfiletypes/ExternalFileTypesTabViewModelTest.java b/src/test/java/org/jabref/gui/preferences/externalfiletypes/ExternalFileTypesTabViewModelTest.java new file mode 100644 index 00000000000..8c730d6b583 --- /dev/null +++ b/src/test/java/org/jabref/gui/preferences/externalfiletypes/ExternalFileTypesTabViewModelTest.java @@ -0,0 +1,98 @@ +package org.jabref.gui.preferences.externalfiletypes; + +import javafx.collections.ObservableList; + +import org.jabref.gui.DialogService; +import org.jabref.preferences.FilePreferences; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Spy; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; + +public class ExternalFileTypesTabViewModelTest { + + private FilePreferences filePreferences = mock(FilePreferences.class); + private DialogService dialogService = mock(DialogService.class); + private ExternalFileTypeItemViewModel externalFileTypeItemViewModel = new ExternalFileTypeItemViewModel(); + + @Spy + private ExternalFileTypesTabViewModel externalFileTypesTabViewModel = spy(new ExternalFileTypesTabViewModel(filePreferences, dialogService)); + + @BeforeEach + void setUp() { + externalFileTypeItemViewModel.nameProperty().set("Excel 2007"); + externalFileTypeItemViewModel.extensionProperty().set("xlsx"); + externalFileTypeItemViewModel.mimetypeProperty().set("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + externalFileTypeItemViewModel.applicationProperty().set("oocalc"); + } + + public void setupViewModelWithoutName() { + externalFileTypeItemViewModel.nameProperty().set(""); + } + + public void viewModelClone(ExternalFileTypeItemViewModel updatedModel) { + updatedModel.nameProperty().set(externalFileTypeItemViewModel.getName()); + updatedModel.extensionProperty().set(externalFileTypeItemViewModel.extensionProperty().get()); + updatedModel.mimetypeProperty().set(externalFileTypeItemViewModel.mimetypeProperty().get()); + updatedModel.applicationProperty().set(externalFileTypeItemViewModel.applicationProperty().get()); + } + + public boolean viewModelIsSameValue(ExternalFileTypeItemViewModel item) { + return !(!item.getName().equals(externalFileTypeItemViewModel.getName()) + || !item.extensionProperty().get().equals(externalFileTypeItemViewModel.extensionProperty().get()) + || !item.mimetypeProperty().get().equals(externalFileTypeItemViewModel.mimetypeProperty().get()) + || !item.applicationProperty().get().equals(externalFileTypeItemViewModel.applicationProperty().get())); + } + + @Test + public void whenExternalFileTypeItemViewModelWithNonEmptyStringValueThenisValidExternalFileTypeReturnTrue() { + assertTrue(externalFileTypesTabViewModel.isValidExternalFileType(externalFileTypeItemViewModel)); + } + + @Test + public void whenExternalFileTypeItemViewModelWithEmptyNameThenisValidExternalFileTypeReturnFalse() { + this.setupViewModelWithoutName(); + assertFalse(externalFileTypesTabViewModel.isValidExternalFileType(externalFileTypeItemViewModel)); + } + + @Test + public void WhenExternalFileTypeItemViewModelIsValidThenAddNewTypeIsSuccessful() { + ArgumentCaptor itemCaptor = ArgumentCaptor.forClass(ExternalFileTypeItemViewModel.class); + doAnswer(mocked -> { + ExternalFileTypeItemViewModel capturedItem = itemCaptor.getValue(); + this.viewModelClone(capturedItem); + return null; + }).when(externalFileTypesTabViewModel).showEditDialog(itemCaptor.capture(), any()); + + externalFileTypesTabViewModel.addNewType(); + + ObservableList actualFileTypes = externalFileTypesTabViewModel.getFileTypes(); + assertEquals(1, actualFileTypes.size()); + assertTrue(viewModelIsSameValue(actualFileTypes.getFirst())); + } + + @Test + public void WhenExternalFileTypeItemViewModelMissNameThenAddNewTypeIsFailed() { + setupViewModelWithoutName(); + ArgumentCaptor itemCaptor = ArgumentCaptor.forClass(ExternalFileTypeItemViewModel.class); + doAnswer(mocked -> { + ExternalFileTypeItemViewModel capturedItem = itemCaptor.getValue(); + viewModelClone(capturedItem); + return null; + }).when(externalFileTypesTabViewModel).showEditDialog(itemCaptor.capture(), any()); + + externalFileTypesTabViewModel.addNewType(); + + ObservableList emptyFileTypes = externalFileTypesTabViewModel.getFileTypes(); + assertEquals(0, emptyFileTypes.size()); + } +}