Skip to content

Commit 1c0e4ec

Browse files
LoayGhreebkoppor
andauthored
Improve document viewer (#11432)
* Improve document viewer * Update CHANGELOG.md * Update CHANGELOG.md * rewriteRun * Update CHANGELOG.md --------- Co-authored-by: Oliver Kopp <[email protected]>
1 parent ac4507a commit 1c0e4ec

File tree

7 files changed

+99
-76
lines changed

7 files changed

+99
-76
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv
5353
- We fixed an issue where the Pubmed/Medline Plain importer would not respect the user defined keyword separator [#11413](https://github.com/JabRef/jabref/issues/11413)
5454
- We fixed an issue where the value of "Override default font settings" was not applied on startup [#11344](https://github.com/JabRef/jabref/issues/11344)
5555
- We fixed an issue where DatabaseChangeDetailsView was not scrollable when reviewing external metadata changes [#11220](https://github.com/JabRef/jabref/issues/11220)
56+
- We fixed an issue where clicking on a page number in the search results tab opens a wrong file in the document viewer. [#11432](https://github.com/JabRef/jabref/pull/11432)
5657

5758
### Removed
5859

src/main/java/org/jabref/gui/documentviewer/DocumentViewModel.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,10 @@
55
import javafx.collections.ObservableList;
66

77
public abstract class DocumentViewModel {
8-
private IntegerProperty maxPages = new SimpleIntegerProperty();
8+
private final IntegerProperty maxPages = new SimpleIntegerProperty();
99

1010
public abstract ObservableList<DocumentPageViewModel> getPages();
1111

12-
public int getMaxPages() {
13-
return maxPages.get();
14-
}
15-
1612
public IntegerProperty maxPagesProperty() {
1713
return maxPages;
1814
}

src/main/java/org/jabref/gui/documentviewer/DocumentViewer.fxml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
<bottom>
4747
<ToolBar>
4848
<HBox alignment="CENTER" spacing="5.0" HBox.hgrow="ALWAYS">
49-
<Button onAction="#previousPage" styleClass="icon-button">
49+
<Button fx:id="previousButton" onAction="#previousPage" styleClass="icon-button">
5050
<graphic>
5151
<JabRefIconView glyph="PREVIOUS_LEFT"/>
5252
</graphic>
@@ -57,7 +57,7 @@
5757
<TextField fx:id="currentPage" minWidth="30.0" prefWidth="40.0"/>
5858
<Label text="of"/>
5959
<Label fx:id="maxPages"/>
60-
<Button onAction="#nextPage" styleClass="icon-button">
60+
<Button fx:id="nextButton" onAction="#nextPage" styleClass="icon-button">
6161
<graphic>
6262
<JabRefIconView glyph="NEXT_RIGHT"/>
6363
</graphic>

src/main/java/org/jabref/gui/documentviewer/DocumentViewerView.java

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,18 @@
22

33
import javafx.event.ActionEvent;
44
import javafx.fxml.FXML;
5+
import javafx.scene.control.Button;
56
import javafx.scene.control.ButtonBar;
67
import javafx.scene.control.ButtonType;
78
import javafx.scene.control.ComboBox;
89
import javafx.scene.control.Label;
910
import javafx.scene.control.ScrollBar;
1011
import javafx.scene.control.TextField;
1112
import javafx.scene.control.ToggleButton;
13+
import javafx.scene.control.ToggleGroup;
1214
import javafx.scene.layout.BorderPane;
1315
import javafx.stage.Modality;
16+
import javafx.stage.Stage;
1417

1518
import org.jabref.gui.StateManager;
1619
import org.jabref.gui.util.BaseDialog;
@@ -29,10 +32,13 @@ public class DocumentViewerView extends BaseDialog<Void> {
2932
@FXML private ScrollBar scrollBar;
3033
@FXML private ComboBox<LinkedFile> fileChoice;
3134
@FXML private BorderPane mainPane;
35+
@FXML private ToggleGroup toggleGroupMode;
3236
@FXML private ToggleButton modeLive;
3337
@FXML private ToggleButton modeLock;
3438
@FXML private TextField currentPage;
3539
@FXML private Label maxPages;
40+
@FXML private Button nextButton;
41+
@FXML private Button previousButton;
3642

3743
@Inject private StateManager stateManager;
3844
@Inject private TaskExecutor taskExecutor;
@@ -65,18 +71,22 @@ private void initialize() {
6571
setupModeButtons();
6672
}
6773

68-
private void setupModeButtons() throws RuntimeException {
69-
viewModel.liveModeProperty().addListener((observable, oldValue, newValue) -> {
70-
modeLive.setSelected(newValue);
74+
private void setupModeButtons() {
75+
// make sure that always one toggle is selected
76+
toggleGroupMode.selectedToggleProperty().addListener((observable, oldToggle, newToggle) -> {
77+
if (newToggle == null) {
78+
oldToggle.setSelected(true);
79+
}
7180
});
7281

73-
modeLive.setOnAction(event -> {
74-
if (!viewModel.liveModeProperty().get()) {
82+
modeLive.selectedProperty().addListener((observable, oldValue, newValue) -> {
83+
if (newValue) {
7584
viewModel.setLiveMode(true);
7685
}
7786
});
78-
modeLock.setOnAction(event -> {
79-
if (viewModel.liveModeProperty().get()) {
87+
88+
modeLock.selectedProperty().addListener((observable, oldValue, newValue) -> {
89+
if (newValue) {
8090
viewModel.setLiveMode(false);
8191
}
8292
});
@@ -92,6 +102,11 @@ private void setupPageControls() {
92102
viewModel.currentPageProperty().bindBidirectional(integerFormatter.valueProperty());
93103
currentPage.setTextFormatter(integerFormatter);
94104
maxPages.textProperty().bind(viewModel.maxPagesProperty().asString());
105+
previousButton.setDisable(true);
106+
viewModel.currentPageProperty().addListener((observable, oldValue, newValue) -> {
107+
nextButton.setDisable(newValue == viewModel.maxPagesProperty().get());
108+
previousButton.setDisable(newValue == 1);
109+
});
95110
}
96111

97112
private void setupFileChoice() {
@@ -103,8 +118,14 @@ private void setupFileChoice() {
103118
(observable, oldValue, newValue) -> viewModel.switchToFile(newValue));
104119
// We always want that the first item is selected after a change
105120
// This also automatically selects the first file on the initial load
106-
fileChoice.itemsProperty().addListener(
107-
(observable, oldValue, newValue) -> fileChoice.getSelectionModel().selectFirst());
121+
Stage stage = (Stage) getDialogPane().getScene().getWindow();
122+
fileChoice.itemsProperty().addListener((observable, oldValue, newValue) -> {
123+
if (newValue.isEmpty()) {
124+
stage.close();
125+
} else {
126+
fileChoice.getSelectionModel().selectFirst();
127+
}
128+
});
108129
fileChoice.itemsProperty().bind(viewModel.filesProperty());
109130
}
110131

@@ -119,8 +140,12 @@ private void setupViewer() {
119140
mainPane.setCenter(viewer);
120141
}
121142

122-
public void setLiveMode(boolean liveMode) {
123-
modeLive.setSelected(liveMode);
143+
public void disableLiveMode() {
144+
modeLock.setSelected(true);
145+
}
146+
147+
public void switchToFile(LinkedFile file) {
148+
fileChoice.getSelectionModel().select(file);
124149
}
125150

126151
public void gotoPage(int pageNumber) {

src/main/java/org/jabref/gui/documentviewer/DocumentViewerViewModel.java

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
import java.nio.file.Path;
55
import java.util.List;
66
import java.util.Objects;
7+
import java.util.Set;
8+
import java.util.stream.Collectors;
79

8-
import javafx.application.Platform;
910
import javafx.beans.property.BooleanProperty;
1011
import javafx.beans.property.IntegerProperty;
1112
import javafx.beans.property.ListProperty;
@@ -19,6 +20,7 @@
1920

2021
import org.jabref.gui.AbstractViewModel;
2122
import org.jabref.gui.StateManager;
23+
import org.jabref.gui.util.UiTaskExecutor;
2224
import org.jabref.logic.util.io.FileUtil;
2325
import org.jabref.model.entry.BibEntry;
2426
import org.jabref.model.entry.LinkedFile;
@@ -38,7 +40,7 @@ public class DocumentViewerViewModel extends AbstractViewModel {
3840
private final PreferencesService preferencesService;
3941
private final ObjectProperty<DocumentViewModel> currentDocument = new SimpleObjectProperty<>();
4042
private final ListProperty<LinkedFile> files = new SimpleListProperty<>();
41-
private final BooleanProperty liveMode = new SimpleBooleanProperty();
43+
private final BooleanProperty liveMode = new SimpleBooleanProperty(true);
4244
private final ObjectProperty<Integer> currentPage = new SimpleObjectProperty<>();
4345
private final IntegerProperty maxPages = new SimpleIntegerProperty();
4446

@@ -48,7 +50,7 @@ public DocumentViewerViewModel(StateManager stateManager, PreferencesService pre
4850

4951
this.stateManager.getSelectedEntries().addListener((ListChangeListener<? super BibEntry>) c -> {
5052
// Switch to currently selected entry in live mode
51-
if (isLiveMode()) {
53+
if (liveMode.get()) {
5254
setCurrentEntries(this.stateManager.getSelectedEntries());
5355
}
5456
});
@@ -61,7 +63,7 @@ public DocumentViewerViewModel(StateManager stateManager, PreferencesService pre
6163
});
6264

6365
// we need to wrap this in run later so that the max pages number is correctly shown
64-
Platform.runLater(() -> maxPages.bindBidirectional(
66+
UiTaskExecutor.runInJavaFXThread(() -> maxPages.bind(
6567
EasyBind.wrapNullable(currentDocument).selectProperty(DocumentViewModel::maxPagesProperty)));
6668
setCurrentEntries(this.stateManager.getSelectedEntries());
6769
}
@@ -78,10 +80,6 @@ public IntegerProperty maxPagesProperty() {
7880
return maxPages;
7981
}
8082

81-
private boolean isLiveMode() {
82-
return liveMode.get();
83-
}
84-
8583
public ObjectProperty<DocumentViewModel> currentDocumentProperty() {
8684
return currentDocument;
8785
}
@@ -91,18 +89,13 @@ public ListProperty<LinkedFile> filesProperty() {
9189
}
9290

9391
private void setCurrentEntries(List<BibEntry> entries) {
94-
if (!entries.isEmpty()) {
95-
BibEntry firstSelectedEntry = entries.getFirst();
96-
setCurrentEntry(firstSelectedEntry);
97-
}
98-
}
99-
100-
private void setCurrentEntry(BibEntry entry) {
101-
stateManager.getActiveDatabase().ifPresent(database -> {
102-
List<LinkedFile> linkedFiles = entry.getFiles();
92+
if (entries.isEmpty()) {
93+
files.clear();
94+
} else {
95+
Set<LinkedFile> linkedFiles = entries.stream().map(BibEntry::getFiles).flatMap(List::stream).collect(Collectors.toSet());
10396
// We don't need to switch to the first file, this is done automatically in the UI part
10497
files.setValue(FXCollections.observableArrayList(linkedFiles));
105-
});
98+
}
10699
}
107100

108101
private void setCurrentDocument(Path path) {
@@ -121,23 +114,28 @@ public void switchToFile(LinkedFile file) {
121114
stateManager.getActiveDatabase()
122115
.flatMap(database -> file.findIn(database, preferencesService.getFilePreferences()))
123116
.ifPresent(this::setCurrentDocument);
117+
currentPage.set(1);
124118
}
125119
}
126120

127-
public BooleanProperty liveModeProperty() {
128-
return liveMode;
129-
}
130-
131121
public void showPage(int pageNumber) {
132-
currentPage.set(pageNumber);
122+
if (pageNumber >= 1 && pageNumber <= maxPages.get()) {
123+
currentPage.set(pageNumber);
124+
} else {
125+
currentPage.set(1);
126+
}
133127
}
134128

135129
public void showNextPage() {
136-
currentPage.set(getCurrentPage() + 1);
130+
if (getCurrentPage() < maxPages.get()) {
131+
currentPage.set(getCurrentPage() + 1);
132+
}
137133
}
138134

139135
public void showPreviousPage() {
140-
currentPage.set(getCurrentPage() - 1);
136+
if (getCurrentPage() > 1) {
137+
currentPage.set(getCurrentPage() - 1);
138+
}
141139
}
142140

143141
public void setLiveMode(boolean value) {

src/main/java/org/jabref/gui/documentviewer/ShowDocumentViewerAction.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,18 @@
1111
import static org.jabref.gui.actions.ActionHelper.needsEntriesSelected;
1212

1313
public class ShowDocumentViewerAction extends SimpleCommand {
14+
private final DialogService dialogService = Injector.instantiateModelOrService(DialogService.class);
15+
private DocumentViewerView documentViewerView;
1416

1517
public ShowDocumentViewerAction(StateManager stateManager, PreferencesService preferences) {
1618
this.executable.bind(needsEntriesSelected(stateManager).and(ActionHelper.isFilePresentForSelectedEntry(stateManager, preferences)));
1719
}
1820

1921
@Override
2022
public void execute() {
21-
DialogService dialogService = Injector.instantiateModelOrService(DialogService.class);
22-
dialogService.showCustomDialog(new DocumentViewerView());
23+
if (documentViewerView == null) {
24+
documentViewerView = new DocumentViewerView();
25+
}
26+
dialogService.showCustomDialog(documentViewerView);
2327
}
2428
}

0 commit comments

Comments
 (0)