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 super FileAnnotationViewModel>) 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 super FileAnnotationViewModel>) 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">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
+
+
+
+
+
+
+
diff --git a/src/main/java/org/jabref/gui/errorconsole/ErrorConsoleController.java b/src/main/java/org/jabref/gui/errorconsole/ErrorConsoleController.java
deleted file mode 100644
index b4a33616966..00000000000
--- a/src/main/java/org/jabref/gui/errorconsole/ErrorConsoleController.java
+++ /dev/null
@@ -1,122 +0,0 @@
-package org.jabref.gui.errorconsole;
-
-import javax.inject.Inject;
-
-import javafx.collections.ListChangeListener;
-import javafx.collections.ObservableList;
-import javafx.fxml.FXML;
-import javafx.scene.Node;
-import javafx.scene.control.Button;
-import javafx.scene.control.ContentDisplay;
-import javafx.scene.control.Label;
-import javafx.scene.control.ListCell;
-import javafx.scene.control.ListView;
-import javafx.scene.control.SelectionMode;
-import javafx.scene.input.KeyEvent;
-import javafx.scene.layout.HBox;
-import javafx.scene.layout.VBox;
-import javafx.util.Callback;
-
-import org.jabref.gui.AbstractController;
-import org.jabref.gui.ClipBoardManager;
-import org.jabref.gui.DialogService;
-import org.jabref.gui.IconTheme;
-import org.jabref.gui.keyboard.KeyBinding;
-import org.jabref.gui.keyboard.KeyBindingRepository;
-import org.jabref.logic.util.BuildInfo;
-
-public class ErrorConsoleController extends AbstractController {
-
- @FXML private Button copyLogButton;
- @FXML private Button clearLogButton;
- @FXML private Button createIssueButton;
- @FXML private ListView messagesListView;
- @FXML private Label descriptionLabel;
-
- @Inject private DialogService dialogService;
- @Inject private ClipBoardManager clipBoardManager;
- @Inject private BuildInfo buildInfo;
- @Inject private KeyBindingRepository keyBindingRepository;
-
- @FXML
- private void initialize() {
- viewModel = new ErrorConsoleViewModel(dialogService, clipBoardManager, buildInfo);
-
- messagesListView.setCellFactory(createCellFactory());
- messagesListView.itemsProperty().bind(viewModel.allMessagesDataProperty());
- messagesListView.scrollTo(viewModel.allMessagesDataProperty().getSize() - 1);
- messagesListView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
- viewModel.allMessagesDataProperty().addListener((ListChangeListener) (change -> {
- int size = viewModel.allMessagesDataProperty().size();
- if (size > 0) {
- messagesListView.scrollTo(size - 1);
- }
- }));
- descriptionLabel.setGraphic(IconTheme.JabRefIcons.CONSOLE.getGraphicNode());
- }
-
- private Callback, ListCell> createCellFactory() {
- return cell -> new ListCell() {
-
- private HBox graphic;
- private Node icon;
- private VBox message;
- private Label heading;
- private Label stacktrace;
-
- {
- graphic = new HBox(10);
- heading = new Label();
- stacktrace = new Label();
- message = new VBox();
- message.getChildren().setAll(heading, stacktrace);
- setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
- }
-
- @Override
- public void updateItem(LogEventViewModel event, boolean empty) {
- super.updateItem(event, empty);
-
- if (event == null || empty) {
- setGraphic(null);
- } else {
- icon = event.getIcon().getGraphicNode();
- heading.setText(event.getDisplayText());
- heading.getStyleClass().setAll(event.getStyleClass());
- stacktrace.setText(event.getStackTrace().orElse(""));
- graphic.getStyleClass().setAll(event.getStyleClass());
- graphic.getChildren().setAll(icon, message);
- setGraphic(graphic);
- }
- }
- };
- }
-
- @FXML
- private void copySelectedLogEntries(KeyEvent event) {
- if (keyBindingRepository.checkKeyCombinationEquality(KeyBinding.COPY, event)) {
- ObservableList selectedEntries = messagesListView.getSelectionModel().getSelectedItems();
- viewModel.copyLog(selectedEntries);
- }
- }
-
- @FXML
- private void copyLog() {
- viewModel.copyLog();
- }
-
- @FXML
- private void clearLog() {
- viewModel.clearLog();
- }
-
- @FXML
- private void createIssue() {
- viewModel.reportIssue();
- }
-
- @FXML
- private void closeErrorDialog() {
- getStage().close();
- }
-}
diff --git a/src/main/java/org/jabref/gui/errorconsole/ErrorConsoleView.java b/src/main/java/org/jabref/gui/errorconsole/ErrorConsoleView.java
index 64b9936a8d9..67881fd6a48 100644
--- a/src/main/java/org/jabref/gui/errorconsole/ErrorConsoleView.java
+++ b/src/main/java/org/jabref/gui/errorconsole/ErrorConsoleView.java
@@ -1,19 +1,138 @@
package org.jabref.gui.errorconsole;
-import javafx.scene.control.Alert.AlertType;
-import javafx.scene.control.DialogPane;
+import javax.inject.Inject;
-import org.jabref.gui.AbstractDialogView;
-import org.jabref.gui.FXDialog;
+import javafx.collections.ListChangeListener;
+import javafx.collections.ObservableList;
+import javafx.fxml.FXML;
+import javafx.scene.Node;
+import javafx.scene.control.ButtonType;
+import javafx.scene.control.ContentDisplay;
+import javafx.scene.control.Label;
+import javafx.scene.control.ListCell;
+import javafx.scene.control.ListView;
+import javafx.scene.control.SelectionMode;
+import javafx.scene.input.KeyEvent;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.VBox;
+import javafx.stage.Modality;
+import javafx.util.Callback;
+
+import org.jabref.gui.ClipBoardManager;
+import org.jabref.gui.DialogService;
+import org.jabref.gui.IconTheme;
+import org.jabref.gui.keyboard.KeyBinding;
+import org.jabref.gui.keyboard.KeyBindingRepository;
+import org.jabref.gui.util.BaseDialog;
+import org.jabref.gui.util.ControlHelper;
import org.jabref.logic.l10n.Localization;
+import org.jabref.logic.util.BuildInfo;
+
+import com.airhacks.afterburner.views.ViewLoader;
+
+public class ErrorConsoleView extends BaseDialog {
+
+ private ErrorConsoleViewModel viewModel;
+
+ @FXML private ButtonType copyLogButton;
+ @FXML private ButtonType clearLogButton;
+ @FXML private ButtonType createIssueButton;
+ @FXML private ListView messagesListView;
+ @FXML private Label descriptionLabel;
+
+ @Inject private DialogService dialogService;
+ @Inject private ClipBoardManager clipBoardManager;
+ @Inject private BuildInfo buildInfo;
+ @Inject private KeyBindingRepository keyBindingRepository;
+
+ public ErrorConsoleView() {
+ this.setTitle(Localization.lang("Event log"));
+ this.setResizable(true);
+ this.initModality(Modality.NONE);
+
+ ViewLoader.view(this)
+ .load()
+ .setAsDialogPane(this);
+
+ ControlHelper.setAction(copyLogButton, getDialogPane(), event -> copyLog());
+ ControlHelper.setAction(clearLogButton, getDialogPane(), event -> clearLog());
+ ControlHelper.setAction(createIssueButton, getDialogPane(), event -> createIssue());
+ }
+
+ @FXML
+ private void initialize() {
+ viewModel = new ErrorConsoleViewModel(dialogService, clipBoardManager, buildInfo);
+ messagesListView.setCellFactory(createCellFactory());
+ messagesListView.itemsProperty().bind(viewModel.allMessagesDataProperty());
+ messagesListView.scrollTo(viewModel.allMessagesDataProperty().getSize() - 1);
+ messagesListView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
+ viewModel.allMessagesDataProperty().addListener((ListChangeListener) (change -> {
+ int size = viewModel.allMessagesDataProperty().size();
+ if (size > 0) {
+ messagesListView.scrollTo(size - 1);
+ }
+ }));
+ descriptionLabel.setGraphic(IconTheme.JabRefIcons.CONSOLE.getGraphicNode());
+ }
-public class ErrorConsoleView extends AbstractDialogView {
+ private Callback, ListCell> createCellFactory() {
+ return cell -> new ListCell() {
- @Override
- public void show() {
- FXDialog errorConsole = new FXDialog(AlertType.ERROR, Localization.lang("Event log"), false);
- errorConsole.setDialogPane((DialogPane) this.getView());
- errorConsole.setResizable(true);
- errorConsole.show();
+ private HBox graphic;
+ private Node icon;
+ private VBox message;
+ private Label heading;
+ private Label stacktrace;
+
+ {
+ graphic = new HBox(10);
+ heading = new Label();
+ stacktrace = new Label();
+ message = new VBox();
+ message.getChildren().setAll(heading, stacktrace);
+ setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
+ }
+
+ @Override
+ public void updateItem(LogEventViewModel event, boolean empty) {
+ super.updateItem(event, empty);
+
+ if (event == null || empty) {
+ setGraphic(null);
+ } else {
+ icon = event.getIcon().getGraphicNode();
+ heading.setText(event.getDisplayText());
+ heading.getStyleClass().setAll(event.getStyleClass());
+ stacktrace.setText(event.getStackTrace().orElse(""));
+ graphic.getStyleClass().setAll(event.getStyleClass());
+ graphic.getChildren().setAll(icon, message);
+ setGraphic(graphic);
+ }
+ }
+ };
+ }
+
+ @FXML
+ private void copySelectedLogEntries(KeyEvent event) {
+ if (keyBindingRepository.checkKeyCombinationEquality(KeyBinding.COPY, event)) {
+ ObservableList selectedEntries = messagesListView.getSelectionModel().getSelectedItems();
+ viewModel.copyLog(selectedEntries);
+ }
+ }
+
+ @FXML
+ private void copyLog() {
+ viewModel.copyLog();
+ }
+
+ @FXML
+ private void clearLog() {
+ viewModel.clearLog();
}
+
+ @FXML
+ private void createIssue() {
+ viewModel.reportIssue();
+ }
+
}
diff --git a/src/main/java/org/jabref/gui/groups/GroupSidePane.java b/src/main/java/org/jabref/gui/groups/GroupSidePane.java
index 5e59a42d430..baecee8f020 100644
--- a/src/main/java/org/jabref/gui/groups/GroupSidePane.java
+++ b/src/main/java/org/jabref/gui/groups/GroupSidePane.java
@@ -12,6 +12,8 @@
import org.jabref.logic.l10n.Localization;
import org.jabref.preferences.JabRefPreferences;
+import com.airhacks.afterburner.views.ViewLoader;
+
/**
* The groups side pane.
*/
@@ -46,7 +48,9 @@ public Action getToggleAction() {
@Override
protected Node createContentPane() {
- return new GroupTreeView().getView();
+ return ViewLoader.view(GroupTreeView.class)
+ .load()
+ .getView();
}
@Override
diff --git a/src/main/java/org/jabref/gui/groups/GroupTree.fxml b/src/main/java/org/jabref/gui/groups/GroupTree.fxml
index 4760b197537..13b117fcda8 100644
--- a/src/main/java/org/jabref/gui/groups/GroupTree.fxml
+++ b/src/main/java/org/jabref/gui/groups/GroupTree.fxml
@@ -11,7 +11,7 @@
+ xmlns="http://javafx.com/javafx/8.0.112" fx:controller="org.jabref.gui.groups.GroupTreeView">
diff --git a/src/main/java/org/jabref/gui/groups/GroupTreeController.java b/src/main/java/org/jabref/gui/groups/GroupTreeController.java
deleted file mode 100644
index 6d7b2cd43e9..00000000000
--- a/src/main/java/org/jabref/gui/groups/GroupTreeController.java
+++ /dev/null
@@ -1,378 +0,0 @@
-package org.jabref.gui.groups;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.time.Duration;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
-import java.util.function.Consumer;
-
-import javax.inject.Inject;
-
-import javafx.beans.property.ObjectProperty;
-import javafx.collections.ObservableList;
-import javafx.css.PseudoClass;
-import javafx.event.ActionEvent;
-import javafx.fxml.FXML;
-import javafx.scene.control.ContextMenu;
-import javafx.scene.control.Control;
-import javafx.scene.control.MenuItem;
-import javafx.scene.control.SelectionMode;
-import javafx.scene.control.SeparatorMenuItem;
-import javafx.scene.control.TextField;
-import javafx.scene.control.TreeItem;
-import javafx.scene.control.TreeTableColumn;
-import javafx.scene.control.TreeTableRow;
-import javafx.scene.control.TreeTableView;
-import javafx.scene.input.ClipboardContent;
-import javafx.scene.input.DragEvent;
-import javafx.scene.input.Dragboard;
-import javafx.scene.input.TransferMode;
-import javafx.scene.layout.StackPane;
-import javafx.scene.text.Text;
-
-import org.jabref.Globals;
-import org.jabref.gui.AbstractController;
-import org.jabref.gui.DialogService;
-import org.jabref.gui.DragAndDropDataFormats;
-import org.jabref.gui.StateManager;
-import org.jabref.gui.util.BindingsHelper;
-import org.jabref.gui.util.RecursiveTreeItem;
-import org.jabref.gui.util.TaskExecutor;
-import org.jabref.gui.util.ViewModelTreeTableCellFactory;
-import org.jabref.logic.l10n.Localization;
-import org.jabref.model.groups.AllEntriesGroup;
-
-import org.controlsfx.control.textfield.CustomTextField;
-import org.controlsfx.control.textfield.TextFields;
-import org.fxmisc.easybind.EasyBind;
-import org.reactfx.util.FxTimer;
-import org.reactfx.util.Timer;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class GroupTreeController extends AbstractController {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(GroupTreeController.class);
-
- @FXML private TreeTableView groupTree;
- @FXML private TreeTableColumn mainColumn;
- @FXML private TreeTableColumn numberColumn;
- @FXML private TreeTableColumn disclosureNodeColumn;
- @FXML private CustomTextField searchField;
-
- @Inject private StateManager stateManager;
- @Inject private DialogService dialogService;
- @Inject private TaskExecutor taskExecutor;
-
- private static void removePseudoClasses(TreeTableRow row, PseudoClass... pseudoClasses) {
- for (PseudoClass pseudoClass : pseudoClasses) {
- row.pseudoClassStateChanged(pseudoClass, false);
- }
- }
-
- @FXML
- public void initialize() {
- viewModel = new GroupTreeViewModel(stateManager, dialogService, taskExecutor);
-
- // Set-up groups tree
- groupTree.setStyle("-fx-font-size: " + Globals.prefs.getFontSizeFX() + "pt;");
- groupTree.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
-
- // Set-up bindings
- Consumer> updateSelectedGroups =
- (newSelectedGroups) -> newSelectedGroups.forEach(this::selectNode);
-
- BindingsHelper.bindContentBidirectional(
- groupTree.getSelectionModel().getSelectedItems(),
- viewModel.selectedGroupsProperty(),
- updateSelectedGroups,
- this::updateSelection
- );
-
- // We try to to prevent publishing changes in the search field directly to the search task that takes some time
- // for larger group structures.
- final Timer searchTask = FxTimer.create(Duration.ofMillis(400), () -> {
- LOGGER.debug("Run group search " + searchField.getText());
- viewModel.filterTextProperty().setValue(searchField.textProperty().getValue());
- });
- searchField.textProperty().addListener((observable, oldValue, newValue) -> searchTask.restart());
-
- groupTree.rootProperty().bind(
- EasyBind.map(viewModel.rootGroupProperty(),
- group -> new RecursiveTreeItem<>(
- group,
- GroupNodeViewModel::getChildren,
- GroupNodeViewModel::expandedProperty,
- viewModel.filterPredicateProperty())));
-
- // Icon and group name
- mainColumn.setCellValueFactory(cellData -> cellData.getValue().valueProperty());
- mainColumn.setCellFactory(new ViewModelTreeTableCellFactory()
- .withText(GroupNodeViewModel::getDisplayName)
- .withIcon(GroupNodeViewModel::getIcon)
- .withTooltip(GroupNodeViewModel::getDescription));
-
- // Number of hits
- PseudoClass anySelected = PseudoClass.getPseudoClass("any-selected");
- PseudoClass allSelected = PseudoClass.getPseudoClass("all-selected");
- numberColumn.setCellFactory(new ViewModelTreeTableCellFactory()
- .withGraphic(group -> {
- final StackPane node = new StackPane();
- node.getStyleClass().setAll("hits");
- if (!group.isRoot()) {
- BindingsHelper.includePseudoClassWhen(node, anySelected,
- group.anySelectedEntriesMatchedProperty());
- BindingsHelper.includePseudoClassWhen(node, allSelected,
- group.allSelectedEntriesMatchedProperty());
- }
- Text text = new Text();
- text.textProperty().bind(group.getHits().asString());
- text.getStyleClass().setAll("text");
- node.getChildren().add(text);
- node.setMaxWidth(Control.USE_PREF_SIZE);
- return node;
- }));
-
- // Arrow indicating expanded status
- disclosureNodeColumn.setCellValueFactory(cellData -> cellData.getValue().valueProperty());
- disclosureNodeColumn.setCellFactory(new ViewModelTreeTableCellFactory()
- .withGraphic(viewModel -> {
- final StackPane disclosureNode = new StackPane();
- disclosureNode.visibleProperty().bind(viewModel.hasChildrenProperty());
- disclosureNode.getStyleClass().setAll("tree-disclosure-node");
-
- final StackPane disclosureNodeArrow = new StackPane();
- disclosureNodeArrow.getStyleClass().setAll("arrow");
- disclosureNode.getChildren().add(disclosureNodeArrow);
- return disclosureNode;
- })
- .withOnMouseClickedEvent(group -> event -> group.toggleExpansion()));
-
- // Set pseudo-classes to indicate if row is root or sub-item ( > 1 deep)
- PseudoClass rootPseudoClass = PseudoClass.getPseudoClass("root");
- PseudoClass subElementPseudoClass = PseudoClass.getPseudoClass("sub");
-
- // Pseudo-classes for drag and drop
- PseudoClass dragOverBottom = PseudoClass.getPseudoClass("dragOver-bottom");
- PseudoClass dragOverCenter = PseudoClass.getPseudoClass("dragOver-center");
- PseudoClass dragOverTop = PseudoClass.getPseudoClass("dragOver-top");
- groupTree.setRowFactory(treeTable -> {
- TreeTableRow row = new TreeTableRow<>();
- row.treeItemProperty().addListener((ov, oldTreeItem, newTreeItem) -> {
- boolean isRoot = newTreeItem == treeTable.getRoot();
- row.pseudoClassStateChanged(rootPseudoClass, isRoot);
-
- boolean isFirstLevel = (newTreeItem != null) && (newTreeItem.getParent() == treeTable.getRoot());
- row.pseudoClassStateChanged(subElementPseudoClass, !isRoot && !isFirstLevel);
-
- });
- // Remove disclosure node since we display custom version in separate column
- // Simply setting to null is not enough since it would be replaced by the default node on every change
- row.setDisclosureNode(null);
- row.disclosureNodeProperty().addListener((observable, oldValue, newValue) -> row.setDisclosureNode(null));
-
- // Add context menu (only for non-null items)
- row.contextMenuProperty().bind(
- EasyBind.monadic(row.itemProperty())
- .map(this::createContextMenuForGroup)
- .orElse((ContextMenu) null));
-
- // Drag and drop support
- row.setOnDragDetected(event -> {
- TreeItem selectedItem = treeTable.getSelectionModel().getSelectedItem();
- if ((selectedItem != null) && (selectedItem.getValue() != null)) {
- Dragboard dragboard = treeTable.startDragAndDrop(TransferMode.MOVE);
-
- // Display the group when dragging
- dragboard.setDragView(row.snapshot(null, null));
-
- // Put the group node as content
- ClipboardContent content = new ClipboardContent();
- content.put(DragAndDropDataFormats.GROUP, selectedItem.getValue().getPath());
- dragboard.setContent(content);
-
- event.consume();
- }
- });
- row.setOnDragOver(event -> {
- Dragboard dragboard = event.getDragboard();
- if ((event.getGestureSource() != row) && row.getItem().acceptableDrop(dragboard)) {
- event.acceptTransferModes(TransferMode.MOVE, TransferMode.LINK);
-
- removePseudoClasses(row, dragOverBottom, dragOverCenter, dragOverTop);
- switch (getDroppingMouseLocation(row, event)) {
- case BOTTOM:
- row.pseudoClassStateChanged(dragOverBottom, true);
- break;
- case CENTER:
- row.pseudoClassStateChanged(dragOverCenter, true);
- break;
- case TOP:
- row.pseudoClassStateChanged(dragOverTop, true);
- break;
- }
- }
- event.consume();
- });
- row.setOnDragExited(event -> {
- removePseudoClasses(row, dragOverBottom, dragOverCenter, dragOverTop);
- });
-
- row.setOnDragDropped(event -> {
- Dragboard dragboard = event.getDragboard();
- boolean success = false;
- if (dragboard.hasContent(DragAndDropDataFormats.GROUP)) {
- String pathToSource = (String) dragboard.getContent(DragAndDropDataFormats.GROUP);
- Optional source = viewModel.rootGroupProperty().get()
- .getChildByPath(pathToSource);
- if (source.isPresent()) {
- source.get().draggedOn(row.getItem(), getDroppingMouseLocation(row, event));
- success = true;
- }
- }
- if (dragboard.hasContent(DragAndDropDataFormats.ENTRIES)) {
- TransferableEntrySelection entrySelection = (TransferableEntrySelection) dragboard
- .getContent(DragAndDropDataFormats.ENTRIES);
-
- row.getItem().addEntriesToGroup(entrySelection.getSelection());
- success = true;
- }
- event.setDropCompleted(success);
- event.consume();
- });
-
- return row;
- });
-
- // Filter text field
- setupClearButtonField(searchField);
- }
-
- private void updateSelection(List> newSelectedGroups) {
- if (newSelectedGroups == null || newSelectedGroups.isEmpty()) {
- viewModel.selectedGroupsProperty().clear();
- } else {
- List list = new ArrayList<>();
- for (TreeItem model : newSelectedGroups) {
- if (model != null && model.getValue() != null && !(model.getValue().getGroupNode().getGroup() instanceof AllEntriesGroup)) {
- list.add(model.getValue());
- }
- }
- viewModel.selectedGroupsProperty().setAll(list);
- }
- }
-
- private void selectNode(GroupNodeViewModel value) {
- getTreeItemByValue(value)
- .ifPresent(treeItem -> groupTree.getSelectionModel().select(treeItem));
- }
-
- private Optional> getTreeItemByValue(GroupNodeViewModel value) {
- return getTreeItemByValue(groupTree.getRoot(), value);
- }
-
- private Optional> getTreeItemByValue(TreeItem root,
- GroupNodeViewModel value) {
- if (root.getValue().equals(value)) {
- return Optional.of(root);
- }
-
- for (TreeItem child : root.getChildren()) {
- Optional> treeItemByValue = getTreeItemByValue(child, value);
- if (treeItemByValue.isPresent()) {
- return treeItemByValue;
- }
- }
-
- return Optional.empty();
- }
-
- private ContextMenu createContextMenuForGroup(GroupNodeViewModel group) {
- ContextMenu menu = new ContextMenu();
-
- MenuItem editGroup = new MenuItem(Localization.lang("Edit group"));
- editGroup.setOnAction(event -> {
- menu.hide();
- viewModel.editGroup(group);
- });
-
- MenuItem addSubgroup = new MenuItem(Localization.lang("Add subgroup"));
- addSubgroup.setOnAction(event -> {
- menu.hide();
- viewModel.addNewSubgroup(group);
- });
- MenuItem removeGroupAndSubgroups = new MenuItem(Localization.lang("Remove group and subgroups"));
- removeGroupAndSubgroups.setOnAction(event -> viewModel.removeGroupAndSubgroups(group));
- MenuItem removeGroupKeepSubgroups = new MenuItem(Localization.lang("Remove group, keep subgroups"));
- removeGroupKeepSubgroups.setOnAction(event -> viewModel.removeGroupKeepSubgroups(group));
- MenuItem removeSubgroups = new MenuItem(Localization.lang("Remove subgroups"));
- removeSubgroups.setOnAction(event -> viewModel.removeSubgroups(group));
-
- MenuItem addEntries = new MenuItem(Localization.lang("Add selected entries to this group"));
- addEntries.setOnAction(event -> viewModel.addSelectedEntries(group));
- MenuItem removeEntries = new MenuItem(Localization.lang("Remove selected entries from this group"));
- removeEntries.setOnAction(event -> viewModel.removeSelectedEntries(group));
-
- MenuItem sortAlphabetically = new MenuItem(Localization.lang("Sort all subgroups (recursively)"));
- sortAlphabetically.setOnAction(event -> viewModel.sortAlphabeticallyRecursive(group));
-
- menu.getItems().add(editGroup);
- menu.getItems().add(new SeparatorMenuItem());
- menu.getItems().addAll(addSubgroup, removeSubgroups, removeGroupAndSubgroups, removeGroupKeepSubgroups);
- menu.getItems().add(new SeparatorMenuItem());
- menu.getItems().addAll(addEntries, removeEntries);
- menu.getItems().add(new SeparatorMenuItem());
- menu.getItems().add(sortAlphabetically);
-
- // TODO: Disable some actions under certain conditions
- //if (group.canBeEdited()) {
- //editGroupPopupAction.setEnabled(false);
- //addGroupPopupAction.setEnabled(false);
- //removeGroupAndSubgroupsPopupAction.setEnabled(false);
- //removeGroupKeepSubgroupsPopupAction.setEnabled(false);
- //} else {
- //editGroupPopupAction.setEnabled(true);
- //addGroupPopupAction.setEnabled(true);
- //addGroupPopupAction.setNode(node);
- //removeGroupAndSubgroupsPopupAction.setEnabled(true);
- //removeGroupKeepSubgroupsPopupAction.setEnabled(true);
- //}
- //sortSubmenu.setEnabled(!node.isLeaf());
- //removeSubgroupsPopupAction.setEnabled(!node.isLeaf());
-
- return menu;
- }
-
- public void addNewGroup(ActionEvent actionEvent) {
- viewModel.addNewGroupToRoot();
- }
-
- /**
- * Workaround taken from https://bitbucket.org/controlsfx/controlsfx/issues/330/making-textfieldssetupclearbuttonfield
- */
- private void setupClearButtonField(CustomTextField customTextField) {
- try {
- Method m = TextFields.class.getDeclaredMethod("setupClearButtonField", TextField.class,
- ObjectProperty.class);
- m.setAccessible(true);
- m.invoke(null, customTextField, customTextField.rightProperty());
- } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) {
- LOGGER.error("Failed to decorate text field with clear button", ex);
- }
- }
-
- /**
- * Determines where the mouse is in the given row.
- */
- private DroppingMouseLocation getDroppingMouseLocation(TreeTableRow row, DragEvent event) {
- if ((row.getHeight() * 0.25) > event.getY()) {
- return DroppingMouseLocation.TOP;
- } else if ((row.getHeight() * 0.75) < event.getY()) {
- return DroppingMouseLocation.BOTTOM;
- } else {
- return DroppingMouseLocation.CENTER;
- }
- }
-}
diff --git a/src/main/java/org/jabref/gui/groups/GroupTreeView.java b/src/main/java/org/jabref/gui/groups/GroupTreeView.java
index 7d5955e5a5c..72fbec509d5 100644
--- a/src/main/java/org/jabref/gui/groups/GroupTreeView.java
+++ b/src/main/java/org/jabref/gui/groups/GroupTreeView.java
@@ -1,10 +1,378 @@
package org.jabref.gui.groups;
-import org.jabref.gui.AbstractView;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Consumer;
-public class GroupTreeView extends AbstractView {
+import javax.inject.Inject;
- public GroupTreeView() {
- super();
+import javafx.beans.property.ObjectProperty;
+import javafx.collections.ObservableList;
+import javafx.css.PseudoClass;
+import javafx.event.ActionEvent;
+import javafx.fxml.FXML;
+import javafx.scene.control.ContextMenu;
+import javafx.scene.control.Control;
+import javafx.scene.control.MenuItem;
+import javafx.scene.control.SelectionMode;
+import javafx.scene.control.SeparatorMenuItem;
+import javafx.scene.control.TextField;
+import javafx.scene.control.TreeItem;
+import javafx.scene.control.TreeTableColumn;
+import javafx.scene.control.TreeTableRow;
+import javafx.scene.control.TreeTableView;
+import javafx.scene.input.ClipboardContent;
+import javafx.scene.input.DragEvent;
+import javafx.scene.input.Dragboard;
+import javafx.scene.input.TransferMode;
+import javafx.scene.layout.StackPane;
+import javafx.scene.text.Text;
+
+import org.jabref.Globals;
+import org.jabref.gui.DialogService;
+import org.jabref.gui.DragAndDropDataFormats;
+import org.jabref.gui.StateManager;
+import org.jabref.gui.util.BindingsHelper;
+import org.jabref.gui.util.RecursiveTreeItem;
+import org.jabref.gui.util.TaskExecutor;
+import org.jabref.gui.util.ViewModelTreeTableCellFactory;
+import org.jabref.logic.l10n.Localization;
+import org.jabref.model.groups.AllEntriesGroup;
+
+import org.controlsfx.control.textfield.CustomTextField;
+import org.controlsfx.control.textfield.TextFields;
+import org.fxmisc.easybind.EasyBind;
+import org.reactfx.util.FxTimer;
+import org.reactfx.util.Timer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class GroupTreeView {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(GroupTreeView.class);
+
+ @FXML private TreeTableView groupTree;
+ @FXML private TreeTableColumn mainColumn;
+ @FXML private TreeTableColumn numberColumn;
+ @FXML private TreeTableColumn disclosureNodeColumn;
+ @FXML private CustomTextField searchField;
+
+ @Inject private StateManager stateManager;
+ @Inject private DialogService dialogService;
+ @Inject private TaskExecutor taskExecutor;
+ private GroupTreeViewModel viewModel;
+
+ private static void removePseudoClasses(TreeTableRow row, PseudoClass... pseudoClasses) {
+ for (PseudoClass pseudoClass : pseudoClasses) {
+ row.pseudoClassStateChanged(pseudoClass, false);
+ }
+ }
+
+ @FXML
+ public void initialize() {
+ viewModel = new GroupTreeViewModel(stateManager, dialogService, taskExecutor);
+
+ // Set-up groups tree
+ groupTree.setStyle("-fx-font-size: " + Globals.prefs.getFontSizeFX() + "pt;");
+ groupTree.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
+
+ // Set-up bindings
+ Consumer> updateSelectedGroups =
+ (newSelectedGroups) -> newSelectedGroups.forEach(this::selectNode);
+
+ BindingsHelper.bindContentBidirectional(
+ groupTree.getSelectionModel().getSelectedItems(),
+ viewModel.selectedGroupsProperty(),
+ updateSelectedGroups,
+ this::updateSelection
+ );
+
+ // We try to to prevent publishing changes in the search field directly to the search task that takes some time
+ // for larger group structures.
+ final Timer searchTask = FxTimer.create(Duration.ofMillis(400), () -> {
+ LOGGER.debug("Run group search " + searchField.getText());
+ viewModel.filterTextProperty().setValue(searchField.textProperty().getValue());
+ });
+ searchField.textProperty().addListener((observable, oldValue, newValue) -> searchTask.restart());
+
+ groupTree.rootProperty().bind(
+ EasyBind.map(viewModel.rootGroupProperty(),
+ group -> new RecursiveTreeItem<>(
+ group,
+ GroupNodeViewModel::getChildren,
+ GroupNodeViewModel::expandedProperty,
+ viewModel.filterPredicateProperty())));
+
+ // Icon and group name
+ mainColumn.setCellValueFactory(cellData -> cellData.getValue().valueProperty());
+ mainColumn.setCellFactory(new ViewModelTreeTableCellFactory()
+ .withText(GroupNodeViewModel::getDisplayName)
+ .withIcon(GroupNodeViewModel::getIcon)
+ .withTooltip(GroupNodeViewModel::getDescription));
+
+ // Number of hits
+ PseudoClass anySelected = PseudoClass.getPseudoClass("any-selected");
+ PseudoClass allSelected = PseudoClass.getPseudoClass("all-selected");
+ numberColumn.setCellFactory(new ViewModelTreeTableCellFactory()
+ .withGraphic(group -> {
+ final StackPane node = new StackPane();
+ node.getStyleClass().setAll("hits");
+ if (!group.isRoot()) {
+ BindingsHelper.includePseudoClassWhen(node, anySelected,
+ group.anySelectedEntriesMatchedProperty());
+ BindingsHelper.includePseudoClassWhen(node, allSelected,
+ group.allSelectedEntriesMatchedProperty());
+ }
+ Text text = new Text();
+ text.textProperty().bind(group.getHits().asString());
+ text.getStyleClass().setAll("text");
+ node.getChildren().add(text);
+ node.setMaxWidth(Control.USE_PREF_SIZE);
+ return node;
+ }));
+
+ // Arrow indicating expanded status
+ disclosureNodeColumn.setCellValueFactory(cellData -> cellData.getValue().valueProperty());
+ disclosureNodeColumn.setCellFactory(new ViewModelTreeTableCellFactory()
+ .withGraphic(viewModel -> {
+ final StackPane disclosureNode = new StackPane();
+ disclosureNode.visibleProperty().bind(viewModel.hasChildrenProperty());
+ disclosureNode.getStyleClass().setAll("tree-disclosure-node");
+
+ final StackPane disclosureNodeArrow = new StackPane();
+ disclosureNodeArrow.getStyleClass().setAll("arrow");
+ disclosureNode.getChildren().add(disclosureNodeArrow);
+ return disclosureNode;
+ })
+ .withOnMouseClickedEvent(group -> event -> group.toggleExpansion()));
+
+ // Set pseudo-classes to indicate if row is root or sub-item ( > 1 deep)
+ PseudoClass rootPseudoClass = PseudoClass.getPseudoClass("root");
+ PseudoClass subElementPseudoClass = PseudoClass.getPseudoClass("sub");
+
+ // Pseudo-classes for drag and drop
+ PseudoClass dragOverBottom = PseudoClass.getPseudoClass("dragOver-bottom");
+ PseudoClass dragOverCenter = PseudoClass.getPseudoClass("dragOver-center");
+ PseudoClass dragOverTop = PseudoClass.getPseudoClass("dragOver-top");
+ groupTree.setRowFactory(treeTable -> {
+ TreeTableRow row = new TreeTableRow<>();
+ row.treeItemProperty().addListener((ov, oldTreeItem, newTreeItem) -> {
+ boolean isRoot = newTreeItem == treeTable.getRoot();
+ row.pseudoClassStateChanged(rootPseudoClass, isRoot);
+
+ boolean isFirstLevel = (newTreeItem != null) && (newTreeItem.getParent() == treeTable.getRoot());
+ row.pseudoClassStateChanged(subElementPseudoClass, !isRoot && !isFirstLevel);
+
+ });
+ // Remove disclosure node since we display custom version in separate column
+ // Simply setting to null is not enough since it would be replaced by the default node on every change
+ row.setDisclosureNode(null);
+ row.disclosureNodeProperty().addListener((observable, oldValue, newValue) -> row.setDisclosureNode(null));
+
+ // Add context menu (only for non-null items)
+ row.contextMenuProperty().bind(
+ EasyBind.monadic(row.itemProperty())
+ .map(this::createContextMenuForGroup)
+ .orElse((ContextMenu) null));
+
+ // Drag and drop support
+ row.setOnDragDetected(event -> {
+ TreeItem selectedItem = treeTable.getSelectionModel().getSelectedItem();
+ if ((selectedItem != null) && (selectedItem.getValue() != null)) {
+ Dragboard dragboard = treeTable.startDragAndDrop(TransferMode.MOVE);
+
+ // Display the group when dragging
+ dragboard.setDragView(row.snapshot(null, null));
+
+ // Put the group node as content
+ ClipboardContent content = new ClipboardContent();
+ content.put(DragAndDropDataFormats.GROUP, selectedItem.getValue().getPath());
+ dragboard.setContent(content);
+
+ event.consume();
+ }
+ });
+ row.setOnDragOver(event -> {
+ Dragboard dragboard = event.getDragboard();
+ if ((event.getGestureSource() != row) && row.getItem().acceptableDrop(dragboard)) {
+ event.acceptTransferModes(TransferMode.MOVE, TransferMode.LINK);
+
+ removePseudoClasses(row, dragOverBottom, dragOverCenter, dragOverTop);
+ switch (getDroppingMouseLocation(row, event)) {
+ case BOTTOM:
+ row.pseudoClassStateChanged(dragOverBottom, true);
+ break;
+ case CENTER:
+ row.pseudoClassStateChanged(dragOverCenter, true);
+ break;
+ case TOP:
+ row.pseudoClassStateChanged(dragOverTop, true);
+ break;
+ }
+ }
+ event.consume();
+ });
+ row.setOnDragExited(event -> {
+ removePseudoClasses(row, dragOverBottom, dragOverCenter, dragOverTop);
+ });
+
+ row.setOnDragDropped(event -> {
+ Dragboard dragboard = event.getDragboard();
+ boolean success = false;
+ if (dragboard.hasContent(DragAndDropDataFormats.GROUP)) {
+ String pathToSource = (String) dragboard.getContent(DragAndDropDataFormats.GROUP);
+ Optional source = viewModel.rootGroupProperty().get()
+ .getChildByPath(pathToSource);
+ if (source.isPresent()) {
+ source.get().draggedOn(row.getItem(), getDroppingMouseLocation(row, event));
+ success = true;
+ }
+ }
+ if (dragboard.hasContent(DragAndDropDataFormats.ENTRIES)) {
+ TransferableEntrySelection entrySelection = (TransferableEntrySelection) dragboard
+ .getContent(DragAndDropDataFormats.ENTRIES);
+
+ row.getItem().addEntriesToGroup(entrySelection.getSelection());
+ success = true;
+ }
+ event.setDropCompleted(success);
+ event.consume();
+ });
+
+ return row;
+ });
+
+ // Filter text field
+ setupClearButtonField(searchField);
+ }
+
+ private void updateSelection(List> newSelectedGroups) {
+ if (newSelectedGroups == null || newSelectedGroups.isEmpty()) {
+ viewModel.selectedGroupsProperty().clear();
+ } else {
+ List list = new ArrayList<>();
+ for (TreeItem model : newSelectedGroups) {
+ if (model != null && model.getValue() != null && !(model.getValue().getGroupNode().getGroup() instanceof AllEntriesGroup)) {
+ list.add(model.getValue());
+ }
+ }
+ viewModel.selectedGroupsProperty().setAll(list);
+ }
+ }
+
+ private void selectNode(GroupNodeViewModel value) {
+ getTreeItemByValue(value)
+ .ifPresent(treeItem -> groupTree.getSelectionModel().select(treeItem));
+ }
+
+ private Optional> getTreeItemByValue(GroupNodeViewModel value) {
+ return getTreeItemByValue(groupTree.getRoot(), value);
+ }
+
+ private Optional> getTreeItemByValue(TreeItem root,
+ GroupNodeViewModel value) {
+ if (root.getValue().equals(value)) {
+ return Optional.of(root);
+ }
+
+ for (TreeItem child : root.getChildren()) {
+ Optional> treeItemByValue = getTreeItemByValue(child, value);
+ if (treeItemByValue.isPresent()) {
+ return treeItemByValue;
+ }
+ }
+
+ return Optional.empty();
+ }
+
+ private ContextMenu createContextMenuForGroup(GroupNodeViewModel group) {
+ ContextMenu menu = new ContextMenu();
+
+ MenuItem editGroup = new MenuItem(Localization.lang("Edit group"));
+ editGroup.setOnAction(event -> {
+ menu.hide();
+ viewModel.editGroup(group);
+ });
+
+ MenuItem addSubgroup = new MenuItem(Localization.lang("Add subgroup"));
+ addSubgroup.setOnAction(event -> {
+ menu.hide();
+ viewModel.addNewSubgroup(group);
+ });
+ MenuItem removeGroupAndSubgroups = new MenuItem(Localization.lang("Remove group and subgroups"));
+ removeGroupAndSubgroups.setOnAction(event -> viewModel.removeGroupAndSubgroups(group));
+ MenuItem removeGroupKeepSubgroups = new MenuItem(Localization.lang("Remove group, keep subgroups"));
+ removeGroupKeepSubgroups.setOnAction(event -> viewModel.removeGroupKeepSubgroups(group));
+ MenuItem removeSubgroups = new MenuItem(Localization.lang("Remove subgroups"));
+ removeSubgroups.setOnAction(event -> viewModel.removeSubgroups(group));
+
+ MenuItem addEntries = new MenuItem(Localization.lang("Add selected entries to this group"));
+ addEntries.setOnAction(event -> viewModel.addSelectedEntries(group));
+ MenuItem removeEntries = new MenuItem(Localization.lang("Remove selected entries from this group"));
+ removeEntries.setOnAction(event -> viewModel.removeSelectedEntries(group));
+
+ MenuItem sortAlphabetically = new MenuItem(Localization.lang("Sort all subgroups (recursively)"));
+ sortAlphabetically.setOnAction(event -> viewModel.sortAlphabeticallyRecursive(group));
+
+ menu.getItems().add(editGroup);
+ menu.getItems().add(new SeparatorMenuItem());
+ menu.getItems().addAll(addSubgroup, removeSubgroups, removeGroupAndSubgroups, removeGroupKeepSubgroups);
+ menu.getItems().add(new SeparatorMenuItem());
+ menu.getItems().addAll(addEntries, removeEntries);
+ menu.getItems().add(new SeparatorMenuItem());
+ menu.getItems().add(sortAlphabetically);
+
+ // TODO: Disable some actions under certain conditions
+ //if (group.canBeEdited()) {
+ //editGroupPopupAction.setEnabled(false);
+ //addGroupPopupAction.setEnabled(false);
+ //removeGroupAndSubgroupsPopupAction.setEnabled(false);
+ //removeGroupKeepSubgroupsPopupAction.setEnabled(false);
+ //} else {
+ //editGroupPopupAction.setEnabled(true);
+ //addGroupPopupAction.setEnabled(true);
+ //addGroupPopupAction.setNode(node);
+ //removeGroupAndSubgroupsPopupAction.setEnabled(true);
+ //removeGroupKeepSubgroupsPopupAction.setEnabled(true);
+ //}
+ //sortSubmenu.setEnabled(!node.isLeaf());
+ //removeSubgroupsPopupAction.setEnabled(!node.isLeaf());
+
+ return menu;
+ }
+
+ public void addNewGroup(ActionEvent actionEvent) {
+ viewModel.addNewGroupToRoot();
+ }
+
+ /**
+ * Workaround taken from https://bitbucket.org/controlsfx/controlsfx/issues/330/making-textfieldssetupclearbuttonfield
+ */
+ private void setupClearButtonField(CustomTextField customTextField) {
+ try {
+ Method m = TextFields.class.getDeclaredMethod("setupClearButtonField", TextField.class,
+ ObjectProperty.class);
+ m.setAccessible(true);
+ m.invoke(null, customTextField, customTextField.rightProperty());
+ } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) {
+ LOGGER.error("Failed to decorate text field with clear button", ex);
+ }
+ }
+
+ /**
+ * Determines where the mouse is in the given row.
+ */
+ private DroppingMouseLocation getDroppingMouseLocation(TreeTableRow row, DragEvent event) {
+ if ((row.getHeight() * 0.25) > event.getY()) {
+ return DroppingMouseLocation.TOP;
+ } else if ((row.getHeight() * 0.75) < event.getY()) {
+ return DroppingMouseLocation.BOTTOM;
+ } else {
+ return DroppingMouseLocation.CENTER;
+ }
}
}
diff --git a/src/main/resources/org/jabref/gui/help/AboutDialog.css b/src/main/java/org/jabref/gui/help/AboutDialog.css
similarity index 100%
rename from src/main/resources/org/jabref/gui/help/AboutDialog.css
rename to src/main/java/org/jabref/gui/help/AboutDialog.css
diff --git a/src/main/java/org/jabref/gui/help/AboutDialog.fxml b/src/main/java/org/jabref/gui/help/AboutDialog.fxml
new file mode 100644
index 00000000000..9ffe83aee39
--- /dev/null
+++ b/src/main/java/org/jabref/gui/help/AboutDialog.fxml
@@ -0,0 +1,91 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/java/org/jabref/gui/help/AboutDialogController.java b/src/main/java/org/jabref/gui/help/AboutDialogController.java
deleted file mode 100644
index 104e326cd38..00000000000
--- a/src/main/java/org/jabref/gui/help/AboutDialogController.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package org.jabref.gui.help;
-
-import javax.inject.Inject;
-
-import javafx.fxml.FXML;
-import javafx.scene.control.TextArea;
-import javafx.scene.image.Image;
-import javafx.scene.image.ImageView;
-
-import org.jabref.gui.AbstractController;
-import org.jabref.gui.ClipBoardManager;
-import org.jabref.gui.DialogService;
-import org.jabref.logic.util.BuildInfo;
-
-import de.codecentric.centerdevice.javafxsvg.SvgImageLoaderFactory;
-
-public class AboutDialogController extends AbstractController {
-
- @FXML protected ImageView iconImage;
- @Inject private DialogService dialogService;
- @Inject private ClipBoardManager clipBoardManager;
- @Inject private BuildInfo buildInfo;
-
- @FXML private TextArea textAreaVersions;
-
- @FXML
- private void initialize() {
- viewModel = new AboutDialogViewModel(dialogService, clipBoardManager, buildInfo);
-
- SvgImageLoaderFactory.install();
- Image icon = new Image(this.getClass().getResourceAsStream("/icons/jabref.svg"));
- iconImage.setImage(icon);
- textAreaVersions.setText(viewModel.getVersionInfo());
-
- }
-
- @FXML
- private void closeAboutDialog() {
- getStage().close();
- }
-
- @FXML
- private void copyVersionToClipboard() {
- viewModel.copyVersionToClipboard();
- }
-
- @FXML
- private void openJabrefWebsite() {
- viewModel.openJabrefWebsite();
- }
-
- @FXML
- private void openExternalLibrariesWebsite() {
- viewModel.openExternalLibrariesWebsite();
- }
-
- @FXML
- private void openGithub() {
- viewModel.openGithub();
- }
-
- @FXML
- public void openChangeLog() {
- viewModel.openChangeLog();
- }
-
- @FXML
- public void openLicense() {
- viewModel.openLicense();
- }
-
- @FXML
- public void openDonation() {
- viewModel.openDonation();
- }
-
-}
diff --git a/src/main/java/org/jabref/gui/help/AboutDialogView.java b/src/main/java/org/jabref/gui/help/AboutDialogView.java
index a716791d129..94f20f2adc9 100644
--- a/src/main/java/org/jabref/gui/help/AboutDialogView.java
+++ b/src/main/java/org/jabref/gui/help/AboutDialogView.java
@@ -1,19 +1,87 @@
package org.jabref.gui.help;
-import javafx.scene.control.Alert.AlertType;
-import javafx.scene.control.DialogPane;
+import javax.inject.Inject;
-import org.jabref.gui.AbstractDialogView;
-import org.jabref.gui.FXDialog;
+import javafx.fxml.FXML;
+import javafx.scene.control.ButtonType;
+import javafx.scene.control.TextArea;
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
+
+import org.jabref.gui.ClipBoardManager;
+import org.jabref.gui.DialogService;
+import org.jabref.gui.util.BaseDialog;
+import org.jabref.gui.util.ControlHelper;
import org.jabref.logic.l10n.Localization;
+import org.jabref.logic.util.BuildInfo;
+
+import com.airhacks.afterburner.views.ViewLoader;
+import de.codecentric.centerdevice.javafxsvg.SvgImageLoaderFactory;
+
+public class AboutDialogView extends BaseDialog {
+
+ @FXML private ButtonType copyVersionButton;
+ @FXML protected ImageView iconImage;
+ @Inject private DialogService dialogService;
+ @Inject private ClipBoardManager clipBoardManager;
+ @Inject private BuildInfo buildInfo;
+
+ @FXML private TextArea textAreaVersions;
+ private AboutDialogViewModel viewModel;
+
+ public AboutDialogView() {
+ this.setTitle(Localization.lang("About JabRef"));
+
+ ViewLoader.view(this)
+ .load()
+ .setAsDialogPane(this);
+
+ ControlHelper.setAction(copyVersionButton, getDialogPane(), event -> copyVersionToClipboard());
+ }
+
+ @FXML
+ private void initialize() {
+ viewModel = new AboutDialogViewModel(dialogService, clipBoardManager, buildInfo);
+
+ SvgImageLoaderFactory.install();
+ Image icon = new Image(this.getClass().getResourceAsStream("/icons/jabref.svg"));
+ iconImage.setImage(icon);
+ textAreaVersions.setText(viewModel.getVersionInfo());
+ }
-public class AboutDialogView extends AbstractDialogView {
+ @FXML
+ private void copyVersionToClipboard() {
+ viewModel.copyVersionToClipboard();
+ }
+
+ @FXML
+ private void openJabrefWebsite() {
+ viewModel.openJabrefWebsite();
+ }
+
+ @FXML
+ private void openExternalLibrariesWebsite() {
+ viewModel.openExternalLibrariesWebsite();
+ }
+
+ @FXML
+ private void openGithub() {
+ viewModel.openGithub();
+ }
+
+ @FXML
+ public void openChangeLog() {
+ viewModel.openChangeLog();
+ }
+
+ @FXML
+ public void openLicense() {
+ viewModel.openLicense();
+ }
- @Override
- public void show() {
- FXDialog aboutDialog = new FXDialog(AlertType.INFORMATION, Localization.lang("About JabRef"));
- aboutDialog.setDialogPane((DialogPane) this.getView());
- aboutDialog.show();
+ @FXML
+ public void openDonation() {
+ viewModel.openDonation();
}
}
diff --git a/src/main/resources/org/jabref/gui/journals/ManageJournalAbbreviations.css b/src/main/java/org/jabref/gui/journals/ManageJournalAbbreviations.css
similarity index 100%
rename from src/main/resources/org/jabref/gui/journals/ManageJournalAbbreviations.css
rename to src/main/java/org/jabref/gui/journals/ManageJournalAbbreviations.css
diff --git a/src/main/resources/org/jabref/gui/journals/ManageJournalAbbreviations.fxml b/src/main/java/org/jabref/gui/journals/ManageJournalAbbreviations.fxml
similarity index 93%
rename from src/main/resources/org/jabref/gui/journals/ManageJournalAbbreviations.fxml
rename to src/main/java/org/jabref/gui/journals/ManageJournalAbbreviations.fxml
index aa54596b500..93115e01b8e 100644
--- a/src/main/resources/org/jabref/gui/journals/ManageJournalAbbreviations.fxml
+++ b/src/main/java/org/jabref/gui/journals/ManageJournalAbbreviations.fxml
@@ -12,7 +12,9 @@
-
+
diff --git a/src/main/java/org/jabref/gui/journals/ManageJournalAbbreviationsController.java b/src/main/java/org/jabref/gui/journals/ManageJournalAbbreviationsController.java
deleted file mode 100644
index 5e6bc92591d..00000000000
--- a/src/main/java/org/jabref/gui/journals/ManageJournalAbbreviationsController.java
+++ /dev/null
@@ -1,365 +0,0 @@
-package org.jabref.gui.journals;
-
-import javax.inject.Inject;
-
-import javafx.concurrent.Task;
-import javafx.fxml.FXML;
-import javafx.scene.control.Button;
-import javafx.scene.control.ComboBox;
-import javafx.scene.control.Label;
-import javafx.scene.control.ProgressIndicator;
-import javafx.scene.control.TableCell;
-import javafx.scene.control.TableColumn;
-import javafx.scene.control.TableView;
-import javafx.scene.control.TextField;
-import javafx.scene.input.KeyCode;
-import javafx.stage.Stage;
-
-import org.jabref.gui.AbstractController;
-import org.jabref.gui.DialogService;
-import org.jabref.gui.IconTheme;
-import org.jabref.gui.util.TaskExecutor;
-import org.jabref.gui.util.ValueTableCellFactory;
-import org.jabref.logic.journals.JournalAbbreviationLoader;
-import org.jabref.preferences.PreferencesService;
-
-public class ManageJournalAbbreviationsController extends AbstractController {
-
- @FXML public Label loadingLabel;
- @FXML public ProgressIndicator progressIndicator;
- @FXML private TableView journalAbbreviationsTable;
- @FXML private TableColumn journalTableNameColumn;
- @FXML private TableColumn journalTableAbbreviationColumn;
- @FXML private TableColumn journalTableEditColumn;
- @FXML private TableColumn journalTableDeleteColumn;
- @FXML private Button cancelButton;
- @FXML private ComboBox journalFilesBox;
- @FXML private Button addJournalFileButton;
- @FXML private Button addNewJournalFileButton;
- @FXML private Button removeJournalAbbreviationsButton;
- @Inject private PreferencesService preferences;
- @Inject private DialogService dialogService;
- @Inject private TaskExecutor taskExecutor;
- @Inject private JournalAbbreviationLoader journalAbbreviationLoader;
-
- @FXML
- private void initialize() {
- viewModel = new ManageJournalAbbreviationsViewModel(preferences, dialogService, taskExecutor, journalAbbreviationLoader);
-
- setUpTable();
- setBindings();
- setButtonStyles();
- viewModel.init();
- }
-
- private void setButtonStyles() {
- addJournalFileButton.setGraphic(IconTheme.JabRefIcons.OPEN.getGraphicNode());
- addNewJournalFileButton.setGraphic(IconTheme.JabRefIcons.NEW.getGraphicNode());
- removeJournalAbbreviationsButton.setGraphic(IconTheme.JabRefIcons.CLOSE.getGraphicNode());
- }
-
- private void setUpTable() {
- journalAbbreviationsTable.setOnKeyPressed(event -> {
- if (event.getCode() == KeyCode.DELETE) {
- viewModel.deleteAbbreviation();
- }
- });
- journalTableNameColumn.setCellValueFactory(cellData -> cellData.getValue().nameProperty());
- journalTableNameColumn.setCellFactory(cell -> new JournalAbbreviationsNameTableEditingCell());
- journalTableAbbreviationColumn.setCellValueFactory(cellData -> cellData.getValue().abbreviationProperty());
- journalTableAbbreviationColumn.setCellFactory(cell -> new JournalAbbreviationsAbbreviationTableEditingCell());
- journalTableEditColumn.setCellValueFactory(cellData -> cellData.getValue().isPseudoAbbreviationProperty());
- journalTableDeleteColumn.setCellValueFactory(cellData -> cellData.getValue().isPseudoAbbreviationProperty());
- journalTableEditColumn.setCellFactory(new ValueTableCellFactory().
- withGraphic(isPseudoAbbreviation -> {
- if (isPseudoAbbreviation) {
- return IconTheme.JabRefIcons.ADD.getGraphicNode();
- } else {
- return viewModel.isAbbreviationEditableAndRemovable() ?
- IconTheme.JabRefIcons.EDIT.getGraphicNode() : null;
- }
- }).
- withOnMouseClickedEvent(isPseudoAbbreviation -> {
- if (isPseudoAbbreviation) {
- return evt -> addAbbreviation();
- } else {
- return viewModel.isAbbreviationEditableAndRemovable() ?
- evt -> editAbbreviation() : evt -> {
- };
- }
- })
- );
-
- journalTableDeleteColumn.setCellFactory(new ValueTableCellFactory().
- withGraphic(isPseudoAbbreviation -> {
- if (!isPseudoAbbreviation && viewModel.isAbbreviationEditableAndRemovable()) {
- return IconTheme.JabRefIcons.DELETE_ENTRY.getGraphicNode();
- } else {
- return null;
- }
- }).
- withOnMouseClickedEvent(isPseudoAbbreviation -> {
- if (!isPseudoAbbreviation && viewModel.isAbbreviationEditableAndRemovable()) {
- return evt -> removeAbbreviation();
- } else {
- return evt -> {
- };
- }
- })
- );
- }
-
- private void setBindings() {
- journalAbbreviationsTable.itemsProperty().bindBidirectional(viewModel.abbreviationsProperty());
- journalFilesBox.itemsProperty().bindBidirectional(viewModel.journalFilesProperty());
-
- viewModel.currentFileProperty().addListener((observable, oldvalue, newvalue) ->
- journalFilesBox.getSelectionModel().select(newvalue));
- journalFilesBox.getSelectionModel().selectedItemProperty()
- .addListener((observable, oldvalue, newvalue) -> viewModel.currentFileProperty().set(newvalue));
-
- viewModel.currentAbbreviationProperty().addListener((observable, oldvalue, newvalue) ->
- journalAbbreviationsTable.getSelectionModel().select(newvalue));
- journalAbbreviationsTable.getSelectionModel().selectedItemProperty()
- .addListener((observable, oldvalue, newvalue) -> viewModel.currentAbbreviationProperty().set(newvalue));
-
- removeJournalAbbreviationsButton.disableProperty().bind(viewModel.isFileRemovableProperty().not());
-
- loadingLabel.visibleProperty().bind(viewModel.isLoadingProperty());
- progressIndicator.visibleProperty().bind(viewModel.isLoadingProperty());
- }
-
- @FXML
- private void addNewFile() {
- viewModel.addNewFile();
- }
-
- @FXML
- private void openFile() {
- viewModel.openFile();
- }
-
- @FXML
- private void removeList() {
- viewModel.removeCurrentFile();
- }
-
- @FXML
- private void addAbbreviation() {
- viewModel.addAbbreviation();
- selectNewAbbreviation();
- }
-
- @FXML
- private void editAbbreviation() {
- journalAbbreviationsTable.edit(journalAbbreviationsTable.getSelectionModel().getSelectedIndex(),
- journalTableNameColumn);
- }
-
- private void selectNewAbbreviation() {
- int lastRow = viewModel.abbreviationsCountProperty().get() - 1;
- journalAbbreviationsTable.scrollTo(lastRow);
- journalAbbreviationsTable.getSelectionModel().select(lastRow);
- journalAbbreviationsTable.getFocusModel().focus(lastRow);
- }
-
- @FXML
- private void removeAbbreviation() {
- viewModel.deleteAbbreviation();
- }
-
- @FXML
- private void closeDialog() {
- Stage stage = (Stage) cancelButton.getScene().getWindow();
- stage.close();
- }
-
- @FXML
- private void saveAbbreviationsAndCloseDialog() {
- Task task = new Task() {
-
- @Override
- protected Void call() {
- viewModel.saveEverythingAndUpdateAutoCompleter();
- return null;
- }
- };
- new Thread(task).start();
- closeDialog();
- }
-
-
- /**
- * This class provides a editable text field that is used as table cell.
- * It handles the editing of the name column.
- */
- public class JournalAbbreviationsNameTableEditingCell extends TableCell {
-
- private TextField textField;
- private String oldName;
- private int editingIndex;
-
- @Override
- public void startEdit() {
- if (!isEmpty() && viewModel.isAbbreviationEditableAndRemovableProperty().get()) {
- oldName = viewModel.currentAbbreviationProperty().get().getName();
- super.startEdit();
- createTextField();
- setText(null);
- setGraphic(textField);
- editingIndex = journalAbbreviationsTable.getSelectionModel().getSelectedIndex();
- textField.requestFocus();
- textField.selectAll();
- }
- }
-
- @Override
- public void cancelEdit() {
- super.cancelEdit();
- setText(getItem());
- setGraphic(null);
- journalAbbreviationsTable.itemsProperty().get().get(editingIndex).setName(oldName);
- }
-
- @Override
- public void updateItem(String item, boolean empty) {
- super.updateItem(item, empty);
- if (empty) {
- setText(null);
- setGraphic(null);
- } else {
- if (isEditing()) {
- if (textField != null) {
- textField.setText(getString());
- }
- setText(null);
- setGraphic(textField);
- } else {
- setText(getString());
- setGraphic(null);
- }
- }
- }
-
- @Override
- public void commitEdit(String name) {
- journalAbbreviationsTable.getSelectionModel().select(editingIndex);
- AbbreviationViewModel current = viewModel.currentAbbreviationProperty().get();
- super.commitEdit(name);
- current.setName(oldName);
- viewModel.editAbbreviation(name, current.getAbbreviation());
- }
-
- private void createTextField() {
- textField = new TextField(getString());
- textField.setMinWidth(this.getWidth() - (this.getGraphicTextGap() * 2));
- textField.focusedProperty().addListener((observable, oldValue, newValue) -> {
- if (!newValue) {
- commitEdit(textField.getText());
- }
- });
- textField.setOnKeyPressed(t -> {
- if (t.getCode() == KeyCode.ENTER) {
- if (isEditing()) {
- journalAbbreviationsTable.requestFocus();
- } else {
- startEdit();
- }
- } else if (t.getCode() == KeyCode.ESCAPE) {
- cancelEdit();
- }
- });
- }
-
- private String getString() {
- return getItem() == null ? "" : getItem();
- }
- }
-
- /**
- * This class provides a editable text field that is used as table cell.
- * It handles the editing of the abbreviation column.
- */
- public class JournalAbbreviationsAbbreviationTableEditingCell extends TableCell {
-
- private TextField textField;
- private String oldAbbreviation;
- private int editingIndex;
-
- @Override
- public void startEdit() {
- if (!isEmpty() && viewModel.isAbbreviationEditableAndRemovableProperty().get()) {
- oldAbbreviation = viewModel.currentAbbreviationProperty().get().getAbbreviation();
- super.startEdit();
- createTextField();
- setText(null);
- setGraphic(textField);
- editingIndex = journalAbbreviationsTable.getSelectionModel().getSelectedIndex();
- textField.requestFocus();
- textField.selectAll();
- }
- }
-
- @Override
- public void cancelEdit() {
- super.cancelEdit();
- setText(getItem());
- setGraphic(null);
- journalAbbreviationsTable.itemsProperty().get().get(editingIndex).setAbbreviation(oldAbbreviation);
- }
-
- @Override
- public void updateItem(String item, boolean empty) {
- super.updateItem(item, empty);
- if (empty) {
- setText(null);
- setGraphic(null);
- } else {
- if (isEditing()) {
- if (textField != null) {
- textField.setText(getString());
- }
- setText(null);
- setGraphic(textField);
- } else {
- setText(getString());
- setGraphic(null);
- }
- }
- }
-
- @Override
- public void commitEdit(String abbreviation) {
- journalAbbreviationsTable.getSelectionModel().select(editingIndex);
- AbbreviationViewModel current = viewModel.currentAbbreviationProperty().get();
- super.commitEdit(abbreviation);
- current.setAbbreviation(oldAbbreviation);
- viewModel.editAbbreviation(current.getName(), abbreviation);
- }
-
- private void createTextField() {
- textField = new TextField(getString());
- textField.setMinWidth(this.getWidth() - (this.getGraphicTextGap() * 2));
- textField.focusedProperty().addListener((observable, oldValue, newValue) -> {
- if (!newValue) {
- commitEdit(textField.getText());
- }
- });
- textField.setOnKeyPressed(t -> {
- if (t.getCode() == KeyCode.ENTER) {
- if (isEditing()) {
- journalAbbreviationsTable.requestFocus();
- } else {
- startEdit();
- }
- } else if (t.getCode() == KeyCode.ESCAPE) {
- cancelEdit();
- }
- });
- }
-
- private String getString() {
- return getItem() == null ? "" : getItem();
- }
- }
-}
diff --git a/src/main/java/org/jabref/gui/journals/ManageJournalAbbreviationsView.java b/src/main/java/org/jabref/gui/journals/ManageJournalAbbreviationsView.java
index 77e9fd2514b..294d8733758 100644
--- a/src/main/java/org/jabref/gui/journals/ManageJournalAbbreviationsView.java
+++ b/src/main/java/org/jabref/gui/journals/ManageJournalAbbreviationsView.java
@@ -1,23 +1,382 @@
package org.jabref.gui.journals;
-import javafx.scene.control.Alert.AlertType;
-import javafx.scene.control.DialogPane;
+import javax.inject.Inject;
-import org.jabref.gui.AbstractDialogView;
-import org.jabref.gui.FXDialog;
+import javafx.concurrent.Task;
+import javafx.fxml.FXML;
+import javafx.scene.control.Button;
+import javafx.scene.control.ComboBox;
+import javafx.scene.control.Label;
+import javafx.scene.control.ProgressIndicator;
+import javafx.scene.control.TableCell;
+import javafx.scene.control.TableColumn;
+import javafx.scene.control.TableView;
+import javafx.scene.control.TextField;
+import javafx.scene.input.KeyCode;
+import javafx.stage.Stage;
+
+import org.jabref.gui.DialogService;
+import org.jabref.gui.IconTheme;
+import org.jabref.gui.util.BaseDialog;
+import org.jabref.gui.util.TaskExecutor;
+import org.jabref.gui.util.ValueTableCellFactory;
+import org.jabref.logic.journals.JournalAbbreviationLoader;
import org.jabref.logic.l10n.Localization;
+import org.jabref.preferences.PreferencesService;
+
+import com.airhacks.afterburner.views.ViewLoader;
/**
* This class controls the user interface of the journal abbreviations dialog.
- * The ui elements and their layout are defined in the fxml file in the resource folder.
+ * The ui elements and their layout are defined in the fxml file.
*/
-public class ManageJournalAbbreviationsView extends AbstractDialogView {
-
- @Override
- public void show() {
- FXDialog journalAbbreviationsDialog = new FXDialog(AlertType.INFORMATION, Localization.lang("Journal abbreviations"));
- journalAbbreviationsDialog.setResizable(true);
- journalAbbreviationsDialog.setDialogPane((DialogPane) this.getView());
- journalAbbreviationsDialog.show();
+public class ManageJournalAbbreviationsView extends BaseDialog {
+
+ @FXML public Label loadingLabel;
+ @FXML public ProgressIndicator progressIndicator;
+ @FXML private TableView journalAbbreviationsTable;
+ @FXML private TableColumn journalTableNameColumn;
+ @FXML private TableColumn journalTableAbbreviationColumn;
+ @FXML private TableColumn journalTableEditColumn;
+ @FXML private TableColumn journalTableDeleteColumn;
+ @FXML private Button cancelButton;
+ @FXML private ComboBox journalFilesBox;
+ @FXML private Button addJournalFileButton;
+ @FXML private Button addNewJournalFileButton;
+ @FXML private Button removeJournalAbbreviationsButton;
+ @Inject private PreferencesService preferences;
+ @Inject private DialogService dialogService;
+ @Inject private TaskExecutor taskExecutor;
+ @Inject private JournalAbbreviationLoader journalAbbreviationLoader;
+ private ManageJournalAbbreviationsViewModel viewModel;
+
+ public ManageJournalAbbreviationsView() {
+ this.setTitle(Localization.lang("Journal abbreviations"));
+ this.setResizable(true);
+
+ ViewLoader.view(this)
+ .load()
+ .setAsDialogPane(this);
+ }
+
+ @FXML
+ private void initialize() {
+ viewModel = new ManageJournalAbbreviationsViewModel(preferences, dialogService, taskExecutor, journalAbbreviationLoader);
+
+ setUpTable();
+ setBindings();
+ setButtonStyles();
+ viewModel.init();
+ }
+
+ private void setButtonStyles() {
+ addJournalFileButton.setGraphic(IconTheme.JabRefIcons.OPEN.getGraphicNode());
+ addNewJournalFileButton.setGraphic(IconTheme.JabRefIcons.NEW.getGraphicNode());
+ removeJournalAbbreviationsButton.setGraphic(IconTheme.JabRefIcons.CLOSE.getGraphicNode());
+ }
+
+ private void setUpTable() {
+ journalAbbreviationsTable.setOnKeyPressed(event -> {
+ if (event.getCode() == KeyCode.DELETE) {
+ viewModel.deleteAbbreviation();
+ }
+ });
+ journalTableNameColumn.setCellValueFactory(cellData -> cellData.getValue().nameProperty());
+ journalTableNameColumn.setCellFactory(cell -> new JournalAbbreviationsNameTableEditingCell());
+ journalTableAbbreviationColumn.setCellValueFactory(cellData -> cellData.getValue().abbreviationProperty());
+ journalTableAbbreviationColumn.setCellFactory(cell -> new JournalAbbreviationsAbbreviationTableEditingCell());
+ journalTableEditColumn.setCellValueFactory(cellData -> cellData.getValue().isPseudoAbbreviationProperty());
+ journalTableDeleteColumn.setCellValueFactory(cellData -> cellData.getValue().isPseudoAbbreviationProperty());
+ journalTableEditColumn.setCellFactory(new ValueTableCellFactory().
+ withGraphic(isPseudoAbbreviation -> {
+ if (isPseudoAbbreviation) {
+ return IconTheme.JabRefIcons.ADD.getGraphicNode();
+ } else {
+ return viewModel.isAbbreviationEditableAndRemovable() ?
+ IconTheme.JabRefIcons.EDIT.getGraphicNode() : null;
+ }
+ }).
+ withOnMouseClickedEvent(isPseudoAbbreviation -> {
+ if (isPseudoAbbreviation) {
+ return evt -> addAbbreviation();
+ } else {
+ return viewModel.isAbbreviationEditableAndRemovable() ?
+ evt -> editAbbreviation() : evt -> {
+ };
+ }
+ })
+ );
+
+ journalTableDeleteColumn.setCellFactory(new ValueTableCellFactory().
+ withGraphic(isPseudoAbbreviation -> {
+ if (!isPseudoAbbreviation && viewModel.isAbbreviationEditableAndRemovable()) {
+ return IconTheme.JabRefIcons.DELETE_ENTRY.getGraphicNode();
+ } else {
+ return null;
+ }
+ }).
+ withOnMouseClickedEvent(isPseudoAbbreviation -> {
+ if (!isPseudoAbbreviation && viewModel.isAbbreviationEditableAndRemovable()) {
+ return evt -> removeAbbreviation();
+ } else {
+ return evt -> {
+ };
+ }
+ })
+ );
+ }
+
+ private void setBindings() {
+ journalAbbreviationsTable.itemsProperty().bindBidirectional(viewModel.abbreviationsProperty());
+ journalFilesBox.itemsProperty().bindBidirectional(viewModel.journalFilesProperty());
+
+ viewModel.currentFileProperty().addListener((observable, oldvalue, newvalue) ->
+ journalFilesBox.getSelectionModel().select(newvalue));
+ journalFilesBox.getSelectionModel().selectedItemProperty()
+ .addListener((observable, oldvalue, newvalue) -> viewModel.currentFileProperty().set(newvalue));
+
+ viewModel.currentAbbreviationProperty().addListener((observable, oldvalue, newvalue) ->
+ journalAbbreviationsTable.getSelectionModel().select(newvalue));
+ journalAbbreviationsTable.getSelectionModel().selectedItemProperty()
+ .addListener((observable, oldvalue, newvalue) -> viewModel.currentAbbreviationProperty().set(newvalue));
+
+ removeJournalAbbreviationsButton.disableProperty().bind(viewModel.isFileRemovableProperty().not());
+
+ loadingLabel.visibleProperty().bind(viewModel.isLoadingProperty());
+ progressIndicator.visibleProperty().bind(viewModel.isLoadingProperty());
+ }
+
+ @FXML
+ private void addNewFile() {
+ viewModel.addNewFile();
+ }
+
+ @FXML
+ private void openFile() {
+ viewModel.openFile();
+ }
+
+ @FXML
+ private void removeList() {
+ viewModel.removeCurrentFile();
+ }
+
+ @FXML
+ private void addAbbreviation() {
+ viewModel.addAbbreviation();
+ selectNewAbbreviation();
+ }
+
+ @FXML
+ private void editAbbreviation() {
+ journalAbbreviationsTable.edit(journalAbbreviationsTable.getSelectionModel().getSelectedIndex(),
+ journalTableNameColumn);
+ }
+
+ private void selectNewAbbreviation() {
+ int lastRow = viewModel.abbreviationsCountProperty().get() - 1;
+ journalAbbreviationsTable.scrollTo(lastRow);
+ journalAbbreviationsTable.getSelectionModel().select(lastRow);
+ journalAbbreviationsTable.getFocusModel().focus(lastRow);
+ }
+
+ @FXML
+ private void removeAbbreviation() {
+ viewModel.deleteAbbreviation();
+ }
+
+ @FXML
+ private void closeDialog() {
+ Stage stage = (Stage) cancelButton.getScene().getWindow();
+ stage.close();
+ }
+
+ @FXML
+ private void saveAbbreviationsAndCloseDialog() {
+ Task task = new Task() {
+
+ @Override
+ protected Void call() {
+ viewModel.saveEverythingAndUpdateAutoCompleter();
+ return null;
+ }
+ };
+ new Thread(task).start();
+ closeDialog();
+ }
+
+
+ /**
+ * This class provides a editable text field that is used as table cell.
+ * It handles the editing of the name column.
+ */
+ public class JournalAbbreviationsNameTableEditingCell extends TableCell {
+
+ private TextField textField;
+ private String oldName;
+ private int editingIndex;
+
+ @Override
+ public void startEdit() {
+ if (!isEmpty() && viewModel.isAbbreviationEditableAndRemovableProperty().get()) {
+ oldName = viewModel.currentAbbreviationProperty().get().getName();
+ super.startEdit();
+ createTextField();
+ setText(null);
+ setGraphic(textField);
+ editingIndex = journalAbbreviationsTable.getSelectionModel().getSelectedIndex();
+ textField.requestFocus();
+ textField.selectAll();
+ }
+ }
+
+ @Override
+ public void cancelEdit() {
+ super.cancelEdit();
+ setText(getItem());
+ setGraphic(null);
+ journalAbbreviationsTable.itemsProperty().get().get(editingIndex).setName(oldName);
+ }
+
+ @Override
+ public void updateItem(String item, boolean empty) {
+ super.updateItem(item, empty);
+ if (empty) {
+ setText(null);
+ setGraphic(null);
+ } else {
+ if (isEditing()) {
+ if (textField != null) {
+ textField.setText(getString());
+ }
+ setText(null);
+ setGraphic(textField);
+ } else {
+ setText(getString());
+ setGraphic(null);
+ }
+ }
+ }
+
+ @Override
+ public void commitEdit(String name) {
+ journalAbbreviationsTable.getSelectionModel().select(editingIndex);
+ AbbreviationViewModel current = viewModel.currentAbbreviationProperty().get();
+ super.commitEdit(name);
+ current.setName(oldName);
+ viewModel.editAbbreviation(name, current.getAbbreviation());
+ }
+
+ private void createTextField() {
+ textField = new TextField(getString());
+ textField.setMinWidth(this.getWidth() - (this.getGraphicTextGap() * 2));
+ textField.focusedProperty().addListener((observable, oldValue, newValue) -> {
+ if (!newValue) {
+ commitEdit(textField.getText());
+ }
+ });
+ textField.setOnKeyPressed(t -> {
+ if (t.getCode() == KeyCode.ENTER) {
+ if (isEditing()) {
+ journalAbbreviationsTable.requestFocus();
+ } else {
+ startEdit();
+ }
+ } else if (t.getCode() == KeyCode.ESCAPE) {
+ cancelEdit();
+ }
+ });
+ }
+
+ private String getString() {
+ return getItem() == null ? "" : getItem();
+ }
+ }
+
+ /**
+ * This class provides a editable text field that is used as table cell.
+ * It handles the editing of the abbreviation column.
+ */
+ public class JournalAbbreviationsAbbreviationTableEditingCell extends TableCell {
+
+ private TextField textField;
+ private String oldAbbreviation;
+ private int editingIndex;
+
+ @Override
+ public void startEdit() {
+ if (!isEmpty() && viewModel.isAbbreviationEditableAndRemovableProperty().get()) {
+ oldAbbreviation = viewModel.currentAbbreviationProperty().get().getAbbreviation();
+ super.startEdit();
+ createTextField();
+ setText(null);
+ setGraphic(textField);
+ editingIndex = journalAbbreviationsTable.getSelectionModel().getSelectedIndex();
+ textField.requestFocus();
+ textField.selectAll();
+ }
+ }
+
+ @Override
+ public void cancelEdit() {
+ super.cancelEdit();
+ setText(getItem());
+ setGraphic(null);
+ journalAbbreviationsTable.itemsProperty().get().get(editingIndex).setAbbreviation(oldAbbreviation);
+ }
+
+ @Override
+ public void updateItem(String item, boolean empty) {
+ super.updateItem(item, empty);
+ if (empty) {
+ setText(null);
+ setGraphic(null);
+ } else {
+ if (isEditing()) {
+ if (textField != null) {
+ textField.setText(getString());
+ }
+ setText(null);
+ setGraphic(textField);
+ } else {
+ setText(getString());
+ setGraphic(null);
+ }
+ }
+ }
+
+ @Override
+ public void commitEdit(String abbreviation) {
+ journalAbbreviationsTable.getSelectionModel().select(editingIndex);
+ AbbreviationViewModel current = viewModel.currentAbbreviationProperty().get();
+ super.commitEdit(abbreviation);
+ current.setAbbreviation(oldAbbreviation);
+ viewModel.editAbbreviation(current.getName(), abbreviation);
+ }
+
+ private void createTextField() {
+ textField = new TextField(getString());
+ textField.setMinWidth(this.getWidth() - (this.getGraphicTextGap() * 2));
+ textField.focusedProperty().addListener((observable, oldValue, newValue) -> {
+ if (!newValue) {
+ commitEdit(textField.getText());
+ }
+ });
+ textField.setOnKeyPressed(t -> {
+ if (t.getCode() == KeyCode.ENTER) {
+ if (isEditing()) {
+ journalAbbreviationsTable.requestFocus();
+ } else {
+ startEdit();
+ }
+ } else if (t.getCode() == KeyCode.ESCAPE) {
+ cancelEdit();
+ }
+ });
+ }
+
+ private String getString() {
+ return getItem() == null ? "" : getItem();
+ }
}
}
diff --git a/src/main/resources/org/jabref/gui/keyboard/KeyBindingsDialog.css b/src/main/java/org/jabref/gui/keyboard/KeyBindingsDialog.css
similarity index 78%
rename from src/main/resources/org/jabref/gui/keyboard/KeyBindingsDialog.css
rename to src/main/java/org/jabref/gui/keyboard/KeyBindingsDialog.css
index afd0aa4b923..ea478c35761 100644
--- a/src/main/resources/org/jabref/gui/keyboard/KeyBindingsDialog.css
+++ b/src/main/java/org/jabref/gui/keyboard/KeyBindingsDialog.css
@@ -9,8 +9,3 @@
.tree-table-row-cell:selected > .tree-table-cell > .icon, .tree-table-row-cell:pressed > .tree-table-cell > .icon {
-fx-fill: white;
}
-
-.dialog-pane *.button-bar {
- -fx-max-height: 0;
- -fx-pref-height: 0;
-}
diff --git a/src/main/java/org/jabref/gui/keyboard/KeyBindingsDialog.fxml b/src/main/java/org/jabref/gui/keyboard/KeyBindingsDialog.fxml
new file mode 100644
index 00000000000..99983bb67aa
--- /dev/null
+++ b/src/main/java/org/jabref/gui/keyboard/KeyBindingsDialog.fxml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/java/org/jabref/gui/keyboard/KeyBindingsDialogController.java b/src/main/java/org/jabref/gui/keyboard/KeyBindingsDialogController.java
deleted file mode 100644
index 4b37931ebea..00000000000
--- a/src/main/java/org/jabref/gui/keyboard/KeyBindingsDialogController.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package org.jabref.gui.keyboard;
-
-import javax.inject.Inject;
-
-import javafx.fxml.FXML;
-import javafx.scene.control.SelectionMode;
-import javafx.scene.control.SelectionModel;
-import javafx.scene.control.TreeItem;
-import javafx.scene.control.TreeTableColumn;
-import javafx.scene.control.TreeTableView;
-
-import org.jabref.gui.AbstractController;
-import org.jabref.gui.DialogService;
-import org.jabref.gui.JabRefIcon;
-import org.jabref.gui.util.RecursiveTreeItem;
-import org.jabref.gui.util.ViewModelTreeTableCellFactory;
-import org.jabref.preferences.PreferencesService;
-
-import org.fxmisc.easybind.EasyBind;
-
-public class KeyBindingsDialogController extends AbstractController {
-
- @FXML private TreeTableView keyBindingsTable;
- @FXML private TreeTableColumn actionColumn;
- @FXML private TreeTableColumn shortcutColumn;
- @FXML private TreeTableColumn resetColumn;
-
- @Inject private KeyBindingRepository keyBindingRepository;
- @Inject private DialogService dialogService;
- @Inject private PreferencesService preferences;
-
- @FXML
- private void initialize() {
- viewModel = new KeyBindingsDialogViewModel(keyBindingRepository, dialogService, preferences);
-
- keyBindingsTable.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
- viewModel.selectedKeyBindingProperty().bind(
- EasyBind.monadic(keyBindingsTable.selectionModelProperty())
- .flatMap(SelectionModel::selectedItemProperty)
- .selectProperty(TreeItem::valueProperty)
- );
- keyBindingsTable.setOnKeyPressed(evt -> viewModel.setNewBindingForCurrent(evt));
- keyBindingsTable.rootProperty().bind(
- EasyBind.map(viewModel.rootKeyBindingProperty(),
- keybinding -> new RecursiveTreeItem<>(keybinding, KeyBindingViewModel::getChildren))
- );
- actionColumn.setCellValueFactory(cellData -> cellData.getValue().getValue().nameProperty());
- shortcutColumn.setCellValueFactory(cellData -> cellData.getValue().getValue().shownBindingProperty());
- resetColumn.setCellFactory(new ViewModelTreeTableCellFactory()
- .withGraphic(keyBinding -> keyBinding.getIcon().map(JabRefIcon::getGraphicNode).orElse(null))
- .withOnMouseClickedEvent(keyBinding -> evt -> keyBinding.resetToDefault())
- );
- }
-
- @FXML
- private void closeDialog() {
- getStage().close();
- }
-
- @FXML
- private void saveKeyBindingsAndCloseDialog() {
- viewModel.saveKeyBindings();
- closeDialog();
- }
-
- @FXML
- private void setDefaultBindings() {
- viewModel.resetToDefault();
- }
-}
diff --git a/src/main/java/org/jabref/gui/keyboard/KeyBindingsDialogView.java b/src/main/java/org/jabref/gui/keyboard/KeyBindingsDialogView.java
index e5a9fd950b2..991fcc55636 100644
--- a/src/main/java/org/jabref/gui/keyboard/KeyBindingsDialogView.java
+++ b/src/main/java/org/jabref/gui/keyboard/KeyBindingsDialogView.java
@@ -1,23 +1,90 @@
package org.jabref.gui.keyboard;
-import javafx.scene.control.Alert.AlertType;
-import javafx.scene.control.DialogPane;
-import javafx.stage.Stage;
+import javax.inject.Inject;
-import org.jabref.gui.AbstractDialogView;
-import org.jabref.gui.FXDialog;
+import javafx.fxml.FXML;
+import javafx.scene.control.ButtonType;
+import javafx.scene.control.SelectionMode;
+import javafx.scene.control.SelectionModel;
+import javafx.scene.control.TreeItem;
+import javafx.scene.control.TreeTableColumn;
+import javafx.scene.control.TreeTableView;
+
+import org.jabref.gui.DialogService;
+import org.jabref.gui.JabRefIcon;
+import org.jabref.gui.util.BaseDialog;
+import org.jabref.gui.util.ControlHelper;
+import org.jabref.gui.util.RecursiveTreeItem;
+import org.jabref.gui.util.ViewModelTreeTableCellFactory;
import org.jabref.logic.l10n.Localization;
+import org.jabref.preferences.PreferencesService;
+
+import com.airhacks.afterburner.views.ViewLoader;
+import org.fxmisc.easybind.EasyBind;
+
+public class KeyBindingsDialogView extends BaseDialog {
+
+ @FXML private ButtonType resetButton;
+ @FXML private ButtonType saveButton;
+ @FXML private TreeTableView keyBindingsTable;
+ @FXML private TreeTableColumn actionColumn;
+ @FXML private TreeTableColumn shortcutColumn;
+ @FXML private TreeTableColumn resetColumn;
+
+ @Inject private KeyBindingRepository keyBindingRepository;
+ @Inject private DialogService dialogService;
+ @Inject private PreferencesService preferences;
+ private KeyBindingsDialogViewModel viewModel;
+
+ public KeyBindingsDialogView() {
+ this.setTitle(Localization.lang("Key bindings"));
+ this.getDialogPane().setPrefSize(375, 475);
+ this.setResizable(true);
+
+ ViewLoader.view(this)
+ .load()
+ .setAsDialogPane(this);
-public class KeyBindingsDialogView extends AbstractDialogView {
+ ControlHelper.setAction(resetButton, getDialogPane(), event -> setDefaultBindings());
+ ControlHelper.setAction(saveButton, getDialogPane(), event -> saveKeyBindingsAndCloseDialog());
+ }
+
+ @FXML
+ private void initialize() {
+ viewModel = new KeyBindingsDialogViewModel(keyBindingRepository, dialogService, preferences);
+
+ keyBindingsTable.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
+ viewModel.selectedKeyBindingProperty().bind(
+ EasyBind.monadic(keyBindingsTable.selectionModelProperty())
+ .flatMap(SelectionModel::selectedItemProperty)
+ .selectProperty(TreeItem::valueProperty)
+ );
+ keyBindingsTable.setOnKeyPressed(evt -> viewModel.setNewBindingForCurrent(evt));
+ keyBindingsTable.rootProperty().bind(
+ EasyBind.map(viewModel.rootKeyBindingProperty(),
+ keybinding -> new RecursiveTreeItem<>(keybinding, KeyBindingViewModel::getChildren))
+ );
+ actionColumn.setCellValueFactory(cellData -> cellData.getValue().getValue().nameProperty());
+ shortcutColumn.setCellValueFactory(cellData -> cellData.getValue().getValue().shownBindingProperty());
+ resetColumn.setCellFactory(new ViewModelTreeTableCellFactory()
+ .withGraphic(keyBinding -> keyBinding.getIcon().map(JabRefIcon::getGraphicNode).orElse(null))
+ .withOnMouseClickedEvent(keyBinding -> evt -> keyBinding.resetToDefault())
+ );
+ }
- @Override
- public void show() {
- FXDialog keyBindingsDialog = new FXDialog(AlertType.INFORMATION, Localization.lang("Key bindings"));
- keyBindingsDialog.setDialogPane((DialogPane) this.getView());
- keyBindingsDialog.setResizable(true);
- ((Stage) keyBindingsDialog.getDialogPane().getScene().getWindow()).setMinHeight(475);
- ((Stage) keyBindingsDialog.getDialogPane().getScene().getWindow()).setMinWidth(375);
- keyBindingsDialog.show();
+ @FXML
+ private void closeDialog() {
+ close();
}
+ @FXML
+ private void saveKeyBindingsAndCloseDialog() {
+ viewModel.saveKeyBindings();
+ closeDialog();
+ }
+
+ @FXML
+ private void setDefaultBindings() {
+ viewModel.resetToDefault();
+ }
}
diff --git a/src/main/java/org/jabref/gui/preftabs/ExternalTab.java b/src/main/java/org/jabref/gui/preftabs/ExternalTab.java
index 83999f529ea..54a143db527 100644
--- a/src/main/java/org/jabref/gui/preftabs/ExternalTab.java
+++ b/src/main/java/org/jabref/gui/preftabs/ExternalTab.java
@@ -55,7 +55,7 @@ public ExternalTab(JabRefFrame frame, PreferencesDialog prefsDiag, JabRefPrefere
JButton editFileTypes = new JButton(Localization.lang("Manage external file types"));
citeCommand = new JTextField(25);
- editFileTypes.addActionListener(ExternalFileTypeEditor.getAction(prefsDiag));
+ editFileTypes.addActionListener(ExternalFileTypeEditor.getAction(frame));
defaultConsole = new JRadioButton(Localization.lang("Use default terminal emulator"));
executeConsole = new JRadioButton(Localization.lang("Execute command") + ":");
diff --git a/src/main/java/org/jabref/gui/preftabs/PreferencesDialog.java b/src/main/java/org/jabref/gui/preftabs/PreferencesDialog.java
index 1980bf42a8b..93cc9196605 100644
--- a/src/main/java/org/jabref/gui/preftabs/PreferencesDialog.java
+++ b/src/main/java/org/jabref/gui/preftabs/PreferencesDialog.java
@@ -14,19 +14,23 @@
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.JButton;
-import javax.swing.JFrame;
+import javax.swing.JComponent;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;
+import javafx.scene.control.ButtonBar;
+import javafx.scene.control.ButtonType;
+import javafx.scene.layout.Region;
+
import org.jabref.Globals;
import org.jabref.JabRefException;
import org.jabref.gui.DialogService;
import org.jabref.gui.GUIGlobals;
-import org.jabref.gui.JabRefDialog;
import org.jabref.gui.JabRefFrame;
-import org.jabref.gui.keyboard.KeyBinder;
+import org.jabref.gui.util.BaseDialog;
+import org.jabref.gui.util.ControlHelper;
import org.jabref.gui.util.DefaultTaskExecutor;
import org.jabref.gui.util.FileDialogConfiguration;
import org.jabref.logic.exporter.ExporterFactory;
@@ -36,10 +40,10 @@
import org.jabref.preferences.JabRefPreferences;
import org.jabref.preferences.JabRefPreferencesFilter;
-import com.jgoodies.forms.builder.ButtonBarBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+
/**
* Preferences dialog. Contains a TabbedPane, and tabs will be defined in
* separate classes. Tabs MUST implement the PrefsTab interface, since this
@@ -49,52 +53,57 @@
* With this design, it should be very easy to add new tabs later.
*
*/
-public class PreferencesDialog extends JabRefDialog {
+public class PreferencesDialog extends BaseDialog {
private static final Logger LOGGER = LoggerFactory.getLogger(PreferencesDialog.class);
private final JPanel main;
+ private final DialogService dialogService;
private final JabRefFrame frame;
- private final JButton importPreferences = new JButton(Localization.lang("Import preferences"));
- private final JButton exportPreferences = new JButton(Localization.lang("Export preferences"));
- private final JButton showPreferences = new JButton(Localization.lang("Show preferences"));
-
- private final JButton resetPreferences = new JButton(Localization.lang("Reset preferences"));
+ private final JabRefPreferences prefs;
public PreferencesDialog(JabRefFrame parent) {
- super((JFrame) null, Localization.lang("JabRef preferences"), false, PreferencesDialog.class);
- JabRefPreferences prefs = JabRefPreferences.getInstance();
+ setTitle(Localization.lang("JabRef preferences"));
+ getDialogPane().setPrefSize(1000, 800);
+ getDialogPane().setMinHeight(Region.USE_PREF_SIZE);
+ setResizable(true);
+
+ ButtonType save = new ButtonType(Localization.lang("Save"), ButtonBar.ButtonData.APPLY);
+ getDialogPane().getButtonTypes().setAll(save, ButtonType.CANCEL);
+ ControlHelper.setAction(save, getDialogPane(), event -> storeAllSettings());
+
+ prefs = JabRefPreferences.getInstance();
frame = parent;
+ dialogService = frame.getDialogService();
main = new JPanel();
- JPanel mainPanel = new JPanel();
- JPanel lower = new JPanel();
- getContentPane().setLayout(new BorderLayout());
- getContentPane().add(mainPanel, BorderLayout.CENTER);
- getContentPane().add(lower, BorderLayout.SOUTH);
+ ControlHelper.setSwingContent(getDialogPane(), constructSwingContent());
+ }
+ private JComponent constructSwingContent() {
+ JPanel mainPanel = new JPanel();
final CardLayout cardLayout = new CardLayout();
main.setLayout(cardLayout);
List tabs = new ArrayList<>();
- tabs.add(new GeneralTab(frame.getDialogService(), prefs));
- tabs.add(new FileTab(frame.getDialogService(), prefs));
+ tabs.add(new GeneralTab(dialogService, prefs));
+ tabs.add(new FileTab(dialogService, prefs));
tabs.add(new TablePrefsTab(prefs));
- tabs.add(new TableColumnsTab(prefs, parent));
- tabs.add(new PreviewPrefsTab(frame.getDialogService()));
+ tabs.add(new TableColumnsTab(prefs, frame));
+ tabs.add(new PreviewPrefsTab(dialogService));
tabs.add(new ExternalTab(frame, this, prefs));
tabs.add(new GroupsPrefsTab(prefs));
tabs.add(new EntryEditorPrefsTab(prefs));
- tabs.add(new BibtexKeyPatternPrefTab(prefs, parent.getCurrentBasePanel()));
+ tabs.add(new BibtexKeyPatternPrefTab(prefs, frame.getCurrentBasePanel()));
tabs.add(new ImportSettingsTab(prefs));
tabs.add(new ExportSortingPrefsTab(prefs));
tabs.add(new NameFormatterTab(prefs));
tabs.add(new XmpPrefsTab(prefs));
- tabs.add(new NetworkTab(frame.getDialogService(), prefs));
- tabs.add(new AdvancedTab(frame.getDialogService(), prefs));
- tabs.add(new AppearancePrefsTab(frame.getDialogService(), prefs));
+ tabs.add(new NetworkTab(dialogService, prefs));
+ tabs.add(new AdvancedTab(dialogService, prefs));
+ tabs.add(new AppearancePrefsTab(dialogService, prefs));
// add all tabs
tabs.forEach(tab -> main.add((Component) tab, tab.getTabName()));
@@ -121,9 +130,13 @@ public PreferencesDialog(JabRefFrame parent) {
JPanel buttons = new JPanel();
buttons.setLayout(new GridLayout(4, 1));
+ JButton importPreferences = new JButton(Localization.lang("Import preferences"));
buttons.add(importPreferences, 0);
+ JButton exportPreferences = new JButton(Localization.lang("Export preferences"));
buttons.add(exportPreferences, 1);
+ JButton showPreferences = new JButton(Localization.lang("Show preferences"));
buttons.add(showPreferences, 2);
+ JButton resetPreferences = new JButton(Localization.lang("Reset preferences"));
buttons.add(resetPreferences, 3);
JPanel westPanel = new JPanel();
@@ -134,20 +147,8 @@ public PreferencesDialog(JabRefFrame parent) {
mainPanel.add(putPanelInScrollPane(main), BorderLayout.CENTER);
mainPanel.add(putPanelInScrollPane(westPanel), BorderLayout.WEST);
- JButton ok = new JButton(Localization.lang("OK"));
- JButton cancel = new JButton(Localization.lang("Cancel"));
- ok.addActionListener(new OkAction());
- CancelAction cancelAction = new CancelAction();
- cancel.addActionListener(cancelAction);
- lower.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
- ButtonBarBuilder buttonBarBuilder = new ButtonBarBuilder(lower);
- buttonBarBuilder.addGlue();
- buttonBarBuilder.addButton(ok);
- buttonBarBuilder.addButton(cancel);
- buttonBarBuilder.addGlue();
-
- // Key bindings:
- KeyBinder.bindCloseDialogKeyToCancelAction(this.getRootPane(), cancelAction);
+ // TODO: Key bindings:
+ // KeyBinder.bindCloseDialogKeyToCancelAction(this.getRootPane(), cancelAction);
// Import and export actions:
exportPreferences.setToolTipText(Localization.lang("Export preferences to file"));
@@ -161,23 +162,20 @@ public PreferencesDialog(JabRefFrame parent) {
.withDefaultExtension(FileType.XML)
.withInitialDirectory(getPrefsExportPath())
.build();
- DialogService ds = frame.getDialogService();
Optional fileName = DefaultTaskExecutor
- .runInJavaFXThread(() -> ds.showFileOpenDialog(fileDialogConfiguration));
+ .runInJavaFXThread(() -> dialogService.showFileOpenDialog(fileDialogConfiguration));
if (fileName.isPresent()) {
try {
prefs.importPreferences(fileName.get().toString());
updateAfterPreferenceChanges();
- DefaultTaskExecutor.runInJavaFXThread(() -> frame.getDialogService().showWarningDialogAndWait(Localization.lang("Import preferences"),
+ DefaultTaskExecutor.runInJavaFXThread(() -> dialogService.showWarningDialogAndWait(Localization.lang("Import preferences"),
Localization.lang("You must restart JabRef for this to come into effect.")));
-
- this.dispose();
} catch (JabRefException ex) {
LOGGER.warn(ex.getMessage(), ex);
- DefaultTaskExecutor.runInJavaFXThread(() -> frame.getDialogService().showErrorDialogAndWait(Localization.lang("Import preferences"), ex));
+ DefaultTaskExecutor.runInJavaFXThread(() -> dialogService.showErrorDialogAndWait(Localization.lang("Import preferences"), ex));
}
}
});
@@ -186,7 +184,7 @@ public PreferencesDialog(JabRefFrame parent) {
e -> new PreferencesFilterDialog(new JabRefPreferencesFilter(prefs), null).setVisible(true));
resetPreferences.addActionListener(e -> {
- boolean resetPreferencesClicked = DefaultTaskExecutor.runInJavaFXThread(() -> frame.getDialogService().showConfirmationDialogAndWait(Localization.lang("Reset preferences"),
+ boolean resetPreferencesClicked = DefaultTaskExecutor.runInJavaFXThread(() -> dialogService.showConfirmationDialogAndWait(Localization.lang("Reset preferences"),
Localization.lang("Are you sure you want to reset all settings to default values?"),
Localization.lang("Reset preferences"), Localization.lang("Cancel")));
@@ -195,12 +193,11 @@ public PreferencesDialog(JabRefFrame parent) {
prefs.clear();
new SharedDatabasePreferences().clear();
- DefaultTaskExecutor.runInJavaFXThread(() -> frame.getDialogService().showWarningDialogAndWait(Localization.lang("Reset preferences"),
+ DefaultTaskExecutor.runInJavaFXThread(() -> dialogService.showWarningDialogAndWait(Localization.lang("Reset preferences"),
Localization.lang("You must restart JabRef for this to come into effect.")));
-
} catch (BackingStoreException ex) {
LOGGER.warn(ex.getMessage(), ex);
- DefaultTaskExecutor.runInJavaFXThread(() -> frame.getDialogService().showErrorDialogAndWait(Localization.lang("Reset preferences"), ex));
+ DefaultTaskExecutor.runInJavaFXThread(() -> dialogService.showErrorDialogAndWait(Localization.lang("Reset preferences"), ex));
}
updateAfterPreferenceChanges();
}
@@ -208,8 +205,7 @@ public PreferencesDialog(JabRefFrame parent) {
setValues();
- pack();
-
+ return mainPanel;
}
private JScrollPane putPanelInScrollPane(JPanel panel) {
@@ -221,15 +217,15 @@ private JScrollPane putPanelInScrollPane(JPanel panel) {
}
private String getPrefsExportPath() {
- return Globals.prefs.get(JabRefPreferences.PREFS_EXPORT_PATH);
+ return prefs.get(JabRefPreferences.PREFS_EXPORT_PATH);
}
private void updateAfterPreferenceChanges() {
setValues();
- Globals.exportFactory = ExporterFactory.create(Globals.prefs, Globals.journalAbbreviationLoader);
+ Globals.exportFactory = ExporterFactory.create(prefs, Globals.journalAbbreviationLoader);
- Globals.prefs.updateEntryEditorTabList();
+ prefs.updateEntryEditorTabList();
}
private void storeAllSettings() {
@@ -244,9 +240,8 @@ private void storeAllSettings() {
for (Component tab : preferenceTabs) {
((PrefsTab) tab).storeSettings();
}
- Globals.prefs.flush();
+ prefs.flush();
- setVisible(false);
GUIGlobals.updateEntryEditorColors();
frame.setupAllTables();
frame.output(Localization.lang("Preferences recorded."));
@@ -261,17 +256,7 @@ public void setValues() {
}
}
- class OkAction extends AbstractAction {
-
- public OkAction() {
- super("OK");
- }
- @Override
- public void actionPerformed(ActionEvent e) {
- storeAllSettings();
- }
- }
class ExportAction extends AbstractAction {
@@ -285,36 +270,22 @@ public void actionPerformed(ActionEvent e) {
FileDialogConfiguration fileDialogConfiguration = new FileDialogConfiguration.Builder()
.addExtensionFilter(FileType.XML)
.withDefaultExtension(FileType.XML)
- .withInitialDirectory(Globals.prefs.get(JabRefPreferences.WORKING_DIRECTORY))
+ .withInitialDirectory(prefs.get(JabRefPreferences.WORKING_DIRECTORY))
.build();
- DialogService ds = frame.getDialogService();
Optional path = DefaultTaskExecutor
- .runInJavaFXThread(() -> ds.showFileSaveDialog(fileDialogConfiguration));
+ .runInJavaFXThread(() -> dialogService.showFileSaveDialog(fileDialogConfiguration));
path.ifPresent(exportFile -> {
try {
storeAllSettings();
- Globals.prefs.exportPreferences(exportFile.toString());
- Globals.prefs.put(JabRefPreferences.PREFS_EXPORT_PATH, exportFile.toString());
+ prefs.exportPreferences(exportFile.toString());
+ prefs.put(JabRefPreferences.PREFS_EXPORT_PATH, exportFile.toString());
} catch (JabRefException ex) {
LOGGER.warn(ex.getMessage(), ex);
- frame.getDialogService().showErrorDialogAndWait(Localization.lang("Export preferences"), ex);
+ dialogService.showErrorDialogAndWait(Localization.lang("Export preferences"), ex);
}
});
}
}
-
- class CancelAction extends AbstractAction {
-
- public CancelAction() {
- super("Cancel");
- }
-
- @Override
- public void actionPerformed(ActionEvent e) {
- setVisible(false);
- }
- }
-
}
diff --git a/src/main/java/org/jabref/gui/util/BaseDialog.java b/src/main/java/org/jabref/gui/util/BaseDialog.java
new file mode 100644
index 00000000000..dce34d0b611
--- /dev/null
+++ b/src/main/java/org/jabref/gui/util/BaseDialog.java
@@ -0,0 +1,31 @@
+package org.jabref.gui.util;
+
+import javafx.scene.control.Dialog;
+import javafx.scene.image.Image;
+import javafx.stage.Stage;
+
+import org.jabref.Globals;
+import org.jabref.gui.IconTheme;
+import org.jabref.gui.keyboard.KeyBinding;
+import org.jabref.gui.keyboard.KeyBindingRepository;
+
+public class BaseDialog extends Dialog {
+
+ protected BaseDialog() {
+ getDialogPane().getScene().setOnKeyPressed(event -> {
+ KeyBindingRepository keyBindingRepository = Globals.getKeyPrefs();
+ if (keyBindingRepository.checkKeyCombinationEquality(KeyBinding.CLOSE_DIALOG, event)) {
+ close();
+ }
+ });
+
+ setDialogIcon(IconTheme.getJabRefImageFX());
+
+ Globals.getThemeLoader().installBaseCss(getDialogPane().getScene());
+ }
+
+ private void setDialogIcon(Image image) {
+ Stage dialogWindow = (Stage) getDialogPane().getScene().getWindow();
+ dialogWindow.getIcons().add(image);
+ }
+}
diff --git a/src/main/java/org/jabref/gui/util/ControlHelper.java b/src/main/java/org/jabref/gui/util/ControlHelper.java
index 971996085e7..d665aa01bab 100644
--- a/src/main/java/org/jabref/gui/util/ControlHelper.java
+++ b/src/main/java/org/jabref/gui/util/ControlHelper.java
@@ -1,9 +1,19 @@
package org.jabref.gui.util;
import java.io.IOException;
+import java.util.function.Consumer;
+import javax.swing.JComponent;
+import javax.swing.SwingUtilities;
+
+import javafx.embed.swing.SwingNode;
+import javafx.event.ActionEvent;
+import javafx.event.Event;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
+import javafx.scene.control.Button;
+import javafx.scene.control.ButtonType;
+import javafx.scene.control.DialogPane;
import org.jabref.Globals;
import org.jabref.logic.l10n.Localization;
@@ -37,4 +47,20 @@ public static void loadFXMLForControl(Parent control) {
LOGGER.error("Problem loading fxml for control", exception);
}
}
+
+ public static void setAction(ButtonType buttonType, DialogPane dialogPane, Consumer consumer) {
+ Button button = (Button) dialogPane.lookupButton(buttonType);
+ button.addEventFilter(ActionEvent.ACTION, (event -> {
+ consumer.accept(event);
+ event.consume();
+ }));
+ }
+
+ public static void setSwingContent(DialogPane dialogPane, JComponent content) {
+ SwingNode node = new SwingNode();
+ SwingUtilities.invokeLater(() -> node.setContent(content));
+ node.setVisible(true);
+
+ dialogPane.setContent(node);
+ }
}
diff --git a/src/main/java/org/jabref/gui/util/ThemeLoader.java b/src/main/java/org/jabref/gui/util/ThemeLoader.java
index ac5f461d4d9..fa06b5a6978 100644
--- a/src/main/java/org/jabref/gui/util/ThemeLoader.java
+++ b/src/main/java/org/jabref/gui/util/ThemeLoader.java
@@ -11,7 +11,7 @@
import javafx.scene.Parent;
import javafx.scene.Scene;
-import org.jabref.gui.AbstractView;
+import org.jabref.gui.JabRefFrame;
import org.jabref.model.util.FileUpdateMonitor;
import org.slf4j.Logger;
@@ -30,7 +30,7 @@
*/
public class ThemeLoader {
- private static final String DEFAULT_PATH_MAIN_CSS = AbstractView.class.getResource("Main.css").toExternalForm();
+ private static final String DEFAULT_PATH_MAIN_CSS = JabRefFrame.class.getResource("Main.css").toExternalForm();
private static final String CSS_SYSTEM_PROPERTY = System.getProperty("jabref.main.css");
private static final Logger LOGGER = LoggerFactory.getLogger(ThemeLoader.class);
private final FileUpdateMonitor fileUpdateMonitor;
diff --git a/src/main/java/org/jabref/logic/l10n/Localization.java b/src/main/java/org/jabref/logic/l10n/Localization.java
index 0d5c647856e..b5cec96a956 100644
--- a/src/main/java/org/jabref/logic/l10n/Localization.java
+++ b/src/main/java/org/jabref/logic/l10n/Localization.java
@@ -112,7 +112,7 @@ public static void setLanguage(String language) {
}
/**
- * Public access to the messages bundle for classes like AbstractView.
+ * Returns the messages bundle, e.g. to load FXML files correctly translated.
*
* @return The internally cashed bundle.
*/
diff --git a/src/main/java/org/jabref/logic/l10n/LocalizationLocator.java b/src/main/java/org/jabref/logic/l10n/LocalizationLocator.java
new file mode 100644
index 00000000000..90034e8440a
--- /dev/null
+++ b/src/main/java/org/jabref/logic/l10n/LocalizationLocator.java
@@ -0,0 +1,12 @@
+package org.jabref.logic.l10n;
+
+import java.util.ResourceBundle;
+
+import com.airhacks.afterburner.views.ResourceLocator;
+
+public class LocalizationLocator implements ResourceLocator {
+ @Override
+ public ResourceBundle getResourceBundle(String s) {
+ return Localization.getMessages();
+ }
+}
diff --git a/src/main/resources/META-INF/services/com.airhacks.afterburner.views.ResourceLocator b/src/main/resources/META-INF/services/com.airhacks.afterburner.views.ResourceLocator
new file mode 100644
index 00000000000..ffe84d0f5a6
--- /dev/null
+++ b/src/main/resources/META-INF/services/com.airhacks.afterburner.views.ResourceLocator
@@ -0,0 +1 @@
+org.jabref.logic.l10n.LocalizationLocator
diff --git a/src/main/resources/org/jabref/gui/help/AboutDialog.fxml b/src/main/resources/org/jabref/gui/help/AboutDialog.fxml
deleted file mode 100644
index 9a4af473361..00000000000
--- a/src/main/resources/org/jabref/gui/help/AboutDialog.fxml
+++ /dev/null
@@ -1,108 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/main/resources/org/jabref/gui/keyboard/KeyBindingsDialog.fxml b/src/main/resources/org/jabref/gui/keyboard/KeyBindingsDialog.fxml
deleted file mode 100644
index 4f326d10030..00000000000
--- a/src/main/resources/org/jabref/gui/keyboard/KeyBindingsDialog.fxml
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/test/java/org/jabref/gui/GUITest.java b/src/test/java/org/jabref/gui/GUITest.java
index e76c9c4398d..5e8472d4330 100644
--- a/src/test/java/org/jabref/gui/GUITest.java
+++ b/src/test/java/org/jabref/gui/GUITest.java
@@ -5,7 +5,6 @@
import javax.swing.JButton;
import org.jabref.gui.dbproperties.DatabasePropertiesDialog;
-import org.jabref.gui.preftabs.PreferencesDialog;
import org.assertj.swing.core.GenericTypeMatcher;
import org.assertj.swing.dependency.jsr305.Nonnull;
@@ -45,24 +44,6 @@ protected boolean isMatching(@Nonnull JButton jButton) {
takeScreenshot(mainFrame, "MainWindowWithOneDatabase");
}
- @Test
- public void testOpenAndSavePreferences() throws IOException {
- mainFrame.menuItemWithPath("Options", "Preferences").click();
-
- robot().waitForIdle();
-
- DialogFixture preferencesDialog = findDialog(PreferencesDialog.class).withTimeout(10_000).using(robot());
- takeScreenshot(preferencesDialog, "PreferencesDialog");
- preferencesDialog.button(new GenericTypeMatcher(JButton.class) {
- @Override
- protected boolean isMatching(@Nonnull JButton jButton) {
- return "OK".equals(jButton.getText());
- }
- }).click();
-
- exitJabRef();
- }
-
/**
* tests different buttons
* sometimes this test clicks some buttons twice to reverse their effect and leaves JabRef as it was before