Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
3f5ce74
feat(JabRef #12276): Adding in Keybind enum for JUMP_TO_FIELD
ZachCraw Oct 20, 2025
383e22f
feat(JabRef #12276): Initialising JumpToField command
ZachCraw Oct 20, 2025
cf9cdc7
docs(JabRef #12276): Adding in english localisation for JUMP to FIELD…
ZachCraw Oct 20, 2025
fbda3f4
feat(JabRef #12276): Creating base fxml for JUMP to field box
ZachCraw Oct 20, 2025
0755740
feat(JabRef #12276): FXML action class to search through loaded fields
ZachCraw Oct 20, 2025
84529b8
feat(JabRef #12276): Class to extract fieldNames for comparison and a…
ZachCraw Oct 20, 2025
848ff0b
feat(JabRef #12276): Implementing field search handling within entryE…
ZachCraw Oct 20, 2025
fb5f482
Merge branch 'JabRef:main' into feat/field_jumping_12276
ZachCraw Oct 20, 2025
d188809
docs(JabRef #12276): Explained addition in CHANGELOG.md
ZachCraw Oct 20, 2025
ae000fc
Merge branch 'feat/field_jumping_12276' of https://github.com/ZachCra…
ZachCraw Oct 20, 2025
ff0e43f
docs(JabRef #12276): Fixing missing blank line in CHANGELOG
ZachCraw Oct 20, 2025
fc798a2
fix(JabRef #12276): Reverting docs deletion to include implementation…
ZachCraw Oct 20, 2025
60c494b
fix(JabRef #12276): Fixing frame focusing and scene hierarchy.
ZachCraw Oct 25, 2025
d5c4405
fix(JabRef #12276): Removing necessary initialisation.
ZachCraw Oct 25, 2025
0dffbf0
Merge branch 'main' into feat/field_jumping_12276
ZachCraw Oct 25, 2025
57da947
docs(JabRef #12276): Changing function names to reflect "select" patt…
ZachCraw Oct 25, 2025
27e03f6
Merge branch 'feat/field_jumping_12276' of https://github.com/ZachCra…
ZachCraw Oct 25, 2025
fbcb65a
Merge branch 'main' into feat/field_jumping_12276
ZachCraw Oct 26, 2025
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv

### Added

- We added a "Jump to Field" dialog (`Ctrl+J`) to quickly search for and navigate to any field across all tabs. [#12276](https://github.com/JabRef/jabref/issues/12276).
- We made the "Configure API key" option in the Web Search preferences tab searchable via preferences search. [#13929](https://github.com/JabRef/jabref/issues/13929)
- We added the integrity check to the jabkit cli application. [#13848](https://github.com/JabRef/jabref/issues/13848)
- We added support for Cygwin-file paths on a Windows Operating System. [#13274](https://github.com/JabRef/jabref/issues/13274)
Expand Down
54 changes: 43 additions & 11 deletions jabgui/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import javafx.scene.input.KeyEvent;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.BorderPane;
import javafx.stage.Modality;

import org.jabref.gui.DialogService;
import org.jabref.gui.LibraryTab;
Expand Down Expand Up @@ -171,15 +172,14 @@ public EntryEditor(Supplier<LibraryTab> tabSupplier, UndoAction undoAction, Redo
});

stateManager.getSelectedEntries().addListener((InvalidationListener) _ -> {
if (stateManager.getSelectedEntries().isEmpty()) {
// [impl->req~entry-editor.keep-showing~1]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please keep this as it referes to implementation spec

// No change in the entry editor
// We allow users to edit the "old" entry
} else {
setCurrentlyEditedEntry(stateManager.getSelectedEntries().getFirst());
}
}
);
if (stateManager.getSelectedEntries().isEmpty()) {
// [impl->req~entry-editor.keep-showing~1]
// No change in the entry editor
// We allow users to edit the "old" entry
} else {
setCurrentlyEditedEntry(stateManager.getSelectedEntries().getFirst());
}
});

EasyBind.listen(preferences.getPreviewPreferences().showPreviewAsExtraTabProperty(),
(_, _, newValue) -> {
Expand Down Expand Up @@ -248,6 +248,10 @@ private void setupKeyBindings() {
tabSupplier.get().selectPreviousEntry();
event.consume();
break;
case JUMP_TO_FIELD:
selectFieldDialog();
event.consume();
break;
case HELP:
new HelpAction(HelpFile.ENTRY_EDITOR, dialogService, preferences.getExternalApplicationsPreferences()).execute();
event.consume();
Expand All @@ -268,6 +272,15 @@ private void setupKeyBindings() {
});
}

public void selectFieldDialog() {
if (getCurrentlyEditedEntry() == null) {
return;
}
JumpToFieldDialog dialog = new JumpToFieldDialog(this);
dialog.initModality(Modality.NONE);
dialog.show();
}

@FXML
private void close() {
stateManager.getEditorShowing().set(false);
Expand Down Expand Up @@ -420,6 +433,10 @@ public BibEntry getCurrentlyEditedEntry() {
return currentlyEditedEntry;
}

public List<EntryEditorTab> getAllPossibleTabs() {
return allPossibleTabs;
}

public void setCurrentlyEditedEntry(@NonNull BibEntry currentlyEditedEntry) {
if (Objects.equals(this.currentlyEditedEntry, currentlyEditedEntry)) {
return;
Expand All @@ -434,15 +451,26 @@ public void setCurrentlyEditedEntry(@NonNull BibEntry currentlyEditedEntry) {
}

typeSubscription = EasyBind.subscribe(this.currentlyEditedEntry.typeProperty(), _ -> {
typeLabel.setText(new TypedBibEntry(currentlyEditedEntry, tabSupplier.get().getBibDatabaseContext().getMode()).getTypeForDisplay());
typeLabel.setText(new TypedBibEntry(this.currentlyEditedEntry, tabSupplier.get().getBibDatabaseContext().getMode()).getTypeForDisplay());
adaptVisibleTabs();
setupToolBar();
getSelectedTab().notifyAboutFocus(currentlyEditedEntry);
getSelectedTab().notifyAboutFocus(this.currentlyEditedEntry);
});

typeLabel.setText(new TypedBibEntry(currentlyEditedEntry, tabSupplier.get().getBibDatabaseContext().getMode()).getTypeForDisplay());

adaptVisibleTabs();

setupToolBar();

if (preferences.getEntryEditorPreferences().showSourceTabByDefault()) {
tabbed.getSelectionModel().select(sourceTab);
}

EntryEditorTab selectedTab = getSelectedTab();
if (selectedTab != null) {
Platform.runLater(() -> selectedTab.notifyAboutFocus(currentlyEditedEntry));
}
}

private EntryEditorTab getSelectedTab() {
Expand Down Expand Up @@ -492,6 +520,10 @@ private void fetchAndMerge(EntryBasedFetcher fetcher) {
new FetchAndMergeEntry(tabSupplier.get().getBibDatabaseContext(), taskExecutor, preferences, dialogService, undoManager).fetchAndMerge(currentlyEditedEntry, fetcher);
}

public void selectField(String fieldName) {
setFocusToField(org.jabref.model.entry.field.FieldFactory.parseField(fieldName));
}

public void setFocusToField(Field field) {
UiTaskExecutor.runInJavaFXThread(() -> {
Field actualField = field;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package org.jabref.gui.entryeditor;

import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.control.TextField;

import org.jabref.gui.util.BaseDialog;
import org.jabref.logic.l10n.Localization;

import com.airhacks.afterburner.views.ViewLoader;
import org.controlsfx.control.textfield.TextFields;

public class JumpToFieldDialog extends BaseDialog<Void> {
@FXML private TextField searchField;
private final EntryEditor entryEditor;
private JumpToFieldViewModel viewModel;

public JumpToFieldDialog(EntryEditor entryEditor) {
this.entryEditor = entryEditor;
this.setTitle(Localization.lang("Jump to field"));

ViewLoader.view(this)
.load()
.setAsDialogPane(this);

this.getDialogPane().getButtonTypes().setAll(ButtonType.OK, ButtonType.CANCEL);

this.setResultConverter(button -> {
if (button == ButtonType.OK) {
jumpToSelectedField();
}
return null;
});

Platform.runLater(() -> searchField.requestFocus());
}

@FXML
private void initialize() {
viewModel = new JumpToFieldViewModel(this.entryEditor);
searchField.textProperty().bindBidirectional(viewModel.searchTextProperty());
TextFields.bindAutoCompletion(searchField, viewModel.getFieldNames());

searchField.setOnAction(event -> {
Button okButton = (Button) getDialogPane().lookupButton(ButtonType.OK);
if (okButton != null) {
okButton.fire();
}
event.consume();
});
}

private void jumpToSelectedField() {
String selectedField = searchField.getText();

if (selectedField != null && !selectedField.isEmpty()) {
String fieldToJumpTo = selectedField.toLowerCase();
entryEditor.selectField(fieldToJumpTo);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package org.jabref.gui.entryeditor;

import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

import org.jabref.gui.AbstractViewModel;
import org.jabref.model.entry.field.Field;

public class JumpToFieldViewModel extends AbstractViewModel {

private final StringProperty searchText = new SimpleStringProperty("");
private final EntryEditor entryEditor;

public JumpToFieldViewModel(EntryEditor entryEditor) {
this.entryEditor = entryEditor;
}

public StringProperty searchTextProperty() {
return searchText;
}

public List<String> getFieldNames() {
if (entryEditor.getCurrentlyEditedEntry() == null) {
return Collections.emptyList();
}

List<String> fieldNames = entryEditor.getAllPossibleTabs().stream()
.filter(FieldsEditorTab.class::isInstance)
.map(FieldsEditorTab.class::cast)
.flatMap(tab -> tab.getShownFields().stream())
.map(Field::getName)
.distinct()
.sorted()
.collect(Collectors.toList());
return fieldNames;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public enum KeyBinding {
CLOSE("Close dialog", Localization.lang("Close dialog"), "Esc", KeyBindingCategory.VIEW),
COPY("Copy", Localization.lang("Copy"), "ctrl+C", KeyBindingCategory.EDIT),
COPY_TITLE("Copy title", Localization.lang("Copy title"), "ctrl+shift+alt+T", KeyBindingCategory.EDIT),
JUMP_TO_FIELD("Jump to field", Localization.lang("Jump to field"), "ctrl+J", KeyBindingCategory.EDIT),

// We migrated from "Copy \\cite{citation key}" to "Copy citation key with configured cite command", therefore we keep the "old string" for backwards comppatibility
COPY_CITE_CITATION_KEY("Copy \\cite{citation key}", Localization.lang("Copy citation key with configured cite command"), "ctrl+K", KeyBindingCategory.EDIT),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.DialogPane?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.VBox?>

<DialogPane prefWidth="300" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="org.jabref.gui.entryeditor.JumpToFieldDialog">
<content>
<VBox>
<TextField fx:id="searchField" promptText="%Type a field name"/>
</VBox>
</content>
</DialogPane>
2 changes: 2 additions & 0 deletions jablib/src/main/resources/l10n/JabRef_en.properties
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,7 @@ Duplicate\ citation\ key=Duplicate citation key
Citation\ key\ '%0'\ to\ select\ not\ found\ in\ open\ libraries.=Citation key '%0' to select not found in open libraries.

Jump\ to\ entry\ in\ library=Jump to entry in library
Jump\ to\ field=Jump to field

Autolink\ files\ with\ names\ starting\ with\ the\ citation\ key=Autolink files with names starting with the citation key
Autolink\ only\ files\ that\ match\ the\ citation\ key=Autolink only files that match the citation key
Expand Down Expand Up @@ -2353,6 +2354,7 @@ Title\ of\ the\ work.=Title of the work.
Total\ number\ of\ pages\ of\ the\ work.=Total number of pages of the work.
Total\ number\ of\ volumes\ of\ a\ multi-volume\ work.=Total number of volumes of a multi-volume work.
Type\ of\ the\ eprint\ identifier,\ e.g.,\ the\ name\ of\ the\ archive,\ repository,\ service,\ or\ system\ the\ eprint\ field\ refers\ to.=Type of the eprint identifier, e.g., the name of the archive, repository, service, or system the eprint field refers to.
Type\ a\ field\ name=Type a field name
URL\ of\ an\ online\ publication.=URL of an online publication.
Volume\ of\ a\ multi-volume\ book\ or\ a\ periodical.=Volume of a multi-volume book or a periodical.
Year\ of\ publication.=Year of publication.
Expand Down
Loading