Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix context menu of the search bar #11446

Merged
merged 21 commits into from
Jul 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
b0017fb
Fix selecting group triggers in all open libraries
LoayGhreeb Jun 29, 2024
b89a9ed
Change color of the search modifier buttons for dark theme
LoayGhreeb Jun 29, 2024
61413f3
Add shortcut to open global search window "Ctrl+shift+F"
LoayGhreeb Jun 29, 2024
fda8f4c
fix keep on top subscription
LoayGhreeb Jun 29, 2024
e26dc17
Fix context menu of the search bar
LoayGhreeb Jun 29, 2024
579abed
Store preview divider position in global search window
LoayGhreeb Jun 30, 2024
6d3a5b7
prevent NPE
LoayGhreeb Jun 29, 2024
d6d455c
Fix update search query triggers in all open libraries
LoayGhreeb Jul 1, 2024
b8a52cc
Adapt GUI test
LoayGhreeb Jul 1, 2024
e13e6a2
Merge branch 'main' into improveSearchPerformance
LoayGhreeb Jul 1, 2024
e537364
Clear search highlight in SourceTab after resetting search query
LoayGhreeb Jul 3, 2024
b7ab701
Merge branch 'main' into improveSearchPerformance
LoayGhreeb Jul 3, 2024
feedcae
Revert "Fix update search query triggers in all open libraries"
LoayGhreeb Jul 8, 2024
0b901a8
Revert "Fix selecting group triggers in all open libraries"
LoayGhreeb Jul 8, 2024
8dd73e9
Merge branch 'main' into improveSearchPerformance
LoayGhreeb Jul 8, 2024
bb2ba59
Remove regexValidator
LoayGhreeb Jul 8, 2024
a6692e6
Merge branch 'improveSearchPerformance' of https://github.com/LoayGhr…
LoayGhreeb Jul 8, 2024
c68c5bf
listen for changes for search flags
LoayGhreeb Jul 8, 2024
227f3c0
Merge branch 'main' into improveSearchPerformance
LoayGhreeb Jul 11, 2024
839bf79
Merge branch 'main' into improveSearchPerformance
LoayGhreeb Jul 17, 2024
21eb34a
Merge remote-tracking branch 'upstream/main' into improveSearchPerfor…
Siedlerchr Jul 24, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 6 additions & 10 deletions src/main/java/org/jabref/gui/Base.css
Original file line number Diff line number Diff line change
Expand Up @@ -1072,29 +1072,25 @@ TextFlow > .tooltip-text-monospaced {
}

/* search modifier buttons */
.mainToolbar .search-field .toggle-button:selected {
.global-search-bar .toggle-button:selected {
-fx-background-color: transparent;
}

.mainToolbar .search-field .toggle-button:hover,
.mainToolbar .search-field .toggle-button:selected:hover {
.global-search-bar .toggle-button:hover,
.global-search-bar .toggle-button:selected:hover {
-fx-background-color: -jr-icon-background-active;
}

.mainToolbar .search-field .toggle-button .glyph-icon {
-fx-fill: derive(-jr-search-text, 80%);
-fx-text-fill: derive(-jr-search-text, 80%);
.global-search-bar .toggle-button .glyph-icon {
-fx-icon-color: derive(-jr-search-text, 80%);
}

.mainToolbar .search-field .toggle-button:selected .glyph-icon {
-fx-fill: -jr-search-text;
-fx-text-fill: -jr-search-text;
.global-search-bar .toggle-button:selected .glyph-icon {
-fx-icon-color: -jr-search-text;
}

/* search text */
.mainToolbar .search-field .label {
.global-search-bar .label {
-fx-padding: 0em 1.8em 0em 0em;
}

Expand Down
18 changes: 2 additions & 16 deletions src/main/java/org/jabref/gui/Dark.css
Original file line number Diff line number Diff line change
Expand Up @@ -143,22 +143,8 @@
-fx-background-color: -jr-background;
}

.mainToolbar .search-field .button .glyph-icon {
-fx-fill: derive(-fx-light-text-color, 80%);
-fx-text-fill: derive(-fx-light-text-color, 80%);
-fx-icon-color: derive(-fx-light-text-color, 80%);
}

.mainToolbar .search-field .toggle-button .glyph-icon {
-fx-fill: -jr-search-text;
-fx-text-fill: -jr-search-text;
-fx-icon-color:-jr-search-text;
}

.mainToolbar .search-field .toggle-button:selected .glyph-icon {
-fx-fill: derive(-fx-light-text-color, 80%);
-fx-text-fill: derive(-fx-light-text-color, 80%);
-fx-icon-color: derive(-fx-light-text-color, 80%);
.global-search-bar .toggle-button .glyph-icon {
-fx-icon-color: derive(-jr-search-background, 50%);
}

.notification-bar > .pane {
Expand Down
12 changes: 7 additions & 5 deletions src/main/java/org/jabref/gui/entryeditor/SourceTab.java
Original file line number Diff line number Diff line change
Expand Up @@ -131,12 +131,14 @@ public SourceTab(BibDatabaseContext bibDatabaseContext,
}

private void highlightSearchPattern() {
if (searchHighlightPattern.isPresent() && (codeArea != null)) {
if (codeArea != null) {
codeArea.setStyleClass(0, codeArea.getLength(), "text");
Matcher matcher = searchHighlightPattern.get().matcher(codeArea.getText());
while (matcher.find()) {
for (int i = 0; i <= matcher.groupCount(); i++) {
codeArea.setStyleClass(matcher.start(), matcher.end(), "search");
if (searchHighlightPattern.isPresent()) {
Matcher matcher = searchHighlightPattern.get().matcher(codeArea.getText());
while (matcher.find()) {
for (int i = 0; i <= matcher.groupCount(); i++) {
codeArea.setStyleClass(matcher.start(), matcher.end(), "search");
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,17 @@ public EditorContextAction(StandardActions command, TextInputControl textInputCo
BooleanBinding hasSelectionBinding = Bindings.createBooleanBinding(() -> textInputControl.getSelection().getLength() > 0, textInputControl.selectionProperty());
BooleanBinding allSelectedBinding = Bindings.createBooleanBinding(() -> textInputControl.getSelection().getLength() == textInputControl.getLength());
BooleanBinding maskTextBinding = (BooleanBinding) BindingsHelper.constantOf(textInputControl instanceof PasswordField); // (maskText("A") != "A");
BooleanBinding undoableBinding = Bindings.createBooleanBinding(textInputControl::isUndoable, textInputControl.undoableProperty());
BooleanBinding redoableBinding = Bindings.createBooleanBinding(textInputControl::isRedoable, textInputControl.redoableProperty());

this.executable.bind(
switch (command) {
case COPY -> editableBinding.and(maskTextBinding.not()).and(hasSelectionBinding);
case CUT -> maskTextBinding.not().and(hasSelectionBinding);
case PASTE -> editableBinding.and(hasStringInClipboardBinding);
case DELETE -> editableBinding.and(hasSelectionBinding);
case UNDO -> undoableBinding;
case REDO -> redoableBinding;
case SELECT_ALL -> {
if (SHOW_HANDLES) {
yield hasTextBinding.and(allSelectedBinding.not());
Expand All @@ -61,6 +65,8 @@ public void execute() {
case PASTE -> textInputControl.paste();
case DELETE -> textInputControl.deleteText(textInputControl.getSelection());
case SELECT_ALL -> textInputControl.selectAll();
case UNDO -> textInputControl.undo();
case REDO -> textInputControl.redo();
}
textInputControl.requestFocus();
}
Expand Down
5 changes: 4 additions & 1 deletion src/main/java/org/jabref/gui/frame/JabRefFrame.java
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,10 @@ private void initKeyBindings() {
event.consume();
break;
case SEARCH:
globalSearchBar.focus();
globalSearchBar.requestFocus();
break;
case OPEN_GLOBAL_SEARCH_DIALOG:
globalSearchBar.openGlobalSearchDialog();
break;
case NEW_ARTICLE:
new NewEntryAction(this::getCurrentLibraryTab, StandardEntryType.Article, dialogService, prefs, stateManager).execute();
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/jabref/gui/icon/IconTheme.java
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ public enum JabRefIcons implements JabRefIcon {
SELECT_ICONS(MaterialDesignA.APPS),
KEEP_SEARCH_STRING(MaterialDesignE.EARTH),
KEEP_ON_TOP(MaterialDesignP.PIN),
KEEP_ON_TOP_OFF(MaterialDesignP.PIN_OFF_OUTLINE),
KEEP_ON_TOP_OFF(MaterialDesignP.PIN_OFF),
OPEN_GLOBAL_SEARCH(MaterialDesignO.OPEN_IN_NEW),
REMOVE_TAGS(MaterialDesignC.CLOSE),
ACCEPT_LEFT(MaterialDesignS.SUBDIRECTORY_ARROW_LEFT),
Expand Down
1 change: 1 addition & 0 deletions src/main/java/org/jabref/gui/keyboard/KeyBinding.java
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ public enum KeyBinding {
SAVE_DATABASE("Save library", Localization.lang("Save library"), "ctrl+S", KeyBindingCategory.FILE),
SAVE_DATABASE_AS("Save library as ...", Localization.lang("Save library as..."), "ctrl+shift+S", KeyBindingCategory.FILE),
SEARCH("Search", Localization.lang("Search"), "ctrl+F", KeyBindingCategory.SEARCH),
OPEN_GLOBAL_SEARCH_DIALOG("Open global search window", Localization.lang("Open global search window"), "ctrl+shift+F", KeyBindingCategory.SEARCH),
SELECT_ALL("Select all", Localization.lang("Select all"), "ctrl+A", KeyBindingCategory.EDIT),
SELECT_FIRST_ENTRY("Select first entry", Localization.lang("Select first entry"), "HOME", KeyBindingCategory.EDIT),
SELECT_LAST_ENTRY("Select last entry", Localization.lang("Select last entry"), "END", KeyBindingCategory.EDIT),
Expand Down
99 changes: 43 additions & 56 deletions src/main/java/org/jabref/gui/search/GlobalSearchBar.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,12 @@

import javax.swing.undo.UndoManager;

import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.collections.SetChangeListener;
import javafx.css.PseudoClass;
import javafx.event.Event;
import javafx.geometry.Insets;
Expand Down Expand Up @@ -55,7 +54,6 @@
import org.jabref.gui.keyboard.KeyBindingRepository;
import org.jabref.gui.search.rules.describer.SearchDescribers;
import org.jabref.gui.util.BindingsHelper;
import org.jabref.gui.util.IconValidationDecorator;
import org.jabref.gui.util.OptionalObjectProperty;
import org.jabref.gui.util.TooltipTextUtil;
import org.jabref.gui.util.UiTaskExecutor;
Expand All @@ -66,10 +64,6 @@
import org.jabref.preferences.PreferencesService;
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.controlsfx.control.textfield.CustomTextField;
Expand Down Expand Up @@ -99,7 +93,6 @@ public class GlobalSearchBar extends HBox {

private final StateManager stateManager;
private final PreferencesService preferencesService;
private final Validator regexValidator;
private final UndoManager undoManager;
private final LibraryTabContainer tabContainer;

Expand Down Expand Up @@ -145,32 +138,22 @@ public GlobalSearchBar(LibraryTabContainer tabContainer,

searchField.addEventFilter(KeyEvent.KEY_PRESSED, event -> {
if (keyBindingRepository.matches(event, KeyBinding.CLEAR_SEARCH)) {
// Clear search and select first entry, if available
searchField.clear();
if (searchType == SearchType.NORMAL_SEARCH) {
tabContainer.getCurrentLibraryTab().getMainTable().getSelectionModel().selectFirst();
tabContainer.getCurrentLibraryTab().getMainTable().requestFocus();
}
event.consume();
}
});

searchField.setContextMenu(SearchFieldRightClickMenu.create(
stateManager,
searchField,
tabContainer,
undoManager));

ObservableList<String> search = stateManager.getWholeSearchHistory();
search.addListener((ListChangeListener.Change<? extends String> change) ->
searchField.setContextMenu(SearchFieldRightClickMenu.create(
stateManager,
searchField,
tabContainer,
undoManager))
);

ClipBoardManager.addX11Support(searchField);

searchField.setContextMenu(SearchFieldRightClickMenu.create(stateManager, searchField));
stateManager.getWholeSearchHistory().addListener((ListChangeListener.Change<? extends String> change) -> {
searchField.getContextMenu().getItems().removeLast();
searchField.getContextMenu().getItems().add(SearchFieldRightClickMenu.createSearchFromHistorySubMenu(stateManager, searchField));
});

regularExpressionButton = IconTheme.JabRefIcons.REG_EX.asToggleButton();
caseSensitiveButton = IconTheme.JabRefIcons.CASE_SENSITIVE.asToggleButton();
fulltextButton = IconTheme.JabRefIcons.FULLTEXT.asToggleButton();
Expand All @@ -184,8 +167,7 @@ public GlobalSearchBar(LibraryTabContainer tabContainer,
.or(caseSensitiveButton.focusedProperty())
.or(fulltextButton.focusedProperty())
.or(keepSearchString.focusedProperty())
.or(searchField.textProperty()
.isNotEmpty());
.or(searchField.textProperty().isNotEmpty());

regularExpressionButton.visibleProperty().unbind();
regularExpressionButton.visibleProperty().bind(focusedOrActive);
Expand All @@ -205,18 +187,10 @@ public GlobalSearchBar(LibraryTabContainer tabContainer,

modifierButtons.setAlignment(Pos.CENTER);
searchField.setRight(new HBox(searchField.getRight(), modifierButtons));
searchField.getStyleClass().add("search-field");
searchField.getStyleClass().add("global-search-bar");
searchField.setMinWidth(100);
HBox.setHgrow(searchField, Priority.ALWAYS);

regexValidator = new FunctionBasedValidator<>(
searchField.textProperty(),
query -> !(regularExpressionButton.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));

LoayGhreeb marked this conversation as resolved.
Show resolved Hide resolved
if (searchType == SearchType.NORMAL_SEARCH) {
this.getChildren().addAll(searchField, openGlobalSearchButton, currentResults);
} else {
Expand Down Expand Up @@ -261,52 +235,64 @@ private void initSearchModifierButtons() {
regularExpressionButton.setSelected(searchPreferences.isRegularExpression());
regularExpressionButton.setTooltip(new Tooltip(Localization.lang("regular expression")));
initSearchModifierButton(regularExpressionButton);
regularExpressionButton.setOnAction(event -> {
searchPreferences.setSearchFlag(SearchRules.SearchFlags.REGULAR_EXPRESSION, regularExpressionButton.isSelected());
regularExpressionButton.selectedProperty().addListener((obs, oldVal, newVal) -> {
searchPreferences.setSearchFlag(SearchRules.SearchFlags.REGULAR_EXPRESSION, newVal);
updateSearchQuery();
});

caseSensitiveButton.setSelected(searchPreferences.isCaseSensitive());
caseSensitiveButton.setTooltip(new Tooltip(Localization.lang("Case sensitive")));
initSearchModifierButton(caseSensitiveButton);
caseSensitiveButton.setOnAction(event -> {
searchPreferences.setSearchFlag(SearchRules.SearchFlags.CASE_SENSITIVE, caseSensitiveButton.isSelected());
caseSensitiveButton.selectedProperty().addListener((obs, oldVal, newVal) -> {
searchPreferences.setSearchFlag(SearchRules.SearchFlags.CASE_SENSITIVE, newVal);
updateSearchQuery();
});

fulltextButton.setSelected(searchPreferences.isFulltext());
fulltextButton.setTooltip(new Tooltip(Localization.lang("Fulltext search")));
initSearchModifierButton(fulltextButton);
fulltextButton.setOnAction(event -> {
searchPreferences.setSearchFlag(SearchRules.SearchFlags.FULLTEXT, fulltextButton.isSelected());
fulltextButton.selectedProperty().addListener((obs, oldVal, newVal) -> {
searchPreferences.setSearchFlag(SearchRules.SearchFlags.FULLTEXT, newVal);
updateSearchQuery();
});

keepSearchString.setSelected(searchPreferences.shouldKeepSearchString());
keepSearchString.setTooltip(new Tooltip(Localization.lang("Keep search string across libraries")));
initSearchModifierButton(keepSearchString);
keepSearchString.setOnAction(evt -> {
searchPreferences.setSearchFlag(SearchRules.SearchFlags.KEEP_SEARCH_STRING, keepSearchString.isSelected());
keepSearchString.selectedProperty().addListener((obs, oldVal, newVal) -> {
searchPreferences.setSearchFlag(SearchRules.SearchFlags.KEEP_SEARCH_STRING, newVal);
updateSearchQuery();
});

openGlobalSearchButton.disableProperty().bindBidirectional(globalSearchActive);
openGlobalSearchButton.setTooltip(new Tooltip(Localization.lang("Search across libraries in a new window")));
initSearchModifierButton(openGlobalSearchButton);
openGlobalSearchButton.setOnAction(evt -> {
globalSearchActive.setValue(true);
if (globalSearchResultDialog == null) {
globalSearchResultDialog = new GlobalSearchResultDialog(undoManager, tabContainer);
}
stateManager.activeGlobalSearchQueryProperty().setValue(searchQueryProperty.get());
updateSearchQuery();
dialogService.showCustomDialogAndWait(globalSearchResultDialog);
globalSearchActive.setValue(false);
openGlobalSearchButton.setOnAction(evt -> openGlobalSearchDialog());

searchPreferences.getObservableSearchFlags().addListener((SetChangeListener.Change<? extends SearchRules.SearchFlags> change) -> {
regularExpressionButton.setSelected(searchPreferences.isRegularExpression());
caseSensitiveButton.setSelected(searchPreferences.isCaseSensitive());
fulltextButton.setSelected(searchPreferences.isFulltext());
keepSearchString.setSelected(searchPreferences.shouldKeepSearchString());
});
}

public void openGlobalSearchDialog() {
if (globalSearchActive.get()) {
return;
}
globalSearchActive.setValue(true);
if (globalSearchResultDialog == null) {
globalSearchResultDialog = new GlobalSearchResultDialog(undoManager, tabContainer);
}
stateManager.activeGlobalSearchQueryProperty().setValue(searchQueryProperty.get());
updateSearchQuery();
dialogService.showCustomDialogAndWait(globalSearchResultDialog);
globalSearchActive.setValue(false);
}

private void initSearchModifierButton(ButtonBase searchButton) {
searchButton.setCursor(Cursor.DEFAULT);
searchButton.setCursor(Cursor.HAND);
searchButton.setMinHeight(28);
searchButton.setMaxHeight(28);
searchButton.setMinWidth(28);
Expand All @@ -319,7 +305,8 @@ private void initSearchModifierButton(ButtonBase searchButton) {
/**
* Focuses the search field if it is not focused.
*/
public void focus() {
@Override
public void requestFocus() {
if (!searchField.isFocused()) {
searchField.requestFocus();
}
Expand All @@ -339,7 +326,7 @@ public void updateSearchQuery() {
}

// Invalid regular expression
if (!regexValidator.getValidationStatus().isValid()) {
if (regularExpressionButton.isSelected() && !validRegex()) {
currentResults.setText(Localization.lang("Invalid regular expression"));
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
<?import javafx.scene.control.ToggleButton?>
<?import javafx.scene.control.Tooltip?>
<?import javafx.scene.layout.VBox?>
<?import org.jabref.gui.icon.JabRefIconView?>
<?import javafx.scene.layout.HBox?>
<DialogPane xmlns="http://javafx.com/javafx/16" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="org.jabref.gui.search.GlobalSearchResultDialog"
Expand All @@ -15,9 +14,6 @@
<VBox>
<HBox fx:id="searchBarContainer" spacing="10" alignment="CENTER_RIGHT">
<ToggleButton fx:id="keepOnTop" styleClass="icon-button,narrow" prefHeight="20.0" prefWidth="20.0">
<graphic>
LoayGhreeb marked this conversation as resolved.
Show resolved Hide resolved
<JabRefIconView glyph="KEEP_ON_TOP"/>
</graphic>
<tooltip>
<Tooltip text="%Keep dialog always on top"/>
</tooltip>
Expand Down
Loading
Loading