Skip to content

Commit 1d75410

Browse files
committed
Add basic implementation
1 parent 5fa313d commit 1d75410

File tree

7 files changed

+167
-0
lines changed

7 files changed

+167
-0
lines changed

jabgui/src/main/java/org/jabref/gui/JabRefGuiStateManager.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ public class JabRefGuiStateManager implements StateManager {
9090
private final List<AiChatWindow> aiChatWindows = new ArrayList<>();
9191
private final BooleanProperty editorShowing = new SimpleBooleanProperty(false);
9292
private final OptionalObjectProperty<Walkthrough> activeWalkthrough = OptionalObjectProperty.empty();
93+
private final BooleanProperty canGoBack = new SimpleBooleanProperty(false);
94+
private final BooleanProperty canGoForward = new SimpleBooleanProperty(false);
9395

9496
@Override
9597
public ObservableList<SidePaneType> getVisibleSidePaneComponents() {
@@ -307,4 +309,28 @@ public void setActiveWalkthrough(Walkthrough walkthrough) {
307309
public Optional<Walkthrough> getActiveWalkthrough() {
308310
return activeWalkthrough.get();
309311
}
312+
313+
@Override
314+
public BooleanProperty canGoBackProperty() {
315+
return canGoBack;
316+
}
317+
318+
@Override
319+
public BooleanProperty canGoForwardProperty() {
320+
return canGoForward;
321+
}
322+
323+
@Override
324+
public void updateNavigationState(boolean canGoBack, boolean canGoForward) {
325+
this.canGoBack.set(canGoBack);
326+
this.canGoForward.set(canGoForward);
327+
}
328+
329+
/**
330+
* Called when switching tabs to reset navigation state
331+
*/
332+
@Override
333+
public void clearNavigationHistory() {
334+
updateNavigationState(false, false);
335+
}
310336
}

jabgui/src/main/java/org/jabref/gui/LibraryTab.java

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.io.IOException;
44
import java.nio.file.Path;
5+
import java.util.ArrayList;
56
import java.util.List;
67
import java.util.Objects;
78
import java.util.Optional;
@@ -118,6 +119,11 @@ public class LibraryTab extends Tab implements CommandSelectionTab {
118119
private final BibEntryTypesManager entryTypesManager;
119120
private final BooleanProperty changedProperty = new SimpleBooleanProperty(false);
120121
private final BooleanProperty nonUndoableChangeProperty = new SimpleBooleanProperty(false);
122+
private final List<BibEntry> previousEntries = new ArrayList<>();
123+
private final List<BibEntry> nextEntries = new ArrayList<>();
124+
private BibEntry currentlyShowing;
125+
private boolean backOrForwardInProgress = false;
126+
121127

122128
private BibDatabaseContext bibDatabaseContext;
123129

@@ -490,6 +496,15 @@ private void createMainTable() {
490496
mainTable.addSelectionListener(event -> {
491497
List<BibEntry> entries = event.getList().stream().map(BibEntryTableViewModel::getEntry).toList();
492498
stateManager.setSelectedEntries(entries);
499+
500+
// track navigation history for single selections
501+
if (entries.size() == 1) {
502+
newEntryShowing(entries.getFirst());
503+
} else if (entries.isEmpty()) {
504+
// when no entries are selected, don't update navigation history
505+
// but still update the navigation state
506+
updateNavigationState();
507+
}
493508
});
494509
}
495510

@@ -964,6 +979,69 @@ public void resetChangedProperties() {
964979
this.changedProperty.setValue(false);
965980
}
966981

982+
public void back() {
983+
navigateToEntry(previousEntries, nextEntries);
984+
}
985+
986+
public void forward() {
987+
navigateToEntry(nextEntries, previousEntries);
988+
}
989+
990+
private void navigateToEntry(List<BibEntry> sourceHistory, List<BibEntry> destinationHistory) {
991+
if (!sourceHistory.isEmpty()) {
992+
BibEntry toShow = sourceHistory.getLast();
993+
sourceHistory.removeLast();
994+
995+
// add current entry to destination history
996+
if (currentlyShowing != null) {
997+
destinationHistory.add(currentlyShowing);
998+
}
999+
1000+
backOrForwardInProgress = true;
1001+
clearAndSelect(toShow);
1002+
updateNavigationState();
1003+
}
1004+
}
1005+
1006+
public boolean canGoBack() {
1007+
return !previousEntries.isEmpty();
1008+
}
1009+
1010+
public boolean canGoForward() {
1011+
return !nextEntries.isEmpty();
1012+
}
1013+
1014+
private void newEntryShowing(BibEntry entry) {
1015+
// skip history updates if this is from a back/forward operation
1016+
if (backOrForwardInProgress) {
1017+
currentlyShowing = entry;
1018+
backOrForwardInProgress = false;
1019+
updateNavigationState();
1020+
return;
1021+
}
1022+
1023+
nextEntries.clear(); // clear forward history when new entry selected
1024+
1025+
if (!Objects.equals(entry, currentlyShowing)) {
1026+
// add the entry we are leaving to the history
1027+
if (currentlyShowing != null) {
1028+
previousEntries.add(currentlyShowing);
1029+
}
1030+
currentlyShowing = entry;
1031+
updateNavigationState();
1032+
}
1033+
}
1034+
1035+
/**
1036+
* Updates the StateManager with current navigation state
1037+
* Only update if this is the active tab
1038+
*/
1039+
public void updateNavigationState() {
1040+
if (stateManager.activeTabProperty().get().filter(tab -> tab == this).isPresent()) {
1041+
stateManager.updateNavigationState(canGoBack(), canGoForward());
1042+
}
1043+
}
1044+
9671045
/**
9681046
* Creates a new library tab. Contents are loaded by the {@code dataLoadingTask}. Most of the other parameters are required by {@code resetChangeMonitor()}.
9691047
*

jabgui/src/main/java/org/jabref/gui/StateManager.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,4 +108,12 @@ public interface StateManager extends SrvStateManager {
108108
void setActiveWalkthrough(Walkthrough walkthrough);
109109

110110
Optional<Walkthrough> getActiveWalkthrough();
111+
112+
BooleanProperty canGoBackProperty();
113+
114+
BooleanProperty canGoForwardProperty();
115+
116+
void updateNavigationState(boolean canGoBack, boolean canGoForward);
117+
118+
void clearNavigationHistory();
111119
}

jabgui/src/main/java/org/jabref/gui/actions/StandardActions.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@ public enum StandardActions implements Action {
9595
MANAGE_KEYWORDS(Localization.lang("Manage keywords")),
9696
MASS_SET_FIELDS(Localization.lang("Manage field names & content")),
9797

98+
BACK(Localization.lang("Back"), IconTheme.JabRefIcons.LEFT, KeyBinding.BACK),
99+
FORWARD(Localization.lang("Forward"), Localization.lang("Forward"), IconTheme.JabRefIcons.RIGHT, KeyBinding.FORWARD),
100+
98101
AUTOMATIC_FIELD_EDITOR(Localization.lang("Automatic field editor")),
99102
TOGGLE_GROUPS(Localization.lang("Groups"), IconTheme.JabRefIcons.TOGGLE_GROUPS, KeyBinding.TOGGLE_GROUPS_INTERFACE),
100103
TOGGLE_OO(Localization.lang("OpenOffice/LibreOffice"), IconTheme.JabRefIcons.FILE_OPENOFFICE, KeyBinding.OPEN_OPEN_OFFICE_LIBRE_OFFICE_CONNECTION),

jabgui/src/main/java/org/jabref/gui/frame/JabRefFrame.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,14 @@ private void initKeyBindings() {
371371
case NEW_INPROCEEDINGS:
372372
new NewEntryAction(StandardEntryType.InProceedings, this::getCurrentLibraryTab, dialogService, preferences, stateManager).execute();
373373
break;
374+
case BACK:
375+
Optional.ofNullable(getCurrentLibraryTab()).ifPresent(LibraryTab::back);
376+
event.consume();
377+
break;
378+
case FORWARD:
379+
Optional.ofNullable(getCurrentLibraryTab()).ifPresent(LibraryTab::forward);
380+
event.consume();
381+
break;
374382
default:
375383
}
376384
}
@@ -411,6 +419,8 @@ private void initBindings() {
411419
// Listen for auto-completer changes after real context is loaded
412420
libraryTab.setAutoCompleterChangedListener(() -> globalSearchBar.setAutoCompleter(libraryTab.getAutoCompleter()));
413421

422+
libraryTab.updateNavigationState();
423+
414424
// [impl->req~maintable.focus~1]
415425
Platform.runLater(() -> libraryTab.getMainTable().requestFocus());
416426

@@ -434,6 +444,7 @@ private void initBindings() {
434444
stateManager.setActiveDatabase(null);
435445
stateManager.activeTabProperty().set(Optional.empty());
436446
stateManager.setSelectedEntries(List.of());
447+
stateManager.clearNavigationHistory();
437448
mainStage.titleProperty().unbind();
438449
mainStage.setTitle(FRAME_TITLE);
439450
}

jabgui/src/main/java/org/jabref/gui/frame/MainToolBar.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import org.jabref.gui.LibraryTabContainer;
1919
import org.jabref.gui.StateManager;
2020
import org.jabref.gui.actions.ActionFactory;
21+
import org.jabref.gui.actions.SimpleCommand;
2122
import org.jabref.gui.actions.StandardActions;
2223
import org.jabref.gui.citationkeypattern.GenerateCitationKeyAction;
2324
import org.jabref.gui.cleanup.CleanupAction;
@@ -57,6 +58,8 @@ public class MainToolBar extends ToolBar {
5758
private final TaskExecutor taskExecutor;
5859
private final BibEntryTypesManager entryTypesManager;
5960
private final ClipBoardManager clipBoardManager;
61+
private SimpleCommand backCommand;
62+
private SimpleCommand forwardCommand;
6063
private final CountingUndoManager undoManager;
6164

6265
private PopOver entryFromIdPopOver;
@@ -99,6 +102,7 @@ private void createToolBar() {
99102

100103
final Button pushToApplicationButton = factory.createIconButton(pushToApplicationCommand.getAction(), pushToApplicationCommand);
101104
pushToApplicationCommand.registerReconfigurable(pushToApplicationButton);
105+
initNavigationCommands();
102106

103107
// Setup Toolbar
104108

@@ -121,6 +125,12 @@ private void createToolBar() {
121125

122126
new Separator(Orientation.VERTICAL),
123127

128+
new HBox(
129+
factory.createIconButton(StandardActions.BACK, backCommand),
130+
factory.createIconButton(StandardActions.FORWARD, forwardCommand)),
131+
132+
new Separator(Orientation.VERTICAL),
133+
124134
new HBox(
125135
factory.createIconButton(StandardActions.UNDO, new UndoAction(frame::getCurrentLibraryTab, undoManager, dialogService, stateManager)),
126136
factory.createIconButton(StandardActions.REDO, new RedoAction(frame::getCurrentLibraryTab, undoManager, dialogService, stateManager)),
@@ -208,4 +218,32 @@ Group createTaskIndicator() {
208218

209219
return new Group(indicator);
210220
}
221+
222+
private void initNavigationCommands() {
223+
backCommand = new SimpleCommand() {
224+
{
225+
executable.bind(stateManager.canGoBackProperty());
226+
}
227+
228+
@Override
229+
public void execute() {
230+
if (frame.getCurrentLibraryTab() != null) {
231+
frame.getCurrentLibraryTab().back();
232+
}
233+
}
234+
};
235+
236+
forwardCommand = new SimpleCommand() {
237+
{
238+
executable.bind(stateManager.canGoForwardProperty());
239+
}
240+
241+
@Override
242+
public void execute() {
243+
if (frame.getCurrentLibraryTab() != null) {
244+
frame.getCurrentLibraryTab().forward();
245+
}
246+
}
247+
};
248+
}
211249
}

jabgui/src/main/java/org/jabref/gui/keyboard/KeyBinding.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ public enum KeyBinding {
6969
IMPORT_INTO_NEW_DATABASE("Import into new library", Localization.lang("Import into new library"), "ctrl+alt+I", KeyBindingCategory.FILE),
7070
MERGE_ENTRIES("Merge entries", Localization.lang("Merge entries"), "ctrl+M", KeyBindingCategory.TOOLS),
7171

72+
BACK("Back", Localization.lang("Back"), "alt+LEFT", KeyBindingCategory.VIEW),
73+
FORWARD("Forward", Localization.lang("Forward"), "alt+RIGHT", KeyBindingCategory.VIEW),
74+
7275
ADD_ENTRY("Add entry", Localization.lang("Add entry"), "ctrl+N", KeyBindingCategory.BIBTEX),
7376
ADD_ENTRY_IDENTIFIER("Enter identifier", Localization.lang("Enter identifier"), "ctrl+alt+shift+N", KeyBindingCategory.BIBTEX),
7477
ADD_ENTRY_PLAINTEXT("Interpret citations", Localization.lang("Interpret citations"), "ctrl+shift+N", KeyBindingCategory.BIBTEX),

0 commit comments

Comments
 (0)