Skip to content

Commit

Permalink
Merge pull request JabRef#9647 from MaryJml/record_search_history
Browse files Browse the repository at this point in the history
Record search history
  • Loading branch information
Siedlerchr authored Mar 18, 2023
2 parents 5c73783 + 82be7ae commit a0cb4be
Show file tree
Hide file tree
Showing 7 changed files with 186 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve
### Added

- We added a field showing the BibTeX/biblatex source for added and deleted entries in the "External Changes Resolver" dialog. [#9509](https://github.com/JabRef/jabref/issues/9509)
- We added a search history list in the search field's right click menu [#7906](https://github.com/JabRef/jabref/issues/7906)
- We added a full text fetcher for IACR eprints. [#9651](https://github.com/JabRef/jabref/pull/9651)
- We added "Attach file from URL" to right-click context menu to download and store a file with the reference library. [#9646](https://github.com/JabRef/jabref/issues/9646)
- We enabled updating an existing entry with data from InspireHEP. [#9351](https://github.com/JabRef/jabref/issues/9351)
Expand Down
23 changes: 23 additions & 0 deletions src/main/java/org/jabref/gui/StateManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ public class StateManager {

private final ObjectProperty<LastAutomaticFieldEditorEdit> lastAutomaticFieldEditorEdit = new SimpleObjectProperty<>();

private final ObservableList<String> searchHistory = FXCollections.observableArrayList();

public StateManager() {
activeGroups.bind(Bindings.valueAt(selectedGroups, activeDatabase.orElseOpt(null)));
}
Expand Down Expand Up @@ -212,4 +214,25 @@ public List<String> collectAllDatabasePaths() {
() -> list.add("")));
return list;
}

public void addSearchHistory(String search) {
searchHistory.remove(search);
searchHistory.add(search);
}

public ObservableList<String> getWholeSearchHistory() {
return searchHistory;
}

public List<String> getLastSearchHistory(int size) {
int sizeSearches = searchHistory.size();
if (size < sizeSearches) {
return searchHistory.subList(sizeSearches - size, sizeSearches);
}
return searchHistory;
}

public void clearSearchHistory() {
searchHistory.clear();
}
}
6 changes: 6 additions & 0 deletions src/main/java/org/jabref/gui/edit/EditAction.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.jabref.gui.edit;

import javafx.scene.control.TextField;
import javafx.scene.control.TextInputControl;
import javafx.scene.web.WebView;

Expand All @@ -22,6 +23,7 @@ public class EditAction extends SimpleCommand {
private static final Logger LOGGER = LoggerFactory.getLogger(EditAction.class);

private final JabRefFrame frame;
private TextField text;
private final StandardActions action;
private final StateManager stateManager;

Expand Down Expand Up @@ -52,8 +54,12 @@ public void execute() {
// DELETE_ENTRY in text field should do forward delete
switch (action) {
case COPY -> textInput.copy();
case UNDO -> textInput.undo();
case REDO -> textInput.redo();
case CUT -> textInput.cut();
case PASTE -> textInput.paste();
case DELETE -> textInput.clear();
case SELECT_ALL -> textInput.selectAll();
case DELETE_ENTRY -> textInput.deleteNextChar();
default -> throw new IllegalStateException("Only cut/copy/paste supported in TextInputControl but got " + action);
}
Expand Down
16 changes: 16 additions & 0 deletions src/main/java/org/jabref/gui/search/GlobalSearchBar.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
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.css.PseudoClass;
import javafx.event.Event;
import javafx.geometry.Insets;
Expand Down Expand Up @@ -138,6 +140,19 @@ public GlobalSearchBar(JabRefFrame frame, StateManager stateManager, Preferences
}
});

searchField.setContextMenu(SearchFieldRightClickMenu.create(
keyBindingRepository,
stateManager,
searchField));

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

ClipBoardManager.addX11Support(searchField);

regularExpressionButton = IconTheme.JabRefIcons.REG_EX.asToggleButton();
Expand Down Expand Up @@ -292,6 +307,7 @@ public void performSearch() {
informUserAboutInvalidSearchQuery();
return;
}
this.stateManager.addSearchHistory(searchField.textProperty().get());
stateManager.setSearchQuery(searchQuery);
}

Expand Down
72 changes: 72 additions & 0 deletions src/main/java/org/jabref/gui/search/SearchFieldRightClickMenu.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package org.jabref.gui.search;

import javafx.scene.control.ContextMenu;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.SeparatorMenuItem;

import org.jabref.gui.StateManager;
import org.jabref.gui.actions.ActionFactory;
import org.jabref.gui.actions.SimpleCommand;
import org.jabref.gui.actions.StandardActions;
import org.jabref.gui.edit.EditAction;
import org.jabref.gui.keyboard.KeyBindingRepository;
import org.jabref.logic.l10n.Localization;

import org.controlsfx.control.textfield.CustomTextField;

public class SearchFieldRightClickMenu {
public static ContextMenu create(KeyBindingRepository keyBindingRepository,
StateManager stateManager,
CustomTextField searchField) {
ActionFactory factory = new ActionFactory(keyBindingRepository);
ContextMenu contextMenu = new ContextMenu();

contextMenu.getItems().addAll(
factory.createMenuItem(StandardActions.UNDO, new EditAction(StandardActions.UNDO, null, stateManager)),
factory.createMenuItem(StandardActions.REDO, new EditAction(StandardActions.REDO, null, stateManager)),
factory.createMenuItem(StandardActions.CUT, new EditAction(StandardActions.CUT, null, stateManager)),
factory.createMenuItem(StandardActions.COPY, new EditAction(StandardActions.COPY, null, stateManager)),
factory.createMenuItem(StandardActions.PASTE, new EditAction(StandardActions.PASTE, null, stateManager)),
factory.createMenuItem(StandardActions.DELETE, new EditAction(StandardActions.DELETE, null, stateManager)),

new SeparatorMenuItem(),

factory.createMenuItem(StandardActions.SELECT_ALL, new EditAction(StandardActions.SELECT_ALL, null, stateManager)),
createSearchFromHistorySubMenu(factory, stateManager, searchField)
);

return contextMenu;
}

private static Menu createSearchFromHistorySubMenu(ActionFactory factory,
StateManager stateManager,
CustomTextField searchField) {
Menu searchFromHistorySubMenu = factory.createMenu(() -> Localization.lang("Search from history..."));

int num = stateManager.getLastSearchHistory(10).size();
if (num == 0) {
MenuItem item = new MenuItem(Localization.lang("your search history is empty"));
searchFromHistorySubMenu.getItems().addAll(item);
} else {
for (int i = 0; i < num; i++) {
int finalI = i;
MenuItem item = factory.createMenuItem(() -> stateManager.getLastSearchHistory(10).get(finalI), new SimpleCommand() {
@Override
public void execute() {
searchField.setText(stateManager.getLastSearchHistory(10).get(finalI));
}
});
searchFromHistorySubMenu.getItems().addAll(item);
}
MenuItem clear = factory.createMenuItem(() -> Localization.lang("Clear history"), new SimpleCommand() {
@Override
public void execute() {
stateManager.clearSearchHistory();
}
});
searchFromHistorySubMenu.getItems().addAll(new SeparatorMenuItem(), clear);
}
return searchFromHistorySubMenu;
}
}
4 changes: 4 additions & 0 deletions src/main/resources/l10n/JabRef_en.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2533,3 +2533,7 @@ Unable\ to\ open\ linked\ eprint.\ Please\ set\ the\ eprinttype\ field=Unable to
Unable\ to\ open\ linked\ eprint.\ Please\ verify\ that\ the\ eprint\ field\ has\ a\ valid\ '%0'\ id=Unable to open linked eprint. Please verify that the eprint field has a valid '%0' id
Main\ directory\ not\ found=Main directory not found
Please\ select\ a\ valid\ main\ directory\ under=Please select a valid main directory under
Search\ from\ history...=Search from history...
your\ search\ history\ is\ empty=your search history is empty
Clear\ history =Clear history
64 changes: 64 additions & 0 deletions src/test/java/org/jabref/gui/search/GetLastSearchHistoryTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package org.jabref.gui.search;

import java.util.List;

import javafx.stage.Stage;

import org.jabref.gui.StateManager;
import org.jabref.testutils.category.GUITest;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.testfx.framework.junit5.ApplicationExtension;
import org.testfx.framework.junit5.Start;

@GUITest
@ExtendWith(ApplicationExtension.class)
public class GetLastSearchHistoryTest {
@Start
void onStart(Stage stage) {
// Needed to init JavaFX thread
stage.show();
}

@Test
void testGetLastSearchHistory() {
StateManager stateManager = new StateManager();
stateManager.addSearchHistory("test1");
stateManager.addSearchHistory("test2");
stateManager.addSearchHistory("test3");
List<String> lastSearchHistory = stateManager.getLastSearchHistory(2);
List<String> expected = List.of("test2", "test3");

Assertions.assertEquals(expected, lastSearchHistory);
}

@Test
void testduplicateSearchHistory() {
StateManager stateManager = new StateManager();
stateManager.addSearchHistory("test1");
stateManager.addSearchHistory("test2");
stateManager.addSearchHistory("test3");
stateManager.addSearchHistory("test1");
List<String> lastSearchHistory = stateManager.getWholeSearchHistory();
List<String> expected = List.of("test2", "test3", "test1");

Assertions.assertEquals(expected, lastSearchHistory);
}

@Test
void testclearSearchHistory() {
StateManager stateManager = new StateManager();
stateManager.addSearchHistory("test1");
stateManager.addSearchHistory("test2");
stateManager.addSearchHistory("test3");
List<String> lastSearchHistory = stateManager.getWholeSearchHistory();
List<String> expected = List.of("test1", "test2", "test3");
Assertions.assertEquals(expected, lastSearchHistory);
stateManager.clearSearchHistory();
lastSearchHistory = stateManager.getWholeSearchHistory();
expected = List.of();
Assertions.assertEquals(expected, lastSearchHistory);
}
}

0 comments on commit a0cb4be

Please sign in to comment.