From 6c19393f40469e20de3e43355691ee643202e536 Mon Sep 17 00:00:00 2001 From: Kevin Klein <38384885+0x002A@users.noreply.github.com> Date: Sat, 3 Sep 2022 13:01:44 +0200 Subject: [PATCH 1/5] Rework the Define study parameters dialog (#9123) * Implement UI changes * Implement default selection * Fix initialization of UI (and add test) * Create constructor for existing studies * Fix behaviour of study database table * Update changelog Co-authored-by: Oliver Kopp --- CHANGELOG.md | 4 +- .../jabref/gui/slr/ManageStudyDefinition.fxml | 242 ++++++++++++------ .../gui/slr/ManageStudyDefinitionView.java | 56 ++-- .../slr/ManageStudyDefinitionViewModel.java | 125 ++++----- .../org/jabref/gui/slr/StudyDatabaseItem.java | 28 +- .../importer/fetcher/ACMPortalFetcher.java | 4 +- .../fetcher/CompositeSearchBasedFetcher.java | 4 +- .../logic/importer/fetcher/DBLPFetcher.java | 3 +- .../jabref/logic/importer/fetcher/IEEE.java | 4 +- .../importer/fetcher/SpringerFetcher.java | 3 +- .../logic/importer/fetcher/SpringerLink.java | 3 +- .../java/org/jabref/model/study/Study.java | 2 +- .../org/jabref/model/study/StudyDatabase.java | 3 + src/main/resources/l10n/JabRef_en.properties | 2 +- .../ManageStudyDefinitionViewModelTest.java | 98 +++++++ 15 files changed, 390 insertions(+), 191 deletions(-) create mode 100644 src/test/java/org/jabref/gui/slr/ManageStudyDefinitionViewModelTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index eca3530c6df..880b7b43b26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,11 +26,11 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve - We changed the button label from "Return to JabRef" to "Return to library" to better indicate the purpose of the action. - We removed "last-search-date" from the SLR feature, because the last-search-date can be deducted from the git logs. - We reworked the External Changes Resolver dialog. [#9021](https://github.com/JabRef/jabref/pull/9021) - +- We reworked the Define study parameters dialog. [#9123](https://github.com/JabRef/jabref/pull/9123) ### Fixed -- We fixed an issue where the possibilty to generate a subdatabase from an aux file was writing empty files when called from the commandline [#9115](https://github.com/JabRef/jabref/issues/9115), [forum#3516](https://discourse.jabref.org/t/export-subdatabase-from-aux-file-on-macos-command-line/3516) +- We fixed an issue where the possibility to generate a subdatabase from an aux file was writing empty files when called from the commandline [#9115](https://github.com/JabRef/jabref/issues/9115), [forum#3516](https://discourse.jabref.org/t/export-subdatabase-from-aux-file-on-macos-command-line/3516) - We fixed the display of issue, number, eid and pages fields in the entry preview. [#8607](https://github.com/JabRef/jabref/pull/8607), [#8372](https://github.com/JabRef/jabref/issues/8372), [Koppor#514](https://github.com/koppor/jabref/issues/514), [forum#2390](https://discourse.jabref.org/t/unable-to-edit-my-bibtex-file-that-i-used-before-vers-5-1/2390), [forum#3462](https://discourse.jabref.org/t/jabref-5-6-need-help-with-export-from-jabref-to-microsoft-word-entry-preview-of-apa-7-not-rendering-correctly/3462) - We fixed the page ranges checker to detect article numbers in the pages field (used at [Check Integrity](https://docs.jabref.org/finding-sorting-and-cleaning-entries/checkintegrity)). [#8607](https://github.com/JabRef/jabref/pull/8607) - The [HtmlToLaTeXFormatter](https://docs.jabref.org/finding-sorting-and-cleaning-entries/saveactions#html-to-latex) keeps single `<` characters. diff --git a/src/main/java/org/jabref/gui/slr/ManageStudyDefinition.fxml b/src/main/java/org/jabref/gui/slr/ManageStudyDefinition.fxml index b6ea1d41f7a..297ee2c1318 100644 --- a/src/main/java/org/jabref/gui/slr/ManageStudyDefinition.fxml +++ b/src/main/java/org/jabref/gui/slr/ManageStudyDefinition.fxml @@ -2,7 +2,6 @@ - @@ -19,50 +18,86 @@ - +
- + - + - + - - + + - - + + - + - - + + - + @@ -70,32 +105,48 @@ - + - + - - + + - + @@ -103,35 +154,54 @@ - + - + - + - - + + - + @@ -139,33 +209,33 @@ - + - - + - + - + @@ -196,6 +277,11 @@
- - + +
diff --git a/src/main/java/org/jabref/gui/slr/ManageStudyDefinitionView.java b/src/main/java/org/jabref/gui/slr/ManageStudyDefinitionView.java index ce1c5f10e3e..ebd7e89619f 100644 --- a/src/main/java/org/jabref/gui/slr/ManageStudyDefinitionView.java +++ b/src/main/java/org/jabref/gui/slr/ManageStudyDefinitionView.java @@ -13,7 +13,6 @@ import javafx.scene.Node; import javafx.scene.control.Button; import javafx.scene.control.ButtonType; -import javafx.scene.control.ComboBox; import javafx.scene.control.Label; import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; @@ -22,6 +21,7 @@ import javafx.scene.control.cell.CheckBoxTableCell; import javafx.scene.control.cell.TextFieldTableCell; import javafx.scene.input.KeyCode; +import javafx.scene.input.MouseButton; import org.jabref.gui.DialogService; import org.jabref.gui.icon.IconTheme; @@ -29,23 +29,26 @@ import org.jabref.gui.util.BaseDialog; import org.jabref.gui.util.DirectoryDialogConfiguration; import org.jabref.gui.util.ValueTableCellFactory; -import org.jabref.gui.util.ViewModelListCellFactory; +import org.jabref.gui.util.ViewModelTableRowFactory; import org.jabref.logic.l10n.Localization; import org.jabref.model.study.Study; import org.jabref.preferences.PreferencesService; import com.airhacks.afterburner.views.ViewLoader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * This class controls the user interface of the study definition management dialog. The UI elements and their layout * are defined in the FXML file. */ public class ManageStudyDefinitionView extends BaseDialog { + private static final Logger LOGGER = LoggerFactory.getLogger(ManageStudyDefinitionView.class); + @FXML private TextField studyTitle; @FXML private TextField addAuthor; @FXML private TextField addResearchQuestion; @FXML private TextField addQuery; - @FXML private ComboBox databaseSelector; @FXML private TextField studyDirectory; @FXML private ButtonType saveButtonType; @@ -66,7 +69,6 @@ public class ManageStudyDefinitionView extends BaseDialog @FXML private TableView databaseTable; @FXML private TableColumn databaseEnabledColumn; @FXML private TableColumn databaseColumn; - @FXML private TableColumn databaseActionColumn; @Inject private DialogService dialogService; @Inject private PreferencesService prefs; @@ -80,7 +82,7 @@ public class ManageStudyDefinitionView extends BaseDialog /** * This can be used to either create new study objects or edit existing ones. * - * @param study null if a new study is created. Otherwise the study object to edit. + * @param study null if a new study is created. Otherwise, the study object to edit. * @param studyDirectory the directory where the study to edit is located (null if a new study is created) */ public ManageStudyDefinitionView(Study study, Path studyDirectory, Path workingDirectory) { @@ -118,11 +120,14 @@ private void setupSaveButton() { @FXML private void initialize() { - viewModel = new ManageStudyDefinitionViewModel( - study, - workingDirectory, - prefs.getImportFormatPreferences(), - prefs.getImporterPreferences()); + if (Objects.isNull(study)) { + viewModel = new ManageStudyDefinitionViewModel( + prefs.getImportFormatPreferences(), + prefs.getImporterPreferences()); + } else { + LOGGER.error("Not yet implemented"); + return; + } // Listen whether any databases are removed from selection -> Add back to the database selector studyTitle.textProperty().bindBidirectional(viewModel.titleProperty()); @@ -161,25 +166,24 @@ private void initQueriesTab() { } private void initDatabasesTab() { - new ViewModelListCellFactory().withText(StudyDatabaseItem::getName) - .install(databaseSelector); - databaseSelector.setItems(viewModel.getNonSelectedDatabases()); + new ViewModelTableRowFactory() + .withOnMouseClickedEvent((entry, event) -> { + if (event.getButton() == MouseButton.PRIMARY) { + entry.setEnabled(!entry.isEnabled()); + } + }) + .install(databaseTable); - setupCommonPropertiesForTables(databaseSelector, this::addDatabase, databaseColumn, databaseActionColumn); + databaseColumn.setReorderable(false); + databaseColumn.setCellFactory(TextFieldTableCell.forTableColumn()); databaseEnabledColumn.setResizable(false); databaseEnabledColumn.setReorderable(false); - databaseEnabledColumn.setCellValueFactory(param -> param.getValue().enabledProperty()); databaseEnabledColumn.setCellFactory(CheckBoxTableCell.forTableColumn(databaseEnabledColumn)); + databaseEnabledColumn.setCellValueFactory(param -> param.getValue().enabledProperty()); + databaseColumn.setEditable(false); databaseColumn.setCellValueFactory(param -> param.getValue().nameProperty()); - databaseActionColumn.setCellValueFactory(param -> param.getValue().nameProperty()); - new ValueTableCellFactory() - .withGraphic(item -> IconTheme.JabRefIcons.DELETE_ENTRY.getGraphicNode()) - .withTooltip(name -> Localization.lang("Remove")) - .withOnMouseClickedEvent(item -> evt -> - viewModel.removeDatabase(item)) - .install(databaseActionColumn); databaseTable.setItems(viewModel.getDatabases()); } @@ -231,14 +235,6 @@ private void addQuery() { addQuery.setText(""); } - /** - * Add selected entry from combobox, push onto database pop from nonselecteddatabase (combobox) - */ - @FXML - private void addDatabase() { - viewModel.addDatabase(databaseSelector.getSelectionModel().getSelectedItem()); - } - @FXML public void selectStudyDirectory() { DirectoryDialogConfiguration directoryDialogConfiguration = new DirectoryDialogConfiguration.Builder() diff --git a/src/main/java/org/jabref/gui/slr/ManageStudyDefinitionViewModel.java b/src/main/java/org/jabref/gui/slr/ManageStudyDefinitionViewModel.java index 01350ab64bb..3f87b2232c3 100644 --- a/src/main/java/org/jabref/gui/slr/ManageStudyDefinitionViewModel.java +++ b/src/main/java/org/jabref/gui/slr/ManageStudyDefinitionViewModel.java @@ -2,9 +2,10 @@ import java.nio.file.InvalidPathException; import java.nio.file.Path; -import java.util.Comparator; +import java.util.List; import java.util.Objects; import java.util.Optional; +import java.util.Set; import java.util.stream.Collectors; import javafx.beans.property.Property; @@ -17,6 +18,11 @@ import org.jabref.logic.importer.ImporterPreferences; import org.jabref.logic.importer.SearchBasedFetcher; import org.jabref.logic.importer.WebFetchers; +import org.jabref.logic.importer.fetcher.ACMPortalFetcher; +import org.jabref.logic.importer.fetcher.CompositeSearchBasedFetcher; +import org.jabref.logic.importer.fetcher.DBLPFetcher; +import org.jabref.logic.importer.fetcher.IEEE; +import org.jabref.logic.importer.fetcher.SpringerFetcher; import org.jabref.model.study.Study; import org.jabref.model.study.StudyDatabase; import org.jabref.model.study.StudyQuery; @@ -31,45 +37,69 @@ public class ManageStudyDefinitionViewModel { private static final Logger LOGGER = LoggerFactory.getLogger(ManageStudyDefinitionViewModel.class); + private static final Set DEFAULT_SELECTION = Set.of( + ACMPortalFetcher.FETCHER_NAME, + IEEE.FETCHER_NAME, + SpringerFetcher.FETCHER_NAME, + DBLPFetcher.FETCHER_NAME); + + private final StringProperty title = new SimpleStringProperty(); private final ObservableList authors = FXCollections.observableArrayList(); private final ObservableList researchQuestions = FXCollections.observableArrayList(); private final ObservableList queries = FXCollections.observableArrayList(); private final ObservableList databases = FXCollections.observableArrayList(); + // Hold the complement of databases for the selector - private final ObservableList nonSelectedDatabases = FXCollections.observableArrayList(); private final SimpleStringProperty directory = new SimpleStringProperty(); - private Study study; + /** + * Constructor for a new study + */ + public ManageStudyDefinitionViewModel(ImportFormatPreferences importFormatPreferences, + ImporterPreferences importerPreferences) { + databases.addAll(WebFetchers.getSearchBasedFetchers(importFormatPreferences, importerPreferences) + .stream() + .map(SearchBasedFetcher::getName) + // The user wants to select specific fetchers + // The fetcher summarizing ALL fetchers can be emulated by selecting ALL fetchers (which happens rarely when doing an SLR) + .filter(name -> !name.equals(CompositeSearchBasedFetcher.FETCHER_NAME)) + .map(name -> { + boolean enabled = DEFAULT_SELECTION.contains(name); + return new StudyDatabaseItem(name, enabled); + }) + .toList()); + } + + /** + * Constructor for an existing study + * + * @param study The study to initialize the UI from + * @param studyDirectory The path where the study resides + */ public ManageStudyDefinitionViewModel(Study study, Path studyDirectory, ImportFormatPreferences importFormatPreferences, ImporterPreferences importerPreferences) { - if (Objects.isNull(study)) { - computeNonSelectedDatabases(importFormatPreferences, importerPreferences); - return; - } - this.study = study; + // copy the content of the study object into the UI fields + authors.addAll(Objects.requireNonNull(study).getAuthors()); title.setValue(study.getTitle()); - authors.addAll(study.getAuthors()); researchQuestions.addAll(study.getResearchQuestions()); queries.addAll(study.getQueries().stream().map(StudyQuery::getQuery).toList()); - databases.addAll(study.getDatabases() - .stream() - .map(studyDatabase -> new StudyDatabaseItem(studyDatabase.getName(), studyDatabase.isEnabled())) - .toList()); - computeNonSelectedDatabases(importFormatPreferences, importerPreferences); - if (!Objects.isNull(studyDirectory)) { - this.directory.set(studyDirectory.toString()); - } - } - - private void computeNonSelectedDatabases(ImportFormatPreferences importFormatPreferences, ImporterPreferences importerPreferences) { - nonSelectedDatabases.addAll(WebFetchers.getSearchBasedFetchers(importFormatPreferences, importerPreferences) - .stream() - .map(SearchBasedFetcher::getName) - .map(s -> new StudyDatabaseItem(s, true)) - .filter(studyDatabase -> !databases.contains(studyDatabase)).toList()); + List studyDatabases = study.getDatabases(); + databases.addAll(WebFetchers.getSearchBasedFetchers(importFormatPreferences, importerPreferences) + .stream() + .map(SearchBasedFetcher::getName) + // The user wants to select specific fetchers + // The fetcher summarizing ALL fetchers can be emulated by selecting ALL fetchers (which happens rarely when doing an SLR) + .filter(name -> !name.equals(CompositeSearchBasedFetcher.FETCHER_NAME)) + .map(name -> { + boolean enabled = studyDatabases.contains(new StudyDatabase(name, true)); + return new StudyDatabaseItem(name, enabled); + }) + .toList()); + + this.directory.set(Objects.requireNonNull(studyDirectory).toString()); } public StringProperty getTitle() { @@ -96,10 +126,6 @@ public ObservableList getDatabases() { return databases; } - public ObservableList getNonSelectedDatabases() { - return nonSelectedDatabases; - } - public void addAuthor(String author) { if (author.isBlank()) { return; @@ -121,29 +147,18 @@ public void addQuery(String query) { queries.add(query); } - public void addDatabase(StudyDatabaseItem database) { - if (Objects.isNull(database)) { - return; - } - nonSelectedDatabases.remove(database); - if (!databases.contains(database)) { - databases.add(database); - } - } - public SlrStudyAndDirectory saveStudy() { - if (Objects.isNull(study)) { - study = new Study(); - } - study.setTitle(title.getValueSafe()); - study.setAuthors(authors); - study.setResearchQuestions(researchQuestions); - study.setQueries(queries.stream().map(StudyQuery::new).collect(Collectors.toList())); - study.setDatabases(databases.stream().map(studyDatabaseItem -> new StudyDatabase(studyDatabaseItem.getName(), studyDatabaseItem.isEnabled())).collect(Collectors.toList())); + Study study = new Study( + authors, + title.getValueSafe(), + researchQuestions, + queries.stream().map(StudyQuery::new).collect(Collectors.toList()), + databases.stream().map(studyDatabaseItem -> new StudyDatabase(studyDatabaseItem.getName(), studyDatabaseItem.isEnabled())).filter(StudyDatabase::isEnabled).collect(Collectors.toList())); Path studyDirectory = null; try { studyDirectory = Path.of(directory.getValueSafe()); - } catch (InvalidPathException e) { + } catch ( + InvalidPathException e) { LOGGER.error("Invalid path was provided: {}", directory); } return new SlrStudyAndDirectory(study, studyDirectory); @@ -153,20 +168,6 @@ public Property titleProperty() { return title; } - public void removeDatabase(String database) { - // If a database is added from the combo box it should be enabled by default - Optional correspondingDatabase = databases.stream().filter(studyDatabaseItem -> studyDatabaseItem.getName().equals(database)).findFirst(); - if (correspondingDatabase.isEmpty()) { - return; - } - StudyDatabaseItem databaseToRemove = correspondingDatabase.get(); - databases.remove(databaseToRemove); - databaseToRemove.setEnabled(true); - nonSelectedDatabases.add(databaseToRemove); - // Resort list - nonSelectedDatabases.sort(Comparator.comparing(StudyDatabaseItem::getName)); - } - public void setStudyDirectory(Optional studyRepositoryRoot) { getDirectory().setValue(studyRepositoryRoot.map(Path::toString).orElseGet(() -> getDirectory().getValueSafe())); } diff --git a/src/main/java/org/jabref/gui/slr/StudyDatabaseItem.java b/src/main/java/org/jabref/gui/slr/StudyDatabaseItem.java index 50ceda09143..c6c77eaaf31 100644 --- a/src/main/java/org/jabref/gui/slr/StudyDatabaseItem.java +++ b/src/main/java/org/jabref/gui/slr/StudyDatabaseItem.java @@ -1,16 +1,23 @@ package org.jabref.gui.slr; +import java.util.Objects; + import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; +import org.jabref.model.study.StudyDatabase; + +/** + * View representation of {@link StudyDatabase} + */ public class StudyDatabaseItem { private final StringProperty name; private final BooleanProperty enabled; public StudyDatabaseItem(String name, boolean enabled) { - this.name = new SimpleStringProperty(name); + this.name = new SimpleStringProperty(Objects.requireNonNull(name)); this.enabled = new SimpleBooleanProperty(enabled); } @@ -38,6 +45,14 @@ public BooleanProperty enabledProperty() { return enabled; } + @Override + public String toString() { + return "StudyDatabaseItem{" + + "name=" + name.get() + + ", enabled=" + enabled.get() + + '}'; + } + @Override public boolean equals(Object o) { if (this == o) { @@ -46,19 +61,12 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) { return false; } - StudyDatabaseItem that = (StudyDatabaseItem) o; - - if (isEnabled() != that.isEnabled()) { - return false; - } - return getName() != null ? getName().equals(that.getName()) : that.getName() == null; + return Object.equals(getName(),that.getName()) && Object.equals(isEnabled(), that.isEnabled()); } @Override public int hashCode() { - int result = getName() != null ? getName().hashCode() : 0; - result = 31 * result + (isEnabled() ? 1 : 0); - return result; + return Objects.hash(getName(), isEnabled()); } } diff --git a/src/main/java/org/jabref/logic/importer/fetcher/ACMPortalFetcher.java b/src/main/java/org/jabref/logic/importer/fetcher/ACMPortalFetcher.java index 10ba0e1b1b4..5fd153a07f2 100644 --- a/src/main/java/org/jabref/logic/importer/fetcher/ACMPortalFetcher.java +++ b/src/main/java/org/jabref/logic/importer/fetcher/ACMPortalFetcher.java @@ -19,6 +19,8 @@ public class ACMPortalFetcher implements SearchBasedParserFetcher { + public static final String FETCHER_NAME = "ACM Portal"; + private static final String SEARCH_URL = "https://dl.acm.org/action/doSearch"; public ACMPortalFetcher() { @@ -28,7 +30,7 @@ public ACMPortalFetcher() { @Override public String getName() { - return "ACM Portal"; + return FETCHER_NAME; } @Override diff --git a/src/main/java/org/jabref/logic/importer/fetcher/CompositeSearchBasedFetcher.java b/src/main/java/org/jabref/logic/importer/fetcher/CompositeSearchBasedFetcher.java index 97506c284a6..bee6f3c7fc9 100644 --- a/src/main/java/org/jabref/logic/importer/fetcher/CompositeSearchBasedFetcher.java +++ b/src/main/java/org/jabref/logic/importer/fetcher/CompositeSearchBasedFetcher.java @@ -17,6 +17,8 @@ public class CompositeSearchBasedFetcher implements SearchBasedFetcher { + public static final String FETCHER_NAME = "SearchAll"; + private static final Logger LOGGER = LoggerFactory.getLogger(CompositeSearchBasedFetcher.class); private final Set fetchers; @@ -36,7 +38,7 @@ public CompositeSearchBasedFetcher(Set searchBasedFetchers, @Override public String getName() { - return "SearchAll"; + return FETCHER_NAME; } @Override diff --git a/src/main/java/org/jabref/logic/importer/fetcher/DBLPFetcher.java b/src/main/java/org/jabref/logic/importer/fetcher/DBLPFetcher.java index d961ce0b3bc..19d1d67ec1a 100644 --- a/src/main/java/org/jabref/logic/importer/fetcher/DBLPFetcher.java +++ b/src/main/java/org/jabref/logic/importer/fetcher/DBLPFetcher.java @@ -33,6 +33,7 @@ * @see Basic API documentation */ public class DBLPFetcher implements SearchBasedParserFetcher { + public static final String FETCHER_NAME = "DBLP"; private static final String BASIC_SEARCH_URL = "https://dblp.org/search/publ/api"; @@ -76,7 +77,7 @@ public void doPostCleanup(BibEntry entry) { @Override public String getName() { - return "DBLP"; + return FETCHER_NAME; } @Override diff --git a/src/main/java/org/jabref/logic/importer/fetcher/IEEE.java b/src/main/java/org/jabref/logic/importer/fetcher/IEEE.java index 3ca57ff3cbf..fe9860c3f44 100644 --- a/src/main/java/org/jabref/logic/importer/fetcher/IEEE.java +++ b/src/main/java/org/jabref/logic/importer/fetcher/IEEE.java @@ -48,9 +48,9 @@ */ public class IEEE implements FulltextFetcher, PagedSearchBasedParserFetcher, CustomizableKeyFetcher { - private static final Logger LOGGER = LoggerFactory.getLogger(IEEE.class); + public static final String FETCHER_NAME = "IEEEXplore"; - private static final String FETCHER_NAME = "IEEEXplore"; + private static final Logger LOGGER = LoggerFactory.getLogger(IEEE.class); private static final String STAMP_BASE_STRING_DOCUMENT = "/stamp/stamp.jsp?tp=&arnumber="; private static final Pattern STAMP_PATTERN = Pattern.compile("(/stamp/stamp.jsp\\?t?p?=?&?arnumber=[0-9]+)"); diff --git a/src/main/java/org/jabref/logic/importer/fetcher/SpringerFetcher.java b/src/main/java/org/jabref/logic/importer/fetcher/SpringerFetcher.java index d0aa60e4494..e1764120e14 100644 --- a/src/main/java/org/jabref/logic/importer/fetcher/SpringerFetcher.java +++ b/src/main/java/org/jabref/logic/importer/fetcher/SpringerFetcher.java @@ -40,13 +40,14 @@ */ public class SpringerFetcher implements PagedSearchBasedParserFetcher, CustomizableKeyFetcher { + public static final String FETCHER_NAME = "Springer"; + private static final Logger LOGGER = LoggerFactory.getLogger(SpringerFetcher.class); private static final String API_URL = "https://api.springernature.com/meta/v1/json"; private static final String API_KEY = new BuildInfo().springerNatureAPIKey; // Springer query using the parameter 'q=doi:10.1007/s11276-008-0131-4s=1' will respond faster private static final String TEST_URL_WITHOUT_API_KEY = "https://api.springernature.com/meta/v1/json?q=doi:10.1007/s11276-008-0131-4s=1&p=1&api_key="; - private static final String FETCHER_NAME = "Springer"; private final ImporterPreferences importerPreferences; diff --git a/src/main/java/org/jabref/logic/importer/fetcher/SpringerLink.java b/src/main/java/org/jabref/logic/importer/fetcher/SpringerLink.java index 78a7a420718..769e7f6c200 100644 --- a/src/main/java/org/jabref/logic/importer/fetcher/SpringerLink.java +++ b/src/main/java/org/jabref/logic/importer/fetcher/SpringerLink.java @@ -27,12 +27,13 @@ * Uses Springer API, see https://dev.springer.com */ public class SpringerLink implements FulltextFetcher { + public static final String FETCHER_NAME = "Springer"; + private static final Logger LOGGER = LoggerFactory.getLogger(SpringerLink.class); private static final String API_URL = "https://api.springer.com/meta/v1/json"; private static final String API_KEY = new BuildInfo().springerNatureAPIKey; private static final String CONTENT_HOST = "link.springer.com"; - private static final String FETCHER_NAME = "Springer"; private final ImporterPreferences importerPreferences; diff --git a/src/main/java/org/jabref/model/study/Study.java b/src/main/java/org/jabref/model/study/Study.java index 1c85a1d77c2..3748f0962bc 100644 --- a/src/main/java/org/jabref/model/study/Study.java +++ b/src/main/java/org/jabref/model/study/Study.java @@ -35,7 +35,7 @@ public Study(List authors, String title, List researchQuestions, /** * Used for Jackson deserialization */ - public Study() { + private Study() { } public List getAuthors() { diff --git a/src/main/java/org/jabref/model/study/StudyDatabase.java b/src/main/java/org/jabref/model/study/StudyDatabase.java index ac71a7160c2..375b59fb57c 100644 --- a/src/main/java/org/jabref/model/study/StudyDatabase.java +++ b/src/main/java/org/jabref/model/study/StudyDatabase.java @@ -1,5 +1,8 @@ package org.jabref.model.study; +/** + * data model for the view {@link org.jabref.gui.slr.StudyDatabaseItem} + */ public class StudyDatabase { private String name; private boolean enabled; diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index 6dff22b68d0..d020d8e5691 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -2406,7 +2406,7 @@ Database=Database Databases=Databases Manage\ study\ definition=Manage study definition Add\ Author\:=Add Author\: -Add\ Database\:=Add Database\: +Select\ Databases\:=Select the databases that should be searched\: Add\ Query\:=Add Query\: Add\ Research\ Question\:=Add Research Question\: Perform\ search\ for\ existing\ systematic\ literature\ review=Perform search for existing systematic literature review diff --git a/src/test/java/org/jabref/gui/slr/ManageStudyDefinitionViewModelTest.java b/src/test/java/org/jabref/gui/slr/ManageStudyDefinitionViewModelTest.java new file mode 100644 index 00000000000..f6f9d927909 --- /dev/null +++ b/src/test/java/org/jabref/gui/slr/ManageStudyDefinitionViewModelTest.java @@ -0,0 +1,98 @@ +package org.jabref.gui.slr; + +import java.nio.file.Path; +import java.util.List; + +import org.jabref.logic.bibtex.FieldContentFormatterPreferences; +import org.jabref.logic.importer.ImportFormatPreferences; +import org.jabref.logic.importer.ImporterPreferences; +import org.jabref.model.study.Study; +import org.jabref.model.study.StudyDatabase; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import org.mockito.Answers; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class ManageStudyDefinitionViewModelTest { + private ImportFormatPreferences importFormatPreferences; + private ImporterPreferences importerPreferences; + + @BeforeEach + void setUp() { + // code taken from org.jabref.logic.importer.WebFetchersTest.setUp + importFormatPreferences = mock(ImportFormatPreferences.class, Answers.RETURNS_DEEP_STUBS); + importerPreferences = mock(ImporterPreferences.class); + FieldContentFormatterPreferences fieldContentFormatterPreferences = mock(FieldContentFormatterPreferences.class); + when(importFormatPreferences.getFieldContentFormatterPreferences()).thenReturn(fieldContentFormatterPreferences); + } + + @Test + public void emptyStudyConstructorFillsDatabasesCorrectly() { + ManageStudyDefinitionViewModel manageStudyDefinitionViewModel = new ManageStudyDefinitionViewModel(importFormatPreferences, importerPreferences); + assertEquals(List.of( + new StudyDatabaseItem("ACM Portal", true), + new StudyDatabaseItem("ArXiv", false), + new StudyDatabaseItem("Biodiversity Heritage", false), + new StudyDatabaseItem("CiteSeerX", false), + new StudyDatabaseItem("Collection of Computer Science Bibliographies", false), + new StudyDatabaseItem("Crossref", false), + new StudyDatabaseItem("DBLP", true), + new StudyDatabaseItem("DOAB", false), + new StudyDatabaseItem("DOAJ", false), + new StudyDatabaseItem("GVK", false), + new StudyDatabaseItem("IEEEXplore", true), + new StudyDatabaseItem("INSPIRE", false), + new StudyDatabaseItem("MathSciNet", false), + new StudyDatabaseItem("Medline/PubMed", false), + new StudyDatabaseItem("ResearchGate", false), + new StudyDatabaseItem("SAO/NASA ADS", false), + new StudyDatabaseItem("SemanticScholar", false), + new StudyDatabaseItem("Springer", true), + new StudyDatabaseItem("zbMATH", false) + ), manageStudyDefinitionViewModel.getDatabases()); + } + + @Test + public void studyConstructorFillsDatabasesCorrectly(@TempDir Path tempDir) { + List databases = List.of( + new StudyDatabase("ACM Portal", true)); + Study study = new Study( + List.of("Name"), + "title", + List.of("Q1"), + List.of(), + databases + ); + ManageStudyDefinitionViewModel manageStudyDefinitionViewModel = new ManageStudyDefinitionViewModel( + study, + tempDir, + importFormatPreferences, + importerPreferences); + assertEquals(List.of( + new StudyDatabaseItem("ACM Portal", true), + new StudyDatabaseItem("ArXiv", false), + new StudyDatabaseItem("Biodiversity Heritage", false), + new StudyDatabaseItem("CiteSeerX", false), + new StudyDatabaseItem("Collection of Computer Science Bibliographies", false), + new StudyDatabaseItem("Crossref", false), + new StudyDatabaseItem("DBLP", false), + new StudyDatabaseItem("DOAB", false), + new StudyDatabaseItem("DOAJ", false), + new StudyDatabaseItem("GVK", false), + new StudyDatabaseItem("IEEEXplore", false), + new StudyDatabaseItem("INSPIRE", false), + new StudyDatabaseItem("MathSciNet", false), + new StudyDatabaseItem("Medline/PubMed", false), + new StudyDatabaseItem("ResearchGate", false), + new StudyDatabaseItem("SAO/NASA ADS", false), + new StudyDatabaseItem("SemanticScholar", false), + new StudyDatabaseItem("Springer", false), + new StudyDatabaseItem("zbMATH", false) + ), manageStudyDefinitionViewModel.getDatabases()); + } +} From ad9aa62e64fef703a80ef6dcc806b12d55f6f586 Mon Sep 17 00:00:00 2001 From: Hugo Rocha de Moura <54285732+hugorochaffs@users.noreply.github.com> Date: Sat, 3 Sep 2022 08:07:47 -0300 Subject: [PATCH 2/5] Fix integrity check for tilde accents in author names (#9097) * Solving tilde error in author names * Fixed checkstyle and removed superfluous new test class * remove latex html conversion and rtf chart * add test to authorlist parser * parameterized tests * fix test * fix test * Convert to parameterized test * fix test and checkstyle * fix checkstyle and tests * Fixed tabstop * add changelog Co-authored-by: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com> Co-authored-by: Siedlerchr --- CHANGELOG.md | 1 + .../logic/importer/AuthorListParser.java | 2 +- .../strings/HTMLUnicodeConversionMaps.java | 2 +- .../jabref/logic/util/strings/RtfCharMap.java | 2 +- .../HtmlToUnicodeFormatterTest.java | 66 +++++++------------ .../logic/importer/AuthorListParserTest.java | 3 +- .../integrity/PersonNamesCheckerTest.java | 65 ++++++++---------- 7 files changed, 58 insertions(+), 83 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 880b7b43b26..9a0cfc8b3ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve ### Fixed +- We fixed an issue where author names with tilde accents (for example ñ) were marked as "Names are not in the standard BibTex format" [#8071](https://github.com/JabRef/jabref/issues/8071) - We fixed an issue where the possibility to generate a subdatabase from an aux file was writing empty files when called from the commandline [#9115](https://github.com/JabRef/jabref/issues/9115), [forum#3516](https://discourse.jabref.org/t/export-subdatabase-from-aux-file-on-macos-command-line/3516) - We fixed the display of issue, number, eid and pages fields in the entry preview. [#8607](https://github.com/JabRef/jabref/pull/8607), [#8372](https://github.com/JabRef/jabref/issues/8372), [Koppor#514](https://github.com/koppor/jabref/issues/514), [forum#2390](https://discourse.jabref.org/t/unable-to-edit-my-bibtex-file-that-i-used-before-vers-5-1/2390), [forum#3462](https://discourse.jabref.org/t/jabref-5-6-need-help-with-export-from-jabref-to-microsoft-word-entry-preview-of-apa-7-not-rendering-correctly/3462) - We fixed the page ranges checker to detect article numbers in the pages field (used at [Check Integrity](https://docs.jabref.org/finding-sorting-and-cleaning-entries/checkintegrity)). [#8607](https://github.com/JabRef/jabref/pull/8607) diff --git a/src/main/java/org/jabref/logic/importer/AuthorListParser.java b/src/main/java/org/jabref/logic/importer/AuthorListParser.java index bc4835c92f2..41acfd2a503 100644 --- a/src/main/java/org/jabref/logic/importer/AuthorListParser.java +++ b/src/main/java/org/jabref/logic/importer/AuthorListParser.java @@ -447,7 +447,7 @@ private Token getToken() { if (c == '\\') { currentBackslash = tokenEnd; } - if ((bracesLevel == 0) && ((",;~-".indexOf(c) != -1) || Character.isWhitespace(c))) { + if ((bracesLevel == 0) && ((",;-".indexOf(c) != -1) || Character.isWhitespace(c))) { break; } tokenEnd++; diff --git a/src/main/java/org/jabref/logic/util/strings/HTMLUnicodeConversionMaps.java b/src/main/java/org/jabref/logic/util/strings/HTMLUnicodeConversionMaps.java index 587f7197218..86973053a09 100644 --- a/src/main/java/org/jabref/logic/util/strings/HTMLUnicodeConversionMaps.java +++ b/src/main/java/org/jabref/logic/util/strings/HTMLUnicodeConversionMaps.java @@ -762,6 +762,7 @@ public class HTMLUnicodeConversionMaps { {"119978", "Oscr", "$\\mathcal{O}$"}, // script capital O -- possibly use \mathscr {"119984", "Uscr", "$\\mathcal{U}$"}, // script capital U -- possibly use \mathscr {"120598", "", "$\\epsilon$"}, // mathematical italic epsilon U+1D716 -- requires amsmath + {"120599", "", "{{\\˜{n}}}"}, // n with tide }; // List of combining accents @@ -888,7 +889,6 @@ public class HTMLUnicodeConversionMaps { // Manual corrections LATEX_HTML_CONVERSION_MAP.put("AA", "Å"); // Overwritten by Å which is less supported LATEX_UNICODE_CONVERSION_MAP.put("AA", "Å"); // Overwritten by Ångstrom symbol - LATEX_UNICODE_CONVERSION_MAP.put("'n", "ń"); // Manual additions // Support relax to the extent that it is simply removed diff --git a/src/main/java/org/jabref/logic/util/strings/RtfCharMap.java b/src/main/java/org/jabref/logic/util/strings/RtfCharMap.java index 46f49f37bfc..393f9685ffb 100644 --- a/src/main/java/org/jabref/logic/util/strings/RtfCharMap.java +++ b/src/main/java/org/jabref/logic/util/strings/RtfCharMap.java @@ -4,7 +4,7 @@ public class RtfCharMap { - private HashMap rtfMap = new HashMap<>(); + private final HashMap rtfMap = new HashMap<>(); public RtfCharMap() { put("`a", "\\'e0"); diff --git a/src/test/java/org/jabref/logic/formatter/bibtexfields/HtmlToUnicodeFormatterTest.java b/src/test/java/org/jabref/logic/formatter/bibtexfields/HtmlToUnicodeFormatterTest.java index 81997715f25..64f14737bb9 100644 --- a/src/test/java/org/jabref/logic/formatter/bibtexfields/HtmlToUnicodeFormatterTest.java +++ b/src/test/java/org/jabref/logic/formatter/bibtexfields/HtmlToUnicodeFormatterTest.java @@ -1,7 +1,11 @@ package org.jabref.logic.formatter.bibtexfields; +import java.util.stream.Stream; + import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -9,52 +13,28 @@ public class HtmlToUnicodeFormatterTest { private HtmlToUnicodeFormatter formatter; + private static Stream data() { + return Stream.of( + Arguments.of("abc", "abc"), + Arguments.of("åäö", "åäö"), + Arguments.of("í", "í"), + Arguments.of("Ε", "Ε"), + Arguments.of("ä", "ä"), + Arguments.of("ä", "ä"), + Arguments.of("ä", "ä"), + Arguments.of("ñ", "ñ"), + Arguments.of("aaa", "

aaa

"), + Arguments.of("bread & butter", "bread & butter")); + } + @BeforeEach public void setUp() { formatter = new HtmlToUnicodeFormatter(); } - @Test - public void formatWithoutHtmlCharactersReturnsSameString() { - assertEquals("abc", formatter.format("abc")); - } - - @Test - public void formatMultipleHtmlCharacters() { - assertEquals("åäö", formatter.format("åäö")); - } - - @Test - public void formatCombinedAccent() { - assertEquals("í", formatter.format("í")); - } - - @Test - public void testBasic() { - assertEquals("aaa", formatter.format("aaa")); - } - - @Test - public void testUmlauts() { - assertEquals("ä", formatter.format("ä")); - assertEquals("ä", formatter.format("ä")); - assertEquals("ä", formatter.format("ä")); - } - - @Test - public void testGreekLetter() { - assertEquals("Ε", formatter.format("Ε")); - } - - @Test - public void testHTMLRemoveTags() { - assertEquals("aaa", formatter.format("

aaa

")); - } - - @Test - public void formatExample() { - assertEquals("bread & butter", formatter.format(formatter.getExampleInput())); + @ParameterizedTest + @MethodSource("data") + void testFormatterWorksCorrectly(String expected, String input) { + assertEquals(expected, formatter.format(input)); } } - - diff --git a/src/test/java/org/jabref/logic/importer/AuthorListParserTest.java b/src/test/java/org/jabref/logic/importer/AuthorListParserTest.java index 7c765d283f9..1ec4e02879c 100644 --- a/src/test/java/org/jabref/logic/importer/AuthorListParserTest.java +++ b/src/test/java/org/jabref/logic/importer/AuthorListParserTest.java @@ -25,7 +25,8 @@ private static Stream data() { Arguments.of("de la Vallée Poussin, Jean Charles Gabriel", new Author("Jean Charles Gabriel", "J. C. G.", "de la", "Vallée Poussin", null)), Arguments.of("de la Vallée Poussin, J. C. G.", new Author("J. C. G.", "J. C. G.", "de la", "Vallée Poussin", null)), Arguments.of("{K}ent-{B}oswell, E. S.", new Author("E. S.", "E. S.", null, "{K}ent-{B}oswell", null)), - Arguments.of("Uhlenhaut, N Henriette", new Author("N Henriette", "N. H.", null, "Uhlenhaut", null)) + Arguments.of("Uhlenhaut, N Henriette", new Author("N Henriette", "N. H.", null, "Uhlenhaut", null)), + Arguments.of("Nu{\\~{n}}ez, Jose", new Author("Jose", "J.", null, "Nu{\\~{n}}ez", null)) ); } diff --git a/src/test/java/org/jabref/logic/integrity/PersonNamesCheckerTest.java b/src/test/java/org/jabref/logic/integrity/PersonNamesCheckerTest.java index e6ed2c2b743..b64900e6122 100644 --- a/src/test/java/org/jabref/logic/integrity/PersonNamesCheckerTest.java +++ b/src/test/java/org/jabref/logic/integrity/PersonNamesCheckerTest.java @@ -29,48 +29,35 @@ public void setUp() throws Exception { checkerb = new PersonNamesChecker(database); } - @Test - public void validNameFirstnameAuthor() throws Exception { - assertEquals(Optional.empty(), checker.checkValue("Kolb, Stefan")); + @ParameterizedTest + @MethodSource("provideValidNames") + public void validNames(String name) { + assertEquals(Optional.empty(), checker.checkValue(name)); } - @Test - public void validNameFirstnameAuthors() throws Exception { - assertEquals(Optional.empty(), checker.checkValue("Kolb, Stefan and Harrer, Simon")); - } + private static Stream provideValidNames() { + return Stream.of( + "Kolb, Stefan", // single [Name, Firstname] + "Kolb, Stefan and Harrer, Simon", // multiple [Name, Firstname] + "Stefan Kolb", // single [Firstname Name] + "Stefan Kolb and Simon Harrer", // multiple [Firstname Name] - @Test - public void validFirstnameNameAuthor() throws Exception { - assertEquals(Optional.empty(), checker.checkValue("Stefan Kolb")); - } + "M. J. Gotay", // second name in front - @Test - public void validFirstnameNameAuthors() throws Exception { - assertEquals(Optional.empty(), checker.checkValue("Stefan Kolb and Simon Harrer")); + "{JabRef}", // corporate name in brackets + "{JabRef} and Stefan Kolb", // mixed corporate name with name + "{JabRef} and Kolb, Stefan", + + "hugo Para{\\~n}os" // tilde in name + ); } @Test - public void complainAboutPersonStringWithTwoManyCommas() throws Exception { + public void complainAboutPersonStringWithTwoManyCommas() { assertEquals(Optional.of("Names are not in the standard BibTeX format."), checker.checkValue("Test1, Test2, Test3, Test4, Test5, Test6")); } - @Test - public void doNotComplainAboutSecondNameInFront() throws Exception { - assertEquals(Optional.empty(), checker.checkValue("M. J. Gotay")); - } - - @Test - public void validCorporateNameInBrackets() throws Exception { - assertEquals(Optional.empty(), checker.checkValue("{JabRef}")); - } - - @Test - public void validCorporateNameAndPerson() throws Exception { - assertEquals(Optional.empty(), checker.checkValue("{JabRef} and Stefan Kolb")); - assertEquals(Optional.empty(), checker.checkValue("{JabRef} and Kolb, Stefan")); - } - @ParameterizedTest @MethodSource("provideCorrectFormats") public void authorNameInCorrectFormatsShouldNotComplain(String input) { @@ -84,13 +71,19 @@ public void authorNameInIncorrectFormatsShouldComplain(String input) { } private static Stream provideCorrectFormats() { - return Stream.of("", "Knuth", "Donald E. Knuth and Kurt Cobain and A. Einstein"); + return Stream.of( + "", + "Knuth", + "Donald E. Knuth and Kurt Cobain and A. Einstein"); } private static Stream provideIncorrectFormats() { - return Stream.of(" Knuth, Donald E. ", - "Knuth, Donald E. and Kurt Cobain and A. Einstein", - ", and Kurt Cobain and A. Einstein", "Donald E. Knuth and Kurt Cobain and ,", - "and Kurt Cobain and A. Einstein", "Donald E. Knuth and Kurt Cobain and"); + return Stream.of( + " Knuth, Donald E. ", + "Knuth, Donald E. and Kurt Cobain and A. Einstein", + ", and Kurt Cobain and A. Einstein", + "Donald E. Knuth and Kurt Cobain and ,", + "and Kurt Cobain and A. Einstein", + "Donald E. Knuth and Kurt Cobain and"); } } From 73f1ad5e55188fd5e198de971b27ef3851732069 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sat, 3 Sep 2022 13:08:25 +0200 Subject: [PATCH 3/5] Fix parsing of JabRef v5.7 study.yml files (#9124) --- CHANGELOG.md | 3 ++- .../jabref/logic/crawler/StudyYamlParser.java | 5 ----- src/main/java/org/jabref/model/study/Study.java | 3 +++ .../logic/crawler/StudyYamlParserTest.java | 12 ++++++++++++ .../jabref/logic/crawler/study-jabref-5.7.yml | 17 +++++++++++++++++ 5 files changed, 34 insertions(+), 6 deletions(-) create mode 100644 src/test/resources/org/jabref/logic/crawler/study-jabref-5.7.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a0cfc8b3ac..762f29b556e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,7 +24,8 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve - We call backup files `.bak` and temporary writing files now `.sav`. - JabRef keeps 10 older versions of a `.bib` file in the [user data dir](https://github.com/harawata/appdirs#supported-directories) (instead of a single `.sav` (now: `.bak`) file in the directory of the `.bib` file) - We changed the button label from "Return to JabRef" to "Return to library" to better indicate the purpose of the action. -- We removed "last-search-date" from the SLR feature, because the last-search-date can be deducted from the git logs. +- We removed "last-search-date" from the SLR feature, because the last-search-date can be deducted from the git logs. [#9116](https://github.com/JabRef/jabref/pull/9116) +- A user can now add arbitrary data into `study.yml`. JabRef just ignores this data. [#9124](https://github.com/JabRef/jabref/pull/9124) - We reworked the External Changes Resolver dialog. [#9021](https://github.com/JabRef/jabref/pull/9021) - We reworked the Define study parameters dialog. [#9123](https://github.com/JabRef/jabref/pull/9123) diff --git a/src/main/java/org/jabref/logic/crawler/StudyYamlParser.java b/src/main/java/org/jabref/logic/crawler/StudyYamlParser.java index df2138434d2..db1bb1b9a9f 100644 --- a/src/main/java/org/jabref/logic/crawler/StudyYamlParser.java +++ b/src/main/java/org/jabref/logic/crawler/StudyYamlParser.java @@ -8,10 +8,8 @@ import org.jabref.model.study.Study; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator; -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; public class StudyYamlParser { @@ -20,7 +18,6 @@ public class StudyYamlParser { */ public Study parseStudyYamlFile(Path studyYamlFile) throws IOException { ObjectMapper yamlMapper = new ObjectMapper(new YAMLFactory()); - yamlMapper.registerModule(new JavaTimeModule()); try (InputStream fileInputStream = new FileInputStream(studyYamlFile.toFile())) { return yamlMapper.readValue(fileInputStream, Study.class); } @@ -32,8 +29,6 @@ public Study parseStudyYamlFile(Path studyYamlFile) throws IOException { public void writeStudyYamlFile(Study study, Path studyYamlFile) throws IOException { ObjectMapper yamlMapper = new ObjectMapper(new YAMLFactory().disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER) .enable(YAMLGenerator.Feature.MINIMIZE_QUOTES)); - yamlMapper.registerModule(new JavaTimeModule()); - yamlMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); yamlMapper.writeValue(studyYamlFile.toFile(), study); } } diff --git a/src/main/java/org/jabref/model/study/Study.java b/src/main/java/org/jabref/model/study/Study.java index 3748f0962bc..c9a416eda4e 100644 --- a/src/main/java/org/jabref/model/study/Study.java +++ b/src/main/java/org/jabref/model/study/Study.java @@ -3,6 +3,7 @@ import java.util.List; import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonPropertyOrder; @@ -12,6 +13,8 @@ * This class defines all aspects of a scientific study relevant to the application. It is a proxy for the file based study definition. */ @JsonPropertyOrder({"authors", "title", "research-questions", "queries", "databases"}) +// The user might add arbitrary content to the YAML +@JsonIgnoreProperties(ignoreUnknown = true) public class Study { private List authors; diff --git a/src/test/java/org/jabref/logic/crawler/StudyYamlParserTest.java b/src/test/java/org/jabref/logic/crawler/StudyYamlParserTest.java index 1b169f7f00a..d4e63f64bc1 100644 --- a/src/test/java/org/jabref/logic/crawler/StudyYamlParserTest.java +++ b/src/test/java/org/jabref/logic/crawler/StudyYamlParserTest.java @@ -18,6 +18,7 @@ class StudyYamlParserTest { @TempDir static Path testDirectory; + Study expectedStudy; @BeforeEach @@ -48,4 +49,15 @@ public void writeStudyFileSuccessfully() throws Exception { Study study = new StudyYamlParser().parseStudyYamlFile(testDirectory.resolve("study.yml")); assertEquals(expectedStudy, study); } + + @Test + public void readsJabRef57StudySuccessfully() throws Exception { + // The field "last-search-date" was removed + // If the field is "just" removed from the datamodel, one gets following exception: + // com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "last-search-date" (class org.jabref.model.study.Study), not marked as ignorable (5 known properties: "authors", "research-questions", "queries", "title", "databases"]) + // This tests ensures that this exception does not occur + URL studyDefinition = StudyYamlParser.class.getResource("study-jabref-5.7.yml"); + Study study = new StudyYamlParser().parseStudyYamlFile(Path.of(studyDefinition.toURI())); + assertEquals(expectedStudy, study); + } } diff --git a/src/test/resources/org/jabref/logic/crawler/study-jabref-5.7.yml b/src/test/resources/org/jabref/logic/crawler/study-jabref-5.7.yml new file mode 100644 index 00000000000..3b5b45bbb66 --- /dev/null +++ b/src/test/resources/org/jabref/logic/crawler/study-jabref-5.7.yml @@ -0,0 +1,17 @@ +authors: + - Jab Ref +title: TestStudyName +last-search-date: 2020-11-26 +research-questions: + - Question1 + - Question2 +queries: + - query: Quantum + - query: Cloud Computing + - query: '"Software Engineering"' +databases: + - name: Springer + - name: ArXiv + - name: Medline/PubMed + - name: IEEEXplore + enabled: false From e3ddb7c92a783b58735154ea98189e76d056b24e Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Sat, 3 Sep 2022 13:24:49 +0200 Subject: [PATCH 4/5] Compile fix --- src/main/java/org/jabref/gui/slr/StudyDatabaseItem.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/slr/StudyDatabaseItem.java b/src/main/java/org/jabref/gui/slr/StudyDatabaseItem.java index c6c77eaaf31..bc2cb7ac859 100644 --- a/src/main/java/org/jabref/gui/slr/StudyDatabaseItem.java +++ b/src/main/java/org/jabref/gui/slr/StudyDatabaseItem.java @@ -62,7 +62,7 @@ public boolean equals(Object o) { return false; } StudyDatabaseItem that = (StudyDatabaseItem) o; - return Object.equals(getName(),that.getName()) && Object.equals(isEnabled(), that.isEnabled()); + return Objects.equals(getName(), that.getName()) && Objects.equals(isEnabled(), that.isEnabled()); } @Override From 069eedc7e95989c6c3aa728b7909d14013a77d5e Mon Sep 17 00:00:00 2001 From: Siedlerchr Date: Sat, 3 Sep 2022 14:08:31 +0200 Subject: [PATCH 5/5] fix l10n --- src/main/resources/l10n/JabRef_en.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index d020d8e5691..c560fc1b280 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -2406,7 +2406,6 @@ Database=Database Databases=Databases Manage\ study\ definition=Manage study definition Add\ Author\:=Add Author\: -Select\ Databases\:=Select the databases that should be searched\: Add\ Query\:=Add Query\: Add\ Research\ Question\:=Add Research Question\: Perform\ search\ for\ existing\ systematic\ literature\ review=Perform search for existing systematic literature review @@ -2416,6 +2415,7 @@ Searching=Searching Start\ new\ systematic\ literature\ review=Start new systematic literature review Study\ Title\:=Study Title\: Study\ repository\ could\ not\ be\ created=Study repository could not be created +Select\ Databases\:=Select Databases: All\ query\ terms\ are\ joined\ using\ the\ logical\ AND,\ and\ OR\ operators=All query terms are joined using the logical AND, and OR operators Finalize=Finalize