-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
Fix Jump to field (ctrl + j) in the entry editor doesn't work #16639
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
Changes from all commits
5536229
d60efad
9a3953a
3765a9d
50e03b9
adecf23
c24e6ae
9291e1a
a178cfb
9b0b16a
b4b9d98
ec4f3cf
d8f42ae
e9f1b83
e596873
5203352
917ac38
f60d6c0
f89b3b3
f727465
a1d7306
54a9101
9661493
45ef1bc
7f24f8b
785cd75
a970eae
7def69b
190841e
3a30381
2dff091
a9dc018
8a87864
4af0f8b
3834d79
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,7 @@ | ||
| package org.jabref.gui.entryeditor; | ||
|
|
||
| import java.util.Collection; | ||
| import java.util.Map; | ||
| import java.util.Optional; | ||
|
|
||
| import javafx.application.Platform; | ||
|
|
@@ -13,9 +14,13 @@ | |
| import javafx.scene.input.KeyEvent; | ||
|
|
||
| import org.jabref.gui.util.UiTaskExecutor; | ||
| import org.jabref.logic.l10n.Localization; | ||
| import org.jabref.logic.util.NotificationService; | ||
| import org.jabref.model.database.BibDatabaseMode; | ||
| import org.jabref.model.entry.EntryConverter; | ||
| import org.jabref.model.entry.field.Field; | ||
| import org.jabref.model.entry.field.FieldFactory; | ||
| import org.jabref.model.entry.field.FieldTextMapper; | ||
|
|
||
| import org.jspecify.annotations.Nullable; | ||
|
|
||
|
|
@@ -27,12 +32,14 @@ class EntryEditorFocusUtils { | |
|
|
||
| private final TabPane tabPane; | ||
| private final Node sceneSource; | ||
| private final NotificationService notificationService; | ||
|
|
||
| private @Nullable Field lastFocusedField; | ||
|
|
||
| EntryEditorFocusUtils(TabPane tabPane, Node sceneSource) { | ||
| EntryEditorFocusUtils(TabPane tabPane, Node sceneSource, NotificationService notificationService) { | ||
| this.tabPane = tabPane; | ||
| this.sceneSource = sceneSource; | ||
| this.notificationService = notificationService; | ||
| } | ||
|
|
||
| // region — field focus capture / restore | ||
|
|
@@ -68,15 +75,34 @@ void restoreLastFocusedField() { | |
| // region — jump to field | ||
|
|
||
| void setFocusToField(Field field) { | ||
| focusField(field, () -> { | ||
| }); | ||
| } | ||
|
|
||
| void focusOrAddField(Field field) { | ||
|
adeifv marked this conversation as resolved.
adeifv marked this conversation as resolved.
|
||
| focusField(field, () -> addFieldViaAllFieldsTab(field)); | ||
| } | ||
|
|
||
| private void focusField(Field field, Runnable onNotFound) { | ||
| UiTaskExecutor.runInJavaFXThread(() -> getTabContainingField(field).ifPresentOrElse( | ||
| tab -> selectTabAndField(tab, field), | ||
| () -> { | ||
| Field aliasField = EntryConverter.FIELD_ALIASES.get(field); | ||
| getTabContainingField(aliasField).ifPresent(tab -> selectTabAndField(tab, aliasField)); | ||
| getTabContainingField(aliasField).ifPresentOrElse( | ||
| tab -> selectTabAndField(tab, aliasField), | ||
| onNotFound | ||
| ); | ||
| } | ||
| )); | ||
| } | ||
|
|
||
| private Field canonicalFieldForActiveMode(Field field, BibDatabaseMode mode) { | ||
|
adeifv marked this conversation as resolved.
|
||
| Map<Field, Field> aliasesToCanonical = mode == BibDatabaseMode.BIBTEX | ||
| ? EntryConverter.FIELD_ALIASES_BIBLATEX_TO_BIBTEX | ||
| : EntryConverter.FIELD_ALIASES_BIBTEX_TO_BIBLATEX; | ||
| return aliasesToCanonical.getOrDefault(field, field); | ||
| } | ||
|
|
||
| private Optional<FieldsEditorTab> getTabContainingField(Field field) { | ||
| return tabPane.getTabs().stream() | ||
| .filter(FieldsEditorTab.class::isInstance) | ||
|
|
@@ -85,6 +111,24 @@ private Optional<FieldsEditorTab> getTabContainingField(Field field) { | |
| .findFirst(); | ||
| } | ||
|
|
||
| private void addFieldViaAllFieldsTab(Field field) { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the main tab is hidden in preferences, findFirst is empty and ctrl+j silently does nothing
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's the easy way out. Good enough for now, because it would be really good to have this PR in main, but please write this down as an issue, which then can be fixed in a follow up. Maybe add a junit test, so if we ever were to remove the main tab completely, this will not regress.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. After removing the check, when the Main tab is hidden, ctrl+j still opens and correctly jumps to any visible field. It does nothing when the target field isn't shown anywhere. I think silently doing nothing is a safe behavior, but it's not user-friendly, as the user gets no feedback about why the field wasn't jumped to. Maybe a good solution would be to tell the user something like "this field can't be jumped to because its tab isn't visible" That needs some thought around, so I'd prefer to handle it in a follow-up PR and keep this one mergeable. What do you think?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🤖 Generated with Claude Code Correct, and it got worse in the meantime: the guard that used to bail out on unknown field names is gone (custom names are created now), so this Fixed in 2dff091 — Verified with |
||
| tabPane.getTabs().stream() | ||
| .filter(AllFieldsTab.class::isInstance) | ||
| .map(AllFieldsTab.class::cast) | ||
| .findFirst() | ||
| .ifPresentOrElse(allFieldsTab -> { | ||
| BibDatabaseMode mode = allFieldsTab.getDatabaseMode(); | ||
| // Custom field names are added as they are typed, like the tab's free-form add row does. | ||
| Field canonicalField = canonicalFieldForActiveMode(field, mode); | ||
| tabPane.getSelectionModel().select(allFieldsTab); | ||
| allFieldsTab.addFieldAndFocus(canonicalField); | ||
| }, | ||
| // No other tab can show a field it was not configured for, so say why nothing happens | ||
| // instead of swallowing the jump. | ||
| () -> notificationService.notify(Localization.lang("Cannot show \"%0\" because the \"%1\" tab is hidden", | ||
| FieldTextMapper.getDisplayName(field), EntryEditorTabModel.BuiltIn.ALL_FIELDS.displayName()))); | ||
| } | ||
|
|
||
| private void selectTabAndField(FieldsEditorTab tab, Field field) { | ||
| Platform.runLater(() -> { | ||
| tabPane.getSelectionModel().select(tab); | ||
|
|
||

Uh oh!
There was an error while loading. Please reload this page.