>) (Class>) List.class;
}
diff --git a/src/main/java/org/jabref/gui/FXDialog.java b/src/main/java/org/jabref/gui/FXDialog.java
index 891eae589f7..a16ea0d77eb 100644
--- a/src/main/java/org/jabref/gui/FXDialog.java
+++ b/src/main/java/org/jabref/gui/FXDialog.java
@@ -1,5 +1,7 @@
package org.jabref.gui;
+import com.airhacks.afterburner.injection.Injector;
+
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Alert;
import javafx.scene.control.Dialog;
@@ -12,8 +14,6 @@
import org.jabref.gui.keyboard.KeyBinding;
import org.jabref.gui.keyboard.KeyBindingRepository;
-import com.airhacks.afterburner.injection.Injector;
-
/**
* This class provides a super class for all dialogs implemented in JavaFX.
*
@@ -59,12 +59,17 @@ public FXDialog(AlertType type, boolean isModal) {
initModality(Modality.NONE);
}
- dialogWindow.getScene().setOnKeyPressed(event -> {
- KeyBindingRepository keyBindingRepository = Injector.instantiateModelOrService(KeyBindingRepository.class);
- if (keyBindingRepository.checkKeyCombinationEquality(KeyBinding.CLOSE, event)) {
- dialogWindow.close();
- }
- });
+ dialogWindow
+ .getScene()
+ .setOnKeyPressed(
+ event -> {
+ KeyBindingRepository keyBindingRepository =
+ Injector.instantiateModelOrService(KeyBindingRepository.class);
+ if (keyBindingRepository.checkKeyCombinationEquality(
+ KeyBinding.CLOSE, event)) {
+ dialogWindow.close();
+ }
+ });
}
public FXDialog(AlertType type) {
diff --git a/src/main/java/org/jabref/gui/JabRefDialogService.java b/src/main/java/org/jabref/gui/JabRefDialogService.java
index dccdc17898d..0e1c3992571 100644
--- a/src/main/java/org/jabref/gui/JabRefDialogService.java
+++ b/src/main/java/org/jabref/gui/JabRefDialogService.java
@@ -1,14 +1,6 @@
package org.jabref.gui;
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.FileSystem;
-import java.nio.file.FileSystems;
-import java.nio.file.Path;
-import java.util.Collection;
-import java.util.List;
-import java.util.Optional;
-import java.util.function.Consumer;
+import com.tobiasdiez.easybind.EasyBind;
import javafx.concurrent.Task;
import javafx.geometry.Pos;
@@ -37,6 +29,11 @@
import javafx.util.Duration;
import javafx.util.StringConverter;
+import org.controlsfx.control.Notifications;
+import org.controlsfx.control.TaskProgressView;
+import org.controlsfx.control.textfield.CustomPasswordField;
+import org.controlsfx.dialog.ExceptionDialog;
+import org.controlsfx.dialog.ProgressDialog;
import org.jabref.gui.help.ErrorConsoleAction;
import org.jabref.gui.icon.IconTheme;
import org.jabref.gui.theme.ThemeManager;
@@ -51,16 +48,19 @@
import org.jabref.logic.importer.FetcherException;
import org.jabref.logic.importer.FetcherServerException;
import org.jabref.logic.l10n.Localization;
-
-import com.tobiasdiez.easybind.EasyBind;
-import org.controlsfx.control.Notifications;
-import org.controlsfx.control.TaskProgressView;
-import org.controlsfx.control.textfield.CustomPasswordField;
-import org.controlsfx.dialog.ExceptionDialog;
-import org.controlsfx.dialog.ProgressDialog;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Path;
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Consumer;
+
/**
* This class provides methods to create default
* JavaFX dialogs which will also work on top of Swing
@@ -97,26 +97,29 @@ private FXDialog createDialog(AlertType type, String title, String content) {
return alert;
}
- private FXDialog createDialogWithOptOut(String title, String content,
- String optOutMessage, Consumer optOutAction) {
+ private FXDialog createDialogWithOptOut(
+ String title, String content, String optOutMessage, Consumer optOutAction) {
FXDialog alert = new FXDialog(AlertType.CONFIRMATION, title, true);
- // Need to force the alert to layout in order to grab the graphic as we are replacing the dialog pane with a custom pane
+ // Need to force the alert to layout in order to grab the graphic as we are replacing the
+ // dialog pane with a custom pane
alert.getDialogPane().applyCss();
Node graphic = alert.getDialogPane().getGraphic();
// Create a new dialog pane that has a checkbox instead of the hide/show details button
// Use the supplied callback for the action of the checkbox
- alert.setDialogPane(new DialogPane() {
- @Override
- protected Node createDetailsButton() {
- CheckBox optOut = new CheckBox();
- optOut.setText(optOutMessage);
- optOut.setOnAction(e -> optOutAction.accept(optOut.isSelected()));
- return optOut;
- }
- });
-
- // Fool the dialog into thinking there is some expandable content; a group won't take up any space if it has no children
+ alert.setDialogPane(
+ new DialogPane() {
+ @Override
+ protected Node createDetailsButton() {
+ CheckBox optOut = new CheckBox();
+ optOut.setText(optOutMessage);
+ optOut.setOnAction(e -> optOutAction.accept(optOut.isSelected()));
+ return optOut;
+ }
+ });
+
+ // Fool the dialog into thinking there is some expandable content; a group won't take up any
+ // space if it has no children
alert.getDialogPane().setExpandableContent(new Group());
alert.getDialogPane().setExpanded(true);
@@ -136,9 +139,16 @@ public static String shortenDialogMessage(String dialogMessage) {
return (dialogMessage.substring(0, JabRefDialogService.DIALOG_SIZE_LIMIT) + "...").trim();
}
- private ChoiceDialog createChoiceDialog(String title, String content, String okButtonLabel, T defaultChoice, Collection choices) {
+ private ChoiceDialog createChoiceDialog(
+ String title,
+ String content,
+ String okButtonLabel,
+ T defaultChoice,
+ Collection choices) {
ChoiceDialog choiceDialog = new ChoiceDialog<>(defaultChoice, choices);
- ((Stage) choiceDialog.getDialogPane().getScene().getWindow()).getIcons().add(IconTheme.getJabRefImage());
+ ((Stage) choiceDialog.getDialogPane().getScene().getWindow())
+ .getIcons()
+ .add(IconTheme.getJabRefImage());
ButtonType okButtonType = new ButtonType(okButtonLabel, ButtonBar.ButtonData.OK_DONE);
choiceDialog.getDialogPane().getButtonTypes().setAll(ButtonType.CANCEL, okButtonType);
choiceDialog.setHeaderText(title);
@@ -149,17 +159,32 @@ private ChoiceDialog createChoiceDialog(String title, String content, Str
}
@Override
- public Optional showChoiceDialogAndWait(String title, String content, String okButtonLabel, T defaultChoice, Collection choices) {
- return createChoiceDialog(title, content, okButtonLabel, defaultChoice, choices).showAndWait();
+ public Optional showChoiceDialogAndWait(
+ String title,
+ String content,
+ String okButtonLabel,
+ T defaultChoice,
+ Collection choices) {
+ return createChoiceDialog(title, content, okButtonLabel, defaultChoice, choices)
+ .showAndWait();
}
@Override
- public Optional showEditableChoiceDialogAndWait(String title, String content, String okButtonLabel, T defaultChoice, Collection choices, StringConverter converter) {
- ChoiceDialog choiceDialog = createChoiceDialog(title, content, okButtonLabel, defaultChoice, choices);
+ public Optional showEditableChoiceDialogAndWait(
+ String title,
+ String content,
+ String okButtonLabel,
+ T defaultChoice,
+ Collection choices,
+ StringConverter converter) {
+ ChoiceDialog choiceDialog =
+ createChoiceDialog(title, content, okButtonLabel, defaultChoice, choices);
ComboBox comboBox = (ComboBox) choiceDialog.getDialogPane().lookup(".combo-box");
comboBox.setEditable(true);
comboBox.setConverter(converter);
- EasyBind.subscribe(comboBox.getEditor().textProperty(), text -> comboBox.setValue(converter.fromString(text)));
+ EasyBind.subscribe(
+ comboBox.getEditor().textProperty(),
+ text -> comboBox.setValue(converter.fromString(text)));
return choiceDialog.showAndWait();
}
@@ -173,7 +198,8 @@ public Optional showInputDialogAndWait(String title, String content) {
}
@Override
- public Optional showInputDialogWithDefaultAndWait(String title, String content, String defaultValue) {
+ public Optional showInputDialogWithDefaultAndWait(
+ String title, String content, String defaultValue) {
TextInputDialog inputDialog = new TextInputDialog(defaultValue);
inputDialog.setHeaderText(title);
inputDialog.setContentText(content);
@@ -224,12 +250,23 @@ public void showErrorDialogAndWait(FetcherException fetcherException) {
String localizedMessage = fetcherException.getLocalizedMessage();
Optional httpResponse = fetcherException.getHttpResponse();
if (httpResponse.isPresent()) {
- this.showInformationDialogAndWait(failedTitle, getContentByCode(httpResponse.get().statusCode()) + "\n\n" + localizedMessage);
+ this.showInformationDialogAndWait(
+ failedTitle,
+ getContentByCode(httpResponse.get().statusCode()) + "\n\n" + localizedMessage);
} else if (fetcherException instanceof FetcherClientException) {
- this.showErrorDialogAndWait(failedTitle, Localization.lang("Something is wrong on JabRef side. Please check the URL and try again.") + "\n\n" + localizedMessage);
+ this.showErrorDialogAndWait(
+ failedTitle,
+ Localization.lang(
+ "Something is wrong on JabRef side. Please check the URL and try again.")
+ + "\n\n"
+ + localizedMessage);
} else if (fetcherException instanceof FetcherServerException) {
- this.showInformationDialogAndWait(failedTitle,
- Localization.lang("Error downloading from URL. Cause is likely the server side.\nPlease try again later or contact the server administrator.") + "\n\n" + localizedMessage);
+ this.showInformationDialogAndWait(
+ failedTitle,
+ Localization.lang(
+ "Error downloading from URL. Cause is likely the server side.\nPlease try again later or contact the server administrator.")
+ + "\n\n"
+ + localizedMessage);
} else {
this.showErrorDialogAndWait(failedTitle, localizedMessage);
}
@@ -246,7 +283,8 @@ public void showErrorDialogAndWait(String title, String content, Throwable excep
@Override
public void showErrorDialogAndWait(String message) {
- FXDialog alert = createDialog(AlertType.ERROR, Localization.lang("Error Occurred"), message);
+ FXDialog alert =
+ createDialog(AlertType.ERROR, Localization.lang("Error Occurred"), message);
alert.showAndWait();
}
@@ -257,7 +295,8 @@ public boolean showConfirmationDialogAndWait(String title, String content) {
}
@Override
- public boolean showConfirmationDialogAndWait(String title, String content, String okButtonLabel) {
+ public boolean showConfirmationDialogAndWait(
+ String title, String content, String okButtonLabel) {
FXDialog alert = createDialog(AlertType.CONFIRMATION, title, content);
ButtonType okButtonType = new ButtonType(okButtonLabel, ButtonBar.ButtonData.OK_DONE);
alert.getButtonTypes().setAll(ButtonType.CANCEL, okButtonType);
@@ -265,8 +304,8 @@ public boolean showConfirmationDialogAndWait(String title, String content, Strin
}
@Override
- public boolean showConfirmationDialogAndWait(String title, String content,
- String okButtonLabel, String cancelButtonLabel) {
+ public boolean showConfirmationDialogAndWait(
+ String title, String content, String okButtonLabel, String cancelButtonLabel) {
FXDialog alert = createDialog(AlertType.CONFIRMATION, title, content);
ButtonType okButtonType = new ButtonType(okButtonLabel, ButtonBar.ButtonData.OK_DONE);
ButtonType cancelButtonType = new ButtonType(cancelButtonLabel, ButtonBar.ButtonData.NO);
@@ -275,17 +314,21 @@ public boolean showConfirmationDialogAndWait(String title, String content,
}
@Override
- public boolean showConfirmationDialogWithOptOutAndWait(String title, String content,
- String optOutMessage, Consumer optOutAction) {
+ public boolean showConfirmationDialogWithOptOutAndWait(
+ String title, String content, String optOutMessage, Consumer optOutAction) {
FXDialog alert = createDialogWithOptOut(title, content, optOutMessage, optOutAction);
alert.getButtonTypes().setAll(ButtonType.YES, ButtonType.NO);
return alert.showAndWait().filter(buttonType -> buttonType == ButtonType.YES).isPresent();
}
@Override
- public boolean showConfirmationDialogWithOptOutAndWait(String title, String content,
- String okButtonLabel, String cancelButtonLabel,
- String optOutMessage, Consumer optOutAction) {
+ public boolean showConfirmationDialogWithOptOutAndWait(
+ String title,
+ String content,
+ String okButtonLabel,
+ String cancelButtonLabel,
+ String optOutMessage,
+ Consumer optOutAction) {
FXDialog alert = createDialogWithOptOut(title, content, optOutMessage, optOutAction);
ButtonType okButtonType = new ButtonType(okButtonLabel, ButtonBar.ButtonData.YES);
ButtonType cancelButtonType = new ButtonType(cancelButtonLabel, ButtonBar.ButtonData.NO);
@@ -294,16 +337,16 @@ public boolean showConfirmationDialogWithOptOutAndWait(String title, String cont
}
@Override
- public Optional showCustomButtonDialogAndWait(AlertType type, String title, String content,
- ButtonType... buttonTypes) {
+ public Optional showCustomButtonDialogAndWait(
+ AlertType type, String title, String content, ButtonType... buttonTypes) {
FXDialog alert = createDialog(type, title, content);
alert.getButtonTypes().setAll(buttonTypes);
return alert.showAndWait();
}
@Override
- public Optional showCustomDialogAndWait(String title, DialogPane contentPane,
- ButtonType... buttonTypes) {
+ public Optional showCustomDialogAndWait(
+ String title, DialogPane contentPane, ButtonType... buttonTypes) {
FXDialog alert = new FXDialog(AlertType.NONE, title);
alert.setDialogPane(contentPane);
alert.getButtonTypes().setAll(buttonTypes);
@@ -336,12 +379,13 @@ public Optional showPasswordDialogAndWait(String title, String header, S
dialog.getDialogPane().setContent(box);
dialog.getDialogPane().getButtonTypes().addAll(ButtonType.CANCEL, ButtonType.OK);
- dialog.setResultConverter(dialogButton -> {
- if (dialogButton == ButtonType.OK) {
- return passwordField.getText();
- }
- return null;
- });
+ dialog.setResultConverter(
+ dialogButton -> {
+ if (dialogButton == ButtonType.OK) {
+ return passwordField.getText();
+ }
+ return null;
+ });
return dialog.showAndWait();
}
@@ -351,15 +395,18 @@ private ProgressDialog createProgressDialog(String title, String content, Ta
progressDialog.setTitle(title);
progressDialog.setContentText(content);
progressDialog.setGraphic(null);
- ((Stage) progressDialog.getDialogPane().getScene().getWindow()).getIcons().add(IconTheme.getJabRefImage());
+ ((Stage) progressDialog.getDialogPane().getScene().getWindow())
+ .getIcons()
+ .add(IconTheme.getJabRefImage());
progressDialog.setOnCloseRequest(evt -> task.cancel());
DialogPane dialogPane = progressDialog.getDialogPane();
dialogPane.getButtonTypes().add(ButtonType.CANCEL);
Button cancelButton = (Button) dialogPane.lookupButton(ButtonType.CANCEL);
- cancelButton.setOnAction(evt -> {
- task.cancel();
- progressDialog.close();
- });
+ cancelButton.setOnAction(
+ evt -> {
+ task.cancel();
+ progressDialog.close();
+ });
progressDialog.initOwner(mainWindow);
return progressDialog;
}
@@ -377,11 +424,13 @@ public void showProgressDialogAndWait(String title, String content, Task
}
@Override
- public Optional showBackgroundProgressDialogAndWait(String title, String content, StateManager stateManager) {
+ public Optional showBackgroundProgressDialogAndWait(
+ String title, String content, StateManager stateManager) {
TaskProgressView> taskProgressView = new TaskProgressView<>();
EasyBind.bindContent(taskProgressView.getTasks(), stateManager.getRunningBackgroundTasks());
taskProgressView.setRetainTasks(false);
- taskProgressView.setGraphicFactory(task -> ThemeManager.getDownloadIconTitleMap.getOrDefault(task.getTitle(), null));
+ taskProgressView.setGraphicFactory(
+ task -> ThemeManager.getDownloadIconTitleMap.getOrDefault(task.getTitle(), null));
Label message = new Label(content);
@@ -397,12 +446,15 @@ public Optional showBackgroundProgressDialogAndWait(String title, St
alert.setResizable(true);
alert.initOwner(mainWindow);
- stateManager.getAnyTasksThatWillNotBeRecoveredRunning().addListener((observable, oldValue, newValue) -> {
- if (!newValue) {
- alert.setResult(ButtonType.YES);
- alert.close();
- }
- });
+ stateManager
+ .getAnyTasksThatWillNotBeRecoveredRunning()
+ .addListener(
+ (observable, oldValue, newValue) -> {
+ if (!newValue) {
+ alert.setResult(ButtonType.YES);
+ alert.close();
+ }
+ });
return alert.showAndWait();
}
@@ -413,31 +465,40 @@ public void notify(String message) {
// The event log is not that user friendly (different purpose).
LOGGER.info(message);
- UiTaskExecutor.runInJavaFXThread(() ->
- Notifications.create()
- .text(message)
- .position(Pos.BOTTOM_CENTER)
- .hideAfter(TOAST_MESSAGE_DISPLAY_TIME)
- .owner(mainWindow)
- .threshold(5,
- Notifications.create()
- .title(Localization.lang("Last notification"))
- .text(
- "(" + Localization.lang("Check the event log to see all notifications") + ")"
- + "\n\n" + message)
- .onAction(e -> {
- ErrorConsoleAction ec = new ErrorConsoleAction();
- ec.execute();
- }))
- .hideCloseButton()
- .show());
+ UiTaskExecutor.runInJavaFXThread(
+ () ->
+ Notifications.create()
+ .text(message)
+ .position(Pos.BOTTOM_CENTER)
+ .hideAfter(TOAST_MESSAGE_DISPLAY_TIME)
+ .owner(mainWindow)
+ .threshold(
+ 5,
+ Notifications.create()
+ .title(Localization.lang("Last notification"))
+ .text(
+ "("
+ + Localization.lang(
+ "Check the event log to see all notifications")
+ + ")"
+ + "\n\n"
+ + message)
+ .onAction(
+ e -> {
+ ErrorConsoleAction ec =
+ new ErrorConsoleAction();
+ ec.execute();
+ }))
+ .hideCloseButton()
+ .show());
}
@Override
public Optional showFileSaveDialog(FileDialogConfiguration fileDialogConfiguration) {
FileChooser chooser = getConfiguredFileChooser(fileDialogConfiguration);
File file = chooser.showSaveDialog(mainWindow);
- Optional.ofNullable(chooser.getSelectedExtensionFilter()).ifPresent(fileDialogConfiguration::setSelectedExtensionFilter);
+ Optional.ofNullable(chooser.getSelectedExtensionFilter())
+ .ifPresent(fileDialogConfiguration::setSelectedExtensionFilter);
return Optional.ofNullable(file).map(File::toPath);
}
@@ -445,27 +506,34 @@ public Optional showFileSaveDialog(FileDialogConfiguration fileDialogConfi
public Optional showFileOpenDialog(FileDialogConfiguration fileDialogConfiguration) {
FileChooser chooser = getConfiguredFileChooser(fileDialogConfiguration);
File file = chooser.showOpenDialog(mainWindow);
- Optional.ofNullable(chooser.getSelectedExtensionFilter()).ifPresent(fileDialogConfiguration::setSelectedExtensionFilter);
+ Optional.ofNullable(chooser.getSelectedExtensionFilter())
+ .ifPresent(fileDialogConfiguration::setSelectedExtensionFilter);
return Optional.ofNullable(file).map(File::toPath);
}
@Override
- public Optional showDirectorySelectionDialog(DirectoryDialogConfiguration directoryDialogConfiguration) {
+ public Optional showDirectorySelectionDialog(
+ DirectoryDialogConfiguration directoryDialogConfiguration) {
DirectoryChooser chooser = getConfiguredDirectoryChooser(directoryDialogConfiguration);
File file = chooser.showDialog(mainWindow);
return Optional.ofNullable(file).map(File::toPath);
}
@Override
- public List showFileOpenDialogAndGetMultipleFiles(FileDialogConfiguration fileDialogConfiguration) {
+ public List showFileOpenDialogAndGetMultipleFiles(
+ FileDialogConfiguration fileDialogConfiguration) {
FileChooser chooser = getConfiguredFileChooser(fileDialogConfiguration);
List files = chooser.showOpenMultipleDialog(mainWindow);
return files != null ? files.stream().map(File::toPath).toList() : List.of();
}
- private DirectoryChooser getConfiguredDirectoryChooser(DirectoryDialogConfiguration directoryDialogConfiguration) {
+ private DirectoryChooser getConfiguredDirectoryChooser(
+ DirectoryDialogConfiguration directoryDialogConfiguration) {
DirectoryChooser chooser = new DirectoryChooser();
- directoryDialogConfiguration.getInitialDirectory().map(Path::toFile).ifPresent(chooser::setInitialDirectory);
+ directoryDialogConfiguration
+ .getInitialDirectory()
+ .map(Path::toFile)
+ .ifPresent(chooser::setInitialDirectory);
return chooser;
}
@@ -474,7 +542,10 @@ private FileChooser getConfiguredFileChooser(FileDialogConfiguration fileDialogC
chooser.getExtensionFilters().addAll(fileDialogConfiguration.getExtensionFilters());
chooser.setSelectedExtensionFilter(fileDialogConfiguration.getDefaultExtension());
chooser.setInitialFileName(fileDialogConfiguration.getInitialFileName());
- fileDialogConfiguration.getInitialDirectory().map(Path::toFile).ifPresent(chooser::setInitialDirectory);
+ fileDialogConfiguration
+ .getInitialDirectory()
+ .map(Path::toFile)
+ .ifPresent(chooser::setInitialDirectory);
return chooser;
}
@@ -512,13 +583,17 @@ public void showCustomWindow(BaseWindow window) {
private String getContentByCode(int statusCode) {
return switch (statusCode) {
case 401 ->
- Localization.lang("Access denied. You are not authorized to access this resource. Please check your credentials and try again. If you believe you should have access, please contact the administrator for assistance.");
+ Localization.lang(
+ "Access denied. You are not authorized to access this resource. Please check your credentials and try again. If you believe you should have access, please contact the administrator for assistance.");
case 403 ->
- Localization.lang("Access denied. You do not have permission to access this resource. Please contact the administrator for assistance or try a different action.");
+ Localization.lang(
+ "Access denied. You do not have permission to access this resource. Please contact the administrator for assistance or try a different action.");
case 404 ->
- Localization.lang("The requested resource could not be found. It seems that the file you are trying to download is not available or has been moved. Please verify the URL and try again. If you believe this is an error, please contact the administrator for further assistance.");
+ Localization.lang(
+ "The requested resource could not be found. It seems that the file you are trying to download is not available or has been moved. Please verify the URL and try again. If you believe this is an error, please contact the administrator for further assistance.");
default ->
- Localization.lang("Something is wrong on JabRef side. Please check the URL and try again.");
+ Localization.lang(
+ "Something is wrong on JabRef side. Please check the URL and try again.");
};
}
}
diff --git a/src/main/java/org/jabref/gui/JabRefGUI.java b/src/main/java/org/jabref/gui/JabRefGUI.java
index 94c223eb6c0..b218c39e2c5 100644
--- a/src/main/java/org/jabref/gui/JabRefGUI.java
+++ b/src/main/java/org/jabref/gui/JabRefGUI.java
@@ -1,9 +1,7 @@
package org.jabref.gui;
-import java.util.List;
-import java.util.Optional;
-
-import javax.swing.undo.UndoManager;
+import com.airhacks.afterburner.injection.Injector;
+import com.tobiasdiez.easybind.EasyBind;
import javafx.application.Application;
import javafx.application.Platform;
@@ -14,6 +12,8 @@
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
+import kong.unirest.core.Unirest;
+
import org.jabref.gui.frame.JabRefFrame;
import org.jabref.gui.help.VersionWorker;
import org.jabref.gui.icon.IconTheme;
@@ -41,13 +41,14 @@
import org.jabref.model.strings.StringUtil;
import org.jabref.model.util.DirectoryMonitor;
import org.jabref.model.util.FileUpdateMonitor;
-
-import com.airhacks.afterburner.injection.Injector;
-import com.tobiasdiez.easybind.EasyBind;
-import kong.unirest.core.Unirest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.List;
+import java.util.Optional;
+
+import javax.swing.undo.UndoManager;
+
/**
* Represents the outer stage and the scene of the JabRef window.
*/
@@ -74,9 +75,10 @@ public class JabRefGUI extends Application {
private Stage mainStage;
- public static void setup(List uiCommands,
- GuiPreferences preferences,
- FileUpdateMonitor fileUpdateMonitor) {
+ public static void setup(
+ List uiCommands,
+ GuiPreferences preferences,
+ FileUpdateMonitor fileUpdateMonitor) {
JabRefGUI.uiCommands = uiCommands;
JabRefGUI.preferences = preferences;
JabRefGUI.fileUpdateMonitor = fileUpdateMonitor;
@@ -86,26 +88,31 @@ public static void setup(List uiCommands,
public void start(Stage stage) {
this.mainStage = stage;
- FallbackExceptionHandler.installExceptionHandler((exception, thread) -> {
- UiTaskExecutor.runInJavaFXThread(() -> {
- DialogService dialogService = Injector.instantiateModelOrService(DialogService.class);
- dialogService.showErrorDialogAndWait("Uncaught exception occurred in " + thread, exception);
- });
- });
+ FallbackExceptionHandler.installExceptionHandler(
+ (exception, thread) -> {
+ UiTaskExecutor.runInJavaFXThread(
+ () -> {
+ DialogService dialogService =
+ Injector.instantiateModelOrService(DialogService.class);
+ dialogService.showErrorDialogAndWait(
+ "Uncaught exception occurred in " + thread, exception);
+ });
+ });
initialize();
- JabRefGUI.mainFrame = new JabRefFrame(
- mainStage,
- dialogService,
- fileUpdateMonitor,
- preferences,
- aiService,
- stateManager,
- countingUndoManager,
- Injector.instantiateModelOrService(BibEntryTypesManager.class),
- clipBoardManager,
- taskExecutor);
+ JabRefGUI.mainFrame =
+ new JabRefFrame(
+ mainStage,
+ dialogService,
+ fileUpdateMonitor,
+ preferences,
+ aiService,
+ stateManager,
+ countingUndoManager,
+ Injector.instantiateModelOrService(BibEntryTypesManager.class),
+ clipBoardManager,
+ taskExecutor);
openWindow();
@@ -113,21 +120,22 @@ public void start(Stage stage) {
if (!fileUpdateMonitor.isActive()) {
dialogService.showErrorDialogAndWait(
- Localization.lang("Unable to monitor file changes. Please close files " +
- "and processes and restart. You may encounter errors if you continue " +
- "with this session."));
+ Localization.lang(
+ "Unable to monitor file changes. Please close files "
+ + "and processes and restart. You may encounter errors if you continue "
+ + "with this session."));
}
BuildInfo buildInfo = Injector.instantiateModelOrService(BuildInfo.class);
- EasyBind.subscribe(preferences.getInternalPreferences().versionCheckEnabledProperty(), enabled -> {
- if (enabled) {
- new VersionWorker(buildInfo.version,
- dialogService,
- taskExecutor,
- preferences)
- .checkForNewVersionDelayed();
- }
- });
+ EasyBind.subscribe(
+ preferences.getInternalPreferences().versionCheckEnabledProperty(),
+ enabled -> {
+ if (enabled) {
+ new VersionWorker(
+ buildInfo.version, dialogService, taskExecutor, preferences)
+ .checkForNewVersionDelayed();
+ }
+ });
setupProxy();
}
@@ -144,12 +152,12 @@ public void initialize() {
JabRefGUI.stateManager = new StateManager();
Injector.setModelOrService(StateManager.class, stateManager);
- Injector.setModelOrService(KeyBindingRepository.class, preferences.getKeyBindingRepository());
+ Injector.setModelOrService(
+ KeyBindingRepository.class, preferences.getKeyBindingRepository());
- JabRefGUI.themeManager = new ThemeManager(
- preferences.getWorkspacePreferences(),
- fileUpdateMonitor,
- Runnable::run);
+ JabRefGUI.themeManager =
+ new ThemeManager(
+ preferences.getWorkspacePreferences(), fileUpdateMonitor, Runnable::run);
Injector.setModelOrService(ThemeManager.class, themeManager);
JabRefGUI.countingUndoManager = new CountingUndoManager();
@@ -166,12 +174,13 @@ public void initialize() {
JabRefGUI.clipBoardManager = new ClipBoardManager();
Injector.setModelOrService(ClipBoardManager.class, clipBoardManager);
- JabRefGUI.aiService = new AiService(
- preferences.getAiPreferences(),
- preferences.getFilePreferences(),
- preferences.getCitationKeyPatternPreferences(),
- dialogService,
- taskExecutor);
+ JabRefGUI.aiService =
+ new AiService(
+ preferences.getAiPreferences(),
+ preferences.getFilePreferences(),
+ preferences.getCitationKeyPatternPreferences(),
+ dialogService,
+ taskExecutor);
Injector.setModelOrService(AiService.class, aiService);
}
@@ -187,10 +196,11 @@ private void setupProxy() {
return;
}
- Optional password = dialogService.showPasswordDialogAndWait(
- Localization.lang("Proxy configuration"),
- Localization.lang("Proxy requires password"),
- Localization.lang("Password"));
+ Optional password =
+ dialogService.showPasswordDialogAndWait(
+ Localization.lang("Proxy configuration"),
+ Localization.lang("Proxy requires password"),
+ Localization.lang("Password"));
if (password.isPresent()) {
preferences.getProxyPreferences().setPassword(password.get());
@@ -209,7 +219,8 @@ private void openWindow() {
mainStage.setMinWidth(580);
mainStage.setMinHeight(330);
- // maximized target state is stored, because "saveWindowState" saves x and y only if not maximized
+ // maximized target state is stored, because "saveWindowState" saves x and y only if not
+ // maximized
boolean windowMaximised = coreGuiPreferences.isWindowMaximised();
LOGGER.debug("Screens: {}", Screen.getScreens());
@@ -223,7 +234,8 @@ private void openWindow() {
mainStage.setHeight(coreGuiPreferences.getSizeY());
LOGGER.debug("NOT saving window positions");
} else {
- LOGGER.info("The JabRef window is outside of screen bounds. Position and size will be corrected to 1024x768. Primary screen will be used.");
+ LOGGER.info(
+ "The JabRef window is outside of screen bounds. Position and size will be corrected to 1024x768. Primary screen will be used.");
Rectangle2D bounds = Screen.getPrimary().getBounds();
mainStage.setX(bounds.getMinX());
mainStage.setY(bounds.getMinY());
@@ -242,10 +254,11 @@ private void openWindow() {
themeManager.installCss(scene);
LOGGER.debug("Handle TextEditor key bindings");
- scene.addEventFilter(KeyEvent.KEY_PRESSED, event -> TextInputKeyBindings.call(
- scene,
- event,
- preferences.getKeyBindingRepository()));
+ scene.addEventFilter(
+ KeyEvent.KEY_PRESSED,
+ event ->
+ TextInputKeyBindings.call(
+ scene, event, preferences.getKeyBindingRepository()));
mainStage.setTitle(JabRefFrame.FRAME_TITLE);
mainStage.getIcons().addAll(IconTheme.getLogoSetFX());
@@ -267,7 +280,7 @@ public void onShowing(WindowEvent event) {
// Open last edited databases
if (uiCommands.stream().noneMatch(UiCommand.BlankWorkspace.class::isInstance)
- && preferences.getWorkspacePreferences().shouldOpenLastEdited()) {
+ && preferences.getWorkspacePreferences().shouldOpenLastEdited()) {
mainFrame.openLastEditedDatabases();
}
}
@@ -302,7 +315,8 @@ private void saveWindowState() {
* @param mainStage JabRef's stage
*/
private void debugLogWindowState(Stage mainStage) {
- LOGGER.debug("""
+ LOGGER.debug(
+ """
screen data:
mainStage.WINDOW_MAXIMISED: {}
mainStage.POS_X: {}
@@ -310,7 +324,11 @@ private void debugLogWindowState(Stage mainStage) {
mainStage.SIZE_X: {}
mainStage.SIZE_Y: {}
""",
- mainStage.isMaximized(), mainStage.getX(), mainStage.getY(), mainStage.getWidth(), mainStage.getHeight());
+ mainStage.isMaximized(),
+ mainStage.getX(),
+ mainStage.getY(),
+ mainStage.getWidth(),
+ mainStage.getHeight());
}
/**
@@ -320,7 +338,8 @@ private boolean isWindowPositionInBounds() {
CoreGuiPreferences coreGuiPreferences = preferences.getGuiPreferences();
if (LOGGER.isDebugEnabled()) {
- Screen.getScreens().forEach(screen -> LOGGER.debug("Screen bounds: {}", screen.getBounds()));
+ Screen.getScreens()
+ .forEach(screen -> LOGGER.debug("Screen bounds: {}", screen.getBounds()));
}
return lowerLeftIsInBounds(coreGuiPreferences) && upperRightIsInBounds(coreGuiPreferences);
@@ -332,19 +351,24 @@ private boolean lowerLeftIsInBounds(CoreGuiPreferences coreGuiPreferences) {
double bottomY = coreGuiPreferences.getPositionY() + coreGuiPreferences.getSizeY();
LOGGER.debug("left x: {}, bottom y: {}", leftX, bottomY);
- boolean inBounds = Screen.getScreens().stream().anyMatch((screen -> screen.getBounds().contains(leftX, bottomY)));
+ boolean inBounds =
+ Screen.getScreens().stream()
+ .anyMatch((screen -> screen.getBounds().contains(leftX, bottomY)));
LOGGER.debug("lower left corner is in bounds: {}", inBounds);
return inBounds;
}
private boolean upperRightIsInBounds(CoreGuiPreferences coreGuiPreferences) {
// The upper right corner is checked as there are most probably the window controls.
- // Windows/PowerToys somehow adds 10 pixels to the right and top of the screen, they are removed
+ // Windows/PowerToys somehow adds 10 pixels to the right and top of the screen, they are
+ // removed
double rightX = coreGuiPreferences.getPositionX() + coreGuiPreferences.getSizeX() - 10.0;
double topY = coreGuiPreferences.getPositionY();
LOGGER.debug("right x: {}, top y: {}", rightX, topY);
- boolean inBounds = Screen.getScreens().stream().anyMatch((screen -> screen.getBounds().contains(rightX, topY)));
+ boolean inBounds =
+ Screen.getScreens().stream()
+ .anyMatch((screen -> screen.getBounds().contains(rightX, topY)));
LOGGER.debug("upper right corner is in bounds: {}", inBounds);
return inBounds;
}
@@ -352,14 +376,12 @@ private boolean upperRightIsInBounds(CoreGuiPreferences coreGuiPreferences) {
// Background tasks
public void startBackgroundTasks() {
RemotePreferences remotePreferences = preferences.getRemotePreferences();
- BibEntryTypesManager bibEntryTypesManager = Injector.instantiateModelOrService(BibEntryTypesManager.class);
+ BibEntryTypesManager bibEntryTypesManager =
+ Injector.instantiateModelOrService(BibEntryTypesManager.class);
if (remotePreferences.useRemoteServer()) {
remoteListenerServerManager.openAndStart(
new CLIMessageHandler(
- mainFrame,
- preferences,
- fileUpdateMonitor,
- bibEntryTypesManager),
+ mainFrame, preferences, fileUpdateMonitor, bibEntryTypesManager),
remotePreferences.getPort());
}
}
@@ -393,7 +415,8 @@ public static void shutdownThreadPools() {
LOGGER.trace("Shutting down fileUpdateMonitor");
fileUpdateMonitor.shutdown();
LOGGER.trace("Shutting down directoryMonitor");
- DirectoryMonitor directoryMonitor = Injector.instantiateModelOrService(DirectoryMonitor.class);
+ DirectoryMonitor directoryMonitor =
+ Injector.instantiateModelOrService(DirectoryMonitor.class);
directoryMonitor.shutdown();
LOGGER.trace("Shutting down HeadlessExecutorService");
HeadlessExecutorService.INSTANCE.shutdownEverything();
diff --git a/src/main/java/org/jabref/gui/LibraryTab.java b/src/main/java/org/jabref/gui/LibraryTab.java
index 3877db193e0..f62be33059e 100644
--- a/src/main/java/org/jabref/gui/LibraryTab.java
+++ b/src/main/java/org/jabref/gui/LibraryTab.java
@@ -1,16 +1,9 @@
package org.jabref.gui;
-import java.io.IOException;
-import java.nio.file.Path;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Random;
-import java.util.function.Supplier;
-import java.util.stream.Collectors;
-
-import javax.swing.undo.UndoManager;
+import com.airhacks.afterburner.injection.Injector;
+import com.google.common.eventbus.Subscribe;
+import com.tobiasdiez.easybind.EasyBind;
+import com.tobiasdiez.easybind.Subscription;
import javafx.animation.PauseTransition;
import javafx.application.Platform;
@@ -36,6 +29,8 @@
import javafx.scene.layout.BorderPane;
import javafx.util.Duration;
+import org.controlsfx.control.NotificationPane;
+import org.controlsfx.control.action.Action;
import org.jabref.gui.actions.StandardActions;
import org.jabref.gui.autocompleter.AutoCompletePreferences;
import org.jabref.gui.autocompleter.PersonNameSuggestionProvider;
@@ -99,16 +94,21 @@
import org.jabref.model.util.DirectoryMonitor;
import org.jabref.model.util.DirectoryMonitorManager;
import org.jabref.model.util.FileUpdateMonitor;
-
-import com.airhacks.afterburner.injection.Injector;
-import com.google.common.eventbus.Subscribe;
-import com.tobiasdiez.easybind.EasyBind;
-import com.tobiasdiez.easybind.Subscription;
-import org.controlsfx.control.NotificationPane;
-import org.controlsfx.control.action.Action;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Random;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+
+import javax.swing.undo.UndoManager;
+
/**
* Represents the ui area where the notifier pane, the library table and the entry editor are shown.
*/
@@ -116,7 +116,10 @@ public class LibraryTab extends Tab {
/**
* Defines the different modes that the tab can operate in
*/
- private enum PanelMode { MAIN_TABLE, MAIN_TABLE_AND_ENTRY_EDITOR }
+ private enum PanelMode {
+ MAIN_TABLE,
+ MAIN_TABLE_AND_ENTRY_EDITOR
+ }
private static final Logger LOGGER = LoggerFactory.getLogger(LibraryTab.class);
private final LibraryTabContainer tabContainer;
@@ -156,7 +159,8 @@ private enum PanelMode { MAIN_TABLE, MAIN_TABLE_AND_ENTRY_EDITOR }
private Subscription dividerPositionSubscription;
private ListProperty selectedGroupsProperty;
- private final OptionalObjectProperty searchQueryProperty = OptionalObjectProperty.empty();
+ private final OptionalObjectProperty searchQueryProperty =
+ OptionalObjectProperty.empty();
private final IntegerProperty resultSize = new SimpleIntegerProperty(0);
private Optional changeMonitor = Optional.empty();
@@ -178,18 +182,19 @@ private enum PanelMode { MAIN_TABLE, MAIN_TABLE_AND_ENTRY_EDITOR }
* If the index is created for the dummy context, the actual context will not be able to open the index until it is closed by the dummy context.
* Closing the index takes time and will slow down opening the library.
*/
- private LibraryTab(BibDatabaseContext bibDatabaseContext,
- LibraryTabContainer tabContainer,
- DialogService dialogService,
- AiService aiService,
- GuiPreferences preferences,
- StateManager stateManager,
- FileUpdateMonitor fileUpdateMonitor,
- BibEntryTypesManager entryTypesManager,
- CountingUndoManager undoManager,
- ClipBoardManager clipBoardManager,
- TaskExecutor taskExecutor,
- boolean isDummyContext) {
+ private LibraryTab(
+ BibDatabaseContext bibDatabaseContext,
+ LibraryTabContainer tabContainer,
+ DialogService dialogService,
+ AiService aiService,
+ GuiPreferences preferences,
+ StateManager stateManager,
+ FileUpdateMonitor fileUpdateMonitor,
+ BibEntryTypesManager entryTypesManager,
+ CountingUndoManager undoManager,
+ ClipBoardManager clipBoardManager,
+ TaskExecutor taskExecutor,
+ boolean isDummyContext) {
this.tabContainer = Objects.requireNonNull(tabContainer);
this.bibDatabaseContext = Objects.requireNonNull(bibDatabaseContext);
this.undoManager = undoManager;
@@ -200,7 +205,9 @@ private LibraryTab(BibDatabaseContext bibDatabaseContext,
this.entryTypesManager = entryTypesManager;
this.clipBoardManager = clipBoardManager;
this.taskExecutor = taskExecutor;
- this.directoryMonitorManager = new DirectoryMonitorManager(Injector.instantiateModelOrService(DirectoryMonitor.class));
+ this.directoryMonitorManager =
+ new DirectoryMonitorManager(
+ Injector.instantiateModelOrService(DirectoryMonitor.class));
this.aiService = aiService;
initializeComponentsAndListeners(isDummyContext);
@@ -225,19 +232,31 @@ private void initializeComponentsAndListeners(boolean isDummyContext) {
bibDatabaseContext.getDatabase().registerListener(this);
bibDatabaseContext.getMetaData().registerListener(this);
- this.selectedGroupsProperty = new SimpleListProperty<>(stateManager.getSelectedGroups(bibDatabaseContext));
- this.tableModel = new MainTableDataModel(getBibDatabaseContext(), preferences, taskExecutor, stateManager, getLuceneManager(), selectedGroupsProperty(), searchQueryProperty(), resultSizeProperty());
+ this.selectedGroupsProperty =
+ new SimpleListProperty<>(stateManager.getSelectedGroups(bibDatabaseContext));
+ this.tableModel =
+ new MainTableDataModel(
+ getBibDatabaseContext(),
+ preferences,
+ taskExecutor,
+ stateManager,
+ getLuceneManager(),
+ selectedGroupsProperty(),
+ searchQueryProperty(),
+ resultSizeProperty());
new CitationStyleCache(bibDatabaseContext);
- annotationCache = new FileAnnotationCache(bibDatabaseContext, preferences.getFilePreferences());
- importHandler = new ImportHandler(
- bibDatabaseContext,
- preferences,
- fileUpdateMonitor,
- undoManager,
- stateManager,
- dialogService,
- taskExecutor);
+ annotationCache =
+ new FileAnnotationCache(bibDatabaseContext, preferences.getFilePreferences());
+ importHandler =
+ new ImportHandler(
+ bibDatabaseContext,
+ preferences,
+ fileUpdateMonitor,
+ undoManager,
+ stateManager,
+ dialogService,
+ taskExecutor);
setupMainPanel();
setupAutoCompletion();
@@ -256,17 +275,23 @@ private void initializeComponentsAndListeners(boolean isDummyContext) {
aiService.setupDatabase(bibDatabaseContext);
- Platform.runLater(() -> {
- EasyBind.subscribe(changedProperty, this::updateTabTitle);
- stateManager.getOpenDatabases().addListener((ListChangeListener) c ->
- updateTabTitle(changedProperty.getValue()));
- });
+ Platform.runLater(
+ () -> {
+ EasyBind.subscribe(changedProperty, this::updateTabTitle);
+ stateManager
+ .getOpenDatabases()
+ .addListener(
+ (ListChangeListener)
+ c -> updateTabTitle(changedProperty.getValue()));
+ });
}
private EntryEditor createEntryEditor() {
Supplier tabSupplier = () -> this;
- return new EntryEditor(this,
- // Actions are recreated here since this avoids passing more parameters and the amount of additional memory consumption is neglegtable.
+ return new EntryEditor(
+ this,
+ // Actions are recreated here since this avoids passing more parameters and the
+ // amount of additional memory consumption is neglegtable.
new UndoAction(tabSupplier, undoManager, dialogService, stateManager),
new RedoAction(tabSupplier, undoManager, dialogService, stateManager));
}
@@ -282,7 +307,8 @@ private static void addModeInfo(StringBuilder text, BibDatabaseContext bibDataba
text.append(modeInfo);
}
- private static void addSharedDbInformation(StringBuilder text, BibDatabaseContext bibDatabaseContext) {
+ private static void addSharedDbInformation(
+ StringBuilder text, BibDatabaseContext bibDatabaseContext) {
text.append(bibDatabaseContext.getDBMSSynchronizer().getDBName());
text.append(" [");
text.append(Localization.lang("shared"));
@@ -298,7 +324,8 @@ private void setDataLoadingTask(BackgroundTask dataLoadingTask) {
* The layout to display in the tab when it is loading
*/
private Node createLoadingAnimationLayout() {
- ProgressIndicator progressIndicator = new ProgressIndicator(ProgressIndicator.INDETERMINATE_PROGRESS);
+ ProgressIndicator progressIndicator =
+ new ProgressIndicator(ProgressIndicator.INDETERMINATE_PROGRESS);
BorderPane pane = new BorderPane();
pane.setCenter(progressIndicator);
return pane;
@@ -323,7 +350,9 @@ private void onDatabaseLoadingSucceed(ParserResult result) {
}
public void createLuceneManager() {
- luceneManager = new LuceneManager(bibDatabaseContext, taskExecutor, preferences.getFilePreferences());
+ luceneManager =
+ new LuceneManager(
+ bibDatabaseContext, taskExecutor, preferences.getFilePreferences());
stateManager.setLuceneManager(bibDatabaseContext, luceneManager);
}
@@ -339,7 +368,10 @@ private void onDatabaseLoadingFailed(Exception ex) {
loading.set(false);
String title = Localization.lang("Connection error");
- String content = "%s\n\n%s".formatted(ex.getMessage(), Localization.lang("A local copy will be opened."));
+ String content =
+ "%s\n\n%s"
+ .formatted(
+ ex.getMessage(), Localization.lang("A local copy will be opened."));
dialogService.showErrorDialogAndWait(title, content, ex);
}
@@ -356,9 +388,14 @@ private void setDatabaseContext(BibDatabaseContext bibDatabaseContext) {
stateManager.activeTabProperty().set(Optional.of(this));
}
- // Remove existing dummy BibDatabaseContext and add correct BibDatabaseContext from ParserResult to trigger changes in the openDatabases list in the stateManager
- Optional foundExistingBibDatabase = stateManager.getOpenDatabases().stream().filter(databaseContext -> databaseContext.equals(this.bibDatabaseContext)).findFirst();
- foundExistingBibDatabase.ifPresent(databaseContext -> stateManager.getOpenDatabases().remove(databaseContext));
+ // Remove existing dummy BibDatabaseContext and add correct BibDatabaseContext from
+ // ParserResult to trigger changes in the openDatabases list in the stateManager
+ Optional foundExistingBibDatabase =
+ stateManager.getOpenDatabases().stream()
+ .filter(databaseContext -> databaseContext.equals(this.bibDatabaseContext))
+ .findFirst();
+ foundExistingBibDatabase.ifPresent(
+ databaseContext -> stateManager.getOpenDatabases().remove(databaseContext));
this.bibDatabaseContext = Objects.requireNonNull(bibDatabaseContext);
@@ -371,22 +408,29 @@ private void setDatabaseContext(BibDatabaseContext bibDatabaseContext) {
public void installAutosaveManagerAndBackupManager() {
if (isDatabaseReadyForAutoSave(bibDatabaseContext)) {
AutosaveManager autosaveManager = AutosaveManager.start(bibDatabaseContext);
- autosaveManager.registerListener(new AutosaveUiManager(this, dialogService, preferences, entryTypesManager));
+ autosaveManager.registerListener(
+ new AutosaveUiManager(this, dialogService, preferences, entryTypesManager));
}
- if (isDatabaseReadyForBackup(bibDatabaseContext) && preferences.getFilePreferences().shouldCreateBackup()) {
- BackupManager.start(this, bibDatabaseContext, Injector.instantiateModelOrService(BibEntryTypesManager.class), preferences);
+ if (isDatabaseReadyForBackup(bibDatabaseContext)
+ && preferences.getFilePreferences().shouldCreateBackup()) {
+ BackupManager.start(
+ this,
+ bibDatabaseContext,
+ Injector.instantiateModelOrService(BibEntryTypesManager.class),
+ preferences);
}
}
private boolean isDatabaseReadyForAutoSave(BibDatabaseContext context) {
return ((context.getLocation() == DatabaseLocation.SHARED)
- || ((context.getLocation() == DatabaseLocation.LOCAL)
- && preferences.getLibraryPreferences().shouldAutoSave()))
+ || ((context.getLocation() == DatabaseLocation.LOCAL)
+ && preferences.getLibraryPreferences().shouldAutoSave()))
&& context.getDatabasePath().isPresent();
}
private boolean isDatabaseReadyForBackup(BibDatabaseContext context) {
- return (context.getLocation() == DatabaseLocation.LOCAL) && context.getDatabasePath().isPresent();
+ return (context.getLocation() == DatabaseLocation.LOCAL)
+ && context.getDatabasePath().isPresent();
}
/**
@@ -433,7 +477,9 @@ public void updateTabTitle(boolean isChanged) {
}
// Unique path fragment
- Optional uniquePathPart = FileUtil.getUniquePathDirectory(stateManager.collectAllDatabasePaths(), databasePath);
+ Optional uniquePathPart =
+ FileUtil.getUniquePathDirectory(
+ stateManager.collectAllDatabasePaths(), databasePath);
uniquePathPart.ifPresent(part -> tabTitle.append(" \u2013 ").append(part));
} else {
if (databaseLocation == DatabaseLocation.LOCAL) {
@@ -444,15 +490,17 @@ public void updateTabTitle(boolean isChanged) {
addSharedDbInformation(toolTipText, bibDatabaseContext);
}
addModeInfo(toolTipText, bibDatabaseContext);
- if ((databaseLocation == DatabaseLocation.LOCAL) && bibDatabaseContext.getDatabase().hasEntries()) {
+ if ((databaseLocation == DatabaseLocation.LOCAL)
+ && bibDatabaseContext.getDatabase().hasEntries()) {
addChangedInformation(toolTipText, Localization.lang("untitled"));
}
}
- UiTaskExecutor.runInJavaFXThread(() -> {
- textProperty().setValue(tabTitle.toString());
- setTooltip(new Tooltip(toolTipText.toString()));
- });
+ UiTaskExecutor.runInJavaFXThread(
+ () -> {
+ textProperty().setValue(tabTitle.toString());
+ setTooltip(new Tooltip(toolTipText.toString()));
+ });
}
@Subscribe
@@ -480,36 +528,44 @@ public void registerUndoableChanges(List changes) {
public void editEntryAndFocusField(BibEntry entry, Field field) {
showAndEdit(entry);
- Platform.runLater(() -> {
- // Focus field and entry in main table (async to give entry editor time to load)
- entryEditor.setFocusToField(field);
- clearAndSelect(entry);
- });
+ Platform.runLater(
+ () -> {
+ // Focus field and entry in main table (async to give entry editor time to load)
+ entryEditor.setFocusToField(field);
+ clearAndSelect(entry);
+ });
}
private void createMainTable() {
- mainTable = new MainTable(tableModel,
- this,
- tabContainer,
- bibDatabaseContext,
- preferences,
- dialogService,
- stateManager,
- preferences.getKeyBindingRepository(),
- clipBoardManager,
- entryTypesManager,
- taskExecutor,
- importHandler);
- // Add the listener that binds selection to state manager (TODO: should be replaced by proper JavaFX binding as soon as table is implemented in JavaFX)
- // content binding between StateManager#getselectedEntries and mainTable#getSelectedEntries does not work here as it does not trigger the ActionHelper#needsEntriesSelected checker for the menubar
- mainTable.addSelectionListener(event -> {
- List entries = event.getList().stream().map(BibEntryTableViewModel::getEntry).toList();
- stateManager.setSelectedEntries(entries);
- if (!entries.isEmpty()) {
- // Update entry editor and preview according to selected entries
- entryEditor.setCurrentlyEditedEntry(entries.getFirst());
- }
- });
+ mainTable =
+ new MainTable(
+ tableModel,
+ this,
+ tabContainer,
+ bibDatabaseContext,
+ preferences,
+ dialogService,
+ stateManager,
+ preferences.getKeyBindingRepository(),
+ clipBoardManager,
+ entryTypesManager,
+ taskExecutor,
+ importHandler);
+ // Add the listener that binds selection to state manager (TODO: should be replaced by
+ // proper JavaFX binding as soon as table is implemented in JavaFX)
+ // content binding between StateManager#getselectedEntries and mainTable#getSelectedEntries
+ // does not work here as it does not trigger the ActionHelper#needsEntriesSelected checker
+ // for the menubar
+ mainTable.addSelectionListener(
+ event -> {
+ List entries =
+ event.getList().stream().map(BibEntryTableViewModel::getEntry).toList();
+ stateManager.setSelectedEntries(entries);
+ if (!entries.isEmpty()) {
+ // Update entry editor and preview according to selected entries
+ entryEditor.setCurrentlyEditedEntry(entries.getFirst());
+ }
+ });
}
public void setupMainPanel() {
@@ -523,10 +579,12 @@ public void setupMainPanel() {
setContent(databaseNotificationPane);
// Saves the divider position as soon as it changes
- // We need to keep a reference to the subscription, otherwise the binding gets garbage collected
- dividerPositionSubscription = EasyBind.valueAt(splitPane.getDividers(), 0)
- .mapObservable(SplitPane.Divider::positionProperty)
- .subscribeToValues(this::saveDividerLocation);
+ // We need to keep a reference to the subscription, otherwise the binding gets garbage
+ // collected
+ dividerPositionSubscription =
+ EasyBind.valueAt(splitPane.getDividers(), 0)
+ .mapObservable(SplitPane.Divider::positionProperty)
+ .subscribeToValues(this::saveDividerLocation);
// Add changePane in case a file is present - otherwise just add the splitPane to the panel
Optional file = bibDatabaseContext.getDatabasePath();
@@ -548,15 +606,17 @@ public void setupMainPanel() {
private void setupAutoCompletion() {
AutoCompletePreferences autoCompletePreferences = preferences.getAutoCompletePreferences();
if (autoCompletePreferences.shouldAutoComplete()) {
- suggestionProviders = new SuggestionProviders(
- getDatabase(),
- Injector.instantiateModelOrService(JournalAbbreviationRepository.class),
- autoCompletePreferences);
+ suggestionProviders =
+ new SuggestionProviders(
+ getDatabase(),
+ Injector.instantiateModelOrService(JournalAbbreviationRepository.class),
+ autoCompletePreferences);
} else {
// Create empty suggestion providers if auto-completion is deactivated
suggestionProviders = new SuggestionProviders();
}
- searchAutoCompleter = new PersonNameSuggestionProvider(FieldFactory.getPersonNameFields(), getDatabase());
+ searchAutoCompleter =
+ new PersonNameSuggestionProvider(FieldFactory.getPersonNameFields(), getDatabase());
}
public SuggestionProvider getAutoCompleter() {
@@ -576,7 +636,8 @@ public void showAndEdit(BibEntry entry) {
if (!splitPane.getItems().contains(entryEditor)) {
splitPane.getItems().addLast(entryEditor);
mode = PanelMode.MAIN_TABLE_AND_ENTRY_EDITOR;
- splitPane.setDividerPositions(preferences.getEntryEditorPreferences().getDividerPosition());
+ splitPane.setDividerPositions(
+ preferences.getEntryEditorPreferences().getDividerPosition());
}
// We use != instead of equals because of performance reasons
@@ -603,11 +664,15 @@ public void clearAndSelect(final BibEntry bibEntry) {
}
public void selectPreviousEntry() {
- mainTable.getSelectionModel().clearAndSelect(mainTable.getSelectionModel().getSelectedIndex() - 1);
+ mainTable
+ .getSelectionModel()
+ .clearAndSelect(mainTable.getSelectionModel().getSelectedIndex() - 1);
}
public void selectNextEntry() {
- mainTable.getSelectionModel().clearAndSelect(mainTable.getSelectionModel().getSelectedIndex() + 1);
+ mainTable
+ .getSelectionModel()
+ .clearAndSelect(mainTable.getSelectionModel().getSelectedIndex() + 1);
}
/**
@@ -624,7 +689,8 @@ public void entryEditorClosing() {
private void ensureNotShowingBottomPanel(List entriesToCheck) {
// This method is not able to close the bottom pane currently
- if ((mode == PanelMode.MAIN_TABLE_AND_ENTRY_EDITOR) && (entriesToCheck.contains(entryEditor.getCurrentlyEditedEntry()))) {
+ if ((mode == PanelMode.MAIN_TABLE_AND_ENTRY_EDITOR)
+ && (entriesToCheck.contains(entryEditor.getCurrentlyEditedEntry()))) {
closeBottomPane();
}
}
@@ -667,7 +733,10 @@ private boolean showDeleteConfirmationDialog(int numberOfEntries) {
String cancelButton = Localization.lang("Keep entry");
if (numberOfEntries > 1) {
title = Localization.lang("Delete multiple entries");
- message = Localization.lang("Really delete the %0 selected entries?", Integer.toString(numberOfEntries));
+ message =
+ Localization.lang(
+ "Really delete the %0 selected entries?",
+ Integer.toString(numberOfEntries));
okButton = Localization.lang("Delete entries");
cancelButton = Localization.lang("Keep entries");
}
@@ -716,20 +785,29 @@ private boolean confirmClose() {
return true;
}
- String filename = getBibDatabaseContext()
- .getDatabasePath()
- .map(Path::toAbsolutePath)
- .map(Path::toString)
- .orElse(Localization.lang("untitled"));
-
- ButtonType saveChanges = new ButtonType(Localization.lang("Save changes"), ButtonBar.ButtonData.YES);
- ButtonType discardChanges = new ButtonType(Localization.lang("Discard changes"), ButtonBar.ButtonData.NO);
- ButtonType returnToLibrary = new ButtonType(Localization.lang("Return to library"), ButtonBar.ButtonData.CANCEL_CLOSE);
-
- Optional response = dialogService.showCustomButtonDialogAndWait(Alert.AlertType.CONFIRMATION,
- Localization.lang("Save before closing"),
- Localization.lang("Library '%0' has changed.", filename),
- saveChanges, discardChanges, returnToLibrary);
+ String filename =
+ getBibDatabaseContext()
+ .getDatabasePath()
+ .map(Path::toAbsolutePath)
+ .map(Path::toString)
+ .orElse(Localization.lang("untitled"));
+
+ ButtonType saveChanges =
+ new ButtonType(Localization.lang("Save changes"), ButtonBar.ButtonData.YES);
+ ButtonType discardChanges =
+ new ButtonType(Localization.lang("Discard changes"), ButtonBar.ButtonData.NO);
+ ButtonType returnToLibrary =
+ new ButtonType(
+ Localization.lang("Return to library"), ButtonBar.ButtonData.CANCEL_CLOSE);
+
+ Optional response =
+ dialogService.showCustomButtonDialogAndWait(
+ Alert.AlertType.CONFIRMATION,
+ Localization.lang("Save before closing"),
+ Localization.lang("Library '%0' has changed.", filename),
+ saveChanges,
+ discardChanges,
+ returnToLibrary);
if (response.isEmpty()) {
return true;
@@ -743,7 +821,12 @@ private boolean confirmClose() {
if (buttonType.equals(saveChanges)) {
try {
- SaveDatabaseAction saveAction = new SaveDatabaseAction(this, dialogService, preferences, Injector.instantiateModelOrService(BibEntryTypesManager.class));
+ SaveDatabaseAction saveAction =
+ new SaveDatabaseAction(
+ this,
+ dialogService,
+ preferences,
+ Injector.instantiateModelOrService(BibEntryTypesManager.class));
if (saveAction.save()) {
return true;
}
@@ -751,14 +834,18 @@ private boolean confirmClose() {
dialogService.notify(Localization.lang("Unable to save library"));
} catch (Throwable ex) {
LOGGER.error("A problem occurred when trying to save the file", ex);
- dialogService.showErrorDialogAndWait(Localization.lang("Save library"), Localization.lang("Could not save file."), ex);
+ dialogService.showErrorDialogAndWait(
+ Localization.lang("Save library"),
+ Localization.lang("Could not save file."),
+ ex);
}
// Save was cancelled or an error occurred.
return false;
}
if (buttonType.equals(discardChanges)) {
- BackupManager.discardBackup(bibDatabaseContext, preferences.getFilePreferences().getBackupDirectory());
+ BackupManager.discardBackup(
+ bibDatabaseContext, preferences.getFilePreferences().getBackupDirectory());
return true;
}
@@ -806,7 +893,8 @@ private void onClosed(Event event) {
LOGGER.error("Problem when shutting down autosave manager", e);
}
try {
- BackupManager.shutdown(bibDatabaseContext,
+ BackupManager.shutdown(
+ bibDatabaseContext,
preferences.getFilePreferences().getBackupDirectory(),
preferences.getFilePreferences().shouldCreateBackup());
} catch (RuntimeException e) {
@@ -875,14 +963,17 @@ public FileAnnotationCache getAnnotationCache() {
public void resetChangeMonitor() {
changeMonitor.ifPresent(DatabaseChangeMonitor::unregister);
- changeMonitor = Optional.of(new DatabaseChangeMonitor(bibDatabaseContext,
- fileUpdateMonitor,
- taskExecutor,
- dialogService,
- preferences,
- databaseNotificationPane,
- undoManager,
- stateManager));
+ changeMonitor =
+ Optional.of(
+ new DatabaseChangeMonitor(
+ bibDatabaseContext,
+ fileUpdateMonitor,
+ taskExecutor,
+ dialogService,
+ preferences,
+ databaseNotificationPane,
+ undoManager,
+ stateManager));
}
public void insertEntry(final BibEntry bibEntry) {
@@ -894,7 +985,8 @@ public void insertEntries(final List entries) {
importHandler.importCleanedEntries(entries);
// Create an UndoableInsertEntries object.
- getUndoManager().addEdit(new UndoableInsertEntries(bibDatabaseContext.getDatabase(), entries));
+ getUndoManager()
+ .addEdit(new UndoableInsertEntries(bibDatabaseContext.getDatabase(), entries));
markBaseChanged();
if (preferences.getEntryEditorPreferences().shouldOpenOnNewEntry()) {
@@ -915,12 +1007,14 @@ public void copyEntry() {
private int doCopyEntry(List selectedEntries) {
if (!selectedEntries.isEmpty()) {
- List stringConstants = bibDatabaseContext.getDatabase().getUsedStrings(selectedEntries);
+ List stringConstants =
+ bibDatabaseContext.getDatabase().getUsedStrings(selectedEntries);
try {
if (stringConstants.isEmpty()) {
clipBoardManager.setContent(selectedEntries, entryTypesManager);
} else {
- clipBoardManager.setContent(selectedEntries, entryTypesManager, stringConstants);
+ clipBoardManager.setContent(
+ selectedEntries, entryTypesManager, stringConstants);
}
return selectedEntries.size();
} catch (IOException e) {
@@ -949,12 +1043,15 @@ public void pasteEntry() {
private List handleNonBibTeXStringData(String data) {
try {
return this.importHandler.handleStringData(data);
- } catch (
- FetcherException exception) {
+ } catch (FetcherException exception) {
if (exception instanceof FetcherClientException) {
- dialogService.showInformationDialogAndWait(Localization.lang("Look up identifier"), Localization.lang("No data was found for the identifier"));
+ dialogService.showInformationDialogAndWait(
+ Localization.lang("Look up identifier"),
+ Localization.lang("No data was found for the identifier"));
} else if (exception instanceof FetcherServerException) {
- dialogService.showInformationDialogAndWait(Localization.lang("Look up identifier"), Localization.lang("Server not available"));
+ dialogService.showInformationDialogAndWait(
+ Localization.lang("Look up identifier"),
+ Localization.lang("Server not available"));
} else {
dialogService.showErrorDialogAndWait(exception);
}
@@ -983,7 +1080,8 @@ public void cutEntry() {
* Removes the selected entries and files linked to selected entries from the database
*/
public void deleteEntry() {
- int entriesDeleted = doDeleteEntry(StandardActions.DELETE_ENTRY, mainTable.getSelectedEntries());
+ int entriesDeleted =
+ doDeleteEntry(StandardActions.DELETE_ENTRY, mainTable.getSelectedEntries());
dialogService.notify(Localization.lang("Deleted %0 entry(ies)", entriesDeleted));
}
@@ -1005,21 +1103,41 @@ private int doDeleteEntry(StandardActions mode, List entries) {
}
// Delete selected entries
- getUndoManager().addEdit(new UndoableRemoveEntries(bibDatabaseContext.getDatabase(), entries, mode == StandardActions.CUT));
+ getUndoManager()
+ .addEdit(
+ new UndoableRemoveEntries(
+ bibDatabaseContext.getDatabase(),
+ entries,
+ mode == StandardActions.CUT));
bibDatabaseContext.getDatabase().removeEntries(entries);
if (mode != StandardActions.CUT) {
- List linkedFileList = entries.stream()
- .flatMap(entry -> entry.getFiles().stream())
- .distinct()
- .toList();
+ List linkedFileList =
+ entries.stream()
+ .flatMap(entry -> entry.getFiles().stream())
+ .distinct()
+ .toList();
if (!linkedFileList.isEmpty()) {
- List viewModels = linkedFileList.stream()
- .map(linkedFile -> LinkedFileViewModel.fromLinkedFile(linkedFile, null, bibDatabaseContext, null, null, preferences))
- .collect(Collectors.toList());
-
- new DeleteFileAction(dialogService, preferences.getFilePreferences(), bibDatabaseContext, viewModels).execute();
+ List viewModels =
+ linkedFileList.stream()
+ .map(
+ linkedFile ->
+ LinkedFileViewModel.fromLinkedFile(
+ linkedFile,
+ null,
+ bibDatabaseContext,
+ null,
+ null,
+ preferences))
+ .collect(Collectors.toList());
+
+ new DeleteFileAction(
+ dialogService,
+ preferences.getFilePreferences(),
+ bibDatabaseContext,
+ viewModels)
+ .execute();
}
}
@@ -1056,55 +1174,59 @@ public void resetChangedProperties() {
* @param dataLoadingTask The task to execute to load the data asynchronously.
* @param file the path to the file (loaded by the dataLoadingTask)
*/
- public static LibraryTab createLibraryTab(BackgroundTask dataLoadingTask,
- Path file,
- DialogService dialogService,
- AiService aiService,
- GuiPreferences preferences,
- StateManager stateManager,
- LibraryTabContainer tabContainer,
- FileUpdateMonitor fileUpdateMonitor,
- BibEntryTypesManager entryTypesManager,
- CountingUndoManager undoManager,
- ClipBoardManager clipBoardManager,
- TaskExecutor taskExecutor) {
+ public static LibraryTab createLibraryTab(
+ BackgroundTask dataLoadingTask,
+ Path file,
+ DialogService dialogService,
+ AiService aiService,
+ GuiPreferences preferences,
+ StateManager stateManager,
+ LibraryTabContainer tabContainer,
+ FileUpdateMonitor fileUpdateMonitor,
+ BibEntryTypesManager entryTypesManager,
+ CountingUndoManager undoManager,
+ ClipBoardManager clipBoardManager,
+ TaskExecutor taskExecutor) {
BibDatabaseContext context = new BibDatabaseContext();
context.setDatabasePath(file);
- LibraryTab newTab = new LibraryTab(
- context,
- tabContainer,
- dialogService,
- aiService,
- preferences,
- stateManager,
- fileUpdateMonitor,
- entryTypesManager,
- undoManager,
- clipBoardManager,
- taskExecutor,
- true);
+ LibraryTab newTab =
+ new LibraryTab(
+ context,
+ tabContainer,
+ dialogService,
+ aiService,
+ preferences,
+ stateManager,
+ fileUpdateMonitor,
+ entryTypesManager,
+ undoManager,
+ clipBoardManager,
+ taskExecutor,
+ true);
newTab.setDataLoadingTask(dataLoadingTask);
- dataLoadingTask.onRunning(newTab::onDatabaseLoadingStarted)
- .onSuccess(newTab::onDatabaseLoadingSucceed)
- .onFailure(newTab::onDatabaseLoadingFailed)
- .executeWith(taskExecutor);
+ dataLoadingTask
+ .onRunning(newTab::onDatabaseLoadingStarted)
+ .onSuccess(newTab::onDatabaseLoadingSucceed)
+ .onFailure(newTab::onDatabaseLoadingFailed)
+ .executeWith(taskExecutor);
return newTab;
}
- public static LibraryTab createLibraryTab(BibDatabaseContext databaseContext,
- LibraryTabContainer tabContainer,
- DialogService dialogService,
- AiService aiService,
- GuiPreferences preferences,
- StateManager stateManager,
- FileUpdateMonitor fileUpdateMonitor,
- BibEntryTypesManager entryTypesManager,
- UndoManager undoManager,
- ClipBoardManager clipBoardManager,
- TaskExecutor taskExecutor) {
+ public static LibraryTab createLibraryTab(
+ BibDatabaseContext databaseContext,
+ LibraryTabContainer tabContainer,
+ DialogService dialogService,
+ AiService aiService,
+ GuiPreferences preferences,
+ StateManager stateManager,
+ FileUpdateMonitor fileUpdateMonitor,
+ BibEntryTypesManager entryTypesManager,
+ UndoManager undoManager,
+ ClipBoardManager clipBoardManager,
+ TaskExecutor taskExecutor) {
Objects.requireNonNull(databaseContext);
return new LibraryTab(
@@ -1133,8 +1255,12 @@ public void listen(EntriesAddedEvent addedEntriesEvent) {
// Automatically add new entries to the selected group (or set of groups)
if (preferences.getGroupsPreferences().shouldAutoAssignGroup()) {
- stateManager.getSelectedGroups(bibDatabaseContext).forEach(
- selectedGroup -> selectedGroup.addEntriesToGroup(addedEntriesEvent.getBibEntries()));
+ stateManager
+ .getSelectedGroups(bibDatabaseContext)
+ .forEach(
+ selectedGroup ->
+ selectedGroup.addEntriesToGroup(
+ addedEntriesEvent.getBibEntries()));
}
}
}
@@ -1161,7 +1287,11 @@ public void listen(EntriesRemovedEvent removedEntriesEvent) {
@Subscribe
public void listen(FieldChangedEvent fieldChangedEvent) {
- luceneManager.updateEntry(fieldChangedEvent.getBibEntry(), fieldChangedEvent.getOldValue(), fieldChangedEvent.getNewValue(), fieldChangedEvent.getField().equals(StandardField.FILE));
+ luceneManager.updateEntry(
+ fieldChangedEvent.getBibEntry(),
+ fieldChangedEvent.getOldValue(),
+ fieldChangedEvent.getNewValue(),
+ fieldChangedEvent.getField().equals(StandardField.FILE));
}
}
@@ -1189,10 +1319,12 @@ public DatabaseNotification getNotificationPane() {
@Override
public String toString() {
- return "LibraryTab{" +
- "bibDatabaseContext=" + bibDatabaseContext +
- ", showing=" + showing +
- '}';
+ return "LibraryTab{"
+ + "bibDatabaseContext="
+ + bibDatabaseContext
+ + ", showing="
+ + showing
+ + '}';
}
public LibraryTabContainer getLibraryTabContainer() {
diff --git a/src/main/java/org/jabref/gui/LibraryTabContainer.java b/src/main/java/org/jabref/gui/LibraryTabContainer.java
index 139653c87ca..1ad7390ade1 100644
--- a/src/main/java/org/jabref/gui/LibraryTabContainer.java
+++ b/src/main/java/org/jabref/gui/LibraryTabContainer.java
@@ -1,19 +1,17 @@
package org.jabref.gui;
-import java.util.List;
-
import org.jabref.model.database.BibDatabaseContext;
-
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
+import java.util.List;
+
@NullMarked
public interface LibraryTabContainer {
List getLibraryTabs();
- @Nullable
- LibraryTab getCurrentLibraryTab();
+ @Nullable LibraryTab getCurrentLibraryTab();
void showLibraryTab(LibraryTab libraryTab);
diff --git a/src/main/java/org/jabref/gui/StateManager.java b/src/main/java/org/jabref/gui/StateManager.java
index e75ffcdc89e..77cb3e5f41a 100644
--- a/src/main/java/org/jabref/gui/StateManager.java
+++ b/src/main/java/org/jabref/gui/StateManager.java
@@ -1,9 +1,7 @@
package org.jabref.gui;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-import java.util.Optional;
+import com.tobiasdiez.easybind.EasyBind;
+import com.tobiasdiez.easybind.EasyBinding;
import javafx.beans.Observable;
import javafx.beans.binding.Bindings;
@@ -33,12 +31,14 @@
import org.jabref.model.entry.BibEntry;
import org.jabref.model.groups.GroupTreeNode;
import org.jabref.model.search.SearchQuery;
-
-import com.tobiasdiez.easybind.EasyBind;
-import com.tobiasdiez.easybind.EasyBinding;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
/**
* This class manages the GUI-state of JabRef, including:
*
@@ -56,26 +56,60 @@ public class StateManager {
private static final Logger LOGGER = LoggerFactory.getLogger(StateManager.class);
private final CustomLocalDragboard localDragboard = new CustomLocalDragboard();
- private final ObservableList openDatabases = FXCollections.observableArrayList();
- private final OptionalObjectProperty activeDatabase = OptionalObjectProperty.empty();
+ private final ObservableList openDatabases =
+ FXCollections.observableArrayList();
+ private final OptionalObjectProperty activeDatabase =
+ OptionalObjectProperty.empty();
private final OptionalObjectProperty activeTab = OptionalObjectProperty.empty();
private final ObservableList selectedEntries = FXCollections.observableArrayList();
- private final ObservableMap> selectedGroups = FXCollections.observableHashMap();
- private final ObservableMap luceneManagers = FXCollections.observableHashMap();
- private final OptionalObjectProperty activeSearchQuery = OptionalObjectProperty.empty();
- private final OptionalObjectProperty activeGlobalSearchQuery = OptionalObjectProperty.empty();
+ private final ObservableMap> selectedGroups =
+ FXCollections.observableHashMap();
+ private final ObservableMap luceneManagers =
+ FXCollections.observableHashMap();
+ private final OptionalObjectProperty activeSearchQuery =
+ OptionalObjectProperty.empty();
+ private final OptionalObjectProperty activeGlobalSearchQuery =
+ OptionalObjectProperty.empty();
private final IntegerProperty searchResultSize = new SimpleIntegerProperty(0);
private final IntegerProperty globalSearchResultSize = new SimpleIntegerProperty(0);
private final OptionalObjectProperty focusOwner = OptionalObjectProperty.empty();
- private final ObservableList, Task>>> backgroundTasksPairs = FXCollections.observableArrayList(task -> new Observable[] {task.getValue().progressProperty(), task.getValue().runningProperty()});
- private final ObservableList> backgroundTasks = EasyBind.map(backgroundTasksPairs, Pair::getValue);
- private final FilteredList