diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c266844ca4..132ec96478b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -125,6 +125,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv - We fixed an issue where "Copy to" was enabled even if no other library was opened. [#13280](https://github.com/JabRef/jabref/pull/13280) - We fixed an issue where the groups were still displayed after closing all libraries. [#13382](https://github.com/JabRef/jabref/issues/13382) - Enhanced field selection logic in the Merge Entries dialog when fetching from DOI to prefer valid years and entry types. [#12549](https://github.com/JabRef/jabref/issues/12549) +- We fixed an issue where opening the Three Way Merge dialog would throw an exception when year field contains an invalid year value. [#13673](https://github.com/JabRef/jabref/issues/13673) - We improved consistency in the Add Buttons. [#13791](https://github.com/JabRef/jabref/pull/13791) - We fixed an issue where theme or font size are not respected for all dialogs [#13558](https://github.com/JabRef/jabref/issues/13558) - We removed unnecessary spacing and margin in the AutomaticFieldEditor. [#13792](https://github.com/JabRef/jabref/pull/13792) diff --git a/jabgui/src/test/java/org/jabref/gui/mergeentries/FieldRowViewModelTest.java b/jabgui/src/test/java/org/jabref/gui/mergeentries/FieldRowViewModelTest.java index f301ebfbcdd..cc0a4179b27 100644 --- a/jabgui/src/test/java/org/jabref/gui/mergeentries/FieldRowViewModelTest.java +++ b/jabgui/src/test/java/org/jabref/gui/mergeentries/FieldRowViewModelTest.java @@ -224,7 +224,7 @@ void newYearShouldBeSelectedForYearsWithLargeValueGap() { } @Test - void yearInRangeShouldBeSelected() { + void selectRightYearWhenInRange() { BibEntry leftEntry = new BibEntry().withField(StandardField.YEAR, "1700"); BibEntry rightEntry = new BibEntry().withField(StandardField.YEAR, "2000"); FieldRowViewModel yearField = new FieldRowViewModel(StandardField.YEAR, leftEntry, rightEntry, mergedEntry, fieldMergerFactory); @@ -232,6 +232,15 @@ void yearInRangeShouldBeSelected() { assertEquals(FieldRowViewModel.Selection.RIGHT, yearField.getSelection()); } + @Test + void selectLeftYearWhenInRange() { + BibEntry leftEntry = new BibEntry().withField(StandardField.YEAR, "2005"); + BibEntry rightEntry = new BibEntry().withField(StandardField.YEAR, "1700"); + FieldRowViewModel yearField = new FieldRowViewModel(StandardField.YEAR, leftEntry, rightEntry, mergedEntry, fieldMergerFactory); + yearField.autoSelectBetterValue(); + assertEquals(FieldRowViewModel.Selection.LEFT, yearField.getSelection()); + } + public FieldRowViewModel createViewModelForField(Field field) { return new FieldRowViewModel(field, leftEntry, rightEntry, mergedEntry, fieldMergerFactory); } diff --git a/jablib/src/main/java/org/jabref/logic/bibtex/comparator/YearFieldValuePlausibilityComparator.java b/jablib/src/main/java/org/jabref/logic/bibtex/comparator/YearFieldValuePlausibilityComparator.java index 5a9b48195ce..c3a941954ba 100644 --- a/jablib/src/main/java/org/jabref/logic/bibtex/comparator/YearFieldValuePlausibilityComparator.java +++ b/jablib/src/main/java/org/jabref/logic/bibtex/comparator/YearFieldValuePlausibilityComparator.java @@ -6,6 +6,7 @@ import java.util.regex.Pattern; import org.jabref.logic.integrity.YearChecker; +import org.jabref.model.strings.StringUtil; public class YearFieldValuePlausibilityComparator extends FieldValuePlausibilityComparator { @@ -21,28 +22,50 @@ public class YearFieldValuePlausibilityComparator extends FieldValuePlausibility @Override public ComparisonResult compare(String leftValue, String rightValue) { - YearChecker checker = new YearChecker(); + boolean isLeftBlank = StringUtil.isBlank(leftValue); + boolean isRightBlank = StringUtil.isBlank(rightValue); + if (isLeftBlank && !isRightBlank) { + return ComparisonResult.RIGHT_BETTER; + } else if (isRightBlank && !isLeftBlank) { + return ComparisonResult.LEFT_BETTER; + } else if (isLeftBlank && isRightBlank) { + return ComparisonResult.UNDETERMINED; + } - boolean leftValid = checker.checkValue(leftValue).isEmpty(); + // left and right values are not blank. - if (leftValid) { - Optional leftYear = extractYear(leftValue); - Optional rightYear = extractYear(rightValue); + boolean leftValueCorrectlyFormatted = YearChecker.isValueCorrectlyFormatted(leftValue); + boolean rightValueCorrectlyFormatted = YearChecker.isValueCorrectlyFormatted(rightValue); + if (leftValueCorrectlyFormatted && !rightValueCorrectlyFormatted) { + return ComparisonResult.LEFT_BETTER; + } else if (rightValueCorrectlyFormatted && !leftValueCorrectlyFormatted) { + return ComparisonResult.RIGHT_BETTER; + } else if (!leftValueCorrectlyFormatted && !rightValueCorrectlyFormatted) { + return ComparisonResult.UNDETERMINED; + } - boolean leftYearInRange = (leftYear.get() >= 1800) && (leftYear.get() <= Year.now().getValue() + 2); + // left and right values are correctly formatted. - if (leftYearInRange) { - int diff = Math.abs(leftYear.get() - rightYear.get()); - if (diff > 10) { - return rightYear.get() > leftYear.get() - ? ComparisonResult.RIGHT_BETTER - : ComparisonResult.LEFT_BETTER; - } - return ComparisonResult.UNDETERMINED; // years are close, undetermined - } + int leftYear = extractYear(leftValue).get(); + int rightYear = extractYear(rightValue).get(); + boolean leftYearInRange = (leftYear >= 1800) && (leftYear <= Year.now().getValue() + 2); + boolean rightYearInRange = (rightYear >= 1800) && (rightYear <= Year.now().getValue() + 2); + if (leftYearInRange && !rightYearInRange) { + return ComparisonResult.LEFT_BETTER; + } else if (rightYearInRange && !leftYearInRange) { return ComparisonResult.RIGHT_BETTER; - } - return ComparisonResult.RIGHT_BETTER; + } else if (!leftYearInRange && !rightYearInRange) { + return ComparisonResult.UNDETERMINED; + } + + int diff = Math.abs(leftYear - rightYear); + if (diff > 10) { + return rightYear > leftYear + ? ComparisonResult.RIGHT_BETTER + : ComparisonResult.LEFT_BETTER; + } + + return ComparisonResult.UNDETERMINED; // years are close, undetermined } /** diff --git a/jablib/src/main/java/org/jabref/logic/integrity/YearChecker.java b/jablib/src/main/java/org/jabref/logic/integrity/YearChecker.java index 3dc98f75d2d..2c756884561 100644 --- a/jablib/src/main/java/org/jabref/logic/integrity/YearChecker.java +++ b/jablib/src/main/java/org/jabref/logic/integrity/YearChecker.java @@ -9,8 +9,7 @@ public class YearChecker implements ValueChecker { - private static final Predicate CONTAINS_FOUR_DIGIT = Pattern.compile("([^0-9]|^)[0-9]{4}([^0-9]|$)") - .asPredicate(); + private static final Predicate CONTAINS_FOUR_DIGIT = Pattern.compile("([^0-9]|^)[0-9]{4}([^0-9]|$)").asPredicate(); private static final Predicate ENDS_WITH_FOUR_DIGIT = Pattern.compile("[0-9]{4}$").asPredicate(); private static final String PUNCTUATION_MARKS = "[(){},.;!?<>%&$]"; @@ -37,4 +36,16 @@ public Optional checkValue(String value) { return Optional.empty(); } + + public static boolean isValueCorrectlyFormatted(String value) { + if (StringUtil.isBlank(value)) { + return false; + } + + if (!CONTAINS_FOUR_DIGIT.test(value.trim())) { + return false; + } + + return ENDS_WITH_FOUR_DIGIT.test(value.replaceAll(PUNCTUATION_MARKS, "")); + } }