diff --git a/build.gradle b/build.gradle index dd891366ede..05e64349175 100644 --- a/build.gradle +++ b/build.gradle @@ -85,6 +85,7 @@ configurations { } dependencies { + // Include all jar-files in the 'lib' folder as dependencies compile fileTree(dir: 'lib', includes: ['*.jar']) compile 'com.jgoodies:jgoodies-common:1.8.1' @@ -123,7 +124,6 @@ dependencies { compile 'com.google.guava:guava:24.1-jre' // JavaFX stuff - compile 'com.airhacks:afterburner.fx:1.7.0' compile 'de.codecentric.centerdevice:javafxsvg:1.3.0' compile 'de.jensd:fontawesomefx-materialdesignfont:1.7.22-4' compile 'de.saxsys:mvvmfx-validation:1.7.0' @@ -132,6 +132,7 @@ dependencies { compile 'org.fxmisc.flowless:flowless:0.6' compile 'org.fxmisc.richtext:richtextfx:0.8.2' compile 'com.sibvisions.external.jvxfx:dndtabpane:0.1' + compile 'javax.inject:javax.inject:1' // Cannot be updated to 9.*.* until Jabref works with Java 9 diff --git a/javafx/scene/control/annotations.xml b/javafx/scene/control/annotations.xml new file mode 100644 index 00000000000..240687d556c --- /dev/null +++ b/javafx/scene/control/annotations.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/lib/afterburner.fx.jar b/lib/afterburner.fx.jar new file mode 100644 index 00000000000..816b3e27f5d Binary files /dev/null and b/lib/afterburner.fx.jar differ diff --git a/src/main/java/org/jabref/gui/AbstractController.java b/src/main/java/org/jabref/gui/AbstractController.java deleted file mode 100644 index 53ad25c113b..00000000000 --- a/src/main/java/org/jabref/gui/AbstractController.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.jabref.gui; - -import java.util.Objects; - -import javafx.fxml.FXML; -import javafx.fxml.FXMLLoader; -import javafx.stage.Stage; - -public class AbstractController { - - @FXML protected T viewModel; - private Stage stage; - - /** - * Gets the associated view model. - * - * Without this method the {@link FXMLLoader} is not able to resolve references in the fxml file of the form - * text="${controller.viewModel.someProperty}" - */ - public T getViewModel() { - return viewModel; - } - - /** - * Returns the stage where this controller is displayed. - * The stage can be used to e.g. close the dialog. - */ - public Stage getStage() { - return stage; - } - - public void setStage(Stage stage) { - this.stage = Objects.requireNonNull(stage); - } -} diff --git a/src/main/java/org/jabref/gui/AbstractDialogView.java b/src/main/java/org/jabref/gui/AbstractDialogView.java deleted file mode 100644 index d7880e3cd11..00000000000 --- a/src/main/java/org/jabref/gui/AbstractDialogView.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.jabref.gui; - -import java.util.function.Function; - -public abstract class AbstractDialogView extends AbstractView { - - public AbstractDialogView() { - super(); - } - - public AbstractDialogView(Function injectionContext) { - super(injectionContext); - } - - public abstract void show(); -} diff --git a/src/main/java/org/jabref/gui/AbstractView.java b/src/main/java/org/jabref/gui/AbstractView.java deleted file mode 100644 index 266ddedb429..00000000000 --- a/src/main/java/org/jabref/gui/AbstractView.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.jabref.gui; - -import java.util.Optional; -import java.util.function.Function; - -import javafx.scene.Parent; -import javafx.stage.Stage; - -import org.jabref.Globals; -import org.jabref.logic.l10n.Localization; - -import com.airhacks.afterburner.views.FXMLView; - -public class AbstractView extends FXMLView { - - public AbstractView() { - this(f -> null); - } - - public AbstractView(Function injectionContext) { - super(injectionContext); - - // Set resource bundle to internal localizations - bundle = Localization.getMessages(); - } - - @Override - public Parent getView() { - Parent view = super.getView(); - - // Add our base css file - Globals.getThemeLoader().installBaseCss(view); - - // Notify controller about the stage, where it is displayed - view.sceneProperty().addListener((observable, oldValue, newValue) -> { - if (newValue != null && newValue.getWindow() instanceof Stage) { - Stage stage = (Stage) newValue.getWindow(); - if (stage != null) { - getController().ifPresent(controller -> controller.setStage(stage)); - } - } - }); - return view; - } - - private Optional getController() { - return Optional.ofNullable(presenterProperty.get()).map( - presenter -> (AbstractController) presenter); - } -} diff --git a/src/main/java/org/jabref/gui/DefaultInjector.java b/src/main/java/org/jabref/gui/DefaultInjector.java index 5c96fe7395b..e94e6fe8697 100644 --- a/src/main/java/org/jabref/gui/DefaultInjector.java +++ b/src/main/java/org/jabref/gui/DefaultInjector.java @@ -59,4 +59,14 @@ public T instantiatePresenter(Class clazz, Function injec return Injector.instantiatePresenter(clazz, injectionContext); } + + @Override + public void injectMembers(Object instance, Function injectionContext) { + LOGGER.debug("Inject into " + instance.getClass().getName()); + + // Use our own method to construct dependencies + Injector.setInstanceSupplier(DefaultInjector::createDependency); + + Injector.injectMembers(instance, injectionContext); + } } diff --git a/src/main/java/org/jabref/gui/actions/CleanupAction.java b/src/main/java/org/jabref/gui/actions/CleanupAction.java index f0f34af7379..d46b77402ef 100644 --- a/src/main/java/org/jabref/gui/actions/CleanupAction.java +++ b/src/main/java/org/jabref/gui/actions/CleanupAction.java @@ -4,16 +4,12 @@ import java.util.Optional; import javax.swing.JOptionPane; -import javax.swing.JScrollPane; - -import javafx.embed.swing.SwingNode; -import javafx.scene.control.ButtonType; -import javafx.scene.control.DialogPane; import org.jabref.Globals; import org.jabref.gui.BasePanel; import org.jabref.gui.DialogService; import org.jabref.gui.JabRefFrame; +import org.jabref.gui.cleanup.CleanupDialog; import org.jabref.gui.cleanup.CleanupPresetPanel; import org.jabref.gui.undo.NamedCompound; import org.jabref.gui.undo.UndoableFieldChange; @@ -67,27 +63,14 @@ public void run() { if (canceled) { return; } - CleanupPresetPanel presetPanel = new CleanupPresetPanel(panel.getBibDatabaseContext(), - CleanupPreset.loadFromPreferences(preferences)); - - SwingNode node = new SwingNode(); - presetPanel.getScrollPane().setVisible(true); - - JScrollPane scrollPane = presetPanel.getScrollPane(); - node.setContent(scrollPane); - node.setVisible(true); - - DialogPane pane = new DialogPane(); - pane.setContent(node); - pane.setPrefSize(600, 600); - - Optional ok = dialogService.showCustomDialogAndWait(Localization.lang("Cleanup entries"), pane, ButtonType.OK, ButtonType.CANCEL); + CleanupDialog cleanupDialog = new CleanupDialog(panel.getBibDatabaseContext(), CleanupPreset.loadFromPreferences(preferences)); - if (!ok.isPresent() || ((ok.isPresent() && (ok.get() == ButtonType.CANCEL)))) { + Optional chosenPreset = cleanupDialog.showAndWait(); + if (!chosenPreset.isPresent()) { canceled = true; return; } - CleanupPreset cleanupPreset = presetPanel.getCleanupPreset(); + CleanupPreset cleanupPreset = chosenPreset.get(); cleanupPreset.storeInPreferences(preferences); if (cleanupPreset.isRenamePDF() && Globals.prefs.getBoolean(JabRefPreferences.ASK_AUTO_NAMING_PDFS_AGAIN)) { diff --git a/src/main/java/org/jabref/gui/actions/CopyFilesAction.java b/src/main/java/org/jabref/gui/actions/CopyFilesAction.java index 8ba3e2db382..39ea9b34d4c 100644 --- a/src/main/java/org/jabref/gui/actions/CopyFilesAction.java +++ b/src/main/java/org/jabref/gui/actions/CopyFilesAction.java @@ -47,8 +47,8 @@ private void showDialog(List data) { dialogService.showInformationDialogAndWait(Localization.lang("Copy linked files to folder..."), Localization.lang("No linked files found for export.")); return; } - CopyFilesDialogView dlg = new CopyFilesDialogView(databaseContext, new CopyFilesResultListDependency(data)); - dlg.show(); + CopyFilesDialogView dialog = new CopyFilesDialogView(databaseContext, new CopyFilesResultListDependency(data)); + dialog.show(); } @Override diff --git a/src/main/java/org/jabref/gui/actions/ShowPreferencesAction.java b/src/main/java/org/jabref/gui/actions/ShowPreferencesAction.java index c6b551ef0a9..6208911fc6b 100644 --- a/src/main/java/org/jabref/gui/actions/ShowPreferencesAction.java +++ b/src/main/java/org/jabref/gui/actions/ShowPreferencesAction.java @@ -14,17 +14,12 @@ public ShowPreferencesAction(JabRefFrame jabRefFrame) { @Override public void execute() { - // output(Localization.lang("Opening preferences...")); if (prefsDialog == null) { prefsDialog = new PreferencesDialog(jabRefFrame); - //prefsDialog.setLocationRelativeTo(JabRefFrame.this); } else { prefsDialog.setValues(); } - prefsDialog.setVisible(true); - //output(""); - + prefsDialog.show(); } - } diff --git a/src/main/java/org/jabref/gui/cleanup/CleanupDialog.java b/src/main/java/org/jabref/gui/cleanup/CleanupDialog.java new file mode 100644 index 00000000000..4ac358e8434 --- /dev/null +++ b/src/main/java/org/jabref/gui/cleanup/CleanupDialog.java @@ -0,0 +1,34 @@ +package org.jabref.gui.cleanup; + +import javax.swing.JScrollPane; + +import javafx.scene.control.ButtonType; + +import org.jabref.gui.util.BaseDialog; +import org.jabref.gui.util.ControlHelper; +import org.jabref.logic.cleanup.CleanupPreset; +import org.jabref.logic.l10n.Localization; +import org.jabref.model.database.BibDatabaseContext; + +public class CleanupDialog extends BaseDialog { + + public CleanupDialog(BibDatabaseContext databaseContext, CleanupPreset initialPreset) { + setTitle(Localization.lang("Cleanup entries")); + getDialogPane().setPrefSize(600, 600); + getDialogPane().getButtonTypes().setAll(ButtonType.OK, ButtonType.CANCEL); + + CleanupPresetPanel presetPanel = new CleanupPresetPanel(databaseContext, initialPreset); + presetPanel.getScrollPane().setVisible(true); + JScrollPane scrollPane = presetPanel.getScrollPane(); + + setResultConverter(button -> { + if (button == ButtonType.OK) { + return presetPanel.getCleanupPreset(); + } else { + return null; + } + }); + + ControlHelper.setSwingContent(getDialogPane(), scrollPane); + } +} diff --git a/src/main/resources/org/jabref/gui/copyfiles/CopyFilesDialog.fxml b/src/main/java/org/jabref/gui/copyfiles/CopyFilesDialog.fxml similarity index 83% rename from src/main/resources/org/jabref/gui/copyfiles/CopyFilesDialog.fxml rename to src/main/java/org/jabref/gui/copyfiles/CopyFilesDialog.fxml index 88aa1b0a03b..671b569acf3 100644 --- a/src/main/resources/org/jabref/gui/copyfiles/CopyFilesDialog.fxml +++ b/src/main/java/org/jabref/gui/copyfiles/CopyFilesDialog.fxml @@ -6,8 +6,9 @@ - - +
diff --git a/src/main/java/org/jabref/gui/copyfiles/CopyFilesDialogController.java b/src/main/java/org/jabref/gui/copyfiles/CopyFilesDialogController.java deleted file mode 100644 index 6c3b79bfa1d..00000000000 --- a/src/main/java/org/jabref/gui/copyfiles/CopyFilesDialogController.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.jabref.gui.copyfiles; - -import javax.inject.Inject; - -import javafx.event.ActionEvent; -import javafx.fxml.FXML; -import javafx.scene.control.TableColumn; -import javafx.scene.control.TableView; -import javafx.scene.paint.Color; -import javafx.scene.text.Text; - -import org.jabref.gui.AbstractController; -import org.jabref.gui.util.ValueTableCellFactory; - -import de.jensd.fx.glyphs.materialdesignicons.MaterialDesignIcon; -import de.jensd.fx.glyphs.materialdesignicons.utils.MaterialDesignIconFactory; - -public class CopyFilesDialogController extends AbstractController { - - @FXML private TableView tvResult; - @FXML private TableColumn colStatus; - @FXML private TableColumn colMessage; - @FXML private TableColumn colFile; - - @Inject private CopyFilesResultListDependency copyfilesresultlistDependency; //This var must have the same name as the key in the View - - @FXML - private void close(@SuppressWarnings("unused") ActionEvent event) { - getStage().close(); - } - - @FXML - private void initialize() { - viewModel = new CopyFilesDialogViewModel(copyfilesresultlistDependency); - setupTable(); - } - - private void setupTable() { - colFile.setCellValueFactory(cellData -> cellData.getValue().getFile()); - colMessage.setCellValueFactory(cellData -> cellData.getValue().getMessage()); - colStatus.setCellValueFactory(cellData -> cellData.getValue().getIcon()); - - colFile.setCellFactory(new ValueTableCellFactory().withText(item -> item).withTooltip(item -> item)); - colStatus.setCellFactory(new ValueTableCellFactory().withGraphic(item -> { - - Text icon = MaterialDesignIconFactory.get().createIcon(item); - if (item == MaterialDesignIcon.CHECK) { - icon.setFill(Color.GREEN); - } - if (item == MaterialDesignIcon.ALERT) { - icon.setFill(Color.RED); - } - return icon; - })); - - tvResult.setItems(viewModel.copyFilesResultListProperty()); - tvResult.setColumnResizePolicy((param) -> true); - } -} diff --git a/src/main/java/org/jabref/gui/copyfiles/CopyFilesDialogView.java b/src/main/java/org/jabref/gui/copyfiles/CopyFilesDialogView.java index 7c7c24b5a90..cd4b33832ea 100644 --- a/src/main/java/org/jabref/gui/copyfiles/CopyFilesDialogView.java +++ b/src/main/java/org/jabref/gui/copyfiles/CopyFilesDialogView.java @@ -1,36 +1,69 @@ package org.jabref.gui.copyfiles; -import java.util.HashMap; -import java.util.Map; -import java.util.function.Function; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.scene.control.TableColumn; +import javafx.scene.control.TableView; +import javafx.scene.paint.Color; +import javafx.scene.text.Text; -import javafx.scene.control.Alert.AlertType; -import javafx.scene.control.DialogPane; - -import org.jabref.gui.AbstractDialogView; -import org.jabref.gui.FXDialog; +import org.jabref.gui.util.BaseDialog; +import org.jabref.gui.util.ValueTableCellFactory; import org.jabref.logic.l10n.Localization; import org.jabref.model.database.BibDatabaseContext; -public class CopyFilesDialogView extends AbstractDialogView { +import com.airhacks.afterburner.views.ViewLoader; +import de.jensd.fx.glyphs.materialdesignicons.MaterialDesignIcon; +import de.jensd.fx.glyphs.materialdesignicons.utils.MaterialDesignIconFactory; + +public class CopyFilesDialogView extends BaseDialog { + + @FXML private TableView tvResult; + @FXML private TableColumn colStatus; + @FXML private TableColumn colMessage; + @FXML private TableColumn colFile; + private final CopyFilesDialogViewModel viewModel; public CopyFilesDialogView(BibDatabaseContext bibDatabaseContext, CopyFilesResultListDependency results) { - super(createContext(bibDatabaseContext, results)); + this.setTitle(Localization.lang("Result")); + this.setResizable(true); + + ViewLoader.view(this) + .load() + .setAsContent(this.getDialogPane()); + + viewModel = new CopyFilesDialogViewModel(results); } - @Override - public void show() { - FXDialog copyFilesResultDlg = new FXDialog(AlertType.INFORMATION, Localization.lang("Result")); - copyFilesResultDlg.setResizable(true); - copyFilesResultDlg.setDialogPane((DialogPane) this.getView()); - copyFilesResultDlg.show(); + @FXML + private void close(@SuppressWarnings("unused") ActionEvent event) { + close(); } - private static Function createContext(BibDatabaseContext bibDatabaseContext, CopyFilesResultListDependency copyfilesresultlistDependency) { - Map context = new HashMap<>(); - //The "keys" of the HashMap must have the same name as the with @inject annotated field in the controller - context.put("bibdatabasecontext", bibDatabaseContext); - context.put("copyfilesresultlistDependency", copyfilesresultlistDependency); - return context::get; + @FXML + private void initialize() { + setupTable(); + } + + private void setupTable() { + colFile.setCellValueFactory(cellData -> cellData.getValue().getFile()); + colMessage.setCellValueFactory(cellData -> cellData.getValue().getMessage()); + colStatus.setCellValueFactory(cellData -> cellData.getValue().getIcon()); + + colFile.setCellFactory(new ValueTableCellFactory().withText(item -> item).withTooltip(item -> item)); + colStatus.setCellFactory(new ValueTableCellFactory().withGraphic(item -> { + + Text icon = MaterialDesignIconFactory.get().createIcon(item); + if (item == MaterialDesignIcon.CHECK) { + icon.setFill(Color.GREEN); + } + if (item == MaterialDesignIcon.ALERT) { + icon.setFill(Color.RED); + } + return icon; + })); + + tvResult.setItems(viewModel.copyFilesResultListProperty()); + tvResult.setColumnResizePolicy((param) -> true); } } diff --git a/src/main/java/org/jabref/gui/documentviewer/DocumentViewer.fxml b/src/main/java/org/jabref/gui/documentviewer/DocumentViewer.fxml index b111649ddf2..57e1f086228 100644 --- a/src/main/java/org/jabref/gui/documentviewer/DocumentViewer.fxml +++ b/src/main/java/org/jabref/gui/documentviewer/DocumentViewer.fxml @@ -15,7 +15,7 @@ + fx:controller="org.jabref.gui.documentviewer.DocumentViewerView"> diff --git a/src/main/java/org/jabref/gui/documentviewer/DocumentViewerController.java b/src/main/java/org/jabref/gui/documentviewer/DocumentViewerController.java deleted file mode 100644 index 08abde5f290..00000000000 --- a/src/main/java/org/jabref/gui/documentviewer/DocumentViewerController.java +++ /dev/null @@ -1,109 +0,0 @@ -package org.jabref.gui.documentviewer; - -import javax.inject.Inject; - -import javafx.event.ActionEvent; -import javafx.fxml.FXML; -import javafx.scene.control.ComboBox; -import javafx.scene.control.Label; -import javafx.scene.control.ScrollBar; -import javafx.scene.control.TextField; -import javafx.scene.control.ToggleButton; -import javafx.scene.layout.BorderPane; - -import org.jabref.gui.AbstractController; -import org.jabref.gui.StateManager; -import org.jabref.gui.util.OnlyIntegerFormatter; -import org.jabref.gui.util.TaskExecutor; -import org.jabref.gui.util.ViewModelListCellFactory; -import org.jabref.model.entry.LinkedFile; - -public class DocumentViewerController extends AbstractController { - - @FXML private ScrollBar scrollBar; - @FXML private ComboBox fileChoice; - @FXML private BorderPane mainPane; - @FXML private ToggleButton modeLive; - @FXML private TextField currentPage; - @FXML private Label maxPages; - - @Inject private StateManager stateManager; - @Inject private TaskExecutor taskExecutor; - private DocumentViewerControl viewer; - - @FXML - private void initialize() { - viewModel = new DocumentViewerViewModel(stateManager); - - setupViewer(); - setupScrollbar(); - setupFileChoice(); - setupPageControls(); - setupModeButtons(); - } - - private void setupModeButtons() { - viewModel.liveModeProperty().bind(modeLive.selectedProperty()); - } - - private void setupScrollbar() { - scrollBar.valueProperty().bindBidirectional(viewer.scrollYProperty()); - scrollBar.maxProperty().bind(viewer.scrollYMaxProperty()); - } - - private void setupPageControls() { - OnlyIntegerFormatter integerFormatter = new OnlyIntegerFormatter(1); - viewModel.currentPageProperty().bindBidirectional(integerFormatter.valueProperty()); - currentPage.setTextFormatter(integerFormatter); - maxPages.textProperty().bind(viewModel.maxPagesProperty().asString()); - } - - private void setupFileChoice() { - ViewModelListCellFactory cellFactory = new ViewModelListCellFactory() - .withText(LinkedFile::getLink); - fileChoice.setButtonCell(cellFactory.call(null)); - fileChoice.setCellFactory(cellFactory); - fileChoice.getSelectionModel().selectedItemProperty().addListener( - (observable, oldValue, newValue) -> viewModel.switchToFile(newValue)); - // We always want that the first item is selected after a change - // This also automatically selects the first file on the initial load - fileChoice.itemsProperty().addListener( - (observable, oldValue, newValue) -> fileChoice.getSelectionModel().selectFirst()); - fileChoice.itemsProperty().bind(viewModel.filesProperty()); - } - - private void setupViewer() { - viewer = new DocumentViewerControl(taskExecutor); - viewModel.currentDocumentProperty().addListener((observable, oldDocument, newDocument) -> { - if (newDocument != null) { - viewer.show(newDocument); - } - }); - viewModel.currentPageProperty().bindBidirectional(viewer.currentPageProperty()); - mainPane.setCenter(viewer); - } - - public void nextPage(ActionEvent actionEvent) { - viewModel.showNextPage(); - } - - public void previousPage(ActionEvent actionEvent) { - viewModel.showPreviousPage(); - } - - public void fitWidth(ActionEvent actionEvent) { - viewer.setPageWidth(viewer.getWidth()); - } - - public void zoomIn(ActionEvent actionEvent) { - viewer.changePageWidth(100); - } - - public void zoomOut(ActionEvent actionEvent) { - viewer.changePageWidth(-100); - } - - public void fitSinglePage(ActionEvent actionEvent) { - viewer.setPageHeight(viewer.getHeight()); - } -} diff --git a/src/main/java/org/jabref/gui/documentviewer/DocumentViewerView.java b/src/main/java/org/jabref/gui/documentviewer/DocumentViewerView.java index 5ca7efd27d2..60ef762d9bc 100644 --- a/src/main/java/org/jabref/gui/documentviewer/DocumentViewerView.java +++ b/src/main/java/org/jabref/gui/documentviewer/DocumentViewerView.java @@ -1,25 +1,130 @@ package org.jabref.gui.documentviewer; -import javafx.scene.control.Alert.AlertType; +import javax.inject.Inject; + +import javafx.event.ActionEvent; +import javafx.fxml.FXML; import javafx.scene.control.ButtonBar; -import javafx.scene.control.DialogPane; +import javafx.scene.control.ButtonType; +import javafx.scene.control.ComboBox; +import javafx.scene.control.Label; +import javafx.scene.control.ScrollBar; +import javafx.scene.control.TextField; +import javafx.scene.control.ToggleButton; +import javafx.scene.layout.BorderPane; +import javafx.stage.Modality; -import org.jabref.gui.AbstractDialogView; -import org.jabref.gui.FXDialog; +import org.jabref.gui.StateManager; +import org.jabref.gui.util.BaseDialog; +import org.jabref.gui.util.OnlyIntegerFormatter; +import org.jabref.gui.util.TaskExecutor; +import org.jabref.gui.util.ViewModelListCellFactory; import org.jabref.logic.l10n.Localization; +import org.jabref.model.entry.LinkedFile; + +import com.airhacks.afterburner.views.ViewLoader; + +public class DocumentViewerView extends BaseDialog { + + @FXML private ScrollBar scrollBar; + @FXML private ComboBox fileChoice; + @FXML private BorderPane mainPane; + @FXML private ToggleButton modeLive; + @FXML private TextField currentPage; + @FXML private Label maxPages; -public class DocumentViewerView extends AbstractDialogView { + @Inject private StateManager stateManager; + @Inject private TaskExecutor taskExecutor; + private DocumentViewerControl viewer; + private DocumentViewerViewModel viewModel; + + public DocumentViewerView() { + this.setTitle(Localization.lang("Document viewer")); + this.initModality(Modality.NONE); + this.setResizable(true); + + ViewLoader.view(this) + .load() + .setAsContent(this.getDialogPane()); + + // Remove button bar at bottom, but add close button to keep the dialog closable by clicking the "x" window symbol + getDialogPane().getButtonTypes().add(ButtonType.CLOSE); + getDialogPane().getChildren().removeIf(node -> node instanceof ButtonBar); + } - @Override - public void show() { - FXDialog dialog = new FXDialog(AlertType.INFORMATION, Localization.lang("Document viewer"), false); - DialogPane dialogPane = (DialogPane) this.getView(); + @FXML + private void initialize() { + viewModel = new DocumentViewerViewModel(stateManager); - // Remove button bar at bottom - dialogPane.getChildren().removeIf(node -> node instanceof ButtonBar); + setupViewer(); + setupScrollbar(); + setupFileChoice(); + setupPageControls(); + setupModeButtons(); + } + + private void setupModeButtons() { + viewModel.liveModeProperty().bind(modeLive.selectedProperty()); + } + + private void setupScrollbar() { + scrollBar.valueProperty().bindBidirectional(viewer.scrollYProperty()); + scrollBar.maxProperty().bind(viewer.scrollYMaxProperty()); + } + + private void setupPageControls() { + OnlyIntegerFormatter integerFormatter = new OnlyIntegerFormatter(1); + viewModel.currentPageProperty().bindBidirectional(integerFormatter.valueProperty()); + currentPage.setTextFormatter(integerFormatter); + maxPages.textProperty().bind(viewModel.maxPagesProperty().asString()); + } + + private void setupFileChoice() { + ViewModelListCellFactory cellFactory = new ViewModelListCellFactory() + .withText(LinkedFile::getLink); + fileChoice.setButtonCell(cellFactory.call(null)); + fileChoice.setCellFactory(cellFactory); + fileChoice.getSelectionModel().selectedItemProperty().addListener( + (observable, oldValue, newValue) -> viewModel.switchToFile(newValue)); + // We always want that the first item is selected after a change + // This also automatically selects the first file on the initial load + fileChoice.itemsProperty().addListener( + (observable, oldValue, newValue) -> fileChoice.getSelectionModel().selectFirst()); + fileChoice.itemsProperty().bind(viewModel.filesProperty()); + } + + private void setupViewer() { + viewer = new DocumentViewerControl(taskExecutor); + viewModel.currentDocumentProperty().addListener((observable, oldDocument, newDocument) -> { + if (newDocument != null) { + viewer.show(newDocument); + } + }); + viewModel.currentPageProperty().bindBidirectional(viewer.currentPageProperty()); + mainPane.setCenter(viewer); + } + + public void nextPage(ActionEvent actionEvent) { + viewModel.showNextPage(); + } + + public void previousPage(ActionEvent actionEvent) { + viewModel.showPreviousPage(); + } + + public void fitWidth(ActionEvent actionEvent) { + viewer.setPageWidth(viewer.getWidth()); + } + + public void zoomIn(ActionEvent actionEvent) { + viewer.changePageWidth(100); + } + + public void zoomOut(ActionEvent actionEvent) { + viewer.changePageWidth(-100); + } - dialog.setDialogPane(dialogPane); - dialog.setResizable(true); - dialog.show(); + public void fitSinglePage(ActionEvent actionEvent) { + viewer.setPageHeight(viewer.getHeight()); } } diff --git a/src/main/java/org/jabref/gui/entryeditor/fileannotationtab/FileAnnotationTab.fxml b/src/main/java/org/jabref/gui/entryeditor/fileannotationtab/FileAnnotationTab.fxml index a9b8bbfb029..d56bfd1de4b 100644 --- a/src/main/java/org/jabref/gui/entryeditor/fileannotationtab/FileAnnotationTab.fxml +++ b/src/main/java/org/jabref/gui/entryeditor/fileannotationtab/FileAnnotationTab.fxml @@ -17,8 +17,9 @@ - - + diff --git a/src/main/java/org/jabref/gui/entryeditor/fileannotationtab/FileAnnotationTab.java b/src/main/java/org/jabref/gui/entryeditor/fileannotationtab/FileAnnotationTab.java index 7b9da1a8179..027f8f8f676 100644 --- a/src/main/java/org/jabref/gui/entryeditor/fileannotationtab/FileAnnotationTab.java +++ b/src/main/java/org/jabref/gui/entryeditor/fileannotationtab/FileAnnotationTab.java @@ -1,5 +1,6 @@ package org.jabref.gui.entryeditor.fileannotationtab; +import javafx.scene.Parent; import javafx.scene.control.Tooltip; import org.jabref.gui.entryeditor.EntryEditorTab; @@ -8,6 +9,8 @@ import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.FieldName; +import com.airhacks.afterburner.views.ViewLoader; + public class FileAnnotationTab extends EntryEditorTab { private final FileAnnotationCache fileAnnotationCache; @@ -26,6 +29,9 @@ public boolean shouldShow(BibEntry entry) { @Override protected void bindToEntry(BibEntry entry) { - setContent(new FileAnnotationTabView(entry, fileAnnotationCache).getView()); + Parent content = ViewLoader.view(new FileAnnotationTabView(entry, fileAnnotationCache)) + .load() + .getView(); + setContent(content); } } diff --git a/src/main/java/org/jabref/gui/entryeditor/fileannotationtab/FileAnnotationTabController.java b/src/main/java/org/jabref/gui/entryeditor/fileannotationtab/FileAnnotationTabController.java deleted file mode 100644 index 40f8dc874b7..00000000000 --- a/src/main/java/org/jabref/gui/entryeditor/fileannotationtab/FileAnnotationTabController.java +++ /dev/null @@ -1,144 +0,0 @@ -package org.jabref.gui.entryeditor.fileannotationtab; - -import java.nio.file.Path; - -import javax.inject.Inject; - -import javafx.beans.binding.Bindings; -import javafx.collections.ListChangeListener; -import javafx.event.ActionEvent; -import javafx.fxml.FXML; -import javafx.geometry.HPos; -import javafx.geometry.Pos; -import javafx.scene.Node; -import javafx.scene.control.ComboBox; -import javafx.scene.control.Label; -import javafx.scene.control.ListView; -import javafx.scene.control.SelectionMode; -import javafx.scene.control.TextArea; -import javafx.scene.layout.ColumnConstraints; -import javafx.scene.layout.GridPane; -import javafx.scene.layout.RowConstraints; -import javafx.scene.text.Font; -import javafx.scene.text.TextAlignment; - -import org.jabref.gui.AbstractController; -import org.jabref.gui.util.ViewModelListCellFactory; -import org.jabref.logic.l10n.Localization; -import org.jabref.logic.pdf.FileAnnotationCache; -import org.jabref.model.entry.BibEntry; -import org.jabref.model.util.FileUpdateMonitor; - -import org.fxmisc.easybind.EasyBind; - -public class FileAnnotationTabController extends AbstractController { - - @FXML - public ComboBox files; - @FXML - public ListView annotationList; - @FXML - public Label author; - @FXML - public Label page; - @FXML - public Label date; - @FXML - public TextArea content; - @FXML - public TextArea marking; - @FXML - public GridPane grid; - - @Inject - private FileAnnotationCache fileAnnotationCache; - @Inject - private BibEntry entry; - @Inject - private FileUpdateMonitor fileMonitor; - - @FXML - public void initialize() { - viewModel = new FileAnnotationTabViewModel(fileAnnotationCache, entry, fileMonitor); - - // Set-up files list - files.getItems().setAll(viewModel.filesProperty().get()); - files.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> viewModel.notifyNewSelectedFile(newValue)); - files.getSelectionModel().selectFirst(); - - // Set-up annotation list - annotationList.getSelectionModel().setSelectionMode(SelectionMode.SINGLE); - annotationList.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> viewModel.notifyNewSelectedAnnotation(newValue)); - ViewModelListCellFactory cellFactory = new ViewModelListCellFactory() - .withTooltip(FileAnnotationViewModel::getMarking) - .withGraphic(annotation -> { - return createFileAnnotationNode(annotation); - }); - annotationList.setCellFactory(cellFactory); - annotationList.setPlaceholder(new Label(Localization.lang("File has no attached annotations"))); - Bindings.bindContent(annotationList.itemsProperty().get(), viewModel.annotationsProperty()); - annotationList.getSelectionModel().selectFirst(); - annotationList.itemsProperty().get().addListener( - (ListChangeListener) c -> annotationList.getSelectionModel().selectFirst()); - - // Set-up details pane - content.textProperty().bind(EasyBind.select(viewModel.currentAnnotationProperty()).selectObject(FileAnnotationViewModel::contentProperty)); - marking.textProperty().bind(EasyBind.select(viewModel.currentAnnotationProperty()).selectObject(FileAnnotationViewModel::markingProperty)); - grid.disableProperty().bind(viewModel.isAnnotationsEmpty()); - } - - private Node createFileAnnotationNode(FileAnnotationViewModel annotation) { - GridPane node = new GridPane(); - - ColumnConstraints firstColumn = new ColumnConstraints(); - ColumnConstraints secondColumn = new ColumnConstraints(); - firstColumn.setPercentWidth(70); - secondColumn.setPercentWidth(30); - firstColumn.setHalignment(HPos.LEFT); - secondColumn.setHalignment(HPos.RIGHT); - node.getColumnConstraints().addAll(firstColumn, secondColumn); - - RowConstraints firstRow = new RowConstraints(); - RowConstraints secondRow = new RowConstraints(); - firstRow.setMinHeight(10); - firstRow.setPrefHeight(15); - secondRow.setMinHeight(10); - secondRow.setPrefHeight(35); - node.getRowConstraints().addAll(firstRow, secondRow); - - Label marking = new Label(annotation.getMarking()); - Label author = new Label(annotation.getAuthor()); - Label date = new Label(annotation.getDate()); - Label page = new Label(Localization.lang("Page") + ": " + annotation.getPage()); - - marking.setFont(new Font("System Bold", 15)); - marking.setPrefWidth(250); - author.setFont(new Font("System", 14)); - - marking.setPrefHeight(10); - author.setPrefHeight(30); - date.setPrefHeight(10); - page.setPrefHeight(30); - - // add alignment for text in the list - marking.setTextAlignment(TextAlignment.LEFT); - marking.setAlignment(Pos.TOP_LEFT); - author.setTextAlignment(TextAlignment.LEFT); - author.setAlignment(Pos.TOP_LEFT); - date.setTextAlignment(TextAlignment.RIGHT); - date.setAlignment(Pos.TOP_RIGHT); - page.setTextAlignment(TextAlignment.RIGHT); - page.setAlignment(Pos.TOP_RIGHT); - - node.add(marking, 0, 0); - node.add(author, 0, 1); - node.add(date, 1, 0); - node.add(page, 1, 1); - - return node; - } - - public void copy(ActionEvent event) { - viewModel.copyCurrentAnnotation(); - } -} diff --git a/src/main/java/org/jabref/gui/entryeditor/fileannotationtab/FileAnnotationTabView.java b/src/main/java/org/jabref/gui/entryeditor/fileannotationtab/FileAnnotationTabView.java index 3e216334b61..aa5179bd56f 100644 --- a/src/main/java/org/jabref/gui/entryeditor/fileannotationtab/FileAnnotationTabView.java +++ b/src/main/java/org/jabref/gui/entryeditor/fileannotationtab/FileAnnotationTabView.java @@ -1,23 +1,137 @@ package org.jabref.gui.entryeditor.fileannotationtab; -import java.util.HashMap; -import java.util.Map; -import java.util.function.Function; +import java.nio.file.Path; -import org.jabref.gui.AbstractView; +import javax.inject.Inject; + +import javafx.beans.binding.Bindings; +import javafx.collections.ListChangeListener; +import javafx.event.ActionEvent; +import javafx.fxml.FXML; +import javafx.geometry.HPos; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.control.ComboBox; +import javafx.scene.control.Label; +import javafx.scene.control.ListView; +import javafx.scene.control.SelectionMode; +import javafx.scene.control.TextArea; +import javafx.scene.layout.ColumnConstraints; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.RowConstraints; +import javafx.scene.text.Font; +import javafx.scene.text.TextAlignment; + +import org.jabref.gui.util.ViewModelListCellFactory; +import org.jabref.logic.l10n.Localization; import org.jabref.logic.pdf.FileAnnotationCache; import org.jabref.model.entry.BibEntry; +import org.jabref.model.util.FileUpdateMonitor; + +import org.fxmisc.easybind.EasyBind; + +public class FileAnnotationTabView { + + @FXML public ComboBox files; + @FXML public ListView annotationList; + @FXML public Label author; + @FXML public Label page; + @FXML public Label date; + @FXML public TextArea content; + @FXML public TextArea marking; + @FXML public GridPane grid; + private final BibEntry entry; + private final FileAnnotationCache fileAnnotationCache; + private FileAnnotationTabViewModel viewModel; -public class FileAnnotationTabView extends AbstractView { + @Inject + private FileUpdateMonitor fileMonitor; public FileAnnotationTabView(BibEntry entry, FileAnnotationCache fileAnnotationCache) { - super(createContext(entry, fileAnnotationCache)); + this.entry = entry; + this.fileAnnotationCache = fileAnnotationCache; + } + + @FXML + public void initialize() { + viewModel = new FileAnnotationTabViewModel(fileAnnotationCache, entry, fileMonitor); + + // Set-up files list + files.getItems().setAll(viewModel.filesProperty().get()); + files.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> viewModel.notifyNewSelectedFile(newValue)); + files.getSelectionModel().selectFirst(); + + // Set-up annotation list + annotationList.getSelectionModel().setSelectionMode(SelectionMode.SINGLE); + annotationList.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> viewModel.notifyNewSelectedAnnotation(newValue)); + ViewModelListCellFactory cellFactory = new ViewModelListCellFactory() + .withTooltip(FileAnnotationViewModel::getMarking) + .withGraphic(this::createFileAnnotationNode); + annotationList.setCellFactory(cellFactory); + annotationList.setPlaceholder(new Label(Localization.lang("File has no attached annotations"))); + Bindings.bindContent(annotationList.itemsProperty().get(), viewModel.annotationsProperty()); + annotationList.getSelectionModel().selectFirst(); + annotationList.itemsProperty().get().addListener( + (ListChangeListener) c -> annotationList.getSelectionModel().selectFirst()); + + // Set-up details pane + content.textProperty().bind(EasyBind.select(viewModel.currentAnnotationProperty()).selectObject(FileAnnotationViewModel::contentProperty)); + marking.textProperty().bind(EasyBind.select(viewModel.currentAnnotationProperty()).selectObject(FileAnnotationViewModel::markingProperty)); + grid.disableProperty().bind(viewModel.isAnnotationsEmpty()); + } + + private Node createFileAnnotationNode(FileAnnotationViewModel annotation) { + GridPane node = new GridPane(); + + ColumnConstraints firstColumn = new ColumnConstraints(); + ColumnConstraints secondColumn = new ColumnConstraints(); + firstColumn.setPercentWidth(70); + secondColumn.setPercentWidth(30); + firstColumn.setHalignment(HPos.LEFT); + secondColumn.setHalignment(HPos.RIGHT); + node.getColumnConstraints().addAll(firstColumn, secondColumn); + + RowConstraints firstRow = new RowConstraints(); + RowConstraints secondRow = new RowConstraints(); + firstRow.setMinHeight(10); + firstRow.setPrefHeight(15); + secondRow.setMinHeight(10); + secondRow.setPrefHeight(35); + node.getRowConstraints().addAll(firstRow, secondRow); + + Label marking = new Label(annotation.getMarking()); + Label author = new Label(annotation.getAuthor()); + Label date = new Label(annotation.getDate()); + Label page = new Label(Localization.lang("Page") + ": " + annotation.getPage()); + + marking.setFont(new Font("System Bold", 15)); + marking.setPrefWidth(250); + author.setFont(new Font("System", 14)); + + marking.setPrefHeight(10); + author.setPrefHeight(30); + date.setPrefHeight(10); + page.setPrefHeight(30); + + // add alignment for text in the list + marking.setTextAlignment(TextAlignment.LEFT); + marking.setAlignment(Pos.TOP_LEFT); + author.setTextAlignment(TextAlignment.LEFT); + author.setAlignment(Pos.TOP_LEFT); + date.setTextAlignment(TextAlignment.RIGHT); + date.setAlignment(Pos.TOP_RIGHT); + page.setTextAlignment(TextAlignment.RIGHT); + page.setAlignment(Pos.TOP_RIGHT); + + node.add(marking, 0, 0); + node.add(author, 0, 1); + node.add(date, 1, 0); + node.add(page, 1, 1); + + return node; } - private static Function createContext(BibEntry entry, FileAnnotationCache fileAnnotationCache) { - Map context = new HashMap<>(); - context.put("entry", entry); - context.put("fileAnnotationCache", fileAnnotationCache); - return context::get; + public void copy(ActionEvent event) { + viewModel.copyCurrentAnnotation(); } } diff --git a/src/main/java/org/jabref/gui/errorconsole/ErrorConsole.css b/src/main/java/org/jabref/gui/errorconsole/ErrorConsole.css index 29153a512a4..f356121a647 100644 --- a/src/main/java/org/jabref/gui/errorconsole/ErrorConsole.css +++ b/src/main/java/org/jabref/gui/errorconsole/ErrorConsole.css @@ -33,8 +33,3 @@ .custom-buttons { -fx-padding: 5.0px; } - -.dialog-pane *.button-bar { - -fx-max-height: 0.0; - -fx-pref-height: 0.0; -} diff --git a/src/main/java/org/jabref/gui/errorconsole/ErrorConsole.fxml b/src/main/java/org/jabref/gui/errorconsole/ErrorConsole.fxml index a82f9e00b4d..ab10833b4fd 100644 --- a/src/main/java/org/jabref/gui/errorconsole/ErrorConsole.fxml +++ b/src/main/java/org/jabref/gui/errorconsole/ErrorConsole.fxml @@ -1,35 +1,25 @@ - - - + + xmlns="http://javafx.com/javafx/8.0.60" fx:controller="org.jabref.gui.errorconsole.ErrorConsoleView"> - - - - - - - -