content = entry.getResolvedFieldOrAliasLatexFree(field, bibDatabase);
+
+ if (content.isPresent()) {
+ return content.get();
+ }
+ }
+ }
+ return "";
+ }
+
+ /**
+ * Format a name field for the table, according to user preferences and with latex expressions translated if
+ * possible.
+ *
+ * @param nameToFormat The contents of the name field.
+ * @return The formatted name field.
+ */
+ private String formatFieldWithAuthorValue(final String nameToFormat) {
+ if (nameToFormat == null) {
+ return null;
+ }
+
+ AuthorList authors = AuthorList.parse(nameToFormat);
+
+ if (((displayStyle == DisplayStyle.FIRSTNAME_LASTNAME)
+ || (displayStyle == DisplayStyle.LASTNAME_FIRSTNAME))
+ && abbreviationStyle == AbbreviationStyle.LASTNAME_ONLY) {
+ return authors.getAsLastNamesLatexFree(false);
+ }
+
+ return switch (displayStyle) {
+ default -> nameToFormat;
+ case FIRSTNAME_LASTNAME -> authors.getAsFirstLastNamesLatexFree(
+ abbreviationStyle == AbbreviationStyle.FULL,
+ false);
+ case LASTNAME_FIRSTNAME -> authors.getAsLastFirstNamesLatexFree(
+ abbreviationStyle == AbbreviationStyle.FULL,
+ false);
+ case NATBIB -> authors.getAsNatbibLatexFree();
+ };
+ }
+}
diff --git a/src/main/java/org/jabref/gui/maintable/MainTableNameFormatter.java b/src/main/java/org/jabref/gui/maintable/MainTableNameFormatter.java
deleted file mode 100644
index 06766cdecbe..00000000000
--- a/src/main/java/org/jabref/gui/maintable/MainTableNameFormatter.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package org.jabref.gui.maintable;
-
-import org.jabref.model.entry.AuthorList;
-import org.jabref.preferences.PreferencesService;
-
-public class MainTableNameFormatter {
-
- private final PreferencesService preferencesService;
-
- MainTableNameFormatter(PreferencesService preferences) {
- this.preferencesService = preferences;
- }
-
- /**
- * Format a name field for the table, according to user preferences and with latex expressions translated if
- * possible.
- *
- * @param nameToFormat The contents of the name field.
- * @return The formatted name field.
- */
- public String formatNameLatexFree(final String nameToFormat) {
- if (nameToFormat == null) {
- return null;
- }
-
- MainTableNameFormatPreferences nameFormatPreferences = preferencesService.getMainTableNameFormatPreferences();
- MainTableNameFormatPreferences.DisplayStyle displayStyle = nameFormatPreferences.getDisplayStyle();
- MainTableNameFormatPreferences.AbbreviationStyle abbreviationStyle = nameFormatPreferences.getAbbreviationStyle();
-
- AuthorList authors = AuthorList.parse(nameToFormat);
-
- if (((displayStyle == MainTableNameFormatPreferences.DisplayStyle.FIRSTNAME_LASTNAME)
- || (displayStyle == MainTableNameFormatPreferences.DisplayStyle.LASTNAME_FIRSTNAME))
- && abbreviationStyle == MainTableNameFormatPreferences.AbbreviationStyle.LASTNAME_ONLY) {
- return authors.getAsLastNamesLatexFree(false);
- }
-
- switch (nameFormatPreferences.getDisplayStyle()) {
- case AS_IS:
- return nameToFormat;
- case NATBIB:
- return authors.getAsNatbibLatexFree();
- case FIRSTNAME_LASTNAME:
- return authors.getAsFirstLastNamesLatexFree(
- abbreviationStyle == MainTableNameFormatPreferences.AbbreviationStyle.FULL,
- false);
- default:
- case LASTNAME_FIRSTNAME:
- return authors.getAsLastFirstNamesLatexFree(
- abbreviationStyle == MainTableNameFormatPreferences.AbbreviationStyle.FULL,
- false);
- }
- }
-}
diff --git a/src/main/java/org/jabref/model/entry/Author.java b/src/main/java/org/jabref/model/entry/Author.java
index 32be4e9ce96..b325a3fa92f 100644
--- a/src/main/java/org/jabref/model/entry/Author.java
+++ b/src/main/java/org/jabref/model/entry/Author.java
@@ -146,8 +146,8 @@ public int hashCode() {
/**
* Compare this object with the given one.
- *
- * Will return true iff the other object is an Author and all fields are identical on a string comparison.
+ *
+ * @return `true` iff the other object is an Author and all fields are `Objects.equals`.
*/
@Override
public boolean equals(Object other) {
diff --git a/src/main/java/org/jabref/model/entry/AuthorList.java b/src/main/java/org/jabref/model/entry/AuthorList.java
index b617b792632..4f2467da8f9 100644
--- a/src/main/java/org/jabref/model/entry/AuthorList.java
+++ b/src/main/java/org/jabref/model/entry/AuthorList.java
@@ -1,12 +1,8 @@
package org.jabref.model.entry;
import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
import java.util.Collections;
-import java.util.HashSet;
import java.util.List;
-import java.util.Locale;
import java.util.Objects;
import java.util.WeakHashMap;
import java.util.stream.Collectors;
@@ -123,8 +119,6 @@
public class AuthorList {
private static final WeakHashMap AUTHOR_CACHE = new WeakHashMap<>();
- // Avoid partition where these values are contained
- private final static Collection AVOID_TERMS_IN_LOWER_CASE = Arrays.asList("jr", "sr", "jnr", "snr", "von", "zu", "van", "der");
private final List authors;
private final String[] authorsFirstFirst = new String[4];
private final String[] authorsFirstFirstLatexFree = new String[4];
@@ -157,7 +151,7 @@ protected AuthorList(Author author) {
}
public AuthorList() {
- this(new ArrayList());
+ this(new ArrayList<>());
}
/**
@@ -168,53 +162,9 @@ public AuthorList() {
* @param authors The string of authors or editors in bibtex format to parse.
* @return An AuthorList object representing the given authors.
*/
- public static AuthorList parse(String authors) {
+ public static AuthorList parse(final String authors) {
Objects.requireNonNull(authors);
- // Handle case names in order lastname, firstname and separated by ","
- // E.g., Ali Babar, M., Dingsøyr, T., Lago, P., van der Vliet, H.
- final boolean authorsContainAND = authors.toUpperCase(Locale.ENGLISH).contains(" AND ");
- final boolean authorsContainOpeningBrace = authors.contains("{");
- final boolean authorsContainSemicolon = authors.contains(";");
- final boolean authorsContainTwoOrMoreCommas = (authors.length() - authors.replace(",", "").length()) >= 2;
- if (!authorsContainAND && !authorsContainOpeningBrace && !authorsContainSemicolon && authorsContainTwoOrMoreCommas) {
- List arrayNameList = Arrays.asList(authors.split(","));
-
- // Delete spaces for correct case identification
- arrayNameList.replaceAll(String::trim);
-
- // Looking for space between pre- and lastname
- boolean spaceInAllParts = arrayNameList.stream().filter(name -> name.contains(" ")).collect(Collectors
- .toList()).size() == arrayNameList.size();
-
- // We hit the comma name separator case
- // Usually the getAsLastFirstNamesWithAnd method would separate them if pre- and lastname are separated with "and"
- // If not, we check if spaces separate pre- and lastname
- if (spaceInAllParts) {
- authors = authors.replaceAll(",", " and");
- } else {
- // Looking for name affixes to avoid
- // arrayNameList needs to reduce by the count off avoiding terms
- // valuePartsCount holds the count of name parts without the avoided terms
-
- int valuePartsCount = arrayNameList.size();
- // Holds the index of each term which needs to be avoided
- Collection avoidIndex = new HashSet<>();
-
- for (int i = 0; i < arrayNameList.size(); i++) {
- if (AVOID_TERMS_IN_LOWER_CASE.contains(arrayNameList.get(i).toLowerCase(Locale.ROOT))) {
- avoidIndex.add(i);
- valuePartsCount--;
- }
- }
-
- if ((valuePartsCount % 2) == 0) {
- // We hit the described special case with name affix like Jr
- authors = buildWithAffix(avoidIndex, arrayNameList).toString();
- }
- }
- }
-
AuthorList authorList = AUTHOR_CACHE.get(authors);
if (authorList == null) {
AuthorListParser parser = new AuthorListParser();
@@ -296,37 +246,6 @@ public static String fixAuthorNatbib(String authors) {
return AuthorList.parse(authors).getAsNatbib();
}
- /**
- * Builds a new array of strings with stringbuilder.
- * Regarding to the name affixes.
- *
- * @return New string with correct seperation
- */
- private static StringBuilder buildWithAffix(Collection indexArray, List nameList) {
- StringBuilder stringBuilder = new StringBuilder();
- // avoidedTimes needs to be increased by the count of avoided terms for correct odd/even calculation
- int avoidedTimes = 0;
- for (int i = 0; i < nameList.size(); i++) {
- if (indexArray.contains(i)) {
- // We hit a name affix
- stringBuilder.append(nameList.get(i));
- stringBuilder.append(',');
- avoidedTimes++;
- } else {
- stringBuilder.append(nameList.get(i));
- if (((i + avoidedTimes) % 2) == 0) {
- // Hit separation between last name and firstname --> comma has to be kept
- stringBuilder.append(',');
- } else {
- // Hit separation between full names (e.g., Ali Babar, M. and Dingsøyr, T.) --> semicolon has to be used
- // Will be treated correctly by AuthorList.parse(authors);
- stringBuilder.append(';');
- }
- }
- }
- return stringBuilder;
- }
-
/**
* Returns the number of author names in this object.
*
@@ -647,10 +566,14 @@ public String getAsFirstLastNamesLatexFree(boolean abbreviate, boolean oxfordCom
/**
* Compare this object with the given one.
*
- * Will return true iff the other object is an Author and all fields are identical on a string comparison.
+ * @return `true` iff the other object is an AuthorList, all contained authors are in the same order (and these
+ * authors' fields are `Objects.equals`)
*/
@Override
public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
if (!(o instanceof AuthorList)) {
return false;
}
diff --git a/src/main/java/org/jabref/model/entry/AuthorListParser.java b/src/main/java/org/jabref/model/entry/AuthorListParser.java
index d584868f17c..eca4ee598e9 100644
--- a/src/main/java/org/jabref/model/entry/AuthorListParser.java
+++ b/src/main/java/org/jabref/model/entry/AuthorListParser.java
@@ -1,6 +1,8 @@
package org.jabref.model.entry;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
@@ -10,6 +12,10 @@
public class AuthorListParser {
+ // Avoid partition where these values are contained
+ private final static Set AVOID_TERMS_IN_LOWER_CASE = Set.of(
+ "jr", "sr", "jnr", "snr", "von", "zu", "van", "der");
+
private static final int TOKEN_GROUP_LENGTH = 4; // number of entries for a token
// the following are offsets of an entry in a group of entries for one token
@@ -21,31 +27,16 @@ public class AuthorListParser {
// "-") comma)
// Token types (returned by getToken procedure)
- private static final int TOKEN_EOF = 0;
-
- private static final int TOKEN_AND = 1;
-
- private static final int TOKEN_COMMA = 2;
-
- private static final int TOKEN_WORD = 3;
+ private enum Token {
+ EOF,
+ AND,
+ COMMA,
+ WORD
+ }
// Constant HashSet containing names of TeX special characters
- private static final Set TEX_NAMES = new HashSet<>();
-
- static {
- TEX_NAMES.add("aa");
- TEX_NAMES.add("ae");
- TEX_NAMES.add("l");
- TEX_NAMES.add("o");
- TEX_NAMES.add("oe");
- TEX_NAMES.add("i");
- TEX_NAMES.add("AA");
- TEX_NAMES.add("AE");
- TEX_NAMES.add("L");
- TEX_NAMES.add("O");
- TEX_NAMES.add("OE");
- TEX_NAMES.add("j");
- }
+ private static final Set TEX_NAMES = Set.of(
+ "aa", "ae", "l", "o", "oe", "i", "AA", "AE", "L", "O", "OE", "j");
/**
* the raw bibtex author/editor field
@@ -61,7 +52,7 @@ public class AuthorListParser {
private int tokenEnd;
/**
* end of token abbreviation (always: tokenStart < tokenAbbrEnd <= tokenEnd), only valid if getToken returns
- * TOKEN_WORD
+ * Token.WORD
*/
private int tokenAbbrEnd;
/**
@@ -82,6 +73,50 @@ public class AuthorListParser {
public AuthorList parse(String listOfNames) {
Objects.requireNonNull(listOfNames);
+ // Handle case names in order lastname, firstname and separated by ","
+ // E.g., Ali Babar, M., Dingsøyr, T., Lago, P., van der Vliet, H.
+ final boolean authorsContainAND = listOfNames.toUpperCase(Locale.ENGLISH).contains(" AND ");
+ final boolean authorsContainOpeningBrace = listOfNames.contains("{");
+ final boolean authorsContainSemicolon = listOfNames.contains(";");
+ final boolean authorsContainTwoOrMoreCommas = (listOfNames.length() - listOfNames.replace(",", "").length()) >= 2;
+ if (!authorsContainAND && !authorsContainOpeningBrace && !authorsContainSemicolon && authorsContainTwoOrMoreCommas) {
+ List arrayNameList = Arrays.asList(listOfNames.split(","));
+
+ // Delete spaces for correct case identification
+ arrayNameList.replaceAll(String::trim);
+
+ // Looking for space between pre- and lastname
+ boolean spaceInAllParts = arrayNameList.stream().filter(name -> name.contains(" "))
+ .count() == arrayNameList.size();
+
+ // We hit the comma name separator case
+ // Usually the getAsLastFirstNamesWithAnd method would separate them if pre- and lastname are separated with "and"
+ // If not, we check if spaces separate pre- and lastname
+ if (spaceInAllParts) {
+ listOfNames = listOfNames.replaceAll(",", " and");
+ } else {
+ // Looking for name affixes to avoid
+ // arrayNameList needs to reduce by the count off avoiding terms
+ // valuePartsCount holds the count of name parts without the avoided terms
+
+ int valuePartsCount = arrayNameList.size();
+ // Holds the index of each term which needs to be avoided
+ Collection avoidIndex = new HashSet<>();
+
+ for (int i = 0; i < arrayNameList.size(); i++) {
+ if (AVOID_TERMS_IN_LOWER_CASE.contains(arrayNameList.get(i).toLowerCase(Locale.ROOT))) {
+ avoidIndex.add(i);
+ valuePartsCount--;
+ }
+ }
+
+ if ((valuePartsCount % 2) == 0) {
+ // We hit the described special case with name affix like Jr
+ listOfNames = buildWithAffix(avoidIndex, arrayNameList).toString();
+ }
+ }
+ }
+
// initialization of parser
original = listOfNames;
tokenStart = 0;
@@ -95,6 +130,37 @@ public AuthorList parse(String listOfNames) {
return new AuthorList(authors);
}
+ /**
+ * Builds a new array of strings with stringbuilder.
+ * Regarding to the name affixes.
+ *
+ * @return New string with correct seperation
+ */
+ private static StringBuilder buildWithAffix(Collection indexArray, List nameList) {
+ StringBuilder stringBuilder = new StringBuilder();
+ // avoidedTimes needs to be increased by the count of avoided terms for correct odd/even calculation
+ int avoidedTimes = 0;
+ for (int i = 0; i < nameList.size(); i++) {
+ if (indexArray.contains(i)) {
+ // We hit a name affix
+ stringBuilder.append(nameList.get(i));
+ stringBuilder.append(',');
+ avoidedTimes++;
+ } else {
+ stringBuilder.append(nameList.get(i));
+ if (((i + avoidedTimes) % 2) == 0) {
+ // Hit separation between last name and firstname --> comma has to be kept
+ stringBuilder.append(',');
+ } else {
+ // Hit separation between full names (e.g., Ali Babar, M. and Dingsøyr, T.) --> semicolon has to be used
+ // Will be treated correctly by AuthorList.parse(authors);
+ stringBuilder.append(';');
+ }
+ }
+ }
+ return stringBuilder;
+ }
+
/**
* Parses one author name and returns preformatted information.
*
@@ -111,20 +177,20 @@ private Optional getAuthor() {
// First step: collect tokens in 'tokens' Vector and calculate indices
boolean continueLoop = true;
while (continueLoop) {
- int token = getToken();
+ Token token = getToken();
switch (token) {
- case TOKEN_EOF:
- case TOKEN_AND:
+ case EOF:
+ case AND:
continueLoop = false;
break;
- case TOKEN_COMMA:
+ case COMMA:
if (commaFirst < 0) {
commaFirst = tokens.size();
} else if (commaSecond < 0) {
commaSecond = tokens.size();
}
break;
- case TOKEN_WORD:
+ case WORD:
tokens.add(original.substring(tokenStart, tokenEnd));
tokens.add(original.substring(tokenStart, tokenAbbrEnd));
tokens.add(tokenTerm);
@@ -305,31 +371,31 @@ private String concatTokens(List