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