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 @@
-
+