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

New global search #8045

Merged
merged 51 commits into from
Sep 2, 2021
Merged
Show file tree
Hide file tree
Changes from 50 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
91509f6
WIP Prepare for adding global search state
Siedlerchr Aug 30, 2021
754155c
Transform to BibEnty list
Siedlerchr Aug 30, 2021
0a6082c
use traditional approach
Siedlerchr Aug 31, 2021
3add3f6
remove observables
Siedlerchr Aug 31, 2021
774a3a5
Proof of concept for Global Search
Siedlerchr Aug 31, 2021
c64aeb4
Add library to sarch results
Siedlerchr Aug 31, 2021
ccdcb46
Add new custom dialog method without modality to enable floating window
Siedlerchr Aug 31, 2021
715d068
Merge remote-tracking branch 'upstream/main' into newGlobalSearch
Siedlerchr Aug 31, 2021
4be7161
update search results
Siedlerchr Aug 31, 2021
326d7ce
refactor
Siedlerchr Aug 31, 2021
0515e88
rename
Siedlerchr Aug 31, 2021
0d7ae9b
change to custom field
Siedlerchr Aug 31, 2021
2f202e4
remove special fields
Siedlerchr Sep 1, 2021
bff8b2b
move dialog to search bar
Siedlerchr Sep 1, 2021
11ad482
checkstyle
Siedlerchr Sep 1, 2021
128d8df
change column name
Siedlerchr Sep 1, 2021
5f38554
checkstyle
Siedlerchr Sep 1, 2021
8d37221
Change GlobalMode Button
Siedlerchr Sep 1, 2021
f2d76f0
Add Tooltip
Siedlerchr Sep 1, 2021
73b6103
fix checkstyle
Siedlerchr Sep 1, 2021
c844215
Update DialogService.java
calixtus Sep 1, 2021
a992002
refactor
Siedlerchr Sep 1, 2021
c362243
Merge branch 'newGlobalSearch' of github.com:JabRef/jabref into newGl…
Siedlerchr Sep 1, 2021
abf2bcf
remove empty line
Siedlerchr Sep 1, 2021
723acda
Add keep search string
Siedlerchr Sep 1, 2021
6231360
Fix css icon for button
Siedlerchr Sep 1, 2021
342f273
checkstyle
Siedlerchr Sep 1, 2021
8e9a5a0
checkstyle again argh
Siedlerchr Sep 1, 2021
44d6c31
fix some checkstle
Siedlerchr Sep 1, 2021
bb5988e
update search results
Siedlerchr Sep 1, 2021
ae228d4
Add Preview tab
Siedlerchr Sep 1, 2021
2068f11
fix accidentally deleted
Siedlerchr Sep 1, 2021
aceaed5
just install a new value table factory for the cell library
Siedlerchr Sep 1, 2021
0433973
WIP: prepare dialog
Siedlerchr Sep 1, 2021
4264a80
single selection
Siedlerchr Sep 1, 2021
c68ff82
remove groups matcher
Siedlerchr Sep 1, 2021
05ae012
inject
Siedlerchr Sep 1, 2021
35b53f7
Convert to GlobalSearchDialog to MVVM
calixtus Sep 1, 2021
1072743
Fixed conversion errors
calixtus Sep 1, 2021
df20354
always on top
Siedlerchr Sep 2, 2021
4a87e9c
Add checkbox for keeping dialog on top
Siedlerchr Sep 2, 2021
bdc5e95
Merge remote-tracking branch 'upstream/main' into newGlobalSearch
Siedlerchr Sep 2, 2021
2303465
check for global search active
Siedlerchr Sep 2, 2021
2fa9328
Remove explicit showNonModalCustomDialogAndWait
calixtus Sep 2, 2021
307cd72
Fixed keep always on top
calixtus Sep 2, 2021
a0bb0b6
Reduced scope of globalSearchActive property
calixtus Sep 2, 2021
d2a922a
Add CHANGELOG entry
koppor Sep 2, 2021
4572081
Add missing CHANGELOG entry
koppor Sep 2, 2021
e7f64fb
Fixed whitespaces
calixtus Sep 2, 2021
cb72abd
Merge remote-tracking branch 'upstream/newGlobalSearch' into newGloba…
calixtus Sep 2, 2021
0f70245
Remove empty line
koppor Sep 2, 2021
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
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve
- We added unprotect_terms to the list of bracketed pattern modifiers [#7826](https://github.com/JabRef/jabref/pull/7960)
- We added a dialog that allows to parse metadata from linked pdfs. [#7929](https://github.com/JabRef/jabref/pull/7929)
- We added an icon picker in group edit dialog. [#6142](https://github.com/JabRef/jabref/issues/6142)
- We added a preference to Opt-In to JabRef's online metadata extraction service (Grobid) usage. [8002](https://github.com/JabRef/jabref/pull/8002)
- We added a preference to Opt-In to JabRef's online metadata extraction service (Grobid) usage. [#8002](https://github.com/JabRef/jabref/pull/8002)
- We readded the possibility to display the search results of all databases ("Global Search"). It is shown in a separate window. [#4096](https://github.com/JabRef/jabref/issues/4096)
- We readded the possibility to keep the search string when switching tabs. It is implemented by a toggle button. [#4096](https://github.com/JabRef/jabref/issues/4096#issuecomment-575986882)

### Changed

Expand Down
7 changes: 7 additions & 0 deletions src/main/java/org/jabref/gui/Base.css
Original file line number Diff line number Diff line change
Expand Up @@ -960,6 +960,13 @@ TextFlow > .tooltip-text-monospaced {
-fx-fill: -jr-search-text;
}


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

/* magnifier glass */
.mainToolbar .search-field .glyph-icon {
-fx-fill: -jr-search-text;
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/org/jabref/gui/Dark.css
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@
-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;
Expand Down
12 changes: 9 additions & 3 deletions src/main/java/org/jabref/gui/JabRefFrame.java
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,8 @@ public JabRefFrame(Stage mainStage) {
this.dialogService = new JabRefDialogService(mainStage, this, prefs);
this.stateManager = Globals.stateManager;
this.pushToApplicationsManager = new PushToApplicationsManager(dialogService, stateManager, prefs);
this.globalSearchBar = new GlobalSearchBar(this, stateManager, prefs);
this.undoManager = Globals.undoManager;
this.globalSearchBar = new GlobalSearchBar(this, stateManager, prefs, undoManager);
this.fileHistory = new FileHistoryMenu(prefs, dialogService, getOpenDatabaseAction());
this.taskExecutor = Globals.TASK_EXECUTOR;
this.setOnKeyTyped(key -> {
Expand Down Expand Up @@ -594,8 +594,14 @@ public void init() {
// Subscribe to the search
EasyBind.subscribe(stateManager.activeSearchQueryProperty(),
query -> {
if (getCurrentLibraryTab() != null) {
getCurrentLibraryTab().setCurrentSearchQuery(query);
if (prefs.getSearchPreferences().isKeepSearchString()) {
for (LibraryTab tab : getLibraryTabs()) {
tab.setCurrentSearchQuery(query);
}
} else {
if (getCurrentLibraryTab() != null) {
getCurrentLibraryTab().setCurrentSearchQuery(query);
}
}
});

Expand Down
17 changes: 4 additions & 13 deletions src/main/java/org/jabref/gui/LibraryTab.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.jabref.gui;

import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
Expand Down Expand Up @@ -109,7 +108,7 @@ public class LibraryTab extends Tab {
// initializing it so we prevent NullPointerException
private BackgroundTask<ParserResult> dataLoadingTask = BackgroundTask.wrap(() -> null);

private IndexingTaskManager indexingTaskManager = new IndexingTaskManager(Globals.TASK_EXECUTOR);
private final IndexingTaskManager indexingTaskManager = new IndexingTaskManager(Globals.TASK_EXECUTOR);

public LibraryTab(JabRefFrame frame,
PreferencesService preferencesService,
Expand Down Expand Up @@ -311,17 +310,9 @@ public void updateTabTitle(boolean isChanged) {
}

// Unique path fragment
List<String> uniquePathParts = FileUtil.uniquePathSubstrings(collectAllDatabasePaths());
Optional<String> uniquePathPart = uniquePathParts.stream()
.filter(part -> databasePath.toString().contains(part)
&& !part.equals(fileName) && part.contains(File.separator))
.findFirst();
if (uniquePathPart.isPresent()) {
String uniquePath = uniquePathPart.get();
// remove filename
uniquePath = uniquePath.substring(0, uniquePath.lastIndexOf(File.separator));
tabTitle.append(" \u2013 ").append(uniquePath);
}
Optional<String> uniquePathPart = FileUtil.getUniquePathFragment(collectAllDatabasePaths(), databasePath);
uniquePathPart.ifPresent(part -> tabTitle.append(" \u2013 ").append(part));

} else {
if (databaseLocation == DatabaseLocation.LOCAL) {
tabTitle.append(Localization.lang("untitled"));
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/jabref/gui/StateManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public class StateManager {
private final OptionalObjectProperty<SearchQuery> activeSearchQuery = OptionalObjectProperty.empty();
private final ObservableMap<BibDatabaseContext, IntegerProperty> searchResultMap = FXCollections.observableHashMap();
private final OptionalObjectProperty<Node> focusOwner = OptionalObjectProperty.empty();
private final ObservableList<Task<?>> backgroundTasks = FXCollections.observableArrayList(task -> new Observable[]{task.progressProperty(), task.runningProperty()});
private final ObservableList<Task<?>> backgroundTasks = FXCollections.observableArrayList(task -> new Observable[] {task.progressProperty(), task.runningProperty()});
private final EasyBinding<Boolean> anyTaskRunning = EasyBind.reduce(backgroundTasks, tasks -> tasks.anyMatch(Task::isRunning));
private final EasyBinding<Double> tasksProgress = EasyBind.reduce(backgroundTasks, tasks -> tasks.filter(Task::isRunning).mapToDouble(Task::getProgress).average().orElse(1));
private final ObservableMap<String, DialogWindowState> dialogWindowStates = FXCollections.observableHashMap();
Expand Down
6 changes: 5 additions & 1 deletion src/main/java/org/jabref/gui/icon/IconTheme.java
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,11 @@ public enum JabRefIcons implements JabRefIcon {
LINK(MaterialDesignL.LINK),
LINK_VARIANT(MaterialDesignL.LINK_VARIANT),
PROTECT_STRING(MaterialDesignC.CODE_BRACES),
SELECT_ICONS(MaterialDesignA.APPS);
SELECT_ICONS(MaterialDesignA.APPS),
KEEP_SEARCH_STRING(MaterialDesignE.EARTH),
KEEP_ON_TOP(MaterialDesignP.PIN),
KEEP_ON_TOP_OFF(MaterialDesignP.PIN_OFF_OUTLINE),
OPEN_GLOBAL_SEARCH(MaterialDesignO.OPEN_IN_NEW);

private final JabRefIcon icon;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ public MainTableDataModel(BibDatabaseContext context, PreferencesService prefere
// We need to wrap the list since otherwise sorting in the table does not work
entriesSorted = new SortedList<>(entriesFiltered);
groupViewMode = preferencesService.getGroupViewMode();

}

private boolean isMatched(ObservableList<GroupTreeNode> groups, Optional<SearchQuery> query, BibEntryTableViewModel entry) {
Expand Down
85 changes: 55 additions & 30 deletions src/main/java/org/jabref/gui/search/GlobalSearchBar.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,21 @@
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

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.css.PseudoClass;
import javafx.event.Event;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Cursor;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonBase;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
Expand All @@ -40,10 +46,12 @@
import org.jabref.gui.autocompleter.AutoCompletionTextInputBinding;
import org.jabref.gui.autocompleter.PersonNameStringConverter;
import org.jabref.gui.autocompleter.SuggestionProvider;
import org.jabref.gui.externalfiletype.ExternalFileTypes;
import org.jabref.gui.icon.IconTheme;
import org.jabref.gui.keyboard.KeyBinding;
import org.jabref.gui.keyboard.KeyBindingRepository;
import org.jabref.gui.search.rules.describer.SearchDescribers;
import org.jabref.gui.undo.CountingUndoManager;
import org.jabref.gui.util.BindingsHelper;
import org.jabref.gui.util.DefaultTaskExecutor;
import org.jabref.gui.util.IconValidationDecorator;
Expand All @@ -54,7 +62,6 @@
import org.jabref.preferences.PreferencesService;
import org.jabref.preferences.SearchPreferences;

import com.tobiasdiez.easybind.EasyBind;
import de.saxsys.mvvmfx.utils.validation.FunctionBasedValidator;
import de.saxsys.mvvmfx.utils.validation.ValidationMessage;
import de.saxsys.mvvmfx.utils.validation.Validator;
Expand All @@ -81,23 +88,30 @@ public class GlobalSearchBar extends HBox {
private final ToggleButton caseSensitiveButton;
private final ToggleButton regularExpressionButton;
private final ToggleButton fulltextButton;
private final Button openGlobalSearchButton;
private final ToggleButton keepSearchString;
// private final Button searchModeButton;
private final Tooltip searchFieldTooltip = new Tooltip();
private final Label currentResults = new Label("");

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

private SearchPreferences searchPreferences;

public GlobalSearchBar(JabRefFrame frame, StateManager stateManager, PreferencesService preferencesService) {
private final BooleanProperty globalSearchActive = new SimpleBooleanProperty(false);
private GlobalSearchResultDialog globalSearchResultDialog;

public GlobalSearchBar(JabRefFrame frame, StateManager stateManager, PreferencesService preferencesService, CountingUndoManager undoManager) {
super();
this.stateManager = stateManager;
this.preferencesService = preferencesService;
this.searchPreferences = preferencesService.getSearchPreferences();
this.undoManager = undoManager;

this.searchField.disableProperty().bind(needsDatabase(stateManager).not());
searchField.disableProperty().bind(needsDatabase(stateManager).not());

// fits the standard "found x entries"-message thus hinders the searchbar to jump around while searching if the frame width is too small
currentResults.setPrefWidth(150);
Expand Down Expand Up @@ -125,13 +139,16 @@ public GlobalSearchBar(JabRefFrame frame, StateManager stateManager, Preferences
regularExpressionButton = IconTheme.JabRefIcons.REG_EX.asToggleButton();
caseSensitiveButton = IconTheme.JabRefIcons.CASE_SENSITIVE.asToggleButton();
fulltextButton = IconTheme.JabRefIcons.FULLTEXT.asToggleButton();
// searchModeButton = new Button();
openGlobalSearchButton = IconTheme.JabRefIcons.OPEN_GLOBAL_SEARCH.asButton();
keepSearchString = IconTheme.JabRefIcons.KEEP_SEARCH_STRING.asToggleButton();

initSearchModifierButtons();

BooleanBinding focusedOrActive = searchField.focusedProperty()
.or(regularExpressionButton.focusedProperty())
.or(caseSensitiveButton.focusedProperty())
.or(fulltextButton.focusedProperty())
.or(keepSearchString.focusedProperty())
.or(searchField.textProperty()
.isNotEmpty());

Expand All @@ -141,8 +158,10 @@ public GlobalSearchBar(JabRefFrame frame, StateManager stateManager, Preferences
caseSensitiveButton.visibleProperty().bind(focusedOrActive);
fulltextButton.visibleProperty().unbind();
fulltextButton.visibleProperty().bind(focusedOrActive);
keepSearchString.visibleProperty().unbind();
keepSearchString.visibleProperty().bind(focusedOrActive);

StackPane modifierButtons = new StackPane(new HBox(regularExpressionButton, caseSensitiveButton, fulltextButton));
StackPane modifierButtons = new StackPane(new HBox(regularExpressionButton, caseSensitiveButton, fulltextButton, keepSearchString));
modifierButtons.setAlignment(Pos.CENTER);
searchField.setRight(new HBox(searchField.getRight(), modifierButtons));
searchField.getStyleClass().add("search-field");
Expand All @@ -152,13 +171,12 @@ public GlobalSearchBar(JabRefFrame frame, StateManager stateManager, Preferences
regexValidator = new FunctionBasedValidator<>(
searchField.textProperty(),
query -> !(regularExpressionButton.isSelected() && !validRegex()),
ValidationMessage.error(Localization.lang("Invalid regular expression"))
);
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));

this.getChildren().addAll(searchField, currentResults);
this.getChildren().addAll(searchField, openGlobalSearchButton, currentResults);
this.setSpacing(4.0);
this.setAlignment(Pos.CENTER_LEFT);

Expand All @@ -170,15 +188,18 @@ public GlobalSearchBar(JabRefFrame frame, StateManager stateManager, Preferences
// Async update
searchTask.restart();
},
query -> setSearchTerm(query.map(SearchQuery::getQuery).orElse(""))
);
query -> setSearchTerm(query.map(SearchQuery::getQuery).orElse("")));

EasyBind.subscribe(this.stateManager.activeSearchQueryProperty(), searchQuery -> {
searchQuery.ifPresent(query -> {
updateResults(this.stateManager.getSearchResultSize().intValue(), SearchDescribers.getSearchDescriberFor(query).getDescription(),
query.isGrammarBasedSearch());
});
});
this.stateManager.activeSearchQueryProperty().addListener((obs, oldvalue, newValue) -> newValue.ifPresent(this::updateSearchResultsForQuery));
this.stateManager.activeDatabaseProperty().addListener((obs, oldValue, newValue) -> stateManager.activeSearchQueryProperty().get().ifPresent(this::updateSearchResultsForQuery));
}

private void updateSearchResultsForQuery(SearchQuery query) {
updateResults(this.stateManager.getSearchResultSize().intValue(), SearchDescribers.getSearchDescriberFor(query).getDescription(),
query.isGrammarBasedSearch());
if ((globalSearchResultDialog != null) && globalSearchActive.getValue()) {
globalSearchResultDialog.updateSearch();
}
}

private void initSearchModifierButtons() {
Expand Down Expand Up @@ -209,25 +230,29 @@ private void initSearchModifierButtons() {
performSearch();
});

// ToDo: Reimplement searchMode (searchModeButton)
/* searchModeButton.setText(searchPreferences.getSearchDisplayMode().getDisplayName());
searchModeButton.setTooltip(new Tooltip(searchPreferences.getSearchDisplayMode().getToolTipText()));
searchModeButton.setOnAction(event -> {
SearchDisplayMode searchDisplayMode = searchPreferences.getSearchDisplayMode();
int nextSearchMode = (searchDisplayMode.ordinal() + 1) % SearchDisplayMode.values().length;
searchDisplayMode = SearchDisplayMode.values()[nextSearchMode];

searchPreferences = searchPreferences..withSearchDisplayMode(searchDisplayMode);
keepSearchString.setSelected(searchPreferences.isKeepSearchString());
keepSearchString.setTooltip(new Tooltip(Localization.lang("Keep search string across libraries")));
initSearchModifierButton(keepSearchString);
keepSearchString.setOnAction(evt -> {
searchPreferences = searchPreferences.withKeepSearchString(keepSearchString.isSelected());
preferencesService.storeSearchPreferences(searchPreferences);
performSearch();
});

searchModeButton.setText(searchDisplayMode.getDisplayName());
searchModeButton.setTooltip(new Tooltip(searchDisplayMode.getToolTipText()));

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);
globalSearchResultDialog = new GlobalSearchResultDialog(ExternalFileTypes.getInstance(), undoManager);
performSearch();
}); */
globalSearchResultDialog.updateSearch();
globalSearchResultDialog.showAndWait();
globalSearchActive.setValue(false);
});
}

private void initSearchModifierButton(ToggleButton searchButton) {
private void initSearchModifierButton(ButtonBase searchButton) {
searchButton.setCursor(Cursor.DEFAULT);
searchButton.setMinHeight(28);
searchButton.setMaxHeight(28);
Expand Down
28 changes: 28 additions & 0 deletions src/main/java/org/jabref/gui/search/GlobalSearchResultDialog.fxml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.ButtonType?>
<?import javafx.scene.control.DialogPane?>
<?import javafx.scene.control.SplitPane?>
<?import javafx.scene.control.ToggleButton?>
<?import javafx.scene.control.Tooltip?>
<?import javafx.scene.layout.VBox?>
<?import org.jabref.gui.icon.JabRefIconView?>
<DialogPane xmlns="http://javafx.com/javafx/16" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="org.jabref.gui.search.GlobalSearchResultDialog"
prefHeight="400.0" prefWidth="600.0">
<content>
<VBox>
<SplitPane fx:id="container" orientation="VERTICAL"/>
<ToggleButton fx:id="keepOnTop" styleClass="icon-button,narrow" prefHeight="20.0" prefWidth="20.0">
<graphic>
<JabRefIconView glyph="KEEP_ON_TOP"/>
</graphic>
<tooltip>
<Tooltip text="%Keep dialog always on top"/>
</tooltip>
</ToggleButton>

</VBox>
</content>
<ButtonType fx:constant="OK"/>
</DialogPane>
Loading