diff --git a/CHANGELOG.md b/CHANGELOG.md index 30842dfaa9d..92f82914c56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv ### Changed +- We replaced the standard ComboBox with a SearchableComboBox and added a free text field in custom Entry Types [#14082](https://github.com/JabRef/jabref/issues/14082) + ### Fixed - We fixed an issue where pressing ESC in the preferences dialog would not always close the dialog. [#8888](https://github.com/JabRef/jabref/issues/8888) diff --git a/jabgui/src/main/java/org/jabref/gui/preferences/customentrytypes/CustomEntryTypesTab.java b/jabgui/src/main/java/org/jabref/gui/preferences/customentrytypes/CustomEntryTypesTab.java index 832cde6eb81..3f6c9e85c28 100644 --- a/jabgui/src/main/java/org/jabref/gui/preferences/customentrytypes/CustomEntryTypesTab.java +++ b/jabgui/src/main/java/org/jabref/gui/preferences/customentrytypes/CustomEntryTypesTab.java @@ -6,7 +6,6 @@ import javafx.fxml.FXML; import javafx.scene.Group; import javafx.scene.control.Button; -import javafx.scene.control.ComboBox; import javafx.scene.control.Label; import javafx.scene.control.TableColumn; import javafx.scene.control.TableRow; @@ -40,6 +39,7 @@ import com.tobiasdiez.easybind.EasyBind; import de.saxsys.mvvmfx.utils.validation.visualization.ControlsFxVisualizer; import jakarta.inject.Inject; +import org.controlsfx.control.SearchableComboBox; public class CustomEntryTypesTab extends AbstractPreferenceTabView implements PreferencesTab { @@ -47,14 +47,16 @@ public class CustomEntryTypesTab extends AbstractPreferenceTabView entryTypColumn; @FXML private TableColumn entryTypeActionsColumn; @FXML private TextField addNewEntryType; + @FXML private TextField addNewCustomFieldText; @FXML private TableView fields; @FXML private TableColumn fieldNameColumn; @FXML private TableColumn fieldTypeColumn; @FXML private TableColumn fieldTypeActionColumn; @FXML private TableColumn fieldTypeMultilineColumn; - @FXML private ComboBox addNewField; + @FXML private SearchableComboBox addNewField; @FXML private Button addNewEntryTypeButton; @FXML private Button addNewFieldButton; + @FXML private Button addNewCustomFieldButton; @Inject private StateManager stateManager; @@ -89,9 +91,13 @@ public void initialize() { addNewEntryTypeButton.disableProperty().bind(viewModel.entryTypeValidationStatus().validProperty().not()); addNewFieldButton.disableProperty().bind(viewModel.fieldValidationStatus().validProperty().not().or(viewModel.selectedEntryTypeProperty().isNull())); + viewModel.newCustomFieldToAddProperty().bindBidirectional(addNewCustomFieldText.textProperty()); + addNewCustomFieldButton.disableProperty().bind(viewModel.customFieldValidationStatus().validProperty().not().or(viewModel.selectedEntryTypeProperty().isNull())); + Platform.runLater(() -> { visualizer.initVisualization(viewModel.entryTypeValidationStatus(), addNewEntryType, true); visualizer.initVisualization(viewModel.fieldValidationStatus(), addNewField, true); + visualizer.initVisualization(viewModel.customFieldValidationStatus(), addNewCustomFieldText, true); }); } @@ -203,7 +209,6 @@ private void setupFieldsTable() { viewModel.newFieldToAddProperty().bindBidirectional(addNewField.valueProperty()); // The valueProperty() of addNewField ComboBox needs to be updated by typing text in the ComboBox textfield, // since the enabled/disabled state of addNewFieldButton won't update otherwise - EasyBind.subscribe(addNewField.getEditor().textProperty(), text -> addNewField.setValue(FieldsUtil.FIELD_STRING_CONVERTER.fromString(text))); } private void makeRotatedColumnHeader(TableColumn column, String text) { @@ -269,6 +274,11 @@ void addNewField() { viewModel.addNewField(); } + @FXML + void addNewCustomField() { + viewModel.addNewCustomField(); + } + @FXML void resetEntryTypes() { boolean reset = dialogService.showConfirmationDialogAndWait( diff --git a/jabgui/src/main/java/org/jabref/gui/preferences/customentrytypes/CustomEntryTypesTabViewModel.java b/jabgui/src/main/java/org/jabref/gui/preferences/customentrytypes/CustomEntryTypesTabViewModel.java index 8b6cde7326e..3ad978dbb14 100644 --- a/jabgui/src/main/java/org/jabref/gui/preferences/customentrytypes/CustomEntryTypesTabViewModel.java +++ b/jabgui/src/main/java/org/jabref/gui/preferences/customentrytypes/CustomEntryTypesTabViewModel.java @@ -31,6 +31,7 @@ import org.jabref.model.entry.field.FieldProperty; import org.jabref.model.entry.field.FieldTextMapper; import org.jabref.model.entry.field.OrFields; +import org.jabref.model.entry.field.UnknownField; import org.jabref.model.entry.types.EntryType; import org.jabref.model.entry.types.UnknownEntryType; @@ -45,6 +46,7 @@ public class CustomEntryTypesTabViewModel implements PreferenceTabViewModel { private final ObjectProperty selectedEntryType = new SimpleObjectProperty<>(); private final StringProperty entryTypeToAdd = new SimpleStringProperty(""); private final ObjectProperty newFieldToAdd = new SimpleObjectProperty<>(); + private final StringProperty newCustomFieldToAdd = new SimpleStringProperty(""); private final ObservableList entryTypesWithFields = FXCollections.observableArrayList(extractor -> new Observable[] {extractor.entryType(), extractor.fields()}); private final List entryTypesToDelete = new ArrayList<>(); @@ -55,6 +57,7 @@ public class CustomEntryTypesTabViewModel implements PreferenceTabViewModel { private final Validator entryTypeValidator; private final Validator fieldValidator; + private final Validator customFieldValidator; private final Set multiLineFields = new HashSet<>(); Predicate isMultiline = field -> this.multiLineFields.contains(field) || field.getProperties().contains(FieldProperty.MULTILINE_TEXT); @@ -78,6 +81,11 @@ public CustomEntryTypesTabViewModel(BibDatabaseMode mode, newFieldToAdd, input -> (input != null) && StringUtil.isNotBlank(FieldTextMapper.getDisplayName(input)), ValidationMessage.error(Localization.lang("Field cannot be empty. Please enter a name."))); + customFieldValidator = new FunctionBasedValidator<>( + newCustomFieldToAdd, + input -> StringUtil.isNotBlank(input) && !input.contains(" "), + ValidationMessage.error(Localization.lang("Field cannot be empty and must not contain spaces.")) + ); } @Override @@ -167,6 +175,26 @@ public void addNewField() { newFieldToAddProperty().setValue(null); } + public void addNewCustomField() { + String fieldName = newCustomFieldToAdd.get().trim(); + Field newField = new UnknownField(fieldName); + + boolean fieldExists = displayNameExists(FieldTextMapper.getDisplayName(newField)); + + if (fieldExists) { + dialogService.showWarningDialogAndWait( + Localization.lang("Duplicate fields"), + Localization.lang("Warning: You added field \"%0\" twice. Only one will be kept.", FieldTextMapper.getDisplayName(newField))); + } else { + this.selectedEntryType.getValue().addField(new FieldViewModel( + newField, + FieldViewModel.Mandatory.REQUIRED, + FieldPriority.IMPORTANT, + false)); + } + newCustomFieldToAdd.set(""); + } + public boolean displayNameExists(String displayName) { ObservableList entryFields = this.selectedEntryType.getValue().fields(); return entryFields.stream().anyMatch(fieldViewModel -> @@ -202,6 +230,10 @@ public ObservableList fieldsForAdding() { return this.fieldsForAdding; } + public StringProperty newCustomFieldToAddProperty() { + return this.newCustomFieldToAdd; + } + public ValidationStatus entryTypeValidationStatus() { return entryTypeValidator.getValidationStatus(); } @@ -209,4 +241,8 @@ public ValidationStatus entryTypeValidationStatus() { public ValidationStatus fieldValidationStatus() { return fieldValidator.getValidationStatus(); } + + public ValidationStatus customFieldValidationStatus() { + return customFieldValidator.getValidationStatus(); + } } diff --git a/jabgui/src/main/resources/org/jabref/gui/preferences/customentrytypes/CustomEntryTypesTab.fxml b/jabgui/src/main/resources/org/jabref/gui/preferences/customentrytypes/CustomEntryTypesTab.fxml index 5dbb82e844b..41a2c515871 100644 --- a/jabgui/src/main/resources/org/jabref/gui/preferences/customentrytypes/CustomEntryTypesTab.fxml +++ b/jabgui/src/main/resources/org/jabref/gui/preferences/customentrytypes/CustomEntryTypesTab.fxml @@ -1,7 +1,6 @@ - @@ -11,6 +10,7 @@ + @@ -30,7 +30,7 @@ - + + + + + + + + + + + + + +