diff --git a/src/main/java/org/jabref/gui/DragAndDropDataFormats.java b/src/main/java/org/jabref/gui/DragAndDropDataFormats.java index 8b658a1655e..4ab27396efa 100644 --- a/src/main/java/org/jabref/gui/DragAndDropDataFormats.java +++ b/src/main/java/org/jabref/gui/DragAndDropDataFormats.java @@ -11,6 +11,7 @@ */ public class DragAndDropDataFormats { + public static final DataFormat FIELD = new DataFormat("dnd/org.jabref.model.entry.field.Field"); public static final DataFormat GROUP = new DataFormat("dnd/org.jabref.model.groups.GroupTreeNode"); public static final DataFormat LINKED_FILE = new DataFormat("dnd/org.jabref.model.entry.LinkedFile"); public static final DataFormat ENTRIES = new DataFormat("dnd/org.jabref.model.entry.BibEntries"); diff --git a/src/main/java/org/jabref/gui/customentrytypes/CustomEntryTypeDialogViewModel.java b/src/main/java/org/jabref/gui/customentrytypes/CustomEntryTypeDialogViewModel.java index 86ecc9980b3..2e91b67a4b7 100644 --- a/src/main/java/org/jabref/gui/customentrytypes/CustomEntryTypeDialogViewModel.java +++ b/src/main/java/org/jabref/gui/customentrytypes/CustomEntryTypeDialogViewModel.java @@ -3,16 +3,12 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.function.Predicate; import java.util.stream.Collectors; import javafx.beans.Observable; -import javafx.beans.property.ListProperty; import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleListProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; @@ -34,7 +30,6 @@ import org.jabref.model.entry.types.UnknownEntryType; import org.jabref.preferences.PreferencesService; -import com.tobiasdiez.easybind.EasyBind; import de.saxsys.mvvmfx.utils.validation.FunctionBasedValidator; import de.saxsys.mvvmfx.utils.validation.ValidationMessage; import de.saxsys.mvvmfx.utils.validation.ValidationStatus; @@ -55,18 +50,14 @@ public Field fromString(String string) { } }; - private final ListProperty entryTypes; - private final ListProperty fields; - private final ObjectProperty selectedEntryTypes = new SimpleObjectProperty<>(); - private final ListProperty fieldsForType; + private final ObservableList fieldsForAdding = FXCollections.observableArrayList(FieldFactory.getStandardFielsdsWithBibTexKey()); + private final ObjectProperty selectedEntryType = new SimpleObjectProperty<>(); private final ObjectProperty selectedFieldToAdd = new SimpleObjectProperty<>(); private final StringProperty entryTypeToAdd = new SimpleStringProperty(""); - private final ObservableList allEntryTypes; - private final ObservableList allFieldsForType = FXCollections.observableArrayList(extractor -> new Observable[] {extractor.fieldName(), extractor.fieldType()}); private final ObjectProperty newFieldToAdd = new SimpleObjectProperty<>(); private final BibDatabaseMode mode; - private final Map> typesWithFields = new HashMap<>(); - private final List typesToRemove = new ArrayList<>(); + private final ObservableList entryTypesWithFields = FXCollections.observableArrayList(extractor -> new Observable[] {extractor.entryType(), extractor.fields()}); + private final List entryTypesToDelete = new ArrayList<>(); private final PreferencesService preferencesService; private final BibEntryTypesManager entryTypesManager; @@ -79,40 +70,33 @@ public CustomEntryTypeDialogViewModel(BibDatabaseMode mode, PreferencesService p this.preferencesService = preferencesService; this.entryTypesManager = entryTypesManager; - Collection allTypes = entryTypesManager.getAllTypes(mode); - allTypes.addAll(entryTypesManager.getAllCustomTypes(mode)); + addAllTypes(); - allEntryTypes = FXCollections.observableArrayList(allTypes); - entryTypes = new SimpleListProperty<>(allEntryTypes); + Predicate notEmpty = input -> (input != null) && !input.trim().isEmpty(); + entryTypeValidator = new FunctionBasedValidator<>(entryTypeToAdd, notEmpty, ValidationMessage.error(Localization.lang("Entry type cannot be empty. Please enter a name."))); + fieldValidator = new FunctionBasedValidator<>(newFieldToAdd, + input -> (input != null) && !input.getDisplayName().isEmpty(), + ValidationMessage.error(Localization.lang("Field cannot be empty. Please enter a name."))); + } - fields = new SimpleListProperty<>(FXCollections.observableArrayList(FieldFactory.getCommonFields())); + public void addAllTypes() { + if (this.entryTypesWithFields.size() > 0) { + this.entryTypesWithFields.clear(); + } + Collection allTypes = entryTypesManager.getAllTypes(mode); for (BibEntryType entryType : allTypes) { - List fields = entryType.getAllFields().stream().map(bibField -> new FieldViewModel(bibField.getField(), entryType.isRequired(bibField.getField()), bibField.getPriority(), entryType)).collect(Collectors.toList()); - typesWithFields.put(entryType, fields); + CustomEntryTypeViewModel viewModel = new CustomEntryTypeViewModel(entryType); + this.entryTypesWithFields.add(viewModel); } - - this.fieldsForType = new SimpleListProperty<>(allFieldsForType); - - EasyBind.subscribe(selectedEntryTypes, type -> { - if (type != null) { - allFieldsForType.setAll(typesWithFields.get(type)); - } - }); - - Predicate notEmpty = input -> (input != null) && !input.trim().isEmpty(); - entryTypeValidator = new FunctionBasedValidator<>(entryTypeToAdd, notEmpty, ValidationMessage.error(Localization.lang("Entry type cannot be empty. Please enter a name."))); - fieldValidator = new FunctionBasedValidator<>(newFieldToAdd, - input -> input != null && !input.getDisplayName().isEmpty(), - ValidationMessage.error(Localization.lang("Field cannot be empty. Please enter a name."))); } - public ListProperty entryTypes() { - return this.entryTypes; + public ObservableList entryTypes() { + return this.entryTypesWithFields; } - public ListProperty fields() { - return this.fields; + public ObservableList fieldsForAdding() { + return this.fieldsForAdding; } public enum FieldType { @@ -138,26 +122,23 @@ public String toString() { public void addNewField() { Field field = newFieldToAdd.getValue(); - FieldViewModel model = new FieldViewModel(field, true, FieldPriority.IMPORTANT, selectedEntryTypes.getValue()); - typesWithFields.computeIfAbsent(selectedEntryTypes.getValue(), key -> new ArrayList<>()).add(model); - allFieldsForType.add(model); + FieldViewModel model = new FieldViewModel(field, true, FieldPriority.IMPORTANT); + this.selectedEntryType.getValue().addField(model); newFieldToAddProperty().setValue(null); } - public void addNewCustomEntryType() { + public CustomEntryTypeViewModel addNewCustomEntryType() { EntryType newentryType = new UnknownEntryType(entryTypeToAdd.getValue()); BibEntryType type = new BibEntryType(newentryType, new ArrayList<>(), Collections.emptyList()); - this.allEntryTypes.add(type); + CustomEntryTypeViewModel viewModel = new CustomEntryTypeViewModel(type); + this.entryTypesWithFields.add(viewModel); this.entryTypeToAdd.setValue(""); - this.typesWithFields.put(type, new ArrayList<>()); - } - public ObjectProperty selectedEntryTypeProperty() { - return this.selectedEntryTypes; + return viewModel; } - public ListProperty fieldsforTypesProperty() { - return this.fieldsForType; + public ObjectProperty selectedEntryTypeProperty() { + return this.selectedEntryType; } public ObjectProperty selectedFieldToAddProperty() { @@ -180,22 +161,27 @@ public ValidationStatus fieldValidationStatus() { return fieldValidator.getValidationStatus(); } - public void removeEntryType(BibEntryType focusedItem) { - typesToRemove.add(focusedItem); - typesWithFields.remove(focusedItem); - allEntryTypes.remove(focusedItem); + public void removeEntryType(CustomEntryTypeViewModel focusedItem) { + entryTypesWithFields.remove(focusedItem); + entryTypesToDelete.add(focusedItem.entryType().getValue()); } public void removeField(FieldViewModel focusedItem) { - typesWithFields.computeIfAbsent(selectedEntryTypes.getValue(), key -> new ArrayList<>()).remove(focusedItem); - allFieldsForType.remove(focusedItem); + selectedEntryType.getValue().removeField(focusedItem); + } + + public void resetAllCustomEntryTypes() { + entryTypesManager.clearAllCustomEntryTypes(mode); + preferencesService.clearBibEntryTypes(mode); + entryTypesManager.addCustomOrModifiedTypes(preferencesService.loadBibEntryTypes(BibDatabaseMode.BIBTEX), + preferencesService.loadBibEntryTypes(BibDatabaseMode.BIBLATEX)); } public void apply() { - for (var typeWithField : typesWithFields.entrySet()) { - BibEntryType type = typeWithField.getKey(); - List allFields = typeWithField.getValue(); + for (var typeWithField : entryTypesWithFields) { + BibEntryType type = typeWithField.entryType().getValue(); + List allFields = typeWithField.fields(); List requiredFields = allFields.stream().filter(field -> field.getFieldType() == FieldType.REQUIRED).map(FieldViewModel::getField).map(OrFields::new).collect(Collectors.toList()); List otherFields = allFields.stream().filter(field -> field.getFieldType() == FieldType.OPTIONAL).map(bibField -> new BibField(bibField.getField(), bibField.getFieldPriority())).collect(Collectors.toList()); @@ -204,13 +190,13 @@ public void apply() { entryTypesManager.addCustomOrModifiedType(newType, mode); } - for (var type : typesToRemove) { - entryTypesManager.removeCustomOrModifiedEntryType(type, mode); + for (var entryType : entryTypesToDelete) { + entryTypesManager.removeCustomOrModifiedEntryType(entryType, mode); } - preferencesService.saveCustomEntryTypes(); + + preferencesService.saveCustomEntryTypes(entryTypesManager); // Reload types from preferences to make sure any modifications are present when reopening the dialog - entryTypesManager.addCustomOrModifiedTypes( - preferencesService.loadBibEntryTypes(BibDatabaseMode.BIBTEX), - preferencesService.loadBibEntryTypes(BibDatabaseMode.BIBLATEX)); + entryTypesManager.addCustomOrModifiedTypes(preferencesService.loadBibEntryTypes(BibDatabaseMode.BIBTEX), + preferencesService.loadBibEntryTypes(BibDatabaseMode.BIBLATEX)); } } diff --git a/src/main/java/org/jabref/gui/customentrytypes/CustomEntryTypeViewModel.java b/src/main/java/org/jabref/gui/customentrytypes/CustomEntryTypeViewModel.java new file mode 100644 index 00000000000..4c9de9f9416 --- /dev/null +++ b/src/main/java/org/jabref/gui/customentrytypes/CustomEntryTypeViewModel.java @@ -0,0 +1,64 @@ +package org.jabref.gui.customentrytypes; + +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; + +import org.jabref.model.entry.BibEntryType; + +public class CustomEntryTypeViewModel { + + private final ObjectProperty entryType = new SimpleObjectProperty<>(); + private final ObservableList fields; + + public CustomEntryTypeViewModel(BibEntryType entryType) { + this.entryType.set(entryType); + + List allFieldsForType = entryType.getAllBibFields().stream().map(bibField -> new FieldViewModel(bibField.getField(), entryType.isRequired(bibField.getField()), bibField.getPriority())).collect(Collectors.toList()); + fields = FXCollections.observableArrayList((allFieldsForType)); + } + + @Override + public int hashCode() { + return Objects.hash(entryType, fields); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof CustomEntryTypeViewModel)) { + return false; + } + CustomEntryTypeViewModel other = (CustomEntryTypeViewModel) obj; + return Objects.equals(entryType, other.entryType) && Objects.equals(fields, other.fields); + } + + public void addField(FieldViewModel field) { + this.fields.add(field); + } + + public ObservableList fields() { + return this.fields; + } + + public ObjectProperty entryType() { + return this.entryType; + } + + public void removeField(FieldViewModel focusedItem) { + this.fields.remove(focusedItem); + } + + @Override + public String toString() { + return "CustomEntryTypeViewModel [entryType=" + entryType + ", fields=" + fields + "]"; + } + +} diff --git a/src/main/java/org/jabref/gui/customentrytypes/CustomizeEntryTypeDialog.fxml b/src/main/java/org/jabref/gui/customentrytypes/CustomizeEntryTypeDialog.fxml index 8e45dc99d80..700338d89af 100644 --- a/src/main/java/org/jabref/gui/customentrytypes/CustomizeEntryTypeDialog.fxml +++ b/src/main/java/org/jabref/gui/customentrytypes/CustomizeEntryTypeDialog.fxml @@ -96,4 +96,5 @@ + diff --git a/src/main/java/org/jabref/gui/customentrytypes/CustomizeEntryTypeDialogView.java b/src/main/java/org/jabref/gui/customentrytypes/CustomizeEntryTypeDialogView.java index 0996859bcab..38ecf48af78 100644 --- a/src/main/java/org/jabref/gui/customentrytypes/CustomizeEntryTypeDialogView.java +++ b/src/main/java/org/jabref/gui/customentrytypes/CustomizeEntryTypeDialogView.java @@ -6,29 +6,42 @@ import javafx.application.Platform; import javafx.beans.property.ReadOnlyStringWrapper; +import javafx.collections.ObservableList; import javafx.fxml.FXML; import javafx.scene.control.Button; import javafx.scene.control.ButtonBar.ButtonData; import javafx.scene.control.ButtonType; import javafx.scene.control.ComboBox; import javafx.scene.control.TableColumn; +import javafx.scene.control.TableRow; import javafx.scene.control.TableView; import javafx.scene.control.TextField; - +import javafx.scene.input.ClipboardContent; +import javafx.scene.input.DragEvent; +import javafx.scene.input.Dragboard; +import javafx.scene.input.MouseEvent; +import javafx.scene.input.TransferMode; + +import org.jabref.gui.DialogService; +import org.jabref.gui.DragAndDropDataFormats; +import org.jabref.gui.StateManager; import org.jabref.gui.customentrytypes.CustomEntryTypeDialogViewModel.FieldType; import org.jabref.gui.icon.IconTheme; import org.jabref.gui.util.BaseDialog; +import org.jabref.gui.util.ControlHelper; +import org.jabref.gui.util.CustomLocalDragboard; import org.jabref.gui.util.RadioButtonCell; import org.jabref.gui.util.ValueTableCellFactory; +import org.jabref.gui.util.ViewModelTableRowFactory; import org.jabref.logic.l10n.Localization; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.database.BibDatabaseMode; -import org.jabref.model.entry.BibEntryType; import org.jabref.model.entry.BibEntryTypesManager; import org.jabref.model.entry.field.Field; import org.jabref.preferences.PreferencesService; import com.airhacks.afterburner.views.ViewLoader; +import com.tobiasdiez.easybind.EasyBind; import de.saxsys.mvvmfx.utils.validation.visualization.ControlsFxVisualizer; public class CustomizeEntryTypeDialogView extends BaseDialog { @@ -36,9 +49,9 @@ public class CustomizeEntryTypeDialogView extends BaseDialog { private final BibDatabaseMode mode; private final BibEntryTypesManager entryTypesManager; - @FXML private TableView entryTypes; - @FXML private TableColumn entryTypColumn; - @FXML private TableColumn entryTypeActionsColumn; + @FXML private TableView entryTypes; + @FXML private TableColumn entryTypColumn; + @FXML private TableColumn entryTypeActionsColumn; @FXML private TextField addNewEntryType; @FXML private TableView fields; @FXML private TableColumn fieldNameColumn; @@ -46,13 +59,18 @@ public class CustomizeEntryTypeDialogView extends BaseDialog { @FXML private TableColumn fieldTypeActionColumn; @FXML private ComboBox addNewField; @FXML private ButtonType applyButton; + @FXML private ButtonType resetButton; @FXML private Button addNewEntryTypeButton; @FXML private Button addNewFieldButton; + @Inject private PreferencesService preferencesService; + @Inject private StateManager stateManager; + @Inject private DialogService dialogService; private CustomEntryTypeDialogViewModel viewModel; private final ControlsFxVisualizer visualizer = new ControlsFxVisualizer(); + private CustomLocalDragboard localDragboard; public CustomizeEntryTypeDialogView(BibDatabaseContext bibDatabaseContext, BibEntryTypesManager entryTypesManager) { this.mode = bibDatabaseContext.getMode(); @@ -68,10 +86,14 @@ public CustomizeEntryTypeDialogView(BibDatabaseContext bibDatabaseContext, BibEn } return null; }); + ControlHelper.setAction(resetButton, getDialogPane(), event -> this.resetEntryTypes()); } @FXML private void initialize() { + // As the state manager gets injected it's not available in the constructor + this.localDragboard = stateManager.getLocalDragboard(); + viewModel = new CustomEntryTypeDialogViewModel(mode, preferencesService, entryTypesManager); setupTable(); @@ -88,14 +110,14 @@ private void setupTable() { // Table View must be editable, otherwise the change of the Radiobuttons does not propagate the commit event fields.setEditable(true); - entryTypColumn.setCellValueFactory(cellData -> new ReadOnlyStringWrapper(cellData.getValue().getType().getDisplayName())); - entryTypes.itemsProperty().bind(viewModel.entryTypes()); + entryTypColumn.setCellValueFactory(cellData -> new ReadOnlyStringWrapper(cellData.getValue().entryType().get().getType().getDisplayName())); + entryTypes.setItems(viewModel.entryTypes()); entryTypes.getSelectionModel().selectFirst(); entryTypeActionsColumn.setSortable(false); entryTypeActionsColumn.setReorderable(false); - entryTypeActionsColumn.setCellValueFactory(cellData -> new ReadOnlyStringWrapper(cellData.getValue().getType().getDisplayName())); - new ValueTableCellFactory() + entryTypeActionsColumn.setCellValueFactory(cellData -> new ReadOnlyStringWrapper(cellData.getValue().entryType().get().getType().getDisplayName())); + new ValueTableCellFactory() .withGraphic(item -> IconTheme.JabRefIcons.DELETE_ENTRY.getGraphicNode()) .withTooltip(name -> Localization.lang("Remove entry type") + " " + name) .withOnMouseClickedEvent(item -> evt -> viewModel.removeEntryType(entryTypes.getSelectionModel().getSelectedItem())) @@ -114,7 +136,7 @@ private void setupTable() { viewModel.selectedEntryTypeProperty().bind(entryTypes.getSelectionModel().selectedItemProperty()); viewModel.entryTypeToAddProperty().bindBidirectional(addNewEntryType.textProperty()); - addNewField.setItems(viewModel.fields()); + addNewField.setItems(viewModel.fieldsForAdding()); addNewField.setConverter(viewModel.FIELD_STRING_CONVERTER); fieldTypeActionColumn.setSortable(false); @@ -128,16 +150,86 @@ private void setupTable() { .install(fieldTypeActionColumn); viewModel.newFieldToAddProperty().bindBidirectional(addNewField.valueProperty()); - fields.itemsProperty().bindBidirectional(viewModel.fieldsforTypesProperty()); + + EasyBind.subscribe(viewModel.selectedEntryTypeProperty(), type -> { + if (type != null) { + var items = type.fields(); + fields.setItems(items); + } + }); + + new ViewModelTableRowFactory() + .setOnDragDetected(this::handleOnDragDetected) + .setOnDragDropped(this::handleOnDragDropped) + .setOnDragOver(this::handleOnDragOver) + .install(fields); +} + + private void handleOnDragOver(FieldViewModel originalItem, DragEvent event) { + if ((event.getGestureSource() != originalItem) && event.getDragboard().hasContent(DragAndDropDataFormats.FIELD)) { + event.acceptTransferModes(TransferMode.MOVE); + } + } + + private void handleOnDragDetected(TableRow row, FieldViewModel fieldViewModel, MouseEvent event) { + row.startFullDrag(); + FieldViewModel field = fields.getSelectionModel().getSelectedItem(); + + ClipboardContent content = new ClipboardContent(); + Dragboard dragboard = fields.startDragAndDrop(TransferMode.MOVE); + content.put(DragAndDropDataFormats.FIELD, ""); + localDragboard.putValue(FieldViewModel.class, field); + dragboard.setContent(content); + event.consume(); + } + + private void handleOnDragDropped(TableRow row, FieldViewModel originalItem, DragEvent event) { + boolean success = false; + + ObservableList items = fields.itemsProperty().get(); + + if (localDragboard.hasType(FieldViewModel.class)) { + FieldViewModel field = localDragboard.getValue(FieldViewModel.class); + int draggedIdx = 0; + for (int i = 0; i < items.size(); i++) { + if (items.get(i).equals(field)) { + draggedIdx = i; + field = items.get(i); + break; + } + } + int thisIdx = items.indexOf(originalItem); + items.set(draggedIdx, originalItem); + items.set(thisIdx, field); + success = true; + } + + event.setDropCompleted(success); + event.consume(); } @FXML void addEntryType() { - viewModel.addNewCustomEntryType(); + CustomEntryTypeViewModel newlyAdded = viewModel.addNewCustomEntryType(); + this.entryTypes.getSelectionModel().select(newlyAdded); + this.entryTypes.scrollTo(newlyAdded); } @FXML void addNewField() { viewModel.addNewField(); } + + private void resetEntryTypes() { + boolean reset = dialogService.showConfirmationDialogAndWait( + Localization.lang("Reset entry types and fields to defaults"), + Localization.lang("This will reset all entry types to their default values and remove all custom entry types"), + Localization.lang("Reset to default")); + if (reset) { + viewModel.resetAllCustomEntryTypes(); + viewModel.addAllTypes(); + this.entryTypes.refresh(); + } + + } } diff --git a/src/main/java/org/jabref/gui/customentrytypes/FieldViewModel.java b/src/main/java/org/jabref/gui/customentrytypes/FieldViewModel.java index ae2f0f853fc..7cb538e4b17 100644 --- a/src/main/java/org/jabref/gui/customentrytypes/FieldViewModel.java +++ b/src/main/java/org/jabref/gui/customentrytypes/FieldViewModel.java @@ -6,7 +6,6 @@ import javafx.beans.property.StringProperty; import org.jabref.gui.customentrytypes.CustomEntryTypeDialogViewModel.FieldType; -import org.jabref.model.entry.BibEntryType; import org.jabref.model.entry.field.Field; import org.jabref.model.entry.field.FieldPriority; @@ -16,18 +15,16 @@ public class FieldViewModel { private final StringProperty fieldName = new SimpleStringProperty(""); private final Field field; private final FieldPriority fieldPriority; - private BibEntryType entryType; - public FieldViewModel(Field field, FieldType fieldType, FieldPriority fieldPriority, BibEntryType entryType) { + public FieldViewModel(Field field, FieldType fieldType, FieldPriority fieldPriority) { this.field = field; - this.entryType = entryType; this.fieldName.setValue(field.getDisplayName()); this.fieldType = new SimpleObjectProperty<>(fieldType); this.fieldPriority = fieldPriority; } - public FieldViewModel(Field field, boolean required, FieldPriority fieldPriority, BibEntryType entryType) { - this(field, required ? FieldType.REQUIRED : FieldType.OPTIONAL, fieldPriority, entryType); + public FieldViewModel(Field field, boolean required, FieldPriority fieldPriority) { + this(field, required ? FieldType.REQUIRED : FieldType.OPTIONAL, fieldPriority); } public ObjectProperty fieldType() { @@ -42,10 +39,6 @@ public Field getField() { return this.field; } - public BibEntryType getEntryType() { - return this.entryType; - } - public FieldPriority getFieldPriority() { return this.fieldPriority; } diff --git a/src/main/java/org/jabref/gui/entryeditor/DeprecatedFieldsTab.java b/src/main/java/org/jabref/gui/entryeditor/DeprecatedFieldsTab.java index af274875217..883bc98da1e 100644 --- a/src/main/java/org/jabref/gui/entryeditor/DeprecatedFieldsTab.java +++ b/src/main/java/org/jabref/gui/entryeditor/DeprecatedFieldsTab.java @@ -1,11 +1,8 @@ package org.jabref.gui.entryeditor; import java.util.Collections; -import java.util.Comparator; import java.util.Optional; -import java.util.SortedSet; -import java.util.TreeSet; -import java.util.stream.Collectors; +import java.util.Set; import javax.swing.undo.UndoManager; @@ -39,16 +36,14 @@ public DeprecatedFieldsTab(BibDatabaseContext databaseContext, SuggestionProvide } @Override - protected SortedSet determineFieldsToShow(BibEntry entry) { + protected Set determineFieldsToShow(BibEntry entry) { Optional entryType = entryTypesManager.enrich(entry.getType(), databaseContext.getMode()); if (entryType.isPresent()) { - return entryType.get().getDeprecatedFields() - .stream() - .filter(entry::hasField) - .collect(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Field::getName)))); + return entryType.get().getDeprecatedFields(); + } else { // Entry type unknown -> treat all fields as required - return Collections.emptySortedSet(); + return Collections.emptySet(); } } } diff --git a/src/main/java/org/jabref/gui/entryeditor/FieldsEditorTab.java b/src/main/java/org/jabref/gui/entryeditor/FieldsEditorTab.java index 1648e569802..9c3d74f2c6a 100644 --- a/src/main/java/org/jabref/gui/entryeditor/FieldsEditorTab.java +++ b/src/main/java/org/jabref/gui/entryeditor/FieldsEditorTab.java @@ -6,7 +6,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.SortedSet; +import java.util.Set; import java.util.stream.Stream; import javax.swing.undo.UndoManager; @@ -196,7 +196,7 @@ protected void previousPreviewStyle() { } } - protected abstract SortedSet determineFieldsToShow(BibEntry entry); + protected abstract Set determineFieldsToShow(BibEntry entry); public Collection getShownFields() { return fields; diff --git a/src/main/java/org/jabref/gui/entryeditor/OptionalFields2Tab.java b/src/main/java/org/jabref/gui/entryeditor/OptionalFields2Tab.java index ae1a32e9a11..b082691ca87 100644 --- a/src/main/java/org/jabref/gui/entryeditor/OptionalFields2Tab.java +++ b/src/main/java/org/jabref/gui/entryeditor/OptionalFields2Tab.java @@ -2,7 +2,7 @@ import java.util.Collections; import java.util.Optional; -import java.util.SortedSet; +import java.util.Set; import javax.swing.undo.UndoManager; @@ -36,13 +36,13 @@ public OptionalFields2Tab(BibDatabaseContext databaseContext, SuggestionProvider } @Override - protected SortedSet determineFieldsToShow(BibEntry entry) { + protected Set determineFieldsToShow(BibEntry entry) { Optional entryType = entryTypesManager.enrich(entry.getType(), databaseContext.getMode()); if (entryType.isPresent()) { return entryType.get().getSecondaryOptionalNotDeprecatedFields(); } else { // Entry type unknown -> treat all fields as required - return Collections.emptySortedSet(); + return Collections.emptySet(); } } } diff --git a/src/main/java/org/jabref/gui/entryeditor/OptionalFieldsTab.java b/src/main/java/org/jabref/gui/entryeditor/OptionalFieldsTab.java index 7ea9364fdc4..38bdf973bb9 100644 --- a/src/main/java/org/jabref/gui/entryeditor/OptionalFieldsTab.java +++ b/src/main/java/org/jabref/gui/entryeditor/OptionalFieldsTab.java @@ -1,11 +1,8 @@ package org.jabref.gui.entryeditor; import java.util.Collections; -import java.util.Comparator; import java.util.Optional; -import java.util.SortedSet; -import java.util.TreeSet; -import java.util.stream.Collectors; +import java.util.Set; import javax.swing.undo.UndoManager; @@ -22,7 +19,6 @@ import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.BibEntryType; import org.jabref.model.entry.BibEntryTypesManager; -import org.jabref.model.entry.field.BibField; import org.jabref.model.entry.field.Field; import org.jabref.preferences.JabRefPreferences; @@ -39,13 +35,13 @@ public OptionalFieldsTab(BibDatabaseContext databaseContext, SuggestionProviders } @Override - protected SortedSet determineFieldsToShow(BibEntry entry) { + protected Set determineFieldsToShow(BibEntry entry) { Optional entryType = entryTypesManager.enrich(entry.getType(), databaseContext.getMode()); if (entryType.isPresent()) { - return entryType.get().getPrimaryOptionalFields().stream().map(BibField::getField).collect(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Field::getName)))); + return entryType.get().getPrimaryOptionalFields(); } else { // Entry type unknown -> treat all fields as required - return Collections.emptySortedSet(); + return Collections.emptySet(); } } } diff --git a/src/main/java/org/jabref/gui/entryeditor/OtherFieldsTab.java b/src/main/java/org/jabref/gui/entryeditor/OtherFieldsTab.java index 7dc924f68cf..0841a7bbd0f 100644 --- a/src/main/java/org/jabref/gui/entryeditor/OtherFieldsTab.java +++ b/src/main/java/org/jabref/gui/entryeditor/OtherFieldsTab.java @@ -1,12 +1,10 @@ package org.jabref.gui.entryeditor; import java.util.Collections; -import java.util.Comparator; +import java.util.LinkedHashSet; import java.util.List; import java.util.Optional; import java.util.Set; -import java.util.SortedSet; -import java.util.TreeSet; import java.util.stream.Collectors; import javax.swing.undo.UndoManager; @@ -62,11 +60,11 @@ public OtherFieldsTab(BibDatabaseContext databaseContext, } @Override - protected SortedSet determineFieldsToShow(BibEntry entry) { + protected Set determineFieldsToShow(BibEntry entry) { Optional entryType = entryTypesManager.enrich(entry.getType(), databaseContext.getMode()); if (entryType.isPresent()) { - Set allKnownFields = entryType.get().getAllFields().stream().map(BibField::getField).collect(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Field::getName)))); - SortedSet otherFields = entry.getFields().stream().filter(field -> !allKnownFields.contains(field)).collect(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Field::getName)))); + Set allKnownFields = entryType.get().getAllFields(); + Set otherFields = entry.getFields().stream().filter(field -> !allKnownFields.contains(field)).collect(Collectors.toCollection(LinkedHashSet::new)); otherFields.removeAll(entryType.get().getDeprecatedFields()); otherFields.removeAll(entryType.get().getOptionalFields().stream().map(BibField::getField).collect(Collectors.toSet())); @@ -75,7 +73,7 @@ protected SortedSet determineFieldsToShow(BibEntry entry) { return otherFields; } else { // Entry type unknown -> treat all fields as required - return Collections.emptySortedSet(); + return Collections.emptySet(); } } } diff --git a/src/main/java/org/jabref/gui/entryeditor/RequiredFieldsTab.java b/src/main/java/org/jabref/gui/entryeditor/RequiredFieldsTab.java index 146bbfbeeb8..604173a87c6 100644 --- a/src/main/java/org/jabref/gui/entryeditor/RequiredFieldsTab.java +++ b/src/main/java/org/jabref/gui/entryeditor/RequiredFieldsTab.java @@ -1,9 +1,8 @@ package org.jabref.gui.entryeditor; -import java.util.Comparator; +import java.util.LinkedHashSet; import java.util.Optional; -import java.util.SortedSet; -import java.util.TreeSet; +import java.util.Set; import javax.swing.undo.UndoManager; @@ -26,6 +25,7 @@ import org.jabref.preferences.JabRefPreferences; public class RequiredFieldsTab extends FieldsEditorTab { + private final BibEntryTypesManager entryTypesManager; public RequiredFieldsTab(BibDatabaseContext databaseContext, SuggestionProviders suggestionProviders, UndoManager undoManager, DialogService dialogService, JabRefPreferences preferences, BibEntryTypesManager entryTypesManager, ExternalFileTypes externalFileTypes, TaskExecutor taskExecutor, JournalAbbreviationRepository journalAbbreviationRepository) { @@ -38,9 +38,9 @@ public RequiredFieldsTab(BibDatabaseContext databaseContext, SuggestionProviders } @Override - protected SortedSet determineFieldsToShow(BibEntry entry) { + protected Set determineFieldsToShow(BibEntry entry) { Optional entryType = entryTypesManager.enrich(entry.getType(), databaseContext.getMode()); - SortedSet fields = new TreeSet<>(Comparator.comparing(Field::getName)); + Set fields = new LinkedHashSet<>(); if (entryType.isPresent()) { for (OrFields orFields : entryType.get().getRequiredFields()) { fields.addAll(orFields); diff --git a/src/main/java/org/jabref/gui/entryeditor/UserDefinedFieldsTab.java b/src/main/java/org/jabref/gui/entryeditor/UserDefinedFieldsTab.java index 3e49477d0e2..634927777be 100644 --- a/src/main/java/org/jabref/gui/entryeditor/UserDefinedFieldsTab.java +++ b/src/main/java/org/jabref/gui/entryeditor/UserDefinedFieldsTab.java @@ -1,9 +1,7 @@ package org.jabref.gui.entryeditor; -import java.util.Comparator; +import java.util.LinkedHashSet; import java.util.Set; -import java.util.SortedSet; -import java.util.TreeSet; import javax.swing.undo.UndoManager; @@ -20,20 +18,19 @@ import org.jabref.preferences.JabRefPreferences; public class UserDefinedFieldsTab extends FieldsEditorTab { - private final SortedSet fields; + private final LinkedHashSet fields; public UserDefinedFieldsTab(String name, Set fields, BibDatabaseContext databaseContext, SuggestionProviders suggestionProviders, UndoManager undoManager, DialogService dialogService, JabRefPreferences preferences, BibEntryTypesManager entryTypesManager, ExternalFileTypes externalFileTypes, TaskExecutor taskExecutor, JournalAbbreviationRepository journalAbbreviationRepository) { super(false, databaseContext, suggestionProviders, undoManager, dialogService, preferences, externalFileTypes, taskExecutor, journalAbbreviationRepository); - this.fields = new TreeSet<>(Comparator.comparing(Field::getName)); - this.fields.addAll(fields); + this.fields = new LinkedHashSet<>(fields); setText(name); setGraphic(IconTheme.JabRefIcons.OPTIONAL.getGraphicNode()); } @Override - protected SortedSet determineFieldsToShow(BibEntry entry) { + protected Set determineFieldsToShow(BibEntry entry) { return fields; } } diff --git a/src/main/java/org/jabref/gui/importer/ImportCustomEntryTypesDialogViewModel.java b/src/main/java/org/jabref/gui/importer/ImportCustomEntryTypesDialogViewModel.java index ae8a634d729..c6f2f5f2b3b 100644 --- a/src/main/java/org/jabref/gui/importer/ImportCustomEntryTypesDialogViewModel.java +++ b/src/main/java/org/jabref/gui/importer/ImportCustomEntryTypesDialogViewModel.java @@ -47,11 +47,11 @@ public ObservableList differentCustomizations() { public void importBibEntryTypes(List checkedUnknownEntryTypes, List checkedDifferentEntryTypes) { if (!checkedUnknownEntryTypes.isEmpty()) { checkedUnknownEntryTypes.forEach(type -> Globals.entryTypesManager.addCustomOrModifiedType(type, mode)); - preferencesService.saveCustomEntryTypes(); + preferencesService.saveCustomEntryTypes(Globals.entryTypesManager); } if (!checkedDifferentEntryTypes.isEmpty()) { checkedUnknownEntryTypes.forEach(type -> Globals.entryTypesManager.addCustomOrModifiedType(type, mode)); - preferencesService.saveCustomEntryTypes(); + preferencesService.saveCustomEntryTypes(Globals.entryTypesManager); } } } diff --git a/src/main/java/org/jabref/logic/integrity/NoBibtexFieldChecker.java b/src/main/java/org/jabref/logic/integrity/NoBibtexFieldChecker.java index c822a231a0a..7d46cb42052 100644 --- a/src/main/java/org/jabref/logic/integrity/NoBibtexFieldChecker.java +++ b/src/main/java/org/jabref/logic/integrity/NoBibtexFieldChecker.java @@ -18,9 +18,9 @@ public class NoBibtexFieldChecker implements EntryChecker { private Set getAllBiblatexOnlyFields() { - Set allBibtexFields = BibtexEntryTypeDefinitions.ALL.stream().flatMap(type -> type.getAllFields().stream()).collect(Collectors.toSet()); + Set allBibtexFields = BibtexEntryTypeDefinitions.ALL.stream().flatMap(type -> type.getAllBibFields().stream()).collect(Collectors.toSet()); return BiblatexEntryTypeDefinitions.ALL.stream() - .flatMap(type -> type.getAllFields().stream()) + .flatMap(type -> type.getAllBibFields().stream()) .filter(field -> !allBibtexFields.contains(field)) .map(BibField::getField) // these fields are displayed by JabRef as default diff --git a/src/main/java/org/jabref/migrations/CustomEntryTypePreferenceMigration.java b/src/main/java/org/jabref/migrations/CustomEntryTypePreferenceMigration.java index 9abb740cd7c..c9e669bb402 100644 --- a/src/main/java/org/jabref/migrations/CustomEntryTypePreferenceMigration.java +++ b/src/main/java/org/jabref/migrations/CustomEntryTypePreferenceMigration.java @@ -37,7 +37,7 @@ static void upgradeStoredBibEntryTypes(BibDatabaseMode defaultBibDatabaseMode) { number++; } - prefs.saveCustomEntryTypes(); + prefs.saveCustomEntryTypes(Globals.entryTypesManager); } /** diff --git a/src/main/java/org/jabref/model/entry/BibEntryType.java b/src/main/java/org/jabref/model/entry/BibEntryType.java index 2c1b2ea0504..2f59f62cbb2 100644 --- a/src/main/java/org/jabref/model/entry/BibEntryType.java +++ b/src/main/java/org/jabref/model/entry/BibEntryType.java @@ -2,10 +2,9 @@ import java.util.Collection; import java.util.Collections; -import java.util.Comparator; +import java.util.LinkedHashSet; import java.util.Objects; -import java.util.SortedSet; -import java.util.TreeSet; +import java.util.Set; import java.util.stream.Collectors; import org.jabref.model.entry.field.BibField; @@ -18,13 +17,13 @@ public class BibEntryType implements Comparable { private final EntryType type; - private final SortedSet requiredFields; - private final SortedSet fields; + private final LinkedHashSet requiredFields; + private final LinkedHashSet fields; public BibEntryType(EntryType type, Collection fields, Collection requiredFields) { this.type = Objects.requireNonNull(type); - this.requiredFields = new TreeSet<>(requiredFields); - this.fields = new TreeSet<>(fields); + this.requiredFields = new LinkedHashSet<>(requiredFields); + this.fields = new LinkedHashSet<>(fields); } public EntryType getType() { @@ -36,10 +35,10 @@ public EntryType getType() { * * @return a List of optional field name Strings */ - public SortedSet getOptionalFields() { - return getAllFields().stream() + public Set getOptionalFields() { + return getAllBibFields().stream() .filter(field -> !isRequired(field.getField())) - .collect(Collectors.toCollection(TreeSet::new)); + .collect(Collectors.toCollection(LinkedHashSet::new)); } public boolean isRequired(Field field) { @@ -54,33 +53,37 @@ public boolean isRequired(Field field) { * * @return a List of required field name Strings */ - public SortedSet getRequiredFields() { - return Collections.unmodifiableSortedSet(requiredFields); + public Set getRequiredFields() { + return Collections.unmodifiableSet(requiredFields); } /** * Returns all defined fields. */ - public SortedSet getAllFields() { - return Collections.unmodifiableSortedSet(fields); + public Set getAllBibFields() { + return Collections.unmodifiableSet(fields); } - public SortedSet getPrimaryOptionalFields() { + public Set getAllFields() { + return fields.stream().map(BibField::getField).collect(Collectors.toCollection(LinkedHashSet::new)); + } + + public Set getPrimaryOptionalFields() { return getOptionalFields().stream() .filter(field -> field.getPriority() == FieldPriority.IMPORTANT) - .collect(Collectors.toCollection(TreeSet::new)); + .map(BibField::getField) + .collect(Collectors.toCollection(LinkedHashSet::new)); } - public SortedSet getSecondaryOptionalFields() { + public Set getSecondaryOptionalFields() { return getOptionalFields().stream() .filter(field -> field.getPriority() == FieldPriority.DETAIL) .map(BibField::getField) - .collect(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Field::getName)))); + .collect(Collectors.toCollection(LinkedHashSet::new)); } - public SortedSet getDeprecatedFields() { - SortedSet deprecatedFields = new TreeSet<>(Comparator.comparing(Field::getName)); - deprecatedFields.addAll(EntryConverter.FIELD_ALIASES_TEX_TO_LTX.keySet()); + public Set getDeprecatedFields() { + Set deprecatedFields = new LinkedHashSet<>(EntryConverter.FIELD_ALIASES_TEX_TO_LTX.keySet()); deprecatedFields.add(StandardField.YEAR); deprecatedFields.add(StandardField.MONTH); @@ -89,9 +92,8 @@ public SortedSet getDeprecatedFields() { return deprecatedFields; } - public SortedSet getSecondaryOptionalNotDeprecatedFields() { - SortedSet optionalFieldsNotPrimaryOrDeprecated = new TreeSet<>(Comparator.comparing(Field::getName)); - optionalFieldsNotPrimaryOrDeprecated.addAll(getSecondaryOptionalFields()); + public Set getSecondaryOptionalNotDeprecatedFields() { + Set optionalFieldsNotPrimaryOrDeprecated = new LinkedHashSet<>(getSecondaryOptionalFields()); optionalFieldsNotPrimaryOrDeprecated.removeAll(getDeprecatedFields()); return optionalFieldsNotPrimaryOrDeprecated; } @@ -99,8 +101,8 @@ public SortedSet getSecondaryOptionalNotDeprecatedFields() { /** * Get list of all optional fields of this entry and their aliases. */ - private SortedSet getOptionalFieldsAndAliases() { - SortedSet optionalFieldsAndAliases = new TreeSet<>(Comparator.comparing(Field::getName)); + private Set getOptionalFieldsAndAliases() { + Set optionalFieldsAndAliases = new LinkedHashSet<>(getOptionalFields().size()); for (BibField field : getOptionalFields()) { optionalFieldsAndAliases.add(field.getField()); if (EntryConverter.FIELD_ALIASES_LTX_TO_TEX.containsKey(field.getField())) { @@ -115,13 +117,14 @@ public boolean equals(Object o) { if (this == o) { return true; } - if (o == null || getClass() != o.getClass()) { + if ((o == null) || (getClass() != o.getClass())) { return false; } BibEntryType that = (BibEntryType) o; return type.equals(that.type) && - requiredFields.equals(that.requiredFields) && - fields.equals(that.fields); + Objects.equals(requiredFields, that.requiredFields) && + Objects.equals(fields, that.fields); + } @Override @@ -132,10 +135,10 @@ public int hashCode() { @Override public String toString() { return "BibEntryType{" + - "type=" + type + - ", requiredFields=" + requiredFields + - ", fields=" + fields + - '}'; + "type=" + type + + ", requiredFields=" + requiredFields + + ", fields=" + fields + + '}'; } @Override diff --git a/src/main/java/org/jabref/model/entry/BibEntryTypeBuilder.java b/src/main/java/org/jabref/model/entry/BibEntryTypeBuilder.java index 6245514dfdf..08f294bc3e1 100644 --- a/src/main/java/org/jabref/model/entry/BibEntryTypeBuilder.java +++ b/src/main/java/org/jabref/model/entry/BibEntryTypeBuilder.java @@ -2,10 +2,9 @@ import java.util.Arrays; import java.util.Collection; -import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.List; import java.util.Set; -import java.util.TreeSet; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -19,9 +18,10 @@ import com.google.common.collect.Streams; public class BibEntryTypeBuilder { + private EntryType type = StandardEntryType.Misc; - private Set fields = new HashSet<>(); - private Set requiredFields = new HashSet<>(); + private Set fields = new LinkedHashSet<>(); + private Set requiredFields = new LinkedHashSet<>(); public BibEntryTypeBuilder withType(EntryType type) { this.type = type; @@ -29,12 +29,12 @@ public BibEntryTypeBuilder withType(EntryType type) { } public BibEntryTypeBuilder withImportantFields(Set newFields) { - return withImportantFields(newFields.stream().map(BibField::getField).collect(Collectors.toSet())); + return withImportantFields(newFields.stream().map(BibField::getField).collect(Collectors.toCollection(LinkedHashSet::new))); } public BibEntryTypeBuilder withImportantFields(Collection newFields) { this.fields = Streams.concat(fields.stream(), newFields.stream().map(field -> new BibField(field, FieldPriority.IMPORTANT))) - .collect(Collectors.toSet()); + .collect(Collectors.toCollection(LinkedHashSet::new)); return this; } @@ -44,7 +44,7 @@ public BibEntryTypeBuilder withImportantFields(Field... newFields) { public BibEntryTypeBuilder withDetailFields(Collection newFields) { this.fields = Streams.concat(fields.stream(), newFields.stream().map(field -> new BibField(field, FieldPriority.DETAIL))) - .collect(Collectors.toSet()); + .collect(Collectors.toCollection(LinkedHashSet::new)); return this; } @@ -58,26 +58,26 @@ public BibEntryTypeBuilder withRequiredFields(Set requiredFields) { } public BibEntryTypeBuilder withRequiredFields(Field... requiredFields) { - this.requiredFields = Arrays.stream(requiredFields).map(OrFields::new).collect(Collectors.toSet()); + this.requiredFields = Arrays.stream(requiredFields).map(OrFields::new).collect(Collectors.toCollection(LinkedHashSet::new)); return this; } public BibEntryTypeBuilder withRequiredFields(OrFields first, Field... requiredFields) { - this.requiredFields = Stream.concat(Stream.of(first), Arrays.stream(requiredFields).map(OrFields::new)).collect(Collectors.toSet()); + this.requiredFields = Stream.concat(Stream.of(first), Arrays.stream(requiredFields).map(OrFields::new)).collect(Collectors.toCollection(LinkedHashSet::new)); return this; } public BibEntryTypeBuilder withRequiredFields(List first, Field... requiredFields) { - this.requiredFields = Stream.concat(first.stream(), Arrays.stream(requiredFields).map(OrFields::new)).collect(Collectors.toSet()); + this.requiredFields = Stream.concat(first.stream(), Arrays.stream(requiredFields).map(OrFields::new)).collect(Collectors.toCollection(LinkedHashSet::new)); return this; } public BibEntryType build() { // Treat required fields as important ones Stream requiredAsImportant = requiredFields.stream() - .flatMap(TreeSet::stream) + .flatMap(Set::stream) .map(field -> new BibField(field, FieldPriority.IMPORTANT)); - Set allFields = Stream.concat(fields.stream(), requiredAsImportant).collect(Collectors.toSet()); + Set 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/BibEntryTypesManager.java b/src/main/java/org/jabref/model/entry/BibEntryTypesManager.java index 49326286e91..f56230a110a 100644 --- a/src/main/java/org/jabref/model/entry/BibEntryTypesManager.java +++ b/src/main/java/org/jabref/model/entry/BibEntryTypesManager.java @@ -1,7 +1,6 @@ package org.jabref.model.entry; import java.util.Collection; -import java.util.Comparator; import java.util.List; import java.util.Optional; import java.util.SortedSet; @@ -11,7 +10,6 @@ import org.jabref.model.database.BibDatabaseMode; import org.jabref.model.entry.field.BibField; -import org.jabref.model.entry.field.Field; import org.jabref.model.entry.field.FieldFactory; import org.jabref.model.entry.types.BiblatexEntryTypeDefinitions; import org.jabref.model.entry.types.BibtexEntryTypeDefinitions; @@ -62,7 +60,6 @@ public static String serialize(BibEntryType entryType) { entryType.getOptionalFields() .stream() .map(BibField::getField) - .sorted(Comparator.comparing(Field::getName)) .collect(Collectors.toList()))); builder.append("]"); return builder.toString(); @@ -120,6 +117,14 @@ public void removeCustomOrModifiedEntryType(BibEntryType entryType, BibDatabaseM } } + public void clearAllCustomEntryTypes(BibDatabaseMode mode) { + if (BibDatabaseMode.BIBLATEX == mode) { + BIBLATEX.clearAllCustomEntryTypes(); + } else if (BibDatabaseMode.BIBTEX == mode) { + BIBTEX.clearAllCustomEntryTypes(); + } + } + public Collection getAllTypes(BibDatabaseMode type) { return type == BibDatabaseMode.BIBLATEX ? BIBLATEX.getAllTypes() : BIBTEX.getAllTypes(); } @@ -183,6 +188,10 @@ private void removeCustomOrModifiedEntryType(BibEntryType type) { customOrModifiedType.remove(type); } + private void clearAllCustomEntryTypes() { + customOrModifiedType.clear(); + } + public SortedSet getAllTypes() { SortedSet allTypes = new TreeSet<>(customOrModifiedType); allTypes.addAll(standardTypes); @@ -191,7 +200,7 @@ public SortedSet getAllTypes() { public boolean isCustomOrModifiedType(BibEntryType entryType) { return customOrModifiedType.stream() - .anyMatch(customizedType -> customizedType.getType().equals(entryType.getType())); + .anyMatch(customizedType -> customizedType.equals(entryType)); } } } 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 9c4e4349d27..b4a69fa9ccd 100644 --- a/src/main/java/org/jabref/model/entry/field/FieldFactory.java +++ b/src/main/java/org/jabref/model/entry/field/FieldFactory.java @@ -3,15 +3,15 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Comparator; import java.util.EnumSet; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.List; import java.util.Set; -import java.util.TreeSet; import java.util.function.Predicate; import java.util.stream.Collectors; +import org.jabref.model.strings.StringUtil; import org.jabref.model.util.OptionalUtil; public class FieldFactory { @@ -47,21 +47,24 @@ public static List getIdentifierFieldNames() { public static OrFields parseOrFields(String fieldNames) { Set fields = Arrays.stream(fieldNames.split(FieldFactory.FIELD_OR_SEPARATOR)) - .map(FieldFactory::parseField) - .collect(Collectors.toSet()); + .filter(StringUtil::isNotBlank) + .map(FieldFactory::parseField) + .collect(Collectors.toCollection(LinkedHashSet::new)); return new OrFields(fields); } public static Set parseOrFieldsList(String fieldNames) { return Arrays.stream(fieldNames.split(FieldFactory.DELIMITER)) + .filter(StringUtil::isNotBlank) .map(FieldFactory::parseOrFields) - .collect(Collectors.toSet()); + .collect(Collectors.toCollection(LinkedHashSet::new)); } public static Set parseFieldList(String fieldNames) { return Arrays.stream(fieldNames.split(FieldFactory.DELIMITER)) + .filter(StringUtil::isNotBlank) .map(FieldFactory::parseField) - .collect(Collectors.toSet()); + .collect(Collectors.toCollection(LinkedHashSet::new)); } public static String serializeFieldsList(Collection fields) { @@ -92,18 +95,33 @@ public static Set getJournalNameFields() { } /** - * Returns a sorted List with all standard fields and including some common internal fields + * Returns a List with all standard fields and including some common internal fields */ public static Set getCommonFields() { - TreeSet publicAndInternalFields = new TreeSet<>(Comparator.comparing(Field::getName)); + EnumSet allFields = EnumSet.allOf(StandardField.class); + + LinkedHashSet publicAndInternalFields = new LinkedHashSet<>(allFields.size() + 3); publicAndInternalFields.add(InternalField.INTERNAL_ALL_FIELD); publicAndInternalFields.add(InternalField.INTERNAL_ALL_TEXT_FIELDS_FIELD); publicAndInternalFields.add(InternalField.KEY_FIELD); - publicAndInternalFields.addAll(EnumSet.allOf(StandardField.class)); + publicAndInternalFields.addAll(allFields); return publicAndInternalFields; } + /** + * Returns a List with all standard fields and the bibtexkey field + */ + public static Set getStandardFielsdsWithBibTexKey() { + EnumSet allFields = EnumSet.allOf(StandardField.class); + + LinkedHashSet standardFieldsWithBibtexKey = new LinkedHashSet<>(allFields.size() + 1); + standardFieldsWithBibtexKey.add(InternalField.KEY_FIELD); + standardFieldsWithBibtexKey.addAll(allFields); + + return standardFieldsWithBibtexKey; + } + public static Set getBookNameFields() { return getFieldsFiltered(field -> field.getProperties().contains(FieldProperty.BOOK_NAME)); } 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 a481527489e..baf848d4392 100644 --- a/src/main/java/org/jabref/model/entry/field/OrFields.java +++ b/src/main/java/org/jabref/model/entry/field/OrFields.java @@ -2,24 +2,20 @@ import java.util.Arrays; import java.util.Collection; -import java.util.Comparator; +import java.util.LinkedHashSet; import java.util.StringJoiner; -import java.util.TreeSet; -public class OrFields extends TreeSet implements Comparable { +public class OrFields extends LinkedHashSet implements Comparable { public OrFields(Field field) { - super(Comparator.comparing(Field::getName)); add(field); } public OrFields(Field... fields) { - super(Comparator.comparing(Field::getName)); addAll(Arrays.asList(fields)); } public OrFields(Collection fields) { - super(Comparator.comparing(Field::getName)); addAll(fields); } diff --git a/src/main/java/org/jabref/preferences/JabRefPreferences.java b/src/main/java/org/jabref/preferences/JabRefPreferences.java index 86a4a756a72..7882c949c7d 100644 --- a/src/main/java/org/jabref/preferences/JabRefPreferences.java +++ b/src/main/java/org/jabref/preferences/JabRefPreferences.java @@ -14,6 +14,7 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; @@ -1010,7 +1011,7 @@ public void flush() { } } - public void storeBibEntryTypes(List BibEntryTypes, BibDatabaseMode bibDatabaseMode) { + public void storeBibEntryTypes(Collection bibEntryTypes, BibDatabaseMode bibDatabaseMode) { Preferences prefsNode = getPrefsNodeForCustomizedEntryTypes(bibDatabaseMode); try { @@ -1018,7 +1019,7 @@ public void storeBibEntryTypes(List BibEntryTypes, BibDatabaseMode clearBibEntryTypes(bibDatabaseMode); // store current custom types - BibEntryTypes.forEach(type -> prefsNode.put(type.getType().getName(), BibEntryTypesManager.serialize(type))); + bibEntryTypes.forEach(type -> prefsNode.put(type.getType().getName(), BibEntryTypesManager.serialize(type))); prefsNode.flush(); } catch (BackingStoreException e) { @@ -1041,41 +1042,54 @@ public List loadBibEntryTypes(BibDatabaseMode bibDatabaseMode) { return storedEntryTypes; } - private void clearAllBibEntryTypes() throws BackingStoreException { + public void clearAllBibEntryTypes() { for (BibDatabaseMode mode : BibDatabaseMode.values()) { clearBibEntryTypes(mode); } } - private void clearBibEntryTypes(BibDatabaseMode mode) throws BackingStoreException { - Preferences prefsNode = getPrefsNodeForCustomizedEntryTypes(mode); - prefsNode.clear(); + @Override + public void clearBibEntryTypes(BibDatabaseMode mode) { + try { + Preferences prefsNode = getPrefsNodeForCustomizedEntryTypes(mode); + prefsNode.clear(); + prefsNode.flush(); + } catch (BackingStoreException e) { + LOGGER.error("Resetting customized entry types failed.", e); + } } public Map getPreferences() { Map result = new HashMap<>(); + try { - for (String key : this.prefs.keys()) { - Object value = getObject(key); - result.put(key, value); - } + addPrefsRecursively(this.prefs, result); } catch (BackingStoreException e) { LOGGER.info("could not retrieve preference keys", e); } return result; } - private Object getObject(String key) { + private void addPrefsRecursively(Preferences prefs, Map result) throws BackingStoreException { + for (String key : prefs.keys()) { + result.put(key, getObject(prefs, key)); + } + for (String child : prefs.childrenNames()) { + addPrefsRecursively(prefs.node(child), result); + } + } + + private Object getObject(Preferences prefs, String key) { try { - return this.get(key); + return prefs.get(key, (String) defaults.get(key)); } catch (ClassCastException e) { try { - return this.getBoolean(key); + return prefs.getBoolean(key, getBooleanDefault(key)); } catch (ClassCastException e2) { try { - return this.getInt(key); + return prefs.getInt(key, getIntDefault(key)); } catch (ClassCastException e3) { - return this.getDouble(key); + return prefs.getDouble(key, getDoubleDefault(key)); } } } @@ -1104,6 +1118,7 @@ public void exportPreferences(String filename) throws JabRefException { } public void exportPreferences(Path file) throws JabRefException { + LOGGER.debug("Exporting preferences ", file.toAbsolutePath()); try (OutputStream os = Files.newOutputStream(file)) { prefs.exportSubtree(os); } catch (BackingStoreException | IOException ex) { @@ -1626,13 +1641,13 @@ public void setShouldWarnAboutDuplicatesForImport(boolean value) { } @Override - public void saveCustomEntryTypes() { - saveCustomEntryTypes(BibDatabaseMode.BIBTEX); - saveCustomEntryTypes(BibDatabaseMode.BIBLATEX); + public void saveCustomEntryTypes(BibEntryTypesManager entryTypesManager) { + saveCustomEntryTypes(BibDatabaseMode.BIBTEX, entryTypesManager); + saveCustomEntryTypes(BibDatabaseMode.BIBLATEX, entryTypesManager); } - private void saveCustomEntryTypes(BibDatabaseMode bibDatabaseMode) { - List customBiblatexBibTexTypes = new ArrayList<>(Globals.entryTypesManager.getAllTypes(bibDatabaseMode)); + private void saveCustomEntryTypes(BibDatabaseMode bibDatabaseMode, BibEntryTypesManager entryTypesManager) { + Collection customBiblatexBibTexTypes = entryTypesManager.getAllTypes(bibDatabaseMode); storeBibEntryTypes(customBiblatexBibTexTypes, bibDatabaseMode); } diff --git a/src/main/java/org/jabref/preferences/PreferencesService.java b/src/main/java/org/jabref/preferences/PreferencesService.java index b23113bda2e..76b49fa5fc1 100644 --- a/src/main/java/org/jabref/preferences/PreferencesService.java +++ b/src/main/java/org/jabref/preferences/PreferencesService.java @@ -37,6 +37,7 @@ import org.jabref.model.bibtexkeypattern.GlobalCitationKeyPattern; import org.jabref.model.database.BibDatabaseMode; import org.jabref.model.entry.BibEntryType; +import org.jabref.model.entry.BibEntryTypesManager; import org.jabref.model.entry.field.Field; import org.jabref.model.metadata.FilePreferences; import org.jabref.model.metadata.SaveOrderConfig; @@ -105,7 +106,9 @@ public interface PreferencesService { void setShouldWarnAboutDuplicatesForImport(boolean value); - void saveCustomEntryTypes(); + void saveCustomEntryTypes(BibEntryTypesManager entryTypesManager); + + void clearBibEntryTypes(BibDatabaseMode mode); List loadBibEntryTypes(BibDatabaseMode mode); @@ -236,4 +239,5 @@ public interface PreferencesService { SpecialFieldsPreferences getSpecialFieldsPreferences(); void storeSpecialFieldsPreferences(SpecialFieldsPreferences specialFieldsPreferences); + } diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index 3bb17ba3aaf..396a11793b5 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -2250,3 +2250,7 @@ Close\ all\ libraries=Close all libraries Close\ other\ libraries=Close other libraries Close\ others=Close others Reveal\ in\ file\ explorer=Reveal in file explorer + +Reset=Reset +Reset\ entry\ types\ and\ fields\ to\ defaults=Reset entry types and fields to defaults +This\ will\ reset\ all\ entry\ types\ to\ their\ default\ values\ and\ remove\ all\ custom\ entry\ types=This will reset all entry types to their default values and remove all custom entry types diff --git a/src/test/java/org/jabref/logic/bibtex/BibEntryWriterTest.java b/src/test/java/org/jabref/logic/bibtex/BibEntryWriterTest.java index 5ebca3902d5..5f402dc9b87 100644 --- a/src/test/java/org/jabref/logic/bibtex/BibEntryWriterTest.java +++ b/src/test/java/org/jabref/logic/bibtex/BibEntryWriterTest.java @@ -22,6 +22,7 @@ import org.jabref.model.util.FileUpdateMonitor; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.mockito.Answers; @@ -63,8 +64,8 @@ void testSerialization() throws IOException { String expected = OS.NEWLINE + "@Article{," + OS.NEWLINE + " author = {Foo Bar}," + OS.NEWLINE + " journal = {International Journal of Something}," + OS.NEWLINE + - " note = {some note}," + OS.NEWLINE + " number = {1}," + OS.NEWLINE + + " note = {some note}," + OS.NEWLINE + "}" + OS.NEWLINE; // @formatter:on @@ -125,8 +126,8 @@ void writeEntryWithOrField() throws Exception { // @formatter:off String expected = OS.NEWLINE + "@InBook{," + OS.NEWLINE + " editor = {Foo Bar}," + OS.NEWLINE + - " note = {some note}," + OS.NEWLINE + " number = {1}," + OS.NEWLINE + + " note = {some note}," + OS.NEWLINE + " journal = {International Journal of Something}," + OS.NEWLINE + "}" + OS.NEWLINE; // @formatter:on @@ -155,8 +156,8 @@ void writeEntryWithOrFieldBothFieldsPresent() throws Exception { String expected = OS.NEWLINE + "@InBook{," + OS.NEWLINE + " author = {Foo Thor}," + OS.NEWLINE + " editor = {Edi Bar}," + OS.NEWLINE + - " note = {some note}," + OS.NEWLINE + " number = {1}," + OS.NEWLINE + + " note = {some note}," + OS.NEWLINE + " journal = {International Journal of Something}," + OS.NEWLINE + "}" + OS.NEWLINE; // @formatter:on @@ -259,8 +260,8 @@ void roundTripWithModification() throws IOException { String expected = OS.NEWLINE + "@Article{test," + OS.NEWLINE + " author = {BlaBla}," + OS.NEWLINE + " journal = {International Journal of Something}," + OS.NEWLINE + - " note = {some note}," + OS.NEWLINE + " number = {1}," + OS.NEWLINE + + " note = {some note}," + OS.NEWLINE + "}" + OS.NEWLINE; // @formatter:on assertEquals(expected, actual); @@ -272,8 +273,8 @@ void roundTripWithCamelCasingInTheOriginalEntryAndResultInLowerCase() throws IOE String bibtexEntry = OS.NEWLINE + "@Article{test," + OS.NEWLINE + " Author = {Foo Bar}," + OS.NEWLINE + " Journal = {International Journal of Something}," + OS.NEWLINE + - " Note = {some note}," + OS.NEWLINE + " Number = {1}," + OS.NEWLINE + + " Note = {some note}," + OS.NEWLINE + " HowPublished = {asdf}," + OS.NEWLINE + "}"; // @formatter:on @@ -295,8 +296,8 @@ void roundTripWithCamelCasingInTheOriginalEntryAndResultInLowerCase() throws IOE String expected = OS.NEWLINE + "@Article{test," + OS.NEWLINE + " author = {BlaBla}," + OS.NEWLINE + " journal = {International Journal of Something}," + OS.NEWLINE + - " note = {some note}," + OS.NEWLINE + " number = {1}," + OS.NEWLINE + + " note = {some note}," + OS.NEWLINE + " howpublished = {asdf}," + OS.NEWLINE + "}" + OS.NEWLINE; // @formatter:on @@ -331,8 +332,8 @@ void testEntryTypeChange() throws IOException { // @formatter:off String expectedNewEntry = OS.NEWLINE + "@InProceedings{test," + OS.NEWLINE + " author = {BlaBla}," + OS.NEWLINE + - " note = {some note}," + OS.NEWLINE + " number = {1}," + OS.NEWLINE + + " note = {some note}," + OS.NEWLINE + " howpublished = {asdf}," + OS.NEWLINE + " journal = {International Journal of Something}," + OS.NEWLINE + "}" + OS.NEWLINE; @@ -346,8 +347,8 @@ void roundTripWithAppendedNewlines() throws IOException { String bibtexEntry = "@Article{test," + OS.NEWLINE + " Author = {Foo Bar}," + OS.NEWLINE + " Journal = {International Journal of Something}," + OS.NEWLINE + - " Note = {some note}," + OS.NEWLINE + - " Number = {1}" + OS.NEWLINE + + " Number = {1}," + OS.NEWLINE + + " Note = {some note}" + OS.NEWLINE + "}\n\n"; // @formatter:on @@ -488,8 +489,8 @@ void addFieldWithLongerLength() throws IOException { String expected = OS.NEWLINE + "@Article{test," + OS.NEWLINE + " author = {BlaBla}," + OS.NEWLINE + " journal = {International Journal of Something}," + OS.NEWLINE + - " note = {some note}," + OS.NEWLINE + " number = {1}," + OS.NEWLINE + + " note = {some note}," + OS.NEWLINE + " howpublished = {asdf}," + OS.NEWLINE + "}" + OS.NEWLINE; // @formatter:on @@ -557,8 +558,8 @@ void roundTripWithPrecedingCommentAndModificationTest() throws IOException { "@Article{test," + OS.NEWLINE + " Author = {Foo Bar}," + OS.NEWLINE + " Journal = {International Journal of Something}," + OS.NEWLINE + - " Note = {some note}," + OS.NEWLINE + - " Number = {1}" + OS.NEWLINE + + " Number = {1}," + OS.NEWLINE + + " Note = {some note}" + OS.NEWLINE + "}"; // @formatter:on @@ -579,14 +580,15 @@ void roundTripWithPrecedingCommentAndModificationTest() throws IOException { "@Article{test," + OS.NEWLINE + " author = {John Doe}," + OS.NEWLINE + " journal = {International Journal of Something}," + OS.NEWLINE + - " note = {some note}," + OS.NEWLINE + " number = {1}," + OS.NEWLINE + + " note = {some note}," + OS.NEWLINE + "}" + OS.NEWLINE; // @formatter:on assertEquals(expected, actual); } + @Disabled("We don't have alphabetic serialization anylonger TODO") @Test void alphabeticSerialization() throws IOException { StringWriter stringWriter = new StringWriter(); @@ -614,8 +616,8 @@ void alphabeticSerialization() throws IOException { " date = {2019-10-16}," + OS.NEWLINE + " journaltitle = {International Journal of Something}," + OS.NEWLINE + " title = {Title}," + OS.NEWLINE + - " note = {some note}," + OS.NEWLINE + " number = {1}," + OS.NEWLINE + + " note = {some note}," + OS.NEWLINE + " chapter = {chapter}," + OS.NEWLINE + " year = {2019}," + OS.NEWLINE + "}" + OS.NEWLINE; diff --git a/src/test/java/org/jabref/logic/exporter/BibtexDatabaseWriterTest.java b/src/test/java/org/jabref/logic/exporter/BibtexDatabaseWriterTest.java index 22b4736c4a5..1e63213a582 100644 --- a/src/test/java/org/jabref/logic/exporter/BibtexDatabaseWriterTest.java +++ b/src/test/java/org/jabref/logic/exporter/BibtexDatabaseWriterTest.java @@ -286,7 +286,7 @@ void writeEntryWithCustomizedTypeAlsoWritesTypeDeclaration() throws Exception { "@Customizedtype{," + OS.NEWLINE + "}" + OS.NEWLINE + OS.NEWLINE + "@Comment{jabref-meta: databaseType:bibtex;}" + OS.NEWLINE + OS.NEWLINE - + "@Comment{jabref-entrytype: customizedtype: req[author;date;title] opt[month;publisher;year]}" + OS.NEWLINE, + + "@Comment{jabref-entrytype: customizedtype: req[title;author;date] opt[year;month;publisher]}" + OS.NEWLINE, stringWriter.toString()); } @@ -730,8 +730,8 @@ public void saveAlsoSavesSecondModification() throws Exception { "@Article{test," + OS.NEWLINE + " author = {Test}," + OS.NEWLINE + " journal = {International Journal of Something}," + OS.NEWLINE + - " note = {some note}," + OS.NEWLINE + " number = {1}," + OS.NEWLINE + + " note = {some note}," + OS.NEWLINE + "}" + OS.NEWLINE + "" + OS.NEWLINE + "@Comment{jabref-meta: databaseType:bibtex;}" + OS.NEWLINE, stringWriter.toString()); diff --git a/src/test/java/org/jabref/model/entry/BibEntryTypesManagerTest.java b/src/test/java/org/jabref/model/entry/BibEntryTypesManagerTest.java index 6d0af169818..83f9938e427 100644 --- a/src/test/java/org/jabref/model/entry/BibEntryTypesManagerTest.java +++ b/src/test/java/org/jabref/model/entry/BibEntryTypesManagerTest.java @@ -1,14 +1,18 @@ package org.jabref.model.entry; import java.util.Collections; +import java.util.List; import java.util.Optional; import java.util.TreeSet; +import java.util.stream.Collectors; import java.util.stream.Stream; import org.jabref.model.database.BibDatabaseMode; import org.jabref.model.entry.field.BibField; import org.jabref.model.entry.field.FieldPriority; +import org.jabref.model.entry.field.OrFields; import org.jabref.model.entry.field.StandardField; +import org.jabref.model.entry.field.UnknownField; import org.jabref.model.entry.types.BiblatexEntryTypeDefinitions; import org.jabref.model.entry.types.BibtexEntryTypeDefinitions; import org.jabref.model.entry.types.EntryType; @@ -41,11 +45,11 @@ private static Stream mode() { void setUp() { newCustomType = new BibEntryType( CUSTOM_TYPE, - Collections.singleton(new BibField(StandardField.AUTHOR, FieldPriority.IMPORTANT)), + List.of(new BibField(StandardField.AUTHOR, FieldPriority.IMPORTANT)), Collections.emptySet()); overwrittenStandardType = new BibEntryType( StandardEntryType.Article, - Collections.singleton(new BibField(StandardField.TITLE, FieldPriority.IMPORTANT)), + List.of(new BibField(StandardField.TITLE, FieldPriority.IMPORTANT)), Collections.emptySet()); entryTypesManager = new BibEntryTypesManager(); } @@ -130,4 +134,79 @@ void standardTypeIsStillAccessibleIfOverwritten(BibDatabaseMode mode) { entryTypesManager.addCustomOrModifiedType(overwrittenStandardType, mode); assertFalse(entryTypesManager.isCustomType(overwrittenStandardType.getType(), mode)); } + + @ParameterizedTest + @MethodSource("mode") + void testParsingEmptyOrFieldsReturnsEmpyCollections(BibDatabaseMode mode) { + String serialized = entryTypesManager.serialize(newCustomType); + Optional type = entryTypesManager.parse(serialized); + assertEquals(Collections.emptySet(), type.get().getRequiredFields()); + } + + @ParameterizedTest + @MethodSource("mode") + void testParsingEmptyOptionalFieldsFieldsReturnsEmpyCollections(BibDatabaseMode mode) { + newCustomType = new BibEntryType( + CUSTOM_TYPE, + Collections.emptySet(), + Collections.singleton(new OrFields(StandardField.AUTHOR))); + + String serialized = entryTypesManager.serialize(newCustomType); + Optional type = entryTypesManager.parse(serialized); + assertEquals(Collections.emptySet(), type.get().getOptionalFields()); + } + + @ParameterizedTest + @MethodSource("mode") + void testsModifyingArticle(BibDatabaseMode mode) { + + overwrittenStandardType = new BibEntryType( + StandardEntryType.Article, + List.of(new BibField(StandardField.TITLE, FieldPriority.IMPORTANT), + new BibField(StandardField.NUMBER, FieldPriority.IMPORTANT), + new BibField(new UnknownField("langid"), FieldPriority.IMPORTANT), + new BibField(StandardField.COMMENT, FieldPriority.IMPORTANT)), + Collections.emptySet()); + + entryTypesManager.addCustomOrModifiedType(overwrittenStandardType, mode); + assertEquals(Collections.singletonList(overwrittenStandardType), entryTypesManager.getAllTypes(mode).stream().filter(t->t.getType().getName().equals("article")).collect(Collectors.toList())); + } + + @ParameterizedTest + @MethodSource("mode") + void testsModifyingArticleWithParsing(BibDatabaseMode mode) { + + overwrittenStandardType = new BibEntryType( + StandardEntryType.Article, + List.of(new BibField(StandardField.TITLE, FieldPriority.IMPORTANT), + new BibField(StandardField.NUMBER, FieldPriority.IMPORTANT), + new BibField(new UnknownField("langid"), FieldPriority.IMPORTANT), + new BibField(StandardField.COMMENT, FieldPriority.IMPORTANT)), + Collections.emptySet()); + + entryTypesManager.addCustomOrModifiedType(overwrittenStandardType, mode); + String serialized = entryTypesManager.serialize(overwrittenStandardType); + Optional type = entryTypesManager.parse(serialized); + + assertEquals(Optional.of(overwrittenStandardType), type); + } + + @ParameterizedTest + @MethodSource("mode") + void testsModifyingArticleWithParsingKeepsListOrder(BibDatabaseMode mode) { + + overwrittenStandardType = new BibEntryType( + StandardEntryType.Article, + List.of(new BibField(StandardField.TITLE, FieldPriority.IMPORTANT), + new BibField(StandardField.NUMBER, FieldPriority.IMPORTANT), + new BibField(new UnknownField("langid"), FieldPriority.IMPORTANT), + new BibField(StandardField.COMMENT, FieldPriority.IMPORTANT)), + Collections.emptySet()); + + entryTypesManager.addCustomOrModifiedType(overwrittenStandardType, mode); + String serialized = entryTypesManager.serialize(overwrittenStandardType); + Optional type = entryTypesManager.parse(serialized); + + assertEquals(overwrittenStandardType.getOptionalFields(), type.get().getOptionalFields()); + } } diff --git a/src/test/resources/testbib/bibWithUserCommentAndEntryChange.bib b/src/test/resources/testbib/bibWithUserCommentAndEntryChange.bib index 326c45842a3..64df3fa78b8 100644 --- a/src/test/resources/testbib/bibWithUserCommentAndEntryChange.bib +++ b/src/test/resources/testbib/bibWithUserCommentAndEntryChange.bib @@ -32,11 +32,11 @@ @Comment this @InProceedings{1137631, author = {Mr. Author}, - booktitle = {SESS '06: Proceedings of the 2006 international workshop on Software engineering for secure systems}, title = {Extending XP practices to support security requirements engineering}, + booktitle = {SESS '06: Proceedings of the 2006 international workshop on Software engineering for secure systems}, year = {2006}, - address = {New York, NY, USA}, pages = {11--18}, + address = {New York, NY, USA}, publisher = {ACM}, bdsk-url-1 = {http://doi.acm.org/10.1145/1137627.1137631}, doi = {http://doi.acm.org/10.1145/1137627.1137631},