diff --git a/src/main/java/org/jabref/gui/Base.css b/src/main/java/org/jabref/gui/Base.css index 35f32a1c71c..3cef89ee044 100644 --- a/src/main/java/org/jabref/gui/Base.css +++ b/src/main/java/org/jabref/gui/Base.css @@ -871,6 +871,10 @@ -fx-text-fill: -jr-search-text; } +.mainToolbar .search-field .label { + -fx-padding: 0em 1.8em 0em 0em; +} + /* The little arrow that shows up when not all tool-bar icons fit into the tool-bar. We want to have a look that matches our icons in the tool-bar */ .mainToolbar .tool-bar-overflow-button > .arrow { diff --git a/src/main/java/org/jabref/gui/search/GlobalSearchBar.java b/src/main/java/org/jabref/gui/search/GlobalSearchBar.java index 6938411b4ad..41d4cbdf4dc 100644 --- a/src/main/java/org/jabref/gui/search/GlobalSearchBar.java +++ b/src/main/java/org/jabref/gui/search/GlobalSearchBar.java @@ -4,10 +4,13 @@ import java.util.List; import java.util.Objects; import java.util.Optional; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; import javafx.animation.KeyFrame; import javafx.animation.KeyValue; import javafx.animation.Timeline; +import javafx.application.Platform; import javafx.beans.binding.Bindings; import javafx.css.PseudoClass; import javafx.event.Event; @@ -48,6 +51,7 @@ import org.jabref.gui.search.rules.describer.SearchDescribers; import org.jabref.gui.util.BindingsHelper; import org.jabref.gui.util.DefaultTaskExecutor; +import org.jabref.gui.util.IconValidationDecorator; import org.jabref.gui.util.TooltipTextUtil; import org.jabref.logic.l10n.Localization; import org.jabref.logic.search.SearchQuery; @@ -55,6 +59,10 @@ import org.jabref.preferences.JabRefPreferences; import org.jabref.preferences.SearchPreferences; +import de.saxsys.mvvmfx.utils.validation.FunctionBasedValidator; +import de.saxsys.mvvmfx.utils.validation.ValidationMessage; +import de.saxsys.mvvmfx.utils.validation.Validator; +import de.saxsys.mvvmfx.utils.validation.visualization.ControlsFxVisualizer; import impl.org.controlsfx.skin.AutoCompletePopup; import org.controlsfx.control.textfield.AutoCompletionBinding; import org.fxmisc.easybind.EasyBind; @@ -81,6 +89,7 @@ public class GlobalSearchBar extends HBox { private final Tooltip tooltip = new Tooltip(); private final StateManager stateManager; private SearchDisplayMode searchDisplayMode; + private Validator regexValidator; public GlobalSearchBar(JabRefFrame frame, StateManager stateManager) { super(); @@ -137,6 +146,15 @@ public GlobalSearchBar(JabRefFrame frame, StateManager stateManager) { searchField.setMaxWidth(initialSize); HBox.setHgrow(searchField, Priority.ALWAYS); + regexValidator = new FunctionBasedValidator<>( + searchField.textProperty(), + query -> !(regularExp.isSelected() && !validRegex()), + ValidationMessage.error(Localization.lang("Invalid regular expression")) + ); + ControlsFxVisualizer visualizer = new ControlsFxVisualizer(); + visualizer.setDecoration(new IconValidationDecorator(Pos.CENTER_LEFT)); + Platform.runLater(() -> { visualizer.initVisualization(regexValidator.getValidationStatus(), searchField); }); + Timer searchTask = FxTimer.create(java.time.Duration.ofMillis(SEARCH_DELAY), this::performSearch); searchField.textProperty().addListener((observable, oldValue, newValue) -> searchTask.restart()); @@ -219,15 +237,30 @@ public void performSearch() { return; } + // Invalid regular expression + if (!regexValidator.getValidationStatus().isValid()) { + currentResults.setText(Localization.lang("Invalid regular expression")); + return; + } + SearchQuery searchQuery = new SearchQuery(this.searchField.getText(), this.caseSensitive.isSelected(), this.regularExp.isSelected()); if (!searchQuery.isValid()) { informUserAboutInvalidSearchQuery(); return; } - stateManager.setSearchQuery(searchQuery); } + private boolean validRegex() { + try { + Pattern.compile(searchField.getText()); + } catch (PatternSyntaxException e) { + LOGGER.debug(e.getMessage()); + return false; + } + return true; + } + private void informUserAboutInvalidSearchQuery() { searchField.pseudoClassStateChanged(CLASS_NO_RESULTS, true); diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index 283a0fd5ddc..902719b523b 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -1399,6 +1399,7 @@ should\ contain\ a\ four\ digit\ number=should contain a four digit number should\ contain\ a\ valid\ page\ number\ range=should contain a valid page number range No\ results\ found.=No results found. Found\ %0\ results.=Found %0 results. +Invalid\ regular\ expression=Invalid regular expression plain\ text=plain text This\ search\ contains\ entries\ in\ which\ any\ field\ contains\ the\ regular\ expression\ %0=This search contains entries in which any field contains the regular expression %0 This\ search\ contains\ entries\ in\ which\ any\ field\ contains\ the\ term\ %0=This search contains entries in which any field contains the term %0