diff --git a/.github/workflows/refresh-journal-lists.yml b/.github/workflows/refresh-journal-lists.yml index 9312ebcd42b..3a6476b011d 100644 --- a/.github/workflows/refresh-journal-lists.yml +++ b/.github/workflows/refresh-journal-lists.yml @@ -1,8 +1,8 @@ name: Refresh Journal Lists on: + # Allow to run manually workflow_dispatch: - # Allow to run manually permissions: contents: read @@ -15,12 +15,9 @@ jobs: name: Refresh Journal List Files runs-on: ubuntu-latest steps: - - name: Fetch all history for all tags and branches - uses: actions/checkout@v3 + - uses: actions/checkout@v3 with: - ref: main - persist-credentials: false - fetch-depth: 0 + persist-credentials: true - name: Set up JDK uses: actions/setup-java@v3 with: @@ -37,24 +34,34 @@ jobs: cd abbrv.jabref.org/journals # remove all lists without dot in them - # we use abbrevatiation lists containing dots in them only (to be consistent) + # we use abbreviation lists containing dots in them only (to be consistent) rm journal_abbreviations_entrez.csv rm journal_abbreviations_medicus.csv - rm journal_abbreviations_webofscience-dots.csv + rm journal_abbreviations_webofscience-dotless.csv # prepare building mkdir -p $GITHUB_WORKSPACE/build/journals cp * $GITHUB_WORKSPACE/build/journals/ # ensure that the .java classes are the most recent ones + mkdir -p $GITHUB_WORKSPACE/buildSrc/src/copied/java/org/jabref/logic/journals cp $GITHUB_WORKSPACE/src/main/java/org/jabref/logic/journals/* $GITHUB_WORKSPACE/buildSrc/src/copied/java/org/jabref/logic/journals # create .mv file cd $GITHUB_WORKSPACE ./gradlew generateJournalAbbreviationList - uses: peter-evans/create-pull-request@v4 + if: github.ref == 'refs/heads/main' with: token: ${{ secrets.GITHUB_TOKEN }} branch: update-journallist title: "[Bot] Update Journal abbrev list" commit-message: Update journal abbrev list + - name: Commit and push changes + uses: EndBug/add-and-commit@v9 + if: github.ref != 'refs/heads/main' + with: + message: 'Update journal abbrev list' + committer_email: actions@github.com + fetch: false + push: true diff --git a/CHANGELOG.md b/CHANGELOG.md index 26f988e8c73..1b0c128a3d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,8 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve - We changed database structure: in MySQL/MariaDB we renamed tables by adding a `JABREF_` prefix, and in PGSQL we moved tables in `jabref` schema. We added `VersionDBStructure` variable in `METADATA` table to indicate current version of structure, this variable is needed for automatic migration. [#9312](https://github.com/JabRef/jabref/issues/9312) - We moved some preferences options to a new tab in the preferences dialog. [#9442](https://github.com/JabRef/jabref/pull/9308) +- We renamed "Medline abbrevation" to "dotless abbreviation". [#9504](https://github.com/JabRef/jabref/pull/9504) +- We now have more "dots" in the offered journal abbrevations. [#9504](https://github.com/JabRef/jabref/pull/9504) @@ -31,6 +33,7 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve - The tab "deprecated fields" is shown in biblatex-mode only. [#7757](https://github.com/JabRef/jabref/issues/7757) - We fixed an issue where the last opened libraries were not remembered when a new unsaved libray was open as well. [#9190](https://github.com/JabRef/jabref/issues/9190) - We fixed an issue where no context menu for the group "All entries" was present. [forum#3682](https://discourse.jabref.org/t/how-sort-groups-a-z-not-subgroups/3682) +- We fixed an issue where extra curly braces in some fields would trigger an exception when selecting the entry or doing an integrity check [#9475](https://github.com/JabRef/jabref/issues/9475), [#9503](https://github.com/JabRef/jabref/issues/9503) - We fixed an issue where entering a date in the format "YYYY/MM" in the entry editor date field caused an exception. [#9492](https://github.com/JabRef/jabref/issues/9492) ### Removed diff --git a/buildSrc/src/copied/java/org/jabref/logic/journals/Abbreviation.java b/buildSrc/src/copied/java/org/jabref/logic/journals/Abbreviation.java index 7a7e4d9cf30..c3c18ff02bf 100644 --- a/buildSrc/src/copied/java/org/jabref/logic/journals/Abbreviation.java +++ b/buildSrc/src/copied/java/org/jabref/logic/journals/Abbreviation.java @@ -1,11 +1,15 @@ package org.jabref.logic.journals; +import java.io.Serializable; import java.util.Objects; -public class Abbreviation implements Comparable { +public class Abbreviation implements Comparable, Serializable { - private final String name; + private static final long serialVersionUID = 1; + + private transient String name; private final String abbreviation; + private transient String dotlessAbbreviation; private final String shortestUniqueAbbreviation; public Abbreviation(String name, String abbreviation) { @@ -13,9 +17,18 @@ public Abbreviation(String name, String abbreviation) { } public Abbreviation(String name, String abbreviation, String shortestUniqueAbbreviation) { - this.name = name; - this.abbreviation = abbreviation; - this.shortestUniqueAbbreviation = shortestUniqueAbbreviation.trim(); + this(name, + abbreviation, + // "L. N." becomes "L N ", we need to remove the double spaces inbetween + abbreviation.replace(".", " ").replace(" ", " ").trim(), + shortestUniqueAbbreviation.trim()); + } + + public Abbreviation(String name, String abbreviation, String dotlessAbbreviation, String shortestUniqueAbbreviation) { + this.name = name.intern(); + this.abbreviation = abbreviation.intern(); + this.dotlessAbbreviation = dotlessAbbreviation.intern(); + this.shortestUniqueAbbreviation = shortestUniqueAbbreviation.trim().intern(); } public String getName() { @@ -34,8 +47,8 @@ public String getShortestUniqueAbbreviation() { return result; } - public String getMedlineAbbreviation() { - return getAbbreviation().replace(".", " ").replace(" ", " ").trim(); + public String getDotlessAbbreviation() { + return this.dotlessAbbreviation; } @Override @@ -46,23 +59,23 @@ public int compareTo(Abbreviation toCompare) { public String getNext(String current) { String currentTrimmed = current.trim(); - if (getMedlineAbbreviation().equals(currentTrimmed)) { + if (getDotlessAbbreviation().equals(currentTrimmed)) { return getShortestUniqueAbbreviation().equals(getAbbreviation()) ? getName() : getShortestUniqueAbbreviation(); } else if (getShortestUniqueAbbreviation().equals(currentTrimmed) && !getShortestUniqueAbbreviation().equals(getAbbreviation())) { return getName(); } else if (getName().equals(currentTrimmed)) { return getAbbreviation(); } else { - return getMedlineAbbreviation(); + return getDotlessAbbreviation(); } } @Override public String toString() { - return String.format("Abbreviation{name=%s, abbreviation=%s, medlineAbbreviation=%s, shortestUniqueAbbreviation=%s}", + return String.format("Abbreviation{name=%s, abbreviation=%s, dotlessAbbreviation=%s, shortestUniqueAbbreviation=%s}", this.name, this.abbreviation, - this.getMedlineAbbreviation(), + this.dotlessAbbreviation, this.shortestUniqueAbbreviation); } diff --git a/buildSrc/src/copied/java/org/jabref/logic/journals/JournalAbbreviationLoader.java b/buildSrc/src/copied/java/org/jabref/logic/journals/JournalAbbreviationLoader.java index 76ba9096791..d74b6a9fc9d 100644 --- a/buildSrc/src/copied/java/org/jabref/logic/journals/JournalAbbreviationLoader.java +++ b/buildSrc/src/copied/java/org/jabref/logic/journals/JournalAbbreviationLoader.java @@ -10,6 +10,14 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +/** + *

+ * This class loads abbreviations from a CSV file and stores them into a MV file + *

+ *

+ * Abbreviations are available at https://github.com/JabRef/abbrv.jabref.org/. + *

+ */ public class JournalAbbreviationLoader { private static final Logger LOGGER = LoggerFactory.getLogger(JournalAbbreviationLoader.class); @@ -26,8 +34,8 @@ public static JournalAbbreviationRepository loadRepository(JournalAbbreviationPr // Initialize with built-in list try { Path tempDir = Files.createTempDirectory("jabref-journal"); - Path tempJournalList = tempDir.resolve("journalList.mv"); - Files.copy(JournalAbbreviationRepository.class.getResourceAsStream("/journals/journalList.mv"), tempJournalList); + Path tempJournalList = tempDir.resolve("journal-list.mv"); + Files.copy(JournalAbbreviationRepository.class.getResourceAsStream("/journals/journal-list.mv"), tempJournalList); repository = new JournalAbbreviationRepository(tempJournalList); tempDir.toFile().deleteOnExit(); tempJournalList.toFile().deleteOnExit(); @@ -39,12 +47,13 @@ public static JournalAbbreviationRepository loadRepository(JournalAbbreviationPr // Read external lists List lists = journalAbbreviationPreferences.getExternalJournalLists(); if (!(lists.isEmpty())) { + // reversing ensures that the latest lists overwrites the former one Collections.reverse(lists); for (String filename : lists) { try { repository.addCustomAbbreviations(readJournalListFromFile(Path.of(filename))); } catch (IOException e) { - LOGGER.error(String.format("Cannot read external journal list file %s", filename), e); + LOGGER.error("Cannot read external journal list file {}", filename, e); } } } diff --git a/buildSrc/src/copied/java/org/jabref/logic/journals/JournalAbbreviationRepository.java b/buildSrc/src/copied/java/org/jabref/logic/journals/JournalAbbreviationRepository.java index 0437e1ae2ae..29b61f0d960 100644 --- a/buildSrc/src/copied/java/org/jabref/logic/journals/JournalAbbreviationRepository.java +++ b/buildSrc/src/copied/java/org/jabref/logic/journals/JournalAbbreviationRepository.java @@ -3,13 +3,14 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Collectors; import org.h2.mvstore.MVMap; import org.h2.mvstore.MVStore; @@ -18,105 +19,89 @@ * A repository for all journal abbreviations, including add and find methods. */ public class JournalAbbreviationRepository { - static final Pattern DOT = Pattern.compile("\\."); static final Pattern QUESTION_MARK = Pattern.compile("\\?"); - private final MVMap fullToAbbreviation; - private final MVMap abbreviationToFull; - private final List customAbbreviations; + private final Map fullToAbbreviationObject = new HashMap<>(); + private final Map abbreviationToAbbreviationObject = new HashMap<>(); + private final Map dotlessToAbbreviationObject = new HashMap<>(); + private final Map shortestUniqueToAbbreviationObject = new HashMap<>(); + private final List customAbbreviations = new ArrayList<>(); public JournalAbbreviationRepository(Path journalList) { MVStore store = new MVStore.Builder().readOnly().fileName(journalList.toAbsolutePath().toString()).open(); - this.fullToAbbreviation = store.openMap("FullToAbbreviation"); - this.abbreviationToFull = store.openMap("AbbreviationToFull"); - this.customAbbreviations = new ArrayList<>(); + MVMap mvFullToAbbreviationObject = store.openMap("FullToAbbreviation"); + + mvFullToAbbreviationObject.forEach((name, abbreviation) -> { + String abbrevationString = abbreviation.getAbbreviation(); + String shortestUniqueAbbreviation = abbreviation.getShortestUniqueAbbreviation(); + Abbreviation newAbbreviation = new Abbreviation( + name, + abbrevationString, + shortestUniqueAbbreviation + ); + fullToAbbreviationObject.put(name, newAbbreviation); + abbreviationToAbbreviationObject.put(abbrevationString, newAbbreviation); + dotlessToAbbreviationObject.put(newAbbreviation.getDotlessAbbreviation(), newAbbreviation); + shortestUniqueToAbbreviationObject.put(shortestUniqueAbbreviation, newAbbreviation); + }); } private static boolean isMatched(String name, Abbreviation abbreviation) { return name.equalsIgnoreCase(abbreviation.getName()) || name.equalsIgnoreCase(abbreviation.getAbbreviation()) - || name.equalsIgnoreCase(abbreviation.getMedlineAbbreviation()) + || name.equalsIgnoreCase(abbreviation.getDotlessAbbreviation()) || name.equalsIgnoreCase(abbreviation.getShortestUniqueAbbreviation()); } private static boolean isMatchedAbbreviated(String name, Abbreviation abbreviation) { + boolean isExpanded = name.equalsIgnoreCase(abbreviation.getName()); + if (isExpanded) { + return false; + } boolean isAbbreviated = name.equalsIgnoreCase(abbreviation.getAbbreviation()) - || name.equalsIgnoreCase(abbreviation.getMedlineAbbreviation()) + || name.equalsIgnoreCase(abbreviation.getDotlessAbbreviation()) || name.equalsIgnoreCase(abbreviation.getShortestUniqueAbbreviation()); - boolean isExpanded = name.equalsIgnoreCase(abbreviation.getName()); - return isAbbreviated && !isExpanded; + return isAbbreviated; } /** - * Returns true if the given journal name is contained in the list either in its full form (e.g Physical Review - * Letters) or its abbreviated form (e.g. Phys. Rev. Lett.). + * Returns true if the given journal name is contained in the list either in its full form + * (e.g., Physical Review Letters) or its abbreviated form (e.g., Phys. Rev. Lett.). */ public boolean isKnownName(String journalName) { - // check for at least one "?" if (QUESTION_MARK.matcher(journalName).find()) { return false; } - String journal = journalName.trim().replaceAll(Matcher.quoteReplacement("\\&"), "&"); - - boolean isKnown = customAbbreviations.stream().anyMatch(abbreviation -> isMatched(journal, abbreviation)); - if (isKnown) { - return true; - } - - return fullToAbbreviation.containsKey(journal) || abbreviationToFull.containsKey(journal) - || findDottedAbbrFromDotless(journal).length() > 0; + return customAbbreviations.stream().anyMatch(abbreviation -> isMatched(journal, abbreviation)) + || fullToAbbreviationObject.containsKey(journal) + || abbreviationToAbbreviationObject.containsKey(journal) + || dotlessToAbbreviationObject.containsKey(journal) + || shortestUniqueToAbbreviationObject.containsKey(journal); } /** * Returns true if the given journal name is in its abbreviated form (e.g. Phys. Rev. Lett.). The test is strict, - * i.e. journals whose abbreviation is the same as the full name are not considered + * i.e., journals whose abbreviation is the same as the full name are not considered */ public boolean isAbbreviatedName(String journalName) { - String journal = journalName.trim(); - - // journal abbreviation must be at least 2 words - boolean isMoreThanTwoWords = journalName.split(" ").length >= 2; - - return customAbbreviations.stream().anyMatch(abbreviation -> isMatchedAbbreviated(journal, abbreviation)) - || abbreviationToFull.containsKey(journal) - || (isMoreThanTwoWords && findDottedAbbrFromDotless(journal).length() > 0); - } - - public String findDottedAbbrFromDotless(String journalName) { - // check for at least one "?" if (QUESTION_MARK.matcher(journalName).find()) { - return "UNKNOWN"; - } - - String foundKey = ""; - - // check for a dot-less abbreviation - if (!DOT.matcher(journalName).find()) { - // use dot-less abbr to find full name using regex - String[] journalSplit = journalName.split(" "); - - for (int i = 0; i < journalSplit.length; i++) { - String word = journalSplit[i] + "[\\.\\s]*"; - journalSplit[i] = word; - } - - String joined = String.join("", journalSplit); - - foundKey = abbreviationToFull.keySet().stream() - .filter(s -> Pattern.compile(joined).matcher(s).find()) - .collect(Collectors.joining()); + return false; } - - return foundKey; + String journal = journalName.trim().replaceAll(Matcher.quoteReplacement("\\&"), "&"); + return customAbbreviations.stream().anyMatch(abbreviation -> isMatchedAbbreviated(journal, abbreviation)) + || abbreviationToAbbreviationObject.containsKey(journal) + || dotlessToAbbreviationObject.containsKey(journal) + || shortestUniqueToAbbreviationObject.containsKey(journal); } /** * Attempts to get the abbreviation of the journal given. * - * @param input The journal name (either abbreviated or full name). + * @param input The journal name (either full name or abbreviated name). */ public Optional get(String input) { + // Clean up input: trim and unescape ampersand String journal = input.trim().replaceAll(Matcher.quoteReplacement("\\&"), "&"); Optional customAbbreviation = customAbbreviations.stream() @@ -126,19 +111,10 @@ public Optional get(String input) { return customAbbreviation; } - return Optional.ofNullable(fullToAbbreviation.get(journal)) - .map(abbreviation -> new Abbreviation(journal, abbreviation)) - .or(() -> { - String abbr = ""; - - // check for dot-less abbr - if (isKnownName(journal) && isAbbreviatedName(journal)) { - abbr = findDottedAbbrFromDotless(journal); - } - - return Optional.ofNullable(abbreviationToFull.get(abbr.equals("") ? journal : abbr)) - .map(fullName -> new Abbreviation(fullName, journal)); - }); + return Optional.ofNullable(fullToAbbreviationObject.get(journal)) + .or(() -> Optional.ofNullable(abbreviationToAbbreviationObject.get(journal))) + .or(() -> Optional.ofNullable(dotlessToAbbreviationObject.get(journal))) + .or(() -> Optional.ofNullable(shortestUniqueToAbbreviationObject.get(journal))); } public void addCustomAbbreviation(Abbreviation abbreviation) { @@ -166,8 +142,8 @@ public Optional getDefaultAbbreviation(String text) { return get(text).map(Abbreviation::getAbbreviation); } - public Optional getMedlineAbbreviation(String text) { - return get(text).map(Abbreviation::getMedlineAbbreviation); + public Optional getDotless(String text) { + return get(text).map(Abbreviation::getDotlessAbbreviation); } public Optional getShortestUniqueAbbreviation(String text) { @@ -175,11 +151,10 @@ public Optional getShortestUniqueAbbreviation(String text) { } public Set getFullNames() { - return fullToAbbreviation.keySet(); + return fullToAbbreviationObject.keySet(); } - public List getAllLoaded() { - return fullToAbbreviation.entrySet().stream().map(entry -> - new Abbreviation(entry.getKey(), entry.getValue())).collect(Collectors.toList()); + public Collection getAllLoaded() { + return fullToAbbreviationObject.values(); } } diff --git a/buildSrc/src/copied/java/org/jabref/logic/journals/package-info.java b/buildSrc/src/copied/java/org/jabref/logic/journals/package-info.java deleted file mode 100644 index 7a967bbd91d..00000000000 --- a/buildSrc/src/copied/java/org/jabref/logic/journals/package-info.java +++ /dev/null @@ -1,7 +0,0 @@ -/** - * The files in this directory are copied from JabRef's main source. - * We need top have a copy, because - * a) symblinks do not work on git for windows out of the box (https://stackoverflow.com/a/59761201/873282) - * b) using a source directory of another project causes issues in i) gradle 7, ii) IntelliJ 2020 and later - */ -package org.jabref.logic.journals; diff --git a/buildSrc/src/main/groovy/org/jabref/build/JournalAbbreviationConverter.groovy b/buildSrc/src/main/groovy/org/jabref/build/JournalAbbreviationConverter.groovy index be89bf1e4d5..64e6e4ed3e5 100644 --- a/buildSrc/src/main/groovy/org/jabref/build/JournalAbbreviationConverter.groovy +++ b/buildSrc/src/main/groovy/org/jabref/build/JournalAbbreviationConverter.groovy @@ -5,6 +5,7 @@ import org.gradle.api.file.DirectoryProperty import org.gradle.api.tasks.* import org.h2.mvstore.MVMap import org.h2.mvstore.MVStore +import org.jabref.logic.journals.Abbreviation import org.jabref.logic.journals.JournalAbbreviationLoader import java.util.stream.Collectors @@ -19,26 +20,28 @@ abstract class JournalAbbreviationConverter extends DefaultTask { @TaskAction def convert() { - def targetFile = outputDir.file("journalList.mv").get().asFile + def targetFile = outputDir.file("journal-list.mv").get().asFile targetFile.delete() MVStore.open(targetFile.toString()).withCloseable { store -> - MVMap fullToAbbreviation = store.openMap("FullToAbbreviation") - MVMap abbreviationToFull = store.openMap("AbbreviationToFull") + MVMap fullToAbbreviation = store.openMap("FullToAbbreviation") inputDir.getAsFileTree().filter({ File f -> f.name.endsWith(".csv") }).getFiles().each { file -> + System.out.println("Loading file " + file.toString() + "...") def abbreviations = JournalAbbreviationLoader.readJournalListFromFile(file.toPath()) + fullToAbbreviation.putAll( abbreviations .stream() - .collect(Collectors.toMap({ abbreviation -> abbreviation.getName() }, { abbreviation -> abbreviation.getAbbreviation() })) + .collect(Collectors.toMap( + { abbreviation -> abbreviation.getName() }, + { abbreviation -> abbreviation }, + (abbreviation1, abbreviation2) -> { + System.out.println("Double entry " + abbreviation1.getName()) + return abbreviation2 + })) ) - - abbreviations - .forEach({ abbreviation -> - abbreviationToFull.putIfAbsent(abbreviation.getAbbreviation(), abbreviation.getName()) - }) } } } diff --git a/src/main/java/org/jabref/gui/JabRefFrame.java b/src/main/java/org/jabref/gui/JabRefFrame.java index 4e22884c71b..4769fd425e7 100644 --- a/src/main/java/org/jabref/gui/JabRefFrame.java +++ b/src/main/java/org/jabref/gui/JabRefFrame.java @@ -868,7 +868,7 @@ private MenuBar createMenu() { factory.createSubMenu(StandardActions.ABBREVIATE, factory.createMenuItem(StandardActions.ABBREVIATE_DEFAULT, new AbbreviateAction(StandardActions.ABBREVIATE_DEFAULT, this, dialogService, stateManager, prefs.getJournalAbbreviationPreferences())), - factory.createMenuItem(StandardActions.ABBREVIATE_MEDLINE, new AbbreviateAction(StandardActions.ABBREVIATE_MEDLINE, this, dialogService, stateManager, prefs.getJournalAbbreviationPreferences())), + factory.createMenuItem(StandardActions.ABBREVIATE_DOTLESS, new AbbreviateAction(StandardActions.ABBREVIATE_DOTLESS, this, dialogService, stateManager, prefs.getJournalAbbreviationPreferences())), factory.createMenuItem(StandardActions.ABBREVIATE_SHORTEST_UNIQUE, new AbbreviateAction(StandardActions.ABBREVIATE_SHORTEST_UNIQUE, this, dialogService, stateManager, prefs.getJournalAbbreviationPreferences()))), factory.createMenuItem(StandardActions.UNABBREVIATE, new AbbreviateAction(StandardActions.UNABBREVIATE, this, dialogService, stateManager, prefs.getJournalAbbreviationPreferences())) diff --git a/src/main/java/org/jabref/gui/actions/StandardActions.java b/src/main/java/org/jabref/gui/actions/StandardActions.java index f37abb775ae..57ae929a1bf 100644 --- a/src/main/java/org/jabref/gui/actions/StandardActions.java +++ b/src/main/java/org/jabref/gui/actions/StandardActions.java @@ -100,9 +100,9 @@ public enum StandardActions implements Action { COPY_DOI(Localization.lang("Copy DOI")), COPY_DOI_URL(Localization.lang("Copy DOI url")), ABBREVIATE(Localization.lang("Abbreviate journal names")), - ABBREVIATE_DEFAULT("DEFAULT", Localization.lang("Abbreviate journal names of the selected entries (DEFAULT abbreviation)"), KeyBinding.ABBREVIATE), - ABBREVIATE_MEDLINE("MEDLINE", Localization.lang("Abbreviate journal names of the selected entries (MEDLINE abbreviation)")), - ABBREVIATE_SHORTEST_UNIQUE("SHORTEST UNIQUE", Localization.lang("Abbreviate journal names of the selected entries (SHORTEST UNIQUE abbreviation)")), + ABBREVIATE_DEFAULT(Localization.lang("default"), Localization.lang("Abbreviate journal names of the selected entries (DEFAULT abbreviation)"), KeyBinding.ABBREVIATE), + ABBREVIATE_DOTLESS(Localization.lang("dotless"), Localization.lang("Abbreviate journal names of the selected entries (DOTLESS abbreviation)")), + ABBREVIATE_SHORTEST_UNIQUE(Localization.lang("shortest unique"), Localization.lang("Abbreviate journal names of the selected entries (SHORTEST UNIQUE abbreviation)")), UNABBREVIATE(Localization.lang("Unabbreviate journal names"), Localization.lang("Unabbreviate journal names of the selected entries"), KeyBinding.UNABBREVIATE), MANAGE_CUSTOM_EXPORTS(Localization.lang("Manage custom exports")), diff --git a/src/main/java/org/jabref/gui/journals/AbbreviateAction.java b/src/main/java/org/jabref/gui/journals/AbbreviateAction.java index 610c250cd7b..ec609f1e18d 100644 --- a/src/main/java/org/jabref/gui/journals/AbbreviateAction.java +++ b/src/main/java/org/jabref/gui/journals/AbbreviateAction.java @@ -54,7 +54,7 @@ public AbbreviateAction(StandardActions action, switch (action) { case ABBREVIATE_DEFAULT -> abbreviationType = AbbreviationType.DEFAULT; - case ABBREVIATE_MEDLINE -> abbreviationType = AbbreviationType.MEDLINE; + case ABBREVIATE_DOTLESS -> abbreviationType = AbbreviationType.DOTLESS; case ABBREVIATE_SHORTEST_UNIQUE -> abbreviationType = AbbreviationType.SHORTEST_UNIQUE; default -> LOGGER.debug("Unknown action: " + action.name()); } @@ -65,7 +65,7 @@ public AbbreviateAction(StandardActions action, @Override public void execute() { if ((action == StandardActions.ABBREVIATE_DEFAULT) - || (action == StandardActions.ABBREVIATE_MEDLINE) + || (action == StandardActions.ABBREVIATE_DOTLESS) || (action == StandardActions.ABBREVIATE_SHORTEST_UNIQUE)) { dialogService.notify(Localization.lang("Abbreviating...")); stateManager.getActiveDatabase().ifPresent(databaseContext -> diff --git a/src/main/java/org/jabref/gui/journals/AbbreviationType.java b/src/main/java/org/jabref/gui/journals/AbbreviationType.java index 4f83eaf49f6..949364e8359 100644 --- a/src/main/java/org/jabref/gui/journals/AbbreviationType.java +++ b/src/main/java/org/jabref/gui/journals/AbbreviationType.java @@ -5,6 +5,6 @@ */ public enum AbbreviationType { DEFAULT, - MEDLINE, + DOTLESS, SHORTEST_UNIQUE } diff --git a/src/main/java/org/jabref/gui/journals/UndoableAbbreviator.java b/src/main/java/org/jabref/gui/journals/UndoableAbbreviator.java index 21cce96f12d..b04a64c95dc 100644 --- a/src/main/java/org/jabref/gui/journals/UndoableAbbreviator.java +++ b/src/main/java/org/jabref/gui/journals/UndoableAbbreviator.java @@ -69,8 +69,8 @@ private String getAbbreviatedName(Abbreviation text) { switch (abbreviationType) { case DEFAULT: return text.getAbbreviation(); - case MEDLINE: - return text.getMedlineAbbreviation(); + case DOTLESS: + return text.getDotlessAbbreviation(); case SHORTEST_UNIQUE: return text.getShortestUniqueAbbreviation(); default: diff --git a/src/main/java/org/jabref/gui/journals/UndoableUnabbreviator.java b/src/main/java/org/jabref/gui/journals/UndoableUnabbreviator.java index c50c148db7d..bf4e1ab5bfe 100644 --- a/src/main/java/org/jabref/gui/journals/UndoableUnabbreviator.java +++ b/src/main/java/org/jabref/gui/journals/UndoableUnabbreviator.java @@ -36,7 +36,7 @@ public boolean unabbreviate(BibDatabase database, BibEntry entry, Field field, C return true; } - String text = entry.getField(field).get(); + String text = entry.getLatexFreeField(field).get(); String origText = text; if (database != null) { text = database.resolveForStrings(text); @@ -50,7 +50,7 @@ public boolean unabbreviate(BibDatabase database, BibEntry entry, Field field, C return false; // Cannot unabbreviate unabbreviated name. } - Abbreviation abbreviation = journalAbbreviationRepository.get(text).get(); // Must be here. + Abbreviation abbreviation = journalAbbreviationRepository.get(text).get(); String newText = abbreviation.getName(); entry.setField(field, newText); ce.addEdit(new UndoableFieldChange(entry, field, origText, newText)); diff --git a/src/main/java/org/jabref/logic/integrity/AbbreviationChecker.java b/src/main/java/org/jabref/logic/integrity/AbbreviationChecker.java index 8e9db3d4fd6..2d6972ea8b6 100644 --- a/src/main/java/org/jabref/logic/integrity/AbbreviationChecker.java +++ b/src/main/java/org/jabref/logic/integrity/AbbreviationChecker.java @@ -1,29 +1,33 @@ package org.jabref.logic.integrity; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; +import java.util.Set; import org.jabref.logic.journals.JournalAbbreviationRepository; import org.jabref.logic.l10n.Localization; -import org.jabref.model.strings.StringUtil; +import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.field.Field; +import org.jabref.model.entry.field.FieldFactory; -public class AbbreviationChecker implements ValueChecker { +public class AbbreviationChecker implements EntryChecker { private final JournalAbbreviationRepository abbreviationRepository; + private final Set fields = FieldFactory.getBookNameFields(); public AbbreviationChecker(JournalAbbreviationRepository abbreviationRepository) { this.abbreviationRepository = abbreviationRepository; } @Override - public Optional checkValue(String value) { - if (StringUtil.isBlank(value)) { - return Optional.empty(); + public List check(BibEntry entry) { + List messages = new ArrayList<>(); + for (Field field : fields) { + Optional value = entry.getLatexFreeField(field); + value.filter(abbreviationRepository::isAbbreviatedName) + .ifPresent(val -> messages.add(new IntegrityMessage(Localization.lang("abbreviation detected"), entry, field))); } - - if (abbreviationRepository.isAbbreviatedName(value)) { - return Optional.of(Localization.lang("abbreviation detected")); - } - - return Optional.empty(); + return messages; } } diff --git a/src/main/java/org/jabref/logic/integrity/FieldCheckers.java b/src/main/java/org/jabref/logic/integrity/FieldCheckers.java index 379973fb98e..0ed0bb82d10 100644 --- a/src/main/java/org/jabref/logic/integrity/FieldCheckers.java +++ b/src/main/java/org/jabref/logic/integrity/FieldCheckers.java @@ -27,9 +27,6 @@ public FieldCheckers(BibDatabaseContext databaseContext, FilePreferences filePre private static Multimap getAllMap(BibDatabaseContext databaseContext, FilePreferences filePreferences, JournalAbbreviationRepository abbreviationRepository, boolean allowIntegerEdition) { ArrayListMultimap fieldCheckers = ArrayListMultimap.create(50, 10); - for (Field field : FieldFactory.getBookNameFields()) { - fieldCheckers.put(field, new AbbreviationChecker(abbreviationRepository)); - } for (Field field : FieldFactory.getPersonNameFields()) { fieldCheckers.put(field, new PersonNamesChecker(databaseContext)); } diff --git a/src/main/java/org/jabref/logic/integrity/JournalInAbbreviationListChecker.java b/src/main/java/org/jabref/logic/integrity/JournalInAbbreviationListChecker.java index d954debab44..6af4601d060 100644 --- a/src/main/java/org/jabref/logic/integrity/JournalInAbbreviationListChecker.java +++ b/src/main/java/org/jabref/logic/integrity/JournalInAbbreviationListChecker.java @@ -22,7 +22,7 @@ public JournalInAbbreviationListChecker(Field field, JournalAbbreviationReposito @Override public List check(BibEntry entry) { - Optional value = entry.getField(field); + Optional value = entry.getLatexFreeField(field); if (value.isEmpty()) { return Collections.emptyList(); } diff --git a/src/main/java/org/jabref/logic/journals/Abbreviation.java b/src/main/java/org/jabref/logic/journals/Abbreviation.java index 7a7e4d9cf30..c3c18ff02bf 100644 --- a/src/main/java/org/jabref/logic/journals/Abbreviation.java +++ b/src/main/java/org/jabref/logic/journals/Abbreviation.java @@ -1,11 +1,15 @@ package org.jabref.logic.journals; +import java.io.Serializable; import java.util.Objects; -public class Abbreviation implements Comparable { +public class Abbreviation implements Comparable, Serializable { - private final String name; + private static final long serialVersionUID = 1; + + private transient String name; private final String abbreviation; + private transient String dotlessAbbreviation; private final String shortestUniqueAbbreviation; public Abbreviation(String name, String abbreviation) { @@ -13,9 +17,18 @@ public Abbreviation(String name, String abbreviation) { } public Abbreviation(String name, String abbreviation, String shortestUniqueAbbreviation) { - this.name = name; - this.abbreviation = abbreviation; - this.shortestUniqueAbbreviation = shortestUniqueAbbreviation.trim(); + this(name, + abbreviation, + // "L. N." becomes "L N ", we need to remove the double spaces inbetween + abbreviation.replace(".", " ").replace(" ", " ").trim(), + shortestUniqueAbbreviation.trim()); + } + + public Abbreviation(String name, String abbreviation, String dotlessAbbreviation, String shortestUniqueAbbreviation) { + this.name = name.intern(); + this.abbreviation = abbreviation.intern(); + this.dotlessAbbreviation = dotlessAbbreviation.intern(); + this.shortestUniqueAbbreviation = shortestUniqueAbbreviation.trim().intern(); } public String getName() { @@ -34,8 +47,8 @@ public String getShortestUniqueAbbreviation() { return result; } - public String getMedlineAbbreviation() { - return getAbbreviation().replace(".", " ").replace(" ", " ").trim(); + public String getDotlessAbbreviation() { + return this.dotlessAbbreviation; } @Override @@ -46,23 +59,23 @@ public int compareTo(Abbreviation toCompare) { public String getNext(String current) { String currentTrimmed = current.trim(); - if (getMedlineAbbreviation().equals(currentTrimmed)) { + if (getDotlessAbbreviation().equals(currentTrimmed)) { return getShortestUniqueAbbreviation().equals(getAbbreviation()) ? getName() : getShortestUniqueAbbreviation(); } else if (getShortestUniqueAbbreviation().equals(currentTrimmed) && !getShortestUniqueAbbreviation().equals(getAbbreviation())) { return getName(); } else if (getName().equals(currentTrimmed)) { return getAbbreviation(); } else { - return getMedlineAbbreviation(); + return getDotlessAbbreviation(); } } @Override public String toString() { - return String.format("Abbreviation{name=%s, abbreviation=%s, medlineAbbreviation=%s, shortestUniqueAbbreviation=%s}", + return String.format("Abbreviation{name=%s, abbreviation=%s, dotlessAbbreviation=%s, shortestUniqueAbbreviation=%s}", this.name, this.abbreviation, - this.getMedlineAbbreviation(), + this.dotlessAbbreviation, this.shortestUniqueAbbreviation); } diff --git a/src/main/java/org/jabref/logic/journals/JournalAbbreviationLoader.java b/src/main/java/org/jabref/logic/journals/JournalAbbreviationLoader.java index 76ba9096791..d74b6a9fc9d 100644 --- a/src/main/java/org/jabref/logic/journals/JournalAbbreviationLoader.java +++ b/src/main/java/org/jabref/logic/journals/JournalAbbreviationLoader.java @@ -10,6 +10,14 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +/** + *

+ * This class loads abbreviations from a CSV file and stores them into a MV file + *

+ *

+ * Abbreviations are available at https://github.com/JabRef/abbrv.jabref.org/. + *

+ */ public class JournalAbbreviationLoader { private static final Logger LOGGER = LoggerFactory.getLogger(JournalAbbreviationLoader.class); @@ -26,8 +34,8 @@ public static JournalAbbreviationRepository loadRepository(JournalAbbreviationPr // Initialize with built-in list try { Path tempDir = Files.createTempDirectory("jabref-journal"); - Path tempJournalList = tempDir.resolve("journalList.mv"); - Files.copy(JournalAbbreviationRepository.class.getResourceAsStream("/journals/journalList.mv"), tempJournalList); + Path tempJournalList = tempDir.resolve("journal-list.mv"); + Files.copy(JournalAbbreviationRepository.class.getResourceAsStream("/journals/journal-list.mv"), tempJournalList); repository = new JournalAbbreviationRepository(tempJournalList); tempDir.toFile().deleteOnExit(); tempJournalList.toFile().deleteOnExit(); @@ -39,12 +47,13 @@ public static JournalAbbreviationRepository loadRepository(JournalAbbreviationPr // Read external lists List lists = journalAbbreviationPreferences.getExternalJournalLists(); if (!(lists.isEmpty())) { + // reversing ensures that the latest lists overwrites the former one Collections.reverse(lists); for (String filename : lists) { try { repository.addCustomAbbreviations(readJournalListFromFile(Path.of(filename))); } catch (IOException e) { - LOGGER.error(String.format("Cannot read external journal list file %s", filename), e); + LOGGER.error("Cannot read external journal list file {}", filename, e); } } } diff --git a/src/main/java/org/jabref/logic/journals/JournalAbbreviationRepository.java b/src/main/java/org/jabref/logic/journals/JournalAbbreviationRepository.java index 0437e1ae2ae..29b61f0d960 100644 --- a/src/main/java/org/jabref/logic/journals/JournalAbbreviationRepository.java +++ b/src/main/java/org/jabref/logic/journals/JournalAbbreviationRepository.java @@ -3,13 +3,14 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Collectors; import org.h2.mvstore.MVMap; import org.h2.mvstore.MVStore; @@ -18,105 +19,89 @@ * A repository for all journal abbreviations, including add and find methods. */ public class JournalAbbreviationRepository { - static final Pattern DOT = Pattern.compile("\\."); static final Pattern QUESTION_MARK = Pattern.compile("\\?"); - private final MVMap fullToAbbreviation; - private final MVMap abbreviationToFull; - private final List customAbbreviations; + private final Map fullToAbbreviationObject = new HashMap<>(); + private final Map abbreviationToAbbreviationObject = new HashMap<>(); + private final Map dotlessToAbbreviationObject = new HashMap<>(); + private final Map shortestUniqueToAbbreviationObject = new HashMap<>(); + private final List customAbbreviations = new ArrayList<>(); public JournalAbbreviationRepository(Path journalList) { MVStore store = new MVStore.Builder().readOnly().fileName(journalList.toAbsolutePath().toString()).open(); - this.fullToAbbreviation = store.openMap("FullToAbbreviation"); - this.abbreviationToFull = store.openMap("AbbreviationToFull"); - this.customAbbreviations = new ArrayList<>(); + MVMap mvFullToAbbreviationObject = store.openMap("FullToAbbreviation"); + + mvFullToAbbreviationObject.forEach((name, abbreviation) -> { + String abbrevationString = abbreviation.getAbbreviation(); + String shortestUniqueAbbreviation = abbreviation.getShortestUniqueAbbreviation(); + Abbreviation newAbbreviation = new Abbreviation( + name, + abbrevationString, + shortestUniqueAbbreviation + ); + fullToAbbreviationObject.put(name, newAbbreviation); + abbreviationToAbbreviationObject.put(abbrevationString, newAbbreviation); + dotlessToAbbreviationObject.put(newAbbreviation.getDotlessAbbreviation(), newAbbreviation); + shortestUniqueToAbbreviationObject.put(shortestUniqueAbbreviation, newAbbreviation); + }); } private static boolean isMatched(String name, Abbreviation abbreviation) { return name.equalsIgnoreCase(abbreviation.getName()) || name.equalsIgnoreCase(abbreviation.getAbbreviation()) - || name.equalsIgnoreCase(abbreviation.getMedlineAbbreviation()) + || name.equalsIgnoreCase(abbreviation.getDotlessAbbreviation()) || name.equalsIgnoreCase(abbreviation.getShortestUniqueAbbreviation()); } private static boolean isMatchedAbbreviated(String name, Abbreviation abbreviation) { + boolean isExpanded = name.equalsIgnoreCase(abbreviation.getName()); + if (isExpanded) { + return false; + } boolean isAbbreviated = name.equalsIgnoreCase(abbreviation.getAbbreviation()) - || name.equalsIgnoreCase(abbreviation.getMedlineAbbreviation()) + || name.equalsIgnoreCase(abbreviation.getDotlessAbbreviation()) || name.equalsIgnoreCase(abbreviation.getShortestUniqueAbbreviation()); - boolean isExpanded = name.equalsIgnoreCase(abbreviation.getName()); - return isAbbreviated && !isExpanded; + return isAbbreviated; } /** - * Returns true if the given journal name is contained in the list either in its full form (e.g Physical Review - * Letters) or its abbreviated form (e.g. Phys. Rev. Lett.). + * Returns true if the given journal name is contained in the list either in its full form + * (e.g., Physical Review Letters) or its abbreviated form (e.g., Phys. Rev. Lett.). */ public boolean isKnownName(String journalName) { - // check for at least one "?" if (QUESTION_MARK.matcher(journalName).find()) { return false; } - String journal = journalName.trim().replaceAll(Matcher.quoteReplacement("\\&"), "&"); - - boolean isKnown = customAbbreviations.stream().anyMatch(abbreviation -> isMatched(journal, abbreviation)); - if (isKnown) { - return true; - } - - return fullToAbbreviation.containsKey(journal) || abbreviationToFull.containsKey(journal) - || findDottedAbbrFromDotless(journal).length() > 0; + return customAbbreviations.stream().anyMatch(abbreviation -> isMatched(journal, abbreviation)) + || fullToAbbreviationObject.containsKey(journal) + || abbreviationToAbbreviationObject.containsKey(journal) + || dotlessToAbbreviationObject.containsKey(journal) + || shortestUniqueToAbbreviationObject.containsKey(journal); } /** * Returns true if the given journal name is in its abbreviated form (e.g. Phys. Rev. Lett.). The test is strict, - * i.e. journals whose abbreviation is the same as the full name are not considered + * i.e., journals whose abbreviation is the same as the full name are not considered */ public boolean isAbbreviatedName(String journalName) { - String journal = journalName.trim(); - - // journal abbreviation must be at least 2 words - boolean isMoreThanTwoWords = journalName.split(" ").length >= 2; - - return customAbbreviations.stream().anyMatch(abbreviation -> isMatchedAbbreviated(journal, abbreviation)) - || abbreviationToFull.containsKey(journal) - || (isMoreThanTwoWords && findDottedAbbrFromDotless(journal).length() > 0); - } - - public String findDottedAbbrFromDotless(String journalName) { - // check for at least one "?" if (QUESTION_MARK.matcher(journalName).find()) { - return "UNKNOWN"; - } - - String foundKey = ""; - - // check for a dot-less abbreviation - if (!DOT.matcher(journalName).find()) { - // use dot-less abbr to find full name using regex - String[] journalSplit = journalName.split(" "); - - for (int i = 0; i < journalSplit.length; i++) { - String word = journalSplit[i] + "[\\.\\s]*"; - journalSplit[i] = word; - } - - String joined = String.join("", journalSplit); - - foundKey = abbreviationToFull.keySet().stream() - .filter(s -> Pattern.compile(joined).matcher(s).find()) - .collect(Collectors.joining()); + return false; } - - return foundKey; + String journal = journalName.trim().replaceAll(Matcher.quoteReplacement("\\&"), "&"); + return customAbbreviations.stream().anyMatch(abbreviation -> isMatchedAbbreviated(journal, abbreviation)) + || abbreviationToAbbreviationObject.containsKey(journal) + || dotlessToAbbreviationObject.containsKey(journal) + || shortestUniqueToAbbreviationObject.containsKey(journal); } /** * Attempts to get the abbreviation of the journal given. * - * @param input The journal name (either abbreviated or full name). + * @param input The journal name (either full name or abbreviated name). */ public Optional get(String input) { + // Clean up input: trim and unescape ampersand String journal = input.trim().replaceAll(Matcher.quoteReplacement("\\&"), "&"); Optional customAbbreviation = customAbbreviations.stream() @@ -126,19 +111,10 @@ public Optional get(String input) { return customAbbreviation; } - return Optional.ofNullable(fullToAbbreviation.get(journal)) - .map(abbreviation -> new Abbreviation(journal, abbreviation)) - .or(() -> { - String abbr = ""; - - // check for dot-less abbr - if (isKnownName(journal) && isAbbreviatedName(journal)) { - abbr = findDottedAbbrFromDotless(journal); - } - - return Optional.ofNullable(abbreviationToFull.get(abbr.equals("") ? journal : abbr)) - .map(fullName -> new Abbreviation(fullName, journal)); - }); + return Optional.ofNullable(fullToAbbreviationObject.get(journal)) + .or(() -> Optional.ofNullable(abbreviationToAbbreviationObject.get(journal))) + .or(() -> Optional.ofNullable(dotlessToAbbreviationObject.get(journal))) + .or(() -> Optional.ofNullable(shortestUniqueToAbbreviationObject.get(journal))); } public void addCustomAbbreviation(Abbreviation abbreviation) { @@ -166,8 +142,8 @@ public Optional getDefaultAbbreviation(String text) { return get(text).map(Abbreviation::getAbbreviation); } - public Optional getMedlineAbbreviation(String text) { - return get(text).map(Abbreviation::getMedlineAbbreviation); + public Optional getDotless(String text) { + return get(text).map(Abbreviation::getDotlessAbbreviation); } public Optional getShortestUniqueAbbreviation(String text) { @@ -175,11 +151,10 @@ public Optional getShortestUniqueAbbreviation(String text) { } public Set getFullNames() { - return fullToAbbreviation.keySet(); + return fullToAbbreviationObject.keySet(); } - public List getAllLoaded() { - return fullToAbbreviation.entrySet().stream().map(entry -> - new Abbreviation(entry.getKey(), entry.getValue())).collect(Collectors.toList()); + public Collection getAllLoaded() { + return fullToAbbreviationObject.values(); } } diff --git a/src/main/resources/journals/journal-list.mv b/src/main/resources/journals/journal-list.mv new file mode 100644 index 00000000000..398e4f1abe3 Binary files /dev/null and b/src/main/resources/journals/journal-list.mv differ diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index 1dd2406af12..d7fdb6b9168 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -28,7 +28,7 @@ Reveal\ in\ File\ Explorer=Reveal in File Explorer %0\ matches\ the\ term\ %1=%0 matches the term %1 Abbreviate\ journal\ names\ of\ the\ selected\ entries\ (DEFAULT\ abbreviation)=Abbreviate journal names of the selected entries (DEFAULT abbreviation) -Abbreviate\ journal\ names\ of\ the\ selected\ entries\ (MEDLINE\ abbreviation)=Abbreviate journal names of the selected entries (MEDLINE abbreviation) +Abbreviate\ journal\ names\ of\ the\ selected\ entries\ (DOTLESS\ abbreviation)=Abbreviate journal names of the selected entries (DOTLESS abbreviation) Abbreviate\ journal\ names\ of\ the\ selected\ entries\ (SHORTEST\ UNIQUE\ abbreviation)=Abbreviate journal names of the selected entries (SHORTEST UNIQUE abbreviation) Abbreviate\ names=Abbreviate names @@ -37,6 +37,12 @@ Abbreviated\ %0\ journal\ names.=Abbreviated %0 journal names. Abbreviation=Abbreviation Abbreviations=Abbreviations +Unabbreviate\ journal\ names\ of\ the\ selected\ entries=Unabbreviate journal names of the selected entries +Unabbreviated\ %0\ journal\ names.=Unabbreviated %0 journal names. + +dotless=dotless +shortest\ unique=shortest unique + About\ JabRef=About JabRef Abstract=Abstract @@ -910,9 +916,6 @@ Trim\ whitespace\ characters=Trim whitespace characters Try\ different\ encoding=Try different encoding -Unabbreviate\ journal\ names\ of\ the\ selected\ entries=Unabbreviate journal names of the selected entries -Unabbreviated\ %0\ journal\ names.=Unabbreviated %0 journal names. - Undo=Undo Unknown\ BibTeX\ entries\:=Unknown BibTeX entries\: diff --git a/src/test/java/org/jabref/logic/integrity/AbbreviationCheckerTest.java b/src/test/java/org/jabref/logic/integrity/AbbreviationCheckerTest.java index ebc1b3bd67f..1969a2e03da 100644 --- a/src/test/java/org/jabref/logic/integrity/AbbreviationCheckerTest.java +++ b/src/test/java/org/jabref/logic/integrity/AbbreviationCheckerTest.java @@ -1,10 +1,13 @@ package org.jabref.logic.integrity; -import java.util.Optional; +import java.util.Collections; import org.jabref.logic.journals.Abbreviation; import org.jabref.logic.journals.JournalAbbreviationLoader; import org.jabref.logic.journals.JournalAbbreviationRepository; +import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.field.StandardField; +import org.jabref.model.entry.types.StandardEntryType; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -16,32 +19,49 @@ class AbbreviationCheckerTest { private JournalAbbreviationRepository abbreviationRepository; private AbbreviationChecker checker; + private BibEntry entry; @BeforeEach void setUp() { abbreviationRepository = JournalAbbreviationLoader.loadBuiltInRepository(); abbreviationRepository.addCustomAbbreviation(new Abbreviation("Test Journal", "T. J.")); + entry = new BibEntry(StandardEntryType.InProceedings); checker = new AbbreviationChecker(abbreviationRepository); } @Test - void checkValueComplainsAboutAbbreviatedJournalName() { - assertNotEquals(Optional.empty(), checker.checkValue("T. J.")); + void checkEntryComplainsAboutAbbreviatedJournalName() { + entry.setField(StandardField.BOOKTITLE, "T. J."); + assertNotEquals(Collections.emptyList(), checker.check(entry)); } @Test - void checkValueDoesNotComplainAboutJournalNameThatHasSameAbbreviation() { + void checkEntryDoesNotComplainAboutJournalNameThatHasSameAbbreviation() { + entry.setField(StandardField.BOOKTITLE, "Journal"); abbreviationRepository.addCustomAbbreviation(new Abbreviation("Journal", "Journal")); - assertEquals(Optional.empty(), checker.checkValue("Journal")); + assertEquals(Collections.emptyList(), checker.check(entry)); } @Test - void checkValueDoesNotComplainAboutJournalNameThatHasΝοAbbreviation() { - assertEquals(Optional.empty(), checker.checkValue("IEEE Software")); + void checkEntryDoesNotComplainAboutJournalNameThatHasΝοAbbreviation() { + entry.setField(StandardField.BOOKTITLE, "IEEE Software"); + assertEquals(Collections.emptyList(), checker.check(entry)); } @Test - void checkValueDoesNotComplainAboutJournalNameThatHasΝοInput() { - assertEquals(Optional.empty(), checker.checkValue("")); + void checkEntryDoesNotComplainAboutJournalNameThatHasΝοInput() { + assertEquals(Collections.emptyList(), checker.check(entry)); + } + + @Test + void checkEntryWorksForLaTeXField() { + entry.setField(StandardField.BOOKTITLE, "Reducing Complexity and Power of Digital Multibit Error-Feedback $\\Delta$$\\Sigma$ Modulators"); + assertEquals(Collections.emptyList(), checker.check(entry)); + } + + @Test + void checkEntryWorksForLaTeXFieldStilContainingIllegalChars() { + entry.setField(StandardField.BOOKTITLE, "Proceedings of the 5\\({}^{\\mbox{th}}\\) Central-European Workshop on Services and their Composition, Rostock, Germany, February 21-22, 2013"); + assertEquals(Collections.emptyList(), checker.check(entry)); } } diff --git a/src/test/java/org/jabref/logic/journals/AbbreviationTest.java b/src/test/java/org/jabref/logic/journals/AbbreviationTest.java index ea7532bf8ee..38a0d7ee132 100644 --- a/src/test/java/org/jabref/logic/journals/AbbreviationTest.java +++ b/src/test/java/org/jabref/logic/journals/AbbreviationTest.java @@ -14,7 +14,7 @@ void testAbbreviationsWithTrailingSpaces() { assertEquals("Long Name", abbreviation.getName()); assertEquals("L. N.", abbreviation.getAbbreviation()); - assertEquals("L N", abbreviation.getMedlineAbbreviation()); + assertEquals("L N", abbreviation.getDotlessAbbreviation()); assertEquals("L. N.", abbreviation.getShortestUniqueAbbreviation()); } @@ -24,7 +24,7 @@ void testAbbreviationsWithTrailingSpacesWithShortestUniqueAbbreviation() { assertEquals("Long Name", abbreviation.getName()); assertEquals("L. N.", abbreviation.getAbbreviation()); - assertEquals("L N", abbreviation.getMedlineAbbreviation()); + assertEquals("L N", abbreviation.getDotlessAbbreviation()); assertEquals("LN", abbreviation.getShortestUniqueAbbreviation()); } @@ -34,7 +34,7 @@ void testAbbreviationsWithSemicolons() { assertEquals("Long Name", abbreviation.getName()); assertEquals("L. N.;LN;M", abbreviation.getAbbreviation()); - assertEquals("L N ;LN;M", abbreviation.getMedlineAbbreviation()); + assertEquals("L N ;LN;M", abbreviation.getDotlessAbbreviation()); assertEquals("L. N.;LN;M", abbreviation.getShortestUniqueAbbreviation()); } @@ -44,7 +44,7 @@ void testAbbreviationsWithSemicolonsWithShortestUniqueAbbreviation() { assertEquals("Long Name", abbreviation.getName()); assertEquals("L. N.;LN;M", abbreviation.getAbbreviation()); - assertEquals("L N ;LN;M", abbreviation.getMedlineAbbreviation()); + assertEquals("L N ;LN;M", abbreviation.getDotlessAbbreviation()); assertEquals("LNLNM", abbreviation.getShortestUniqueAbbreviation()); } @@ -89,13 +89,13 @@ void testGetNextElementWithTrailingSpacesWithShortestUniqueAbbreviation() { @Test void testDefaultAndMedlineAbbreviationsAreSame() { Abbreviation abbreviation = new Abbreviation("Long Name", "L N"); - assertEquals(abbreviation.getAbbreviation(), abbreviation.getMedlineAbbreviation()); + assertEquals(abbreviation.getAbbreviation(), abbreviation.getDotlessAbbreviation()); } @Test void testDefaultAndMedlineAbbreviationsAreSameWithShortestUniqueAbbreviation() { Abbreviation abbreviation = new Abbreviation("Long Name", "L N", "LN"); - assertEquals(abbreviation.getAbbreviation(), abbreviation.getMedlineAbbreviation()); + assertEquals(abbreviation.getAbbreviation(), abbreviation.getDotlessAbbreviation()); } @Test diff --git a/src/test/java/org/jabref/logic/journals/AbbreviationsTest.java b/src/test/java/org/jabref/logic/journals/AbbreviationsTest.java index 3f2d01f3f47..075148c1f53 100644 --- a/src/test/java/org/jabref/logic/journals/AbbreviationsTest.java +++ b/src/test/java/org/jabref/logic/journals/AbbreviationsTest.java @@ -20,7 +20,7 @@ void getNextAbbreviationAbbreviatesJournalTitle() { } @Test - void getNextAbbreviationConvertsAbbreviationToDotLessAbbreviation() { + void getNextAbbreviationConvertsAbbreviationToDotlessAbbreviation() { assertEquals("2D Mater", repository.getNextAbbreviation("2D Mater.").get()); } } diff --git a/src/test/java/org/jabref/logic/journals/JournalAbbreviationRepositoryTest.java b/src/test/java/org/jabref/logic/journals/JournalAbbreviationRepositoryTest.java index 66f8567709b..42194347d92 100644 --- a/src/test/java/org/jabref/logic/journals/JournalAbbreviationRepositoryTest.java +++ b/src/test/java/org/jabref/logic/journals/JournalAbbreviationRepositoryTest.java @@ -19,14 +19,18 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; -@AllowedToUseSwing("UndoableUnabbreviator and UndoableAbbreviator requires Swing Compound Edit in order test the abbreviation and unabreviation of journal titles") +@AllowedToUseSwing("UndoableUnabbreviator and UndoableAbbreviator requires Swing Compound Edit in order test the abbreviation and unabbreviation of journal titles") class JournalAbbreviationRepositoryTest { private JournalAbbreviationRepository repository; + private BibDatabase bibDatabase = new BibDatabase(); + private UndoableUnabbreviator undoableUnabbreviator; + @BeforeEach void setUp() { repository = JournalAbbreviationLoader.loadBuiltInRepository(); + undoableUnabbreviator = new UndoableUnabbreviator(repository); } @Test @@ -42,8 +46,8 @@ void oneElement() { assertEquals("L. N.", repository.getDefaultAbbreviation("Long Name").orElse("WRONG")); assertEquals("UNKNOWN", repository.getDefaultAbbreviation("?").orElse("UNKNOWN")); - assertEquals("L N", repository.getMedlineAbbreviation("Long Name").orElse("WRONG")); - assertEquals("UNKNOWN", repository.getMedlineAbbreviation("?").orElse("UNKNOWN")); + assertEquals("L N", repository.getDotless("Long Name").orElse("WRONG")); + assertEquals("UNKNOWN", repository.getDotless("?").orElse("UNKNOWN")); assertEquals("L. N.", repository.getShortestUniqueAbbreviation("Long Name").orElse("WRONG")); assertEquals("UNKNOWN", repository.getShortestUniqueAbbreviation("?").orElse("UNKNOWN")); @@ -67,8 +71,8 @@ void oneElementWithShortestUniqueAbbreviation() { assertEquals("L. N.", repository.getDefaultAbbreviation("Long Name").orElse("WRONG")); assertEquals("UNKNOWN", repository.getDefaultAbbreviation("?").orElse("UNKNOWN")); - assertEquals("L N", repository.getMedlineAbbreviation("Long Name").orElse("WRONG")); - assertEquals("UNKNOWN", repository.getMedlineAbbreviation("?").orElse("UNKNOWN")); + assertEquals("L N", repository.getDotless("Long Name").orElse("WRONG")); + assertEquals("UNKNOWN", repository.getDotless("?").orElse("UNKNOWN")); assertEquals("LN", repository.getShortestUniqueAbbreviation("Long Name").orElse("WRONG")); assertEquals("UNKNOWN", repository.getShortestUniqueAbbreviation("?").orElse("UNKNOWN")); @@ -162,9 +166,7 @@ void testAbbreviationsWithEscapedAmpersand() { @Test void testJournalAbbreviationWithEscapedAmpersand() { - BibDatabase bibDatabase = new BibDatabase(); - JournalAbbreviationRepository journalAbbreviationRepository = JournalAbbreviationLoader.loadBuiltInRepository(); - UndoableAbbreviator undoableAbbreviator = new UndoableAbbreviator(journalAbbreviationRepository, AbbreviationType.DEFAULT, false); + UndoableAbbreviator undoableAbbreviator = new UndoableAbbreviator(repository, AbbreviationType.DEFAULT, false); BibEntry entryWithEscapedAmpersandInJournal = new BibEntry(StandardEntryType.Article); entryWithEscapedAmpersandInJournal.setField(StandardField.JOURNAL, "ACS Applied Materials \\& Interfaces"); @@ -177,10 +179,6 @@ void testJournalAbbreviationWithEscapedAmpersand() { @Test void testJournalUnabbreviate() { - BibDatabase bibDatabase = new BibDatabase(); - JournalAbbreviationRepository journalAbbreviationRepository = JournalAbbreviationLoader.loadBuiltInRepository(); - UndoableUnabbreviator undoableUnabbreviator = new UndoableUnabbreviator(journalAbbreviationRepository); - BibEntry abbreviatedJournalEntry = new BibEntry(StandardEntryType.Article); abbreviatedJournalEntry.setField(StandardField.JOURNAL, "ACS Appl. Mater. Interfaces"); @@ -192,9 +190,7 @@ void testJournalUnabbreviate() { @Test void testJournalAbbreviateWithoutEscapedAmpersand() { - BibDatabase bibDatabase = new BibDatabase(); - JournalAbbreviationRepository journalAbbreviationRepository = JournalAbbreviationLoader.loadBuiltInRepository(); - UndoableAbbreviator undoableAbbreviator = new UndoableAbbreviator(journalAbbreviationRepository, AbbreviationType.DEFAULT, false); + UndoableAbbreviator undoableAbbreviator = new UndoableAbbreviator(repository, AbbreviationType.DEFAULT, false); BibEntry entryWithoutEscapedAmpersandInJournal = new BibEntry(StandardEntryType.Article) .withField(StandardField.JOURNAL, "ACS Applied Materials & Interfaces"); @@ -207,9 +203,7 @@ void testJournalAbbreviateWithoutEscapedAmpersand() { @Test void testJournalAbbreviateWithEmptyFJournal() { - BibDatabase bibDatabase = new BibDatabase(); - JournalAbbreviationRepository journalAbbreviationRepository = JournalAbbreviationLoader.loadBuiltInRepository(); - UndoableAbbreviator undoableAbbreviator = new UndoableAbbreviator(journalAbbreviationRepository, AbbreviationType.DEFAULT, true); + UndoableAbbreviator undoableAbbreviator = new UndoableAbbreviator(repository, AbbreviationType.DEFAULT, true); BibEntry entryWithoutEscapedAmpersandInJournal = new BibEntry(StandardEntryType.Article) .withField(StandardField.JOURNAL, "ACS Applied Materials & Interfaces") @@ -224,10 +218,6 @@ void testJournalAbbreviateWithEmptyFJournal() { @Test void testUnabbreviateWithJournalExistsAndFJournalNot() { - BibDatabase bibDatabase = new BibDatabase(); - JournalAbbreviationRepository journalAbbreviationRepository = JournalAbbreviationLoader.loadBuiltInRepository(); - UndoableUnabbreviator undoableUnabbreviator = new UndoableUnabbreviator(journalAbbreviationRepository); - BibEntry abbreviatedJournalEntry = new BibEntry(StandardEntryType.Article) .withField(StandardField.JOURNAL, "ACS Appl. Mater. Interfaces"); @@ -239,10 +229,6 @@ void testUnabbreviateWithJournalExistsAndFJournalNot() { @Test void testUnabbreviateWithJournalExistsAndFJournalExists() { - BibDatabase bibDatabase = new BibDatabase(); - JournalAbbreviationRepository journalAbbreviationRepository = JournalAbbreviationLoader.loadBuiltInRepository(); - UndoableUnabbreviator undoableUnabbreviator = new UndoableUnabbreviator(journalAbbreviationRepository); - BibEntry abbreviatedJournalEntry = new BibEntry(StandardEntryType.Article) .withField(StandardField.JOURNAL, "ACS Appl. Mater. Interfaces") .withField(AMSField.FJOURNAL, "ACS Applied Materials & Interfaces"); @@ -255,16 +241,65 @@ void testUnabbreviateWithJournalExistsAndFJournalExists() { @Test void testJournalDotlessAbbreviation() { - BibDatabase bibDatabase = new BibDatabase(); - JournalAbbreviationRepository journalAbbreviationRepository = JournalAbbreviationLoader.loadBuiltInRepository(); - UndoableUnabbreviator undoableUnabbreviator = new UndoableUnabbreviator(journalAbbreviationRepository); + BibEntry abbreviatedJournalEntry = new BibEntry(StandardEntryType.Article) + .withField(StandardField.JOURNAL, "ACS Appl Mater Interfaces"); - BibEntry abbreviatedJournalEntry = new BibEntry(StandardEntryType.Article); - abbreviatedJournalEntry.setField(StandardField.JOURNAL, "ACS Appl Mater Interfaces"); + undoableUnabbreviator.unabbreviate(bibDatabase, abbreviatedJournalEntry, StandardField.JOURNAL, new CompoundEdit()); + BibEntry expectedAbbreviatedJournalEntry = new BibEntry(StandardEntryType.Article) + .withField(StandardField.JOURNAL, "ACS Applied Materials & Interfaces"); + assertEquals(expectedAbbreviatedJournalEntry, abbreviatedJournalEntry); + } + + @Test + void testJournalDotlessAbbreviationWithCurlyBraces() { + BibEntry abbreviatedJournalEntry = new BibEntry(StandardEntryType.Article) + .withField(StandardField.JOURNAL, "{ACS Appl Mater Interfaces}"); undoableUnabbreviator.unabbreviate(bibDatabase, abbreviatedJournalEntry, StandardField.JOURNAL, new CompoundEdit()); BibEntry expectedAbbreviatedJournalEntry = new BibEntry(StandardEntryType.Article) .withField(StandardField.JOURNAL, "ACS Applied Materials & Interfaces"); assertEquals(expectedAbbreviatedJournalEntry, abbreviatedJournalEntry); } + + /** + * Tests Issue 9475 + */ + @Test + void testTitleEmbeddedWithCurlyBracesHavingNoChangesKeepsBraces() { + BibEntry abbreviatedJournalEntry = new BibEntry(StandardEntryType.InCollection) + .withField(StandardField.JOURNAL, "{The Visualization Handbook}"); + + undoableUnabbreviator.unabbreviate(bibDatabase, abbreviatedJournalEntry, StandardField.JOURNAL, new CompoundEdit()); + + BibEntry expectedAbbreviatedJournalEntry = new BibEntry(StandardEntryType.InCollection) + .withField(StandardField.JOURNAL, "{The Visualization Handbook}"); + assertEquals(expectedAbbreviatedJournalEntry, abbreviatedJournalEntry); + } + + /** + * Tests Issue 9503 + */ + @Test + void testTitleWithNestedCurlyBracesHavingNoChangesKeepsBraces() { + BibEntry abbreviatedJournalEntry = new BibEntry(StandardEntryType.InProceedings) + .withField(StandardField.BOOKTITLE, "2015 {IEEE} International Conference on Digital Signal Processing, {DSP} 2015, Singapore, July 21-24, 2015"); + + undoableUnabbreviator.unabbreviate(bibDatabase, abbreviatedJournalEntry, StandardField.JOURNAL, new CompoundEdit()); + + BibEntry expectedAbbreviatedJournalEntry = new BibEntry(StandardEntryType.InProceedings) + .withField(StandardField.BOOKTITLE, "2015 {IEEE} International Conference on Digital Signal Processing, {DSP} 2015, Singapore, July 21-24, 2015"); + assertEquals(expectedAbbreviatedJournalEntry, abbreviatedJournalEntry); + } + + @Test + void testDotlessForPhysRevB() { + BibEntry abbreviatedJournalEntry = new BibEntry(StandardEntryType.Article) + .withField(StandardField.JOURNAL, "Phys Rev B"); + + undoableUnabbreviator.unabbreviate(bibDatabase, abbreviatedJournalEntry, StandardField.JOURNAL, new CompoundEdit()); + + BibEntry expectedAbbreviatedJournalEntry = new BibEntry(StandardEntryType.Article) + .withField(StandardField.JOURNAL, "Physical Review B"); + assertEquals(expectedAbbreviatedJournalEntry, abbreviatedJournalEntry); + } }