From 67748209b2b90dc96f8df4df9135b515a671c381 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Mon, 11 Mar 2024 22:15:17 +0100 Subject: [PATCH] Use SequencedSet for required and optional fields (#11007) --- .../gui/entryeditor/RequiredFieldsTab.java | 2 +- .../CustomEntryTypePreferenceMigration.java | 9 ++--- .../org/jabref/model/entry/BibEntryType.java | 21 ++++++------ .../model/entry/BibEntryTypeBuilder.java | 34 +++++++++++-------- .../jabref/model/entry/EntryConverter.java | 2 +- .../model/entry/field/FieldFactory.java | 5 +-- .../jabref/model/entry/field/OrFields.java | 11 ++++-- .../types/BibtexEntryTypeDefinitions.java | 4 ++- 8 files changed, 52 insertions(+), 36 deletions(-) diff --git a/src/main/java/org/jabref/gui/entryeditor/RequiredFieldsTab.java b/src/main/java/org/jabref/gui/entryeditor/RequiredFieldsTab.java index 9e7d03eae64..a4939e66d79 100644 --- a/src/main/java/org/jabref/gui/entryeditor/RequiredFieldsTab.java +++ b/src/main/java/org/jabref/gui/entryeditor/RequiredFieldsTab.java @@ -58,7 +58,7 @@ protected SequencedSet determineFieldsToShow(BibEntry entry) { for (OrFields orFields : entryType.get().getRequiredFields()) { fields.addAll(orFields.getFields()); } - // Add the edit field for Bibtex-key. + // Add the edit field for BibTeX key (AKA citation key) fields.add(InternalField.KEY_FIELD); } else { // Entry type unknown -> treat all fields as required diff --git a/src/main/java/org/jabref/migrations/CustomEntryTypePreferenceMigration.java b/src/main/java/org/jabref/migrations/CustomEntryTypePreferenceMigration.java index e2973ea207a..59db3eb61dd 100644 --- a/src/main/java/org/jabref/migrations/CustomEntryTypePreferenceMigration.java +++ b/src/main/java/org/jabref/migrations/CustomEntryTypePreferenceMigration.java @@ -1,6 +1,7 @@ package org.jabref.migrations; import java.util.ArrayList; +import java.util.LinkedHashSet; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; @@ -57,18 +58,18 @@ private static Optional getBibEntryType(int number, JabRefPreferen BibEntryTypeBuilder entryTypeBuilder = new BibEntryTypeBuilder() .withType(EntryTypeFactory.parse(name)) - .withRequiredFields(req.stream().map(FieldFactory::parseOrFields).collect(Collectors.toList())); + .withRequiredFields(req.stream().map(FieldFactory::parseOrFields).collect(Collectors.toCollection(LinkedHashSet::new))); if (priOpt.isEmpty()) { entryTypeBuilder = entryTypeBuilder - .withImportantFields(opt.stream().map(FieldFactory::parseField).collect(Collectors.toSet())); + .withImportantFields(opt.stream().map(FieldFactory::parseField).collect(Collectors.toCollection(LinkedHashSet::new))); return Optional.of(entryTypeBuilder.build()); } else { List secondary = new ArrayList<>(opt); secondary.removeAll(priOpt); entryTypeBuilder = entryTypeBuilder - .withImportantFields(priOpt.stream().map(FieldFactory::parseField).collect(Collectors.toSet())) - .withDetailFields(secondary.stream().map(FieldFactory::parseField).collect(Collectors.toSet())); + .withImportantFields(priOpt.stream().map(FieldFactory::parseField).collect(Collectors.toCollection(LinkedHashSet::new))) + .withDetailFields(secondary.stream().map(FieldFactory::parseField).collect(Collectors.toCollection(LinkedHashSet::new))); return Optional.of(entryTypeBuilder.build()); } } diff --git a/src/main/java/org/jabref/model/entry/BibEntryType.java b/src/main/java/org/jabref/model/entry/BibEntryType.java index b58a9e89098..b804d8255e7 100644 --- a/src/main/java/org/jabref/model/entry/BibEntryType.java +++ b/src/main/java/org/jabref/model/entry/BibEntryType.java @@ -2,6 +2,7 @@ import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Objects; import java.util.SequencedSet; @@ -21,8 +22,8 @@ public class BibEntryType implements Comparable { private final EntryType type; - private final LinkedHashSet requiredFields; - private final LinkedHashSet fields; + private final SequencedSet requiredFields; + private final SequencedSet fields; /** * Provides an enriched EntryType with information about defined standards as mandatory fields etc. @@ -43,7 +44,7 @@ public EntryType getType() { return type; } - public Set getOptionalFields() { + public SequencedSet getOptionalFields() { return getAllBibFields().stream() .filter(field -> !isRequired(field.field())) .collect(Collectors.toCollection(LinkedHashSet::new)); @@ -61,15 +62,15 @@ public boolean isRequired(Field field) { * * @return a Set of required field name Strings */ - public Set getRequiredFields() { - return Collections.unmodifiableSet(requiredFields); + public SequencedSet getRequiredFields() { + return Collections.unmodifiableSequencedSet(requiredFields); } /** * Returns all defined fields. */ - public Set getAllBibFields() { - return Collections.unmodifiableSet(fields); + public SequencedSet getAllBibFields() { + return Collections.unmodifiableSequencedSet(fields); } public Set getAllFields() { @@ -90,11 +91,11 @@ public SequencedSet getSecondaryOptionalFields() { .collect(Collectors.toCollection(LinkedHashSet::new)); } - public SequencedSet getDeprecatedFields(BibDatabaseMode mode) { + public Set getDeprecatedFields(BibDatabaseMode mode) { if (mode == BibDatabaseMode.BIBTEX) { - return new LinkedHashSet<>(); + return Set.of(); } - SequencedSet deprecatedFields = new LinkedHashSet<>(EntryConverter.FIELD_ALIASES_BIBTEX_TO_BIBLATEX.keySet()); + Set deprecatedFields = new HashSet<>(EntryConverter.FIELD_ALIASES_BIBTEX_TO_BIBLATEX.keySet()); // Only the optional fields which are mapped to another BibLaTeX name should be shown as "deprecated" deprecatedFields.retainAll(getOptionalFieldsAndAliases()); diff --git a/src/main/java/org/jabref/model/entry/BibEntryTypeBuilder.java b/src/main/java/org/jabref/model/entry/BibEntryTypeBuilder.java index b8613157ac6..91656a6c50d 100644 --- a/src/main/java/org/jabref/model/entry/BibEntryTypeBuilder.java +++ b/src/main/java/org/jabref/model/entry/BibEntryTypeBuilder.java @@ -1,9 +1,9 @@ package org.jabref.model.entry; import java.util.Arrays; -import java.util.Collection; import java.util.LinkedHashSet; -import java.util.List; +import java.util.SequencedCollection; +import java.util.SequencedSet; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -20,29 +20,25 @@ public class BibEntryTypeBuilder { private EntryType type = StandardEntryType.Misc; - private Set fields = new LinkedHashSet<>(); - private Set requiredFields = new LinkedHashSet<>(); + private SequencedSet fields = new LinkedHashSet<>(); + private SequencedSet requiredFields = new LinkedHashSet<>(); public BibEntryTypeBuilder withType(EntryType type) { this.type = type; return this; } - public BibEntryTypeBuilder withImportantFields(Set newFields) { - return withImportantFields(newFields.stream().map(BibField::field).collect(Collectors.toCollection(LinkedHashSet::new))); - } - - public BibEntryTypeBuilder withImportantFields(Collection newFields) { + public BibEntryTypeBuilder withImportantFields(SequencedSet newFields) { this.fields = Streams.concat(fields.stream(), newFields.stream().map(field -> new BibField(field, FieldPriority.IMPORTANT))) .collect(Collectors.toCollection(LinkedHashSet::new)); return this; } public BibEntryTypeBuilder withImportantFields(Field... newFields) { - return withImportantFields(Arrays.asList(newFields)); + return withImportantFields(Arrays.stream(newFields).collect(Collectors.toCollection(LinkedHashSet::new))); } - public BibEntryTypeBuilder withDetailFields(Collection newFields) { + public BibEntryTypeBuilder withDetailFields(SequencedCollection newFields) { this.fields = Streams.concat(fields.stream(), newFields.stream().map(field -> new BibField(field, FieldPriority.DETAIL))) .collect(Collectors.toCollection(LinkedHashSet::new)); return this; @@ -52,11 +48,21 @@ public BibEntryTypeBuilder withDetailFields(Field... fields) { return withDetailFields(Arrays.asList(fields)); } - public BibEntryTypeBuilder withRequiredFields(Set requiredFields) { + public BibEntryTypeBuilder withRequiredFields(SequencedSet requiredFields) { this.requiredFields = requiredFields; return this; } + public BibEntryTypeBuilder addRequiredFields(OrFields... requiredFields) { + this.requiredFields.addAll(Arrays.asList(requiredFields)); + return this; + } + + public BibEntryTypeBuilder addRequiredFields(Field... requiredFields) { + this.requiredFields.addAll(Arrays.stream(requiredFields).map(OrFields::new).toList()); + return this; + } + public BibEntryTypeBuilder withRequiredFields(Field... requiredFields) { this.requiredFields = Arrays.stream(requiredFields).map(OrFields::new).collect(Collectors.toCollection(LinkedHashSet::new)); return this; @@ -67,7 +73,7 @@ public BibEntryTypeBuilder withRequiredFields(OrFields first, Field... requiredF return this; } - public BibEntryTypeBuilder withRequiredFields(List first, Field... requiredFields) { + public BibEntryTypeBuilder withRequiredFields(SequencedSet first, Field... requiredFields) { this.requiredFields = Stream.concat(first.stream(), Arrays.stream(requiredFields).map(OrFields::new)).collect(Collectors.toCollection(LinkedHashSet::new)); return this; } @@ -78,7 +84,7 @@ public BibEntryType build() { .map(OrFields::getFields) .flatMap(Set::stream) .map(field -> new BibField(field, FieldPriority.IMPORTANT)); - Set allFields = Stream.concat(fields.stream(), requiredAsImportant).collect(Collectors.toCollection(LinkedHashSet::new)); + SequencedSet allFields = Stream.concat(fields.stream(), requiredAsImportant).collect(Collectors.toCollection(LinkedHashSet::new)); return new BibEntryType(type, allFields, requiredFields); } } diff --git a/src/main/java/org/jabref/model/entry/EntryConverter.java b/src/main/java/org/jabref/model/entry/EntryConverter.java index 0a6f6621dd9..162afb219d1 100644 --- a/src/main/java/org/jabref/model/entry/EntryConverter.java +++ b/src/main/java/org/jabref/model/entry/EntryConverter.java @@ -8,7 +8,7 @@ import org.jabref.model.entry.field.StandardField; /** - * Converts Entry models from BibTex to biblatex and back. + * Converts Entry models from BibTeX to biblatex and back. */ public class EntryConverter { diff --git a/src/main/java/org/jabref/model/entry/field/FieldFactory.java b/src/main/java/org/jabref/model/entry/field/FieldFactory.java index 645a1295221..5c0a9036d2b 100644 --- a/src/main/java/org/jabref/model/entry/field/FieldFactory.java +++ b/src/main/java/org/jabref/model/entry/field/FieldFactory.java @@ -8,6 +8,7 @@ import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; +import java.util.SequencedSet; import java.util.Set; import java.util.TreeSet; import java.util.function.Predicate; @@ -64,14 +65,14 @@ public static OrFields parseOrFields(String fieldNames) { return new OrFields(fields); } - public static Set parseOrFieldsList(String fieldNames) { + public static SequencedSet parseOrFieldsList(String fieldNames) { return Arrays.stream(fieldNames.split(FieldFactory.DELIMITER)) .filter(StringUtil::isNotBlank) .map(FieldFactory::parseOrFields) .collect(Collectors.toCollection(LinkedHashSet::new)); } - public static Set parseFieldList(String fieldNames) { + public static SequencedSet parseFieldList(String fieldNames) { return Arrays.stream(fieldNames.split(FieldFactory.DELIMITER)) .filter(StringUtil::isNotBlank) .map(FieldFactory::parseField) diff --git a/src/main/java/org/jabref/model/entry/field/OrFields.java b/src/main/java/org/jabref/model/entry/field/OrFields.java index 253a7257cfb..5a49202d718 100644 --- a/src/main/java/org/jabref/model/entry/field/OrFields.java +++ b/src/main/java/org/jabref/model/entry/field/OrFields.java @@ -4,12 +4,17 @@ import java.util.Collection; import java.util.LinkedHashSet; import java.util.Objects; -import java.util.Set; +import java.util.SequencedSet; import java.util.StringJoiner; +/** + * Represents a choice between two (or more) fields or any combination of them. + *

+ * Example is that a BibEntry requires either an author or an editor, but both can be be present. + */ public class OrFields implements Comparable { - private LinkedHashSet fields = new LinkedHashSet<>(); + private SequencedSet fields = new LinkedHashSet<>(); public OrFields(Field field) { fields.add(field); @@ -35,7 +40,7 @@ public Field getPrimary() { return fields.getFirst(); } - public Set getFields() { + public SequencedSet getFields() { return this.fields; } diff --git a/src/main/java/org/jabref/model/entry/types/BibtexEntryTypeDefinitions.java b/src/main/java/org/jabref/model/entry/types/BibtexEntryTypeDefinitions.java index 594301642b7..d2109ebc8d4 100644 --- a/src/main/java/org/jabref/model/entry/types/BibtexEntryTypeDefinitions.java +++ b/src/main/java/org/jabref/model/entry/types/BibtexEntryTypeDefinitions.java @@ -69,7 +69,9 @@ public class BibtexEntryTypeDefinitions { */ private static final BibEntryType INBOOK = new BibEntryTypeBuilder() .withType(StandardEntryType.InBook) - .withRequiredFields(Arrays.asList(new OrFields(StandardField.CHAPTER, StandardField.PAGES), new OrFields(StandardField.AUTHOR, StandardField.EDITOR)), StandardField.TITLE, StandardField.PUBLISHER, StandardField.YEAR) + .addRequiredFields(new OrFields(StandardField.AUTHOR, StandardField.EDITOR)) + .addRequiredFields(StandardField.TITLE, StandardField.PUBLISHER, StandardField.YEAR) + .addRequiredFields(new OrFields(StandardField.CHAPTER, StandardField.PAGES)) .withImportantFields(StandardField.VOLUME, StandardField.NUMBER, StandardField.SERIES, StandardField.TYPE, StandardField.ADDRESS, StandardField.EDITION, StandardField.MONTH, StandardField.ISBN, StandardField.NOTE) .build();