From f86ce7c33880ffa73f46e037be8ea10fa59c9c7e Mon Sep 17 00:00:00 2001 From: dpolishc Date: Sat, 18 May 2019 20:52:07 +0200 Subject: [PATCH 001/103] Duplicate check on import should be run in background Task #4963 --- .../gui/importer/ImportEntriesDialog.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/jabref/gui/importer/ImportEntriesDialog.java b/src/main/java/org/jabref/gui/importer/ImportEntriesDialog.java index ae5352deade..0beb12ad8c6 100644 --- a/src/main/java/org/jabref/gui/importer/ImportEntriesDialog.java +++ b/src/main/java/org/jabref/gui/importer/ImportEntriesDialog.java @@ -1,6 +1,7 @@ package org.jabref.gui.importer; import java.util.List; +import java.util.concurrent.Callable; import javax.inject.Inject; import javax.swing.undo.UndoManager; @@ -20,6 +21,7 @@ import javafx.scene.layout.VBox; import javafx.scene.text.Text; +import org.jabref.Globals; import org.jabref.gui.DialogService; import org.jabref.gui.StateManager; import org.jabref.gui.icon.IconTheme; @@ -108,12 +110,15 @@ private void initialize() { container.getStyleClass().add("entry-container"); BindingsHelper.includePseudoClassWhen(container, entrySelected, addToggle.selectedProperty()); - if (viewModel.hasDuplicate(entry)) { - Button duplicateButton = IconTheme.JabRefIcons.DUPLICATE.asButton(); - duplicateButton.setTooltip(new Tooltip(Localization.lang("Possible duplicate of existing entry. Click to resolve."))); - duplicateButton.setOnAction(event -> viewModel.resolveDuplicate(entry)); - container.getChildren().add(1, duplicateButton); - } + Callable hasDuplicateEntryTask = () -> viewModel.hasDuplicate(entry); + BackgroundTask.wrap(hasDuplicateEntryTask).onSuccess(e -> { + if (e) { + Button duplicateButton = IconTheme.JabRefIcons.DUPLICATE.asButton(); + duplicateButton.setTooltip(new Tooltip(Localization.lang("Possible duplicate of existing entry. Click to resolve."))); + duplicateButton.setOnAction(event -> viewModel.resolveDuplicate(entry)); + container.getChildren().add(1, duplicateButton); + } + }).executeWith(Globals.TASK_EXECUTOR); return container; }) From ebefc8581a7c900bbb2c96a335af17f6fcbe280f Mon Sep 17 00:00:00 2001 From: dpolishc Date: Mon, 20 May 2019 07:26:07 +0200 Subject: [PATCH 002/103] fixup! fixup! Too big error message #4963 (updating controlsfx, setting maxWidth and reverting off the temporary fix) --- .../gui/importer/ImportEntriesDialog.java | 3 +- .../gui/importer/ImportEntriesViewModel.java | 35 ++++++++++--------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/main/java/org/jabref/gui/importer/ImportEntriesDialog.java b/src/main/java/org/jabref/gui/importer/ImportEntriesDialog.java index 0beb12ad8c6..0aaeb427217 100644 --- a/src/main/java/org/jabref/gui/importer/ImportEntriesDialog.java +++ b/src/main/java/org/jabref/gui/importer/ImportEntriesDialog.java @@ -110,8 +110,7 @@ private void initialize() { container.getStyleClass().add("entry-container"); BindingsHelper.includePseudoClassWhen(container, entrySelected, addToggle.selectedProperty()); - Callable hasDuplicateEntryTask = () -> viewModel.hasDuplicate(entry); - BackgroundTask.wrap(hasDuplicateEntryTask).onSuccess(e -> { + BackgroundTask.wrap(() -> viewModel.hasDuplicate(entry)).onSuccess(e -> { if (e) { Button duplicateButton = IconTheme.JabRefIcons.DUPLICATE.asButton(); duplicateButton.setTooltip(new Tooltip(Localization.lang("Possible duplicate of existing entry. Click to resolve."))); diff --git a/src/main/java/org/jabref/gui/importer/ImportEntriesViewModel.java b/src/main/java/org/jabref/gui/importer/ImportEntriesViewModel.java index 6f0b2fad4ad..218038a349d 100644 --- a/src/main/java/org/jabref/gui/importer/ImportEntriesViewModel.java +++ b/src/main/java/org/jabref/gui/importer/ImportEntriesViewModel.java @@ -9,7 +9,7 @@ import javafx.beans.property.StringProperty; import javafx.collections.FXCollections; import javafx.collections.ObservableList; - +import org.jabref.Globals; import org.jabref.gui.AbstractViewModel; import org.jabref.gui.DialogService; import org.jabref.gui.StateManager; @@ -25,6 +25,10 @@ import org.jabref.model.util.FileUpdateMonitor; import org.jabref.preferences.PreferencesService; +import javax.swing.undo.UndoManager; +import java.util.List; +import java.util.Optional; + public class ImportEntriesViewModel extends AbstractViewModel { private final BackgroundTask> task; @@ -75,22 +79,21 @@ public void importEntries(List entriesToImport) { // Check if we are supposed to warn about duplicates. // If so, then see if there are duplicates, and warn if yes. if (preferences.shouldWarnAboutDuplicatesForImport()) { - boolean containsDuplicate = entriesToImport.stream() - .anyMatch(this::hasDuplicate); - - if (containsDuplicate) { - boolean continueImport = dialogService.showConfirmationDialogWithOptOutAndWait(Localization.lang("Duplicates found"), - Localization.lang("There are possible duplicates (marked with an icon) that haven't been resolved. Continue?"), - Localization.lang("Continue with import"), - Localization.lang("Cancel import"), - Localization.lang("Disable this confirmation dialog"), - optOut -> preferences.setShouldWarnAboutDuplicatesForImport(!optOut)); - - if (!continueImport) { - dialogService.notify(Localization.lang("Import canceled")); - return; + BackgroundTask.wrap(() -> entriesToImport.stream() + .anyMatch(this::hasDuplicate)).onSuccess(e -> { + if (e) { + boolean continueImport = dialogService.showConfirmationDialogWithOptOutAndWait(Localization.lang("Duplicates found"), + Localization.lang("There are possible duplicates (marked with an icon) that haven't been resolved. Continue?"), + Localization.lang("Continue with import"), + Localization.lang("Cancel import"), + Localization.lang("Disable this confirmation dialog"), + optOut -> preferences.setShouldWarnAboutDuplicatesForImport(!optOut)); + + if (!continueImport) { + dialogService.notify(Localization.lang("Import canceled")); + } } - } + }).executeWith(Globals.TASK_EXECUTOR); } ImportHandler importHandler = new ImportHandler( From 6ec9ee8ed83080d71639426b8fe7da8783e6425f Mon Sep 17 00:00:00 2001 From: dpolishc Date: Mon, 20 May 2019 07:56:43 +0200 Subject: [PATCH 003/103] Duplicate check on import should be run in background Task #4963 (adding background task for view model) --- .../java/org/jabref/gui/importer/ImportEntriesDialog.java | 1 - .../org/jabref/gui/importer/ImportEntriesViewModel.java | 8 ++------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/jabref/gui/importer/ImportEntriesDialog.java b/src/main/java/org/jabref/gui/importer/ImportEntriesDialog.java index 0aaeb427217..af0264f0229 100644 --- a/src/main/java/org/jabref/gui/importer/ImportEntriesDialog.java +++ b/src/main/java/org/jabref/gui/importer/ImportEntriesDialog.java @@ -1,7 +1,6 @@ package org.jabref.gui.importer; import java.util.List; -import java.util.concurrent.Callable; import javax.inject.Inject; import javax.swing.undo.UndoManager; diff --git a/src/main/java/org/jabref/gui/importer/ImportEntriesViewModel.java b/src/main/java/org/jabref/gui/importer/ImportEntriesViewModel.java index 218038a349d..df85f6bdc48 100644 --- a/src/main/java/org/jabref/gui/importer/ImportEntriesViewModel.java +++ b/src/main/java/org/jabref/gui/importer/ImportEntriesViewModel.java @@ -1,14 +1,10 @@ package org.jabref.gui.importer; -import java.util.List; -import java.util.Optional; - -import javax.swing.undo.UndoManager; - import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; import javafx.collections.FXCollections; import javafx.collections.ObservableList; + import org.jabref.Globals; import org.jabref.gui.AbstractViewModel; import org.jabref.gui.DialogService; @@ -54,7 +50,7 @@ public ImportEntriesViewModel(BackgroundTask> task, TaskExecutor this.message.bind(task.messageProperty()); task.onSuccess(entriesToImport -> entries.addAll(entriesToImport)) - .executeWith(taskExecutor); + .executeWith(taskExecutor); } public String getMessage() { From c27f6e637d677c4b8a428d38fed3d434f714711c Mon Sep 17 00:00:00 2001 From: dpolishc Date: Mon, 20 May 2019 08:03:00 +0200 Subject: [PATCH 004/103] Duplicate check on import should be run in background Task #4963 (checkstyle fix) --- .../org/jabref/gui/importer/ImportEntriesViewModel.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/jabref/gui/importer/ImportEntriesViewModel.java b/src/main/java/org/jabref/gui/importer/ImportEntriesViewModel.java index df85f6bdc48..dc8d533338d 100644 --- a/src/main/java/org/jabref/gui/importer/ImportEntriesViewModel.java +++ b/src/main/java/org/jabref/gui/importer/ImportEntriesViewModel.java @@ -1,5 +1,10 @@ package org.jabref.gui.importer; +import java.util.List; +import java.util.Optional; + +import javax.swing.undo.UndoManager; + import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; import javafx.collections.FXCollections; @@ -21,10 +26,6 @@ import org.jabref.model.util.FileUpdateMonitor; import org.jabref.preferences.PreferencesService; -import javax.swing.undo.UndoManager; -import java.util.List; -import java.util.Optional; - public class ImportEntriesViewModel extends AbstractViewModel { private final BackgroundTask> task; From bb5b2a92ccf1c77f11258edd9b23e461ac4b9c64 Mon Sep 17 00:00:00 2001 From: dpolishc Date: Tue, 21 May 2019 21:28:22 +0200 Subject: [PATCH 005/103] Duplicate check on import should be run in background Task #4963 --- .../gui/importer/ImportEntriesViewModel.java | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/jabref/gui/importer/ImportEntriesViewModel.java b/src/main/java/org/jabref/gui/importer/ImportEntriesViewModel.java index dc8d533338d..b4372d4cba5 100644 --- a/src/main/java/org/jabref/gui/importer/ImportEntriesViewModel.java +++ b/src/main/java/org/jabref/gui/importer/ImportEntriesViewModel.java @@ -88,24 +88,24 @@ public void importEntries(List entriesToImport) { if (!continueImport) { dialogService.notify(Localization.lang("Import canceled")); + } else { + ImportHandler importHandler = new ImportHandler( + dialogService, + database, + ExternalFileTypes.getInstance(), + preferences.getFilePreferences(), + preferences.getImportFormatPreferences(), + preferences.getUpdateFieldPreferences(), + fileUpdateMonitor, + undoManager, + stateManager); + importHandler.importEntries(entriesToImport); + dialogService.notify(Localization.lang("Number of entries successfully imported") + ": " + entriesToImport.size()); } } }).executeWith(Globals.TASK_EXECUTOR); } - ImportHandler importHandler = new ImportHandler( - dialogService, - database, - ExternalFileTypes.getInstance(), - preferences.getFilePreferences(), - preferences.getImportFormatPreferences(), - preferences.getUpdateFieldPreferences(), - fileUpdateMonitor, - undoManager, - stateManager); - importHandler.importEntries(entriesToImport); - - dialogService.notify(Localization.lang("Number of entries successfully imported") + ": " + entriesToImport.size()); } /** From f7c0551d47d1278a3e1d04c9ec92aab39904dffa Mon Sep 17 00:00:00 2001 From: dpolishc Date: Sun, 26 May 2019 21:40:55 +0200 Subject: [PATCH 006/103] Duplicate check on import should be run in background Task #4963 --- .../gui/importer/ImportEntriesViewModel.java | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/jabref/gui/importer/ImportEntriesViewModel.java b/src/main/java/org/jabref/gui/importer/ImportEntriesViewModel.java index b4372d4cba5..40706fdc070 100644 --- a/src/main/java/org/jabref/gui/importer/ImportEntriesViewModel.java +++ b/src/main/java/org/jabref/gui/importer/ImportEntriesViewModel.java @@ -89,25 +89,33 @@ public void importEntries(List entriesToImport) { if (!continueImport) { dialogService.notify(Localization.lang("Import canceled")); } else { - ImportHandler importHandler = new ImportHandler( - dialogService, - database, - ExternalFileTypes.getInstance(), - preferences.getFilePreferences(), - preferences.getImportFormatPreferences(), - preferences.getUpdateFieldPreferences(), - fileUpdateMonitor, - undoManager, - stateManager); - importHandler.importEntries(entriesToImport); + buildImportHandlerThenImportEntries(entriesToImport); dialogService.notify(Localization.lang("Number of entries successfully imported") + ": " + entriesToImport.size()); } + } else { + buildImportHandlerThenImportEntries(entriesToImport); } }).executeWith(Globals.TASK_EXECUTOR); + } else { + buildImportHandlerThenImportEntries(entriesToImport); } } + private void buildImportHandlerThenImportEntries(List entriesToImport) { + ImportHandler importHandler = new ImportHandler( + dialogService, + database, + ExternalFileTypes.getInstance(), + preferences.getFilePreferences(), + preferences.getImportFormatPreferences(), + preferences.getUpdateFieldPreferences(), + fileUpdateMonitor, + undoManager, + stateManager); + importHandler.importEntries(entriesToImport); + } + /** * Checks if there are duplicates to the given entry in the list of entries to be imported. * From 300eae70c935ee5a2ca26ec096e8af725a8d93c3 Mon Sep 17 00:00:00 2001 From: dpolishc Date: Mon, 27 May 2019 19:14:10 +0200 Subject: [PATCH 007/103] Duplicate check on import should be run in background Task (changing var name) --- .../java/org/jabref/gui/importer/ImportEntriesViewModel.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jabref/gui/importer/ImportEntriesViewModel.java b/src/main/java/org/jabref/gui/importer/ImportEntriesViewModel.java index 40706fdc070..5f94d08c85a 100644 --- a/src/main/java/org/jabref/gui/importer/ImportEntriesViewModel.java +++ b/src/main/java/org/jabref/gui/importer/ImportEntriesViewModel.java @@ -77,8 +77,8 @@ public void importEntries(List entriesToImport) { // If so, then see if there are duplicates, and warn if yes. if (preferences.shouldWarnAboutDuplicatesForImport()) { BackgroundTask.wrap(() -> entriesToImport.stream() - .anyMatch(this::hasDuplicate)).onSuccess(e -> { - if (e) { + .anyMatch(this::hasDuplicate)).onSuccess(duplicateFound -> { + if (duplicateFound) { boolean continueImport = dialogService.showConfirmationDialogWithOptOutAndWait(Localization.lang("Duplicates found"), Localization.lang("There are possible duplicates (marked with an icon) that haven't been resolved. Continue?"), Localization.lang("Continue with import"), From 006a443776ec58cac174d7d6aac98d61dfe4b87f Mon Sep 17 00:00:00 2001 From: dpolishc Date: Sun, 2 Jun 2019 16:00:00 +0200 Subject: [PATCH 008/103] Duplicate check on import should be run in background Task #4963 --- .../java/org/jabref/gui/importer/ImportEntriesViewModel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/importer/ImportEntriesViewModel.java b/src/main/java/org/jabref/gui/importer/ImportEntriesViewModel.java index 5f94d08c85a..b7fec8440c9 100644 --- a/src/main/java/org/jabref/gui/importer/ImportEntriesViewModel.java +++ b/src/main/java/org/jabref/gui/importer/ImportEntriesViewModel.java @@ -90,7 +90,6 @@ public void importEntries(List entriesToImport) { dialogService.notify(Localization.lang("Import canceled")); } else { buildImportHandlerThenImportEntries(entriesToImport); - dialogService.notify(Localization.lang("Number of entries successfully imported") + ": " + entriesToImport.size()); } } else { buildImportHandlerThenImportEntries(entriesToImport); @@ -114,6 +113,7 @@ private void buildImportHandlerThenImportEntries(List entriesToImport) undoManager, stateManager); importHandler.importEntries(entriesToImport); + dialogService.notify(Localization.lang("Number of entries successfully imported") + ": " + entriesToImport.size()); } /** From a6fc6f3d90f0b497357c3610f64de73cef4ef81d Mon Sep 17 00:00:00 2001 From: dpolishc Date: Sun, 2 Jun 2019 22:06:08 +0200 Subject: [PATCH 009/103] Duplicate check on import should be run in background #4963 --- .../java/org/jabref/gui/importer/ImportEntriesDialog.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jabref/gui/importer/ImportEntriesDialog.java b/src/main/java/org/jabref/gui/importer/ImportEntriesDialog.java index af0264f0229..40ad459433b 100644 --- a/src/main/java/org/jabref/gui/importer/ImportEntriesDialog.java +++ b/src/main/java/org/jabref/gui/importer/ImportEntriesDialog.java @@ -109,8 +109,8 @@ private void initialize() { container.getStyleClass().add("entry-container"); BindingsHelper.includePseudoClassWhen(container, entrySelected, addToggle.selectedProperty()); - BackgroundTask.wrap(() -> viewModel.hasDuplicate(entry)).onSuccess(e -> { - if (e) { + BackgroundTask.wrap(() -> viewModel.hasDuplicate(entry)).onSuccess(duplicateFound -> { + if (duplicateFound) { Button duplicateButton = IconTheme.JabRefIcons.DUPLICATE.asButton(); duplicateButton.setTooltip(new Tooltip(Localization.lang("Possible duplicate of existing entry. Click to resolve."))); duplicateButton.setOnAction(event -> viewModel.resolveDuplicate(entry)); From 9a5b7d1c31c4bbbdf945acdbb9a633efd14073d4 Mon Sep 17 00:00:00 2001 From: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com> Date: Tue, 4 Jun 2019 23:44:25 +0200 Subject: [PATCH 010/103] Select push app in preferences (#5024) * Added Submenu to change external push-app * Rewording, Respacing and Optimizing * Rewording Confusing PushApplications to PushToApplicationsManager * Refactoring and unifying PtAAction with ToolbarButton * Refactor simplified * Reword l10n * Refactor for checks * Added eye-candy * Added eye-candy * Changelog * whitespaces * Rewording, Sorting, Simplifying * Whitespace * Rewording, Sorting * Refactor var-declaration * Removed Submenu and Added Preferences Setting * Fixed compiletime-error * Added App-settings-button * Changelog * Whitespaces and superflous * Revert persistent actionInformation * Removed superfluous declaration * Added eyecandy * Refactor so simplify * Refactor for some minor requests * Refactor of PushToApplicationSettings * Checkstyle --- CHANGELOG.md | 1 + src/main/java/org/jabref/gui/JabRefFrame.java | 25 +++--- .../jabref/gui/preferences/ExternalTab.java | 60 +++++++++----- .../gui/push/PushToApplicationAction.java | 23 +++--- .../gui/push/PushToApplicationSettings.java | 80 +++++++------------ .../push/PushToApplicationSettingsDialog.java | 22 ----- .../gui/push/PushToApplicationsManager.java | 54 ++++++++++--- .../jabref/gui/push/PushToEmacsSettings.java | 15 ++-- .../jabref/gui/push/PushToLyxSettings.java | 7 +- .../jabref/gui/push/PushToVimSettings.java | 15 ++-- .../jabref/preferences/JabRefPreferences.java | 13 +++ src/main/resources/l10n/JabRef_en.properties | 5 +- 12 files changed, 173 insertions(+), 147 deletions(-) delete mode 100644 src/main/java/org/jabref/gui/push/PushToApplicationSettingsDialog.java diff --git a/CHANGELOG.md b/CHANGELOG.md index f5c6b08442d..bc0063bb095 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -65,6 +65,7 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# - The Medline fetcher now normalizes the author names according to the BibTeX-Standard [#4345](https://github.com/JabRef/jabref/issues/4345) - We added an option on the Linked File Viewer to rename the attached file of an entry directly on the JabRef. [#4844](https://github.com/JabRef/jabref/issues/4844) - We added an option in the preference dialog box that allows user to enable helpful tooltips.[#3599](https://github.com/JabRef/jabref/issues/3599) +- We moved the dropdown menu for selecting the push-application from the toolbar into the external application preferences. [#674](https://github.com/JabRef/jabref/issues/674) ### Fixed diff --git a/src/main/java/org/jabref/gui/JabRefFrame.java b/src/main/java/org/jabref/gui/JabRefFrame.java index e70d9429b6d..ef9074973d9 100644 --- a/src/main/java/org/jabref/gui/JabRefFrame.java +++ b/src/main/java/org/jabref/gui/JabRefFrame.java @@ -28,6 +28,7 @@ import javafx.scene.control.ButtonType; import javafx.scene.control.Menu; import javafx.scene.control.MenuBar; +import javafx.scene.control.MenuItem; import javafx.scene.control.ProgressBar; import javafx.scene.control.Separator; import javafx.scene.control.SeparatorMenuItem; @@ -154,7 +155,7 @@ public class JabRefFrame extends BorderPane { private final CountingUndoManager undoManager; private SidePaneManager sidePaneManager; private TabPane tabbedPane; - private PushToApplicationsManager pushApplications; + private final PushToApplicationsManager pushToApplicationsManager; private final DialogService dialogService; private SidePane sidePane; @@ -162,6 +163,7 @@ public JabRefFrame(Stage mainStage) { this.mainStage = mainStage; this.dialogService = new JabRefDialogService(mainStage, this); this.stateManager = Globals.stateManager; + this.pushToApplicationsManager = new PushToApplicationsManager(dialogService, stateManager); this.undoManager = Globals.undoManager; } @@ -449,8 +451,6 @@ public boolean quit() { private void initLayout() { setProgressBarVisible(false); - pushApplications = new PushToApplicationsManager(this.getDialogService()); - BorderPane head = new BorderPane(); head.setTop(createMenu()); head.setCenter(createToolbar()); @@ -520,7 +520,10 @@ private Node createToolbar() { leftSide.prefWidthProperty().bind(sidePane.widthProperty()); leftSide.maxWidthProperty().bind(sidePane.widthProperty()); - PushToApplicationAction pushToApplicationAction = new PushToApplicationAction(stateManager, this.getPushApplications(), this.getDialogService()); + final PushToApplicationAction pushToApplicationAction = getPushToApplicationsManager().getPushToApplicationAction(); + final Button pushToApplicationButton = factory.createIconButton(pushToApplicationAction.getActionInformation(), pushToApplicationAction); + pushToApplicationsManager.setToolBarButton(pushToApplicationButton); + HBox rightSide = new HBox( factory.createIconButton(StandardActions.NEW_ARTICLE, new NewEntryAction(this, BiblatexEntryTypes.ARTICLE, dialogService, Globals.prefs, stateManager)), factory.createIconButton(StandardActions.DELETE_ENTRY, new OldDatabaseCommandWrapper(Actions.DELETE, this, stateManager)), @@ -531,7 +534,7 @@ private Node createToolbar() { factory.createIconButton(StandardActions.COPY, new OldDatabaseCommandWrapper(Actions.COPY, this, stateManager)), factory.createIconButton(StandardActions.PASTE, new OldDatabaseCommandWrapper(Actions.PASTE, this, stateManager)), new Separator(Orientation.VERTICAL), - factory.createIconButton(pushToApplicationAction.getActionInformation(), pushToApplicationAction), + pushToApplicationButton, factory.createIconButton(StandardActions.GENERATE_CITE_KEYS, new OldDatabaseCommandWrapper(Actions.MAKE_KEY, this, stateManager)), factory.createIconButton(StandardActions.CLEANUP_ENTRIES, new OldDatabaseCommandWrapper(Actions.CLEANUP, this, stateManager)), new Separator(Orientation.VERTICAL), @@ -759,7 +762,11 @@ private MenuBar createMenu() { factory.createMenuItem(StandardActions.SET_FILE_LINKS, new AutoLinkFilesAction(this, prefs, stateManager, undoManager)) ); - final PushToApplicationAction pushToApplicationAction = new PushToApplicationAction(stateManager, this.getPushApplications(), this.getDialogService()); + // PushToApplication + final PushToApplicationAction pushToApplicationAction = pushToApplicationsManager.getPushToApplicationAction(); + final MenuItem pushToApplicationMenuItem = factory.createMenuItem(pushToApplicationAction.getActionInformation(), pushToApplicationAction); + pushToApplicationsManager.setMenuItem(pushToApplicationMenuItem); + tools.getItems().addAll( factory.createMenuItem(StandardActions.NEW_SUB_LIBRARY_FROM_AUX, new NewSubLibraryAction(this, stateManager)), factory.createMenuItem(StandardActions.FIND_UNLINKED_FILES, new FindUnlinkedFilesAction(this, stateManager)), @@ -776,7 +783,7 @@ private MenuBar createMenu() { factory.createMenuItem(StandardActions.GENERATE_CITE_KEYS, new OldDatabaseCommandWrapper(Actions.MAKE_KEY, this, stateManager)), factory.createMenuItem(StandardActions.REPLACE_ALL, new OldDatabaseCommandWrapper(Actions.REPLACE_ALL, this, stateManager)), factory.createMenuItem(StandardActions.SEND_AS_EMAIL, new OldDatabaseCommandWrapper(Actions.SEND_AS_EMAIL, this, stateManager)), - factory.createMenuItem(pushToApplicationAction.getActionInformation(), pushToApplicationAction), + pushToApplicationMenuItem, factory.createSubMenu(StandardActions.ABBREVIATE, factory.createMenuItem(StandardActions.ABBREVIATE_ISO, new OldDatabaseCommandWrapper(Actions.ABBREVIATE_ISO, this, stateManager)), @@ -1192,8 +1199,8 @@ public SidePaneManager getSidePaneManager() { return sidePaneManager; } - public PushToApplicationsManager getPushApplications() { - return pushApplications; + public PushToApplicationsManager getPushToApplicationsManager() { + return pushToApplicationsManager; } public GlobalSearchBar getGlobalSearchBar() { diff --git a/src/main/java/org/jabref/gui/preferences/ExternalTab.java b/src/main/java/org/jabref/gui/preferences/ExternalTab.java index afb52861d68..a2bca6c0077 100644 --- a/src/main/java/org/jabref/gui/preferences/ExternalTab.java +++ b/src/main/java/org/jabref/gui/preferences/ExternalTab.java @@ -3,7 +3,10 @@ import javafx.geometry.Pos; import javafx.scene.Node; import javafx.scene.control.Button; +import javafx.scene.control.ButtonType; import javafx.scene.control.CheckBox; +import javafx.scene.control.ComboBox; +import javafx.scene.control.DialogPane; import javafx.scene.control.Label; import javafx.scene.control.RadioButton; import javafx.scene.control.Separator; @@ -18,8 +21,9 @@ import org.jabref.gui.externalfiletype.EditExternalFileTypesAction; import org.jabref.gui.push.PushToApplication; import org.jabref.gui.push.PushToApplicationSettings; -import org.jabref.gui.push.PushToApplicationSettingsDialog; +import org.jabref.gui.push.PushToApplicationsManager; import org.jabref.gui.util.FileDialogConfiguration; +import org.jabref.gui.util.ViewModelListCellFactory; import org.jabref.logic.l10n.Localization; import org.jabref.logic.util.OS; import org.jabref.model.strings.StringUtil; @@ -30,6 +34,8 @@ class ExternalTab implements PrefsTab { private final JabRefFrame frame; private final JabRefPreferences prefs; private final TextField emailSubject; + private final ComboBox pushToApplicationComboBox; + private final TextField citeCommand; private final CheckBox openFoldersOfAttachedFiles; @@ -58,6 +64,10 @@ public ExternalTab(JabRefFrame frame, PreferencesDialog prefsDiag, JabRefPrefere dialogService = frame.getDialogService(); builder.setVgap(7); + pushToApplicationComboBox = new ComboBox<>(); + Button pushToApplicationSettingsButton = new Button(Localization.lang("Application settings")); + pushToApplicationSettingsButton.setOnAction(e -> showPushToApplicationSettings()); + Button editFileTypes = new Button(Localization.lang("Manage external file types")); citeCommand = new TextField(); editFileTypes.setOnAction(e -> new EditExternalFileTypesAction().execute()); @@ -147,13 +157,19 @@ public ExternalTab(JabRefFrame frame, PreferencesDialog prefsDiag, JabRefPrefere externalPrograms.getStyleClass().add("sectionHeader"); builder.add(externalPrograms, 1, 9); - GridPane butpan = new GridPane(); - int index = 0; - for (PushToApplication pushToApplication : frame.getPushApplications().getApplications()) { - addSettingsButton(pushToApplication, butpan, index); - index++; - } - builder.add(butpan, 1, 10); + // PushToApplication configuration + HBox pushToApplicationHBox = new HBox(); + pushToApplicationHBox.setAlignment(Pos.CENTER_LEFT); + pushToApplicationHBox.setSpacing(10); + pushToApplicationHBox.getChildren().add(new Label(Localization.lang("Application to push entries to:"))); + new ViewModelListCellFactory() + .withText(application -> application.getApplicationName()) + .withIcon(application -> application.getIcon()) + .install(pushToApplicationComboBox); + pushToApplicationComboBox.getItems().addAll(frame.getPushToApplicationsManager().getApplications()); + pushToApplicationHBox.getChildren().add(pushToApplicationComboBox); + pushToApplicationHBox.getChildren().add(pushToApplicationSettingsButton); + builder.add(pushToApplicationHBox, 1, 10); // Cite command configuration HBox citeCommandBox = new HBox(); @@ -197,24 +213,13 @@ public Node getBuilder() { return builder; } - private void addSettingsButton(final PushToApplication application, GridPane panel, int index) { - PushToApplicationSettings settings = frame.getPushApplications().getSettings(application); - Button button = new Button(Localization.lang("Settings for %0", application.getApplicationName())); - button.setPrefSize(150, 20); - button.setOnAction(e -> PushToApplicationSettingsDialog.showSettingsDialog(dialogService, settings, index)); - if ((index % 2) == 0) { - panel.add(button, 1, (index / 2) + 1); - } else { - panel.add(button, 2, (index / 2) + 1); - } - } - @Override public void setValues() { emailSubject.setText(prefs.get(JabRefPreferences.EMAIL_SUBJECT)); openFoldersOfAttachedFiles.setSelected(prefs.getBoolean(JabRefPreferences.OPEN_FOLDERS_OF_ATTACHED_FILES)); + pushToApplicationComboBox.setValue(prefs.getActivePushToApplication(frame.getPushToApplicationsManager())); citeCommand.setText(prefs.get(JabRefPreferences.CITE_COMMAND)); defaultConsole.setSelected(Globals.prefs.getBoolean(JabRefPreferences.USE_DEFAULT_CONSOLE_APPLICATION)); @@ -244,6 +249,7 @@ public void setValues() { public void storeSettings() { prefs.put(JabRefPreferences.EMAIL_SUBJECT, emailSubject.getText()); prefs.putBoolean(JabRefPreferences.OPEN_FOLDERS_OF_ATTACHED_FILES, openFoldersOfAttachedFiles.isSelected()); + prefs.setActivePushToApplication(pushToApplicationComboBox.getValue(), frame.getPushToApplicationsManager()); prefs.put(JabRefPreferences.CITE_COMMAND, citeCommand.getText()); prefs.putBoolean(JabRefPreferences.USE_DEFAULT_CONSOLE_APPLICATION, defaultConsole.isSelected()); prefs.put(JabRefPreferences.CONSOLE_COMMAND, consoleCommand.getText()); @@ -276,6 +282,20 @@ private void updateExecuteConsoleButtonAndFieldEnabledState() { consoleCommand.setDisable(!executeConsole.isSelected()); } + private void showPushToApplicationSettings() { + PushToApplicationsManager manager = frame.getPushToApplicationsManager(); + PushToApplication selectedApplication = pushToApplicationComboBox.getValue(); + PushToApplicationSettings settings = manager.getSettings(selectedApplication); + DialogPane dialogPane = new DialogPane(); + dialogPane.setContent(settings.getSettingsPane()); + + dialogService.showCustomDialogAndWait(Localization.lang("Application settings"), dialogPane, ButtonType.OK, ButtonType.CANCEL).ifPresent(btn -> { + if (btn == ButtonType.OK) { + settings.storeSettings(); + } + }); + } + private void showConsoleChooser() { dialogService.showFileOpenDialog(fileDialogConfiguration).ifPresent(file -> consoleCommand.setText(file.toAbsolutePath().toString())); } diff --git a/src/main/java/org/jabref/gui/push/PushToApplicationAction.java b/src/main/java/org/jabref/gui/push/PushToApplicationAction.java index ecfb54763ad..a042a1210cb 100644 --- a/src/main/java/org/jabref/gui/push/PushToApplicationAction.java +++ b/src/main/java/org/jabref/gui/push/PushToApplicationAction.java @@ -25,12 +25,13 @@ */ public class PushToApplicationAction extends SimpleCommand { - private final PushToApplication operation; private final StateManager stateManager; private final DialogService dialogService; + private PushToApplication application; + public PushToApplicationAction(StateManager stateManager, PushToApplicationsManager pushToApplicationsManager, DialogService dialogService) { - this.operation = pushToApplicationsManager.getLastUsedApplication(Globals.prefs); + this.application = Globals.prefs.getActivePushToApplication(pushToApplicationsManager); this.stateManager = stateManager; this.dialogService = dialogService; @@ -38,12 +39,15 @@ public PushToApplicationAction(StateManager stateManager, PushToApplicationsMana this.statusMessage.bind(BindingsHelper.ifThenElse(this.executable, "", Localization.lang("This operation requires one or more entries to be selected."))); } + public void updateApplication(PushToApplication application) { + this.application = application; + } + public Action getActionInformation() { return new Action() { - @Override public Optional getIcon() { - return Optional.of(operation.getIcon()); + return Optional.of(application.getIcon()); } @Override @@ -53,7 +57,7 @@ public Optional getKeyBinding() { @Override public String getText() { - return Localization.lang("Push entries to external application (%0)", operation.getApplicationName()); + return Localization.lang("Push entries to external application (%0)", application.getApplicationName()); } @Override @@ -86,11 +90,11 @@ private static String getKeyString(List entries) { @Override public void execute() { // If required, check that all entries have BibTeX keys defined: - if (operation.requiresBibtexKeys()) { + if (application.requiresBibtexKeys()) { for (BibEntry entry : stateManager.getSelectedEntries()) { if (StringUtil.isBlank(entry.getCiteKeyOptional())) { dialogService.showErrorDialogAndWait( - operation.getApplicationName(), + application.getApplicationName(), Localization.lang("This operation requires all selected entries to have BibTeX keys defined.")); return; @@ -100,13 +104,12 @@ public void execute() { // All set, call the operation in a new thread: BackgroundTask.wrap(this::pushEntries) - .onSuccess(s -> operation.operationCompleted()) + .onSuccess(s -> application.operationCompleted()) .executeWith(Globals.TASK_EXECUTOR); - } private void pushEntries() { BibDatabaseContext database = stateManager.getActiveDatabase().orElseThrow(() -> new NullPointerException("Database null")); - operation.pushEntries(database, stateManager.getSelectedEntries(), getKeyString(stateManager.getSelectedEntries())); + application.pushEntries(database, stateManager.getSelectedEntries(), getKeyString(stateManager.getSelectedEntries())); } } diff --git a/src/main/java/org/jabref/gui/push/PushToApplicationSettings.java b/src/main/java/org/jabref/gui/push/PushToApplicationSettings.java index 5bf9d5a75f7..5758eefb892 100644 --- a/src/main/java/org/jabref/gui/push/PushToApplicationSettings.java +++ b/src/main/java/org/jabref/gui/push/PushToApplicationSettings.java @@ -13,70 +13,42 @@ public class PushToApplicationSettings { - protected final TextField path = new TextField(); - protected Label commandLabel = new Label(); - protected GridPane jfxSettings; - protected AbstractPushToApplication application; - private DialogService dialogService; + protected final Label commandLabel; + protected final TextField path; + protected final GridPane settingsPane; + private final AbstractPushToApplication application; + private final DialogService dialogService; + private final Button browse; - public PushToApplicationSettings(DialogService dialogService) { + public PushToApplicationSettings(PushToApplication application, DialogService dialogService) { + this.application = (AbstractPushToApplication) application; this.dialogService = dialogService; - } + settingsPane = new GridPane(); - public GridPane getJFXSettingPane(int n) { - switch (n) { - case 0: - application = new PushToEmacs(dialogService); - break; - case 1: - application = new PushToLyx(dialogService); - break; - case 2: - application = new PushToTexmaker(dialogService); - break; - case 3: - application = new PushToTeXstudio(dialogService); - break; - case 4: - application = new PushToVim(dialogService); - break; - case 5: - application = new PushToWinEdt(dialogService); - break; - default: - application = null; - break; - } - application.initParameters(); - String commandPath = Globals.prefs.get(application.commandPathPreferenceKey); - if (jfxSettings == null) { - initJFXSettingsPanel(); - } - path.setText(commandPath); + commandLabel = new Label(); + path = new TextField(); + browse = new Button(Localization.lang("Browse")); - return jfxSettings; - } + this.application.initParameters(); - protected void initJFXSettingsPanel() { - jfxSettings = new GridPane(); - StringBuilder label = new StringBuilder(Localization.lang("Path to %0", application.getApplicationName())); // In case the application name and the actual command is not the same, add the command in brackets - if (application.getCommandName() == null) { - label.append(':'); + StringBuilder commandLine = new StringBuilder(Localization.lang("Path to %0", application.getApplicationName())); + if (this.application.getCommandName() == null) { + commandLine.append(':'); } else { - label.append(" (").append(application.getCommandName()).append("):"); + commandLine.append(" (").append(this.application.getCommandName()).append("):"); } - commandLabel = new Label(label.toString()); - jfxSettings.add(commandLabel, 0, 0); - jfxSettings.add(path, 1, 0); - Button browse = new Button(Localization.lang("Browse")); + commandLabel.setText(commandLine.toString()); + settingsPane.add(commandLabel, 0, 0); - FileDialogConfiguration fileDialogConfiguration = new FileDialogConfiguration.Builder() - .withInitialDirectory(Globals.prefs.get(JabRefPreferences.WORKING_DIRECTORY)).build(); + path.setText(Globals.prefs.get(this.application.commandPathPreferenceKey)); + settingsPane.add(path, 1, 0); + FileDialogConfiguration fileDialogConfiguration = new FileDialogConfiguration.Builder() + .withInitialDirectory(Globals.prefs.get(JabRefPreferences.WORKING_DIRECTORY)).build(); browse.setOnAction(e -> dialogService.showFileOpenDialog(fileDialogConfiguration) .ifPresent(f -> path.setText(f.toAbsolutePath().toString()))); - jfxSettings.add(browse, 2, 0); + settingsPane.add(browse, 2, 0); } /** @@ -87,4 +59,8 @@ protected void initJFXSettingsPanel() { public void storeSettings() { Globals.prefs.put(application.commandPathPreferenceKey, path.getText()); } + + public GridPane getSettingsPane() { + return settingsPane; + } } diff --git a/src/main/java/org/jabref/gui/push/PushToApplicationSettingsDialog.java b/src/main/java/org/jabref/gui/push/PushToApplicationSettingsDialog.java deleted file mode 100644 index 4374c7322a0..00000000000 --- a/src/main/java/org/jabref/gui/push/PushToApplicationSettingsDialog.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.jabref.gui.push; - -import javafx.scene.control.ButtonType; -import javafx.scene.control.DialogPane; - -import org.jabref.gui.DialogService; -import org.jabref.logic.l10n.Localization; - -public class PushToApplicationSettingsDialog { - - public static void showSettingsDialog(DialogService dialogService, PushToApplicationSettings toApp, int n) { - - DialogPane dialogPane = new DialogPane(); - dialogPane.setContent(toApp.getJFXSettingPane(n)); - - dialogService.showCustomDialogAndWait(Localization.lang("App settings"), dialogPane, ButtonType.OK, ButtonType.CANCEL).ifPresent(btn -> { - if (btn == ButtonType.OK) { - toApp.storeSettings(); - } - }); - } -} diff --git a/src/main/java/org/jabref/gui/push/PushToApplicationsManager.java b/src/main/java/org/jabref/gui/push/PushToApplicationsManager.java index e7bfaf78b3b..64dbc4be850 100644 --- a/src/main/java/org/jabref/gui/push/PushToApplicationsManager.java +++ b/src/main/java/org/jabref/gui/push/PushToApplicationsManager.java @@ -3,8 +3,13 @@ import java.util.ArrayList; import java.util.List; +import javafx.scene.control.Button; +import javafx.scene.control.MenuItem; + +import org.jabref.Globals; import org.jabref.gui.DialogService; -import org.jabref.preferences.JabRefPreferences; +import org.jabref.gui.StateManager; +import org.jabref.gui.actions.ActionFactory; public class PushToApplicationsManager { @@ -12,7 +17,11 @@ public class PushToApplicationsManager { private final DialogService dialogService; - public PushToApplicationsManager(DialogService dialogService) { + private final PushToApplicationAction action; + private MenuItem menuItem; + private Button toolBarButton; + + public PushToApplicationsManager(DialogService dialogService, StateManager stateManager) { this.dialogService = dialogService; // Set up the current available choices: applications = new ArrayList<>(); @@ -22,29 +31,56 @@ public PushToApplicationsManager(DialogService dialogService) { applications.add(new PushToTeXstudio(dialogService)); applications.add(new PushToVim(dialogService)); applications.add(new PushToWinEdt(dialogService)); + + this.action = new PushToApplicationAction(stateManager, this, dialogService); } public List getApplications() { return applications; } + public PushToApplicationAction getPushToApplicationAction() { + return action; + } + + public void setMenuItem(MenuItem menuItem) { + this.menuItem = menuItem; + } + + public void setToolBarButton(Button toolBarButton) { + this.toolBarButton = toolBarButton; + } + public PushToApplicationSettings getSettings(PushToApplication application) { if (application instanceof PushToEmacs) { - return new PushToEmacsSettings(dialogService); + return new PushToEmacsSettings(application, dialogService); } else if (application instanceof PushToLyx) { - return new PushToLyxSettings(dialogService); + return new PushToLyxSettings(application, dialogService); } else if (application instanceof PushToVim) { - return new PushToVimSettings(dialogService); + return new PushToVimSettings(application, dialogService); } else { - return new PushToApplicationSettings(dialogService); + return new PushToApplicationSettings(application, dialogService); } } - public PushToApplication getLastUsedApplication(JabRefPreferences preferences) { - String appSelected = preferences.get(JabRefPreferences.PUSH_TO_APPLICATION); + public PushToApplication getApplicationByName(String applicationName) { return applications.stream() - .filter(application -> application.getApplicationName().equals(appSelected)) + .filter(application -> application.getApplicationName().equals(applicationName)) .findAny() .orElse(applications.get(0)); } + + public void updateApplicationAction() { + final ActionFactory factory = new ActionFactory(Globals.getKeyPrefs()); + + action.updateApplication(Globals.prefs.getActivePushToApplication(this)); + + if (menuItem != null) { + factory.configureMenuItem(action.getActionInformation(), action, menuItem); + } + + if (toolBarButton != null) { + factory.configureIconButton(action.getActionInformation(), action, toolBarButton); + } + } } diff --git a/src/main/java/org/jabref/gui/push/PushToEmacsSettings.java b/src/main/java/org/jabref/gui/push/PushToEmacsSettings.java index 0147276b652..5e3364f1939 100644 --- a/src/main/java/org/jabref/gui/push/PushToEmacsSettings.java +++ b/src/main/java/org/jabref/gui/push/PushToEmacsSettings.java @@ -12,19 +12,16 @@ public class PushToEmacsSettings extends PushToApplicationSettings { private final TextField additionalParams = new TextField(); - public PushToEmacsSettings (DialogService dialogService) { super(dialogService); } + public PushToEmacsSettings(PushToApplication application, DialogService dialogService) { + super(application, dialogService); + settingsPane.add(new Label(Localization.lang("Additional parameters") + ":"), 0, 1); + settingsPane.add(additionalParams, 1, 1); + additionalParams.setText(Globals.prefs.get(JabRefPreferences.EMACS_ADDITIONAL_PARAMETERS)); + } @Override public void storeSettings() { super.storeSettings(); Globals.prefs.put(JabRefPreferences.EMACS_ADDITIONAL_PARAMETERS, additionalParams.getText()); } - - @Override - protected void initJFXSettingsPanel() { - super.initJFXSettingsPanel(); - jfxSettings.add(new Label(Localization.lang("Additional parameters") + ":"), 0, 1); - jfxSettings.add(additionalParams, 1, 1); - additionalParams.setText(Globals.prefs.get(JabRefPreferences.EMACS_ADDITIONAL_PARAMETERS)); - } } diff --git a/src/main/java/org/jabref/gui/push/PushToLyxSettings.java b/src/main/java/org/jabref/gui/push/PushToLyxSettings.java index 85fe05a97e4..70ae6e2132e 100644 --- a/src/main/java/org/jabref/gui/push/PushToLyxSettings.java +++ b/src/main/java/org/jabref/gui/push/PushToLyxSettings.java @@ -7,11 +7,8 @@ public class PushToLyxSettings extends PushToApplicationSettings { - public PushToLyxSettings (DialogService dialogService) { super(dialogService); } - - @Override - protected void initJFXSettingsPanel() { - super.initJFXSettingsPanel(); + public PushToLyxSettings(PushToApplication application, DialogService dialogService) { + super(application, dialogService); path.setText(Globals.prefs.get(JabRefPreferences.LYXPIPE)); commandLabel.setText(Localization.lang("Path to LyX pipe") + ":"); } diff --git a/src/main/java/org/jabref/gui/push/PushToVimSettings.java b/src/main/java/org/jabref/gui/push/PushToVimSettings.java index 70438ed9115..fa08f9de83a 100644 --- a/src/main/java/org/jabref/gui/push/PushToVimSettings.java +++ b/src/main/java/org/jabref/gui/push/PushToVimSettings.java @@ -12,19 +12,16 @@ public class PushToVimSettings extends PushToApplicationSettings { private final TextField vimServer = new TextField(); - public PushToVimSettings (DialogService dialogService) { super(dialogService); } + public PushToVimSettings(PushToApplication application, DialogService dialogService) { + super(application, dialogService); + settingsPane.add(new Label(Localization.lang("Vim server name") + ":"), 0, 1); + settingsPane.add(vimServer, 1, 1); + vimServer.setText(Globals.prefs.get(JabRefPreferences.VIM_SERVER)); + } @Override public void storeSettings() { super.storeSettings(); Globals.prefs.put(JabRefPreferences.VIM_SERVER, vimServer.getText()); } - - @Override - protected void initJFXSettingsPanel() { - super.initJFXSettingsPanel(); - jfxSettings.add(new Label(Localization.lang("Vim server name") + ":"), 0, 1); - jfxSettings.add(vimServer, 1, 1); - vimServer.setText(Globals.prefs.get(JabRefPreferences.VIM_SERVER)); - } } diff --git a/src/main/java/org/jabref/preferences/JabRefPreferences.java b/src/main/java/org/jabref/preferences/JabRefPreferences.java index 8ea32b20878..253b64cb8e4 100644 --- a/src/main/java/org/jabref/preferences/JabRefPreferences.java +++ b/src/main/java/org/jabref/preferences/JabRefPreferences.java @@ -53,6 +53,8 @@ import org.jabref.gui.maintable.MainTablePreferences; import org.jabref.gui.mergeentries.MergeEntries; import org.jabref.gui.preferences.ImportSettingsTab; +import org.jabref.gui.push.PushToApplication; +import org.jabref.gui.push.PushToApplicationsManager; import org.jabref.gui.util.ThemeLoader; import org.jabref.logic.bibtex.FieldContentParserPreferences; import org.jabref.logic.bibtex.LatexFieldFormatterPreferences; @@ -2105,4 +2107,15 @@ private void saveCustomEntryTypes(BibDatabaseMode bibDatabaseMode) { storeCustomEntryTypes(customBiblatexBibTexTypes, bibDatabaseMode); } + + public PushToApplication getActivePushToApplication(PushToApplicationsManager manager) { + return manager.getApplicationByName(get(JabRefPreferences.PUSH_TO_APPLICATION)); + } + + public void setActivePushToApplication(PushToApplication application, PushToApplicationsManager manager) { + if (application.getApplicationName() != get(PUSH_TO_APPLICATION)) { + put(PUSH_TO_APPLICATION, application.getApplicationName()); + manager.updateApplicationAction(); + } + } } diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index 58822acd1ce..28e5ce1f177 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -67,6 +67,8 @@ Append\ library=Append library Application=Application +Application\ to\ push\ entries\ to\:=Application to push entries to: + Apply=Apply Arguments\ passed\ on\ to\ running\ JabRef\ instance.\ Shutting\ down.=Arguments passed on to running JabRef instance. Shutting down. @@ -1044,7 +1046,6 @@ Reset=Reset Use\ IEEE\ LaTeX\ abbreviations=Use IEEE LaTeX abbreviations When\ opening\ file\ link,\ search\ for\ matching\ file\ if\ no\ link\ is\ defined=When opening file link, search for matching file if no link is defined -Settings\ for\ %0=Settings for %0 Line\ %0\:\ Found\ corrupted\ BibTeX\ key\ %1.=Line %0: Found corrupted BibTeX key %1. Line\ %0\:\ Found\ corrupted\ BibTeX\ key\ %1\ (contains\ whitespaces).=Line %0: Found corrupted BibTeX key %1 (contains whitespaces). Line\ %0\:\ Found\ corrupted\ BibTeX\ key\ %1\ (comma\ missing).=Line %0: Found corrupted BibTeX key %1 (comma missing). @@ -2086,7 +2087,7 @@ Rename\ file\ to\ a\ given\ name=Rename file to a given name New\ Filename=New Filename Rename\ file\ to\ defined\ pattern=Rename file to defined pattern -App\ settings=App settings +Application\ settings=Application settings Export\ an\ input\ to\ a\ file=Export an input to a file Export\ preferences\ to\ a\ file=Export preferences to a file From c612072a38842ab0201fc3bde23f06e95cc4bde2 Mon Sep 17 00:00:00 2001 From: yurickyh Date: Wed, 5 Jun 2019 19:15:43 -0300 Subject: [PATCH 011/103] Change TreeMap for LinkedHashMap on create function. The reason for changing the type of the object is because TreeMap automatically orders by the key. Signed-off-by: kaiquekk Signed-off-by: yurickyh --- .../java/org/jabref/gui/entryeditor/EntryEditorTabList.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jabref/gui/entryeditor/EntryEditorTabList.java b/src/main/java/org/jabref/gui/entryeditor/EntryEditorTabList.java index f35f8c94ad6..e59854ede62 100644 --- a/src/main/java/org/jabref/gui/entryeditor/EntryEditorTabList.java +++ b/src/main/java/org/jabref/gui/entryeditor/EntryEditorTabList.java @@ -3,7 +3,7 @@ import java.util.Arrays; import java.util.List; import java.util.Map; -import java.util.TreeMap; +import java.util.LinkedHashMap; import org.jabref.preferences.JabRefPreferences; @@ -17,7 +17,7 @@ private EntryEditorTabList() { } public static Map> create(JabRefPreferences preferences) { - Map> tabs = new TreeMap<>(); + Map> tabs = new LinkedHashMap<>(); int i = 0; String name; if (preferences.hasKey(JabRefPreferences.CUSTOM_TAB_NAME + 0)) { From d78997c0eefcf316402ef9537dcf126cf74852e2 Mon Sep 17 00:00:00 2001 From: yurickyh Date: Wed, 5 Jun 2019 19:20:53 -0300 Subject: [PATCH 012/103] Remove the character '-' on KEY_ILLEGAL_CHARACTERS and KEY_UNWANTED_CHARACTERS constants. The character '-' was removed because it was not able to use it when defining a new field. Signed-off-by: kaiquekk Signed-off-by: yurickyh --- .../org/jabref/logic/bibtexkeypattern/BibtexKeyGenerator.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/jabref/logic/bibtexkeypattern/BibtexKeyGenerator.java b/src/main/java/org/jabref/logic/bibtexkeypattern/BibtexKeyGenerator.java index 02a2fce80ac..4c24ef286c1 100644 --- a/src/main/java/org/jabref/logic/bibtexkeypattern/BibtexKeyGenerator.java +++ b/src/main/java/org/jabref/logic/bibtexkeypattern/BibtexKeyGenerator.java @@ -26,8 +26,8 @@ public class BibtexKeyGenerator extends BracketedPattern { */ public static final String APPENDIX_CHARACTERS = "abcdefghijklmnopqrstuvwxyz"; private static final Logger LOGGER = LoggerFactory.getLogger(BibtexKeyGenerator.class); - private static final String KEY_ILLEGAL_CHARACTERS = "{}(),\\\"-#~^:'`ʹ"; - private static final String KEY_UNWANTED_CHARACTERS = "{}(),\\\"-"; + private static final String KEY_ILLEGAL_CHARACTERS = "{}(),\\\"#~^:'`ʹ"; + private static final String KEY_UNWANTED_CHARACTERS = "{}(),\\\""; private final AbstractBibtexKeyPattern citeKeyPattern; private final BibDatabase database; private final BibtexKeyPatternPreferences bibtexKeyPatternPreferences; From ad6e549f329395999216ad1e7341d453d8a141c8 Mon Sep 17 00:00:00 2001 From: kaiquekk Date: Wed, 5 Jun 2019 19:54:40 -0300 Subject: [PATCH 013/103] Add changes in CHANGELOG. Signed-off-by: kaiquekk --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bc0063bb095..8280cf8ec43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -66,6 +66,7 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# - We added an option on the Linked File Viewer to rename the attached file of an entry directly on the JabRef. [#4844](https://github.com/JabRef/jabref/issues/4844) - We added an option in the preference dialog box that allows user to enable helpful tooltips.[#3599](https://github.com/JabRef/jabref/issues/3599) - We moved the dropdown menu for selecting the push-application from the toolbar into the external application preferences. [#674](https://github.com/JabRef/jabref/issues/674) +- We added the option to set up a general field with a name containing "-" and removed the alphabetical ordering of the tabs. [#5019](https://github.com/JabRef/jabref/issues/5019) ### Fixed From c527f710cf943789aef0016ee1e05024108ba146 Mon Sep 17 00:00:00 2001 From: kaiquekk Date: Wed, 5 Jun 2019 20:02:54 -0300 Subject: [PATCH 014/103] Fix checkstyle error. Signed-off-by: kaiquekk --- .../java/org/jabref/gui/entryeditor/EntryEditorTabList.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/entryeditor/EntryEditorTabList.java b/src/main/java/org/jabref/gui/entryeditor/EntryEditorTabList.java index e59854ede62..49a337788a9 100644 --- a/src/main/java/org/jabref/gui/entryeditor/EntryEditorTabList.java +++ b/src/main/java/org/jabref/gui/entryeditor/EntryEditorTabList.java @@ -1,9 +1,9 @@ package org.jabref.gui.entryeditor; import java.util.Arrays; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.LinkedHashMap; import org.jabref.preferences.JabRefPreferences; From 57782e47f0878168c94ed2e9a609c921c8e2cd1c Mon Sep 17 00:00:00 2001 From: kaiquekk Date: Wed, 5 Jun 2019 20:31:21 -0300 Subject: [PATCH 015/103] Remove option to name a field with hyphen. Remove the option to name a custom general field containing a hyphen and update the error message to be more clear about it. Signed-off-by: kaiquekk --- CHANGELOG.md | 2 +- .../CustomizeGeneralFieldsDialogViewModel.java | 2 +- .../org/jabref/logic/bibtexkeypattern/BibtexKeyGenerator.java | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8280cf8ec43..468e99f68d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -66,7 +66,7 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `# - We added an option on the Linked File Viewer to rename the attached file of an entry directly on the JabRef. [#4844](https://github.com/JabRef/jabref/issues/4844) - We added an option in the preference dialog box that allows user to enable helpful tooltips.[#3599](https://github.com/JabRef/jabref/issues/3599) - We moved the dropdown menu for selecting the push-application from the toolbar into the external application preferences. [#674](https://github.com/JabRef/jabref/issues/674) -- We added the option to set up a general field with a name containing "-" and removed the alphabetical ordering of the tabs. [#5019](https://github.com/JabRef/jabref/issues/5019) +- We removed the alphabetical ordering of the custom tabs and updated the error message when trying to create a general field with a name containing an illegal character. [#5019](https://github.com/JabRef/jabref/issues/5019) ### Fixed diff --git a/src/main/java/org/jabref/gui/customizefields/CustomizeGeneralFieldsDialogViewModel.java b/src/main/java/org/jabref/gui/customizefields/CustomizeGeneralFieldsDialogViewModel.java index 1d388df6555..638ffc9014f 100644 --- a/src/main/java/org/jabref/gui/customizefields/CustomizeGeneralFieldsDialogViewModel.java +++ b/src/main/java/org/jabref/gui/customizefields/CustomizeGeneralFieldsDialogViewModel.java @@ -60,7 +60,7 @@ public void saveFields() { String title = Localization.lang("Error"); String content = Localization.lang("Field names are not allowed to contain white space or the following " + "characters") - + ": # { } ~ , ^ &"; + + ": # { } ( ) ~ , ^ & - \" ' ` ʹ \\"; dialogService.showInformationDialogAndWait(title, content); return; } diff --git a/src/main/java/org/jabref/logic/bibtexkeypattern/BibtexKeyGenerator.java b/src/main/java/org/jabref/logic/bibtexkeypattern/BibtexKeyGenerator.java index 4c24ef286c1..02a2fce80ac 100644 --- a/src/main/java/org/jabref/logic/bibtexkeypattern/BibtexKeyGenerator.java +++ b/src/main/java/org/jabref/logic/bibtexkeypattern/BibtexKeyGenerator.java @@ -26,8 +26,8 @@ public class BibtexKeyGenerator extends BracketedPattern { */ public static final String APPENDIX_CHARACTERS = "abcdefghijklmnopqrstuvwxyz"; private static final Logger LOGGER = LoggerFactory.getLogger(BibtexKeyGenerator.class); - private static final String KEY_ILLEGAL_CHARACTERS = "{}(),\\\"#~^:'`ʹ"; - private static final String KEY_UNWANTED_CHARACTERS = "{}(),\\\""; + private static final String KEY_ILLEGAL_CHARACTERS = "{}(),\\\"-#~^:'`ʹ"; + private static final String KEY_UNWANTED_CHARACTERS = "{}(),\\\"-"; private final AbstractBibtexKeyPattern citeKeyPattern; private final BibDatabase database; private final BibtexKeyPatternPreferences bibtexKeyPatternPreferences; From dd4f0a08905cf2ef3d2e3231b1fb87c1950fab9c Mon Sep 17 00:00:00 2001 From: Christoph Date: Thu, 6 Jun 2019 10:08:22 +0200 Subject: [PATCH 016/103] convert search worker to javafx (#4897) * convert search worker to javafx * remove obsolete search worker * Add search query update result count * First attempt at creating search highlighter for source tab * Add custom css for codeArea highlighting on Search * fix exception loop * inline search listener * refactor searchQueryHighlightobservable * fix checkstyle * fireSearchQueryHighlitghter on focus change * Add sample js for highlighting * add search query highlither to handle the highlighting * add new regex js * remove highlith listener before adding new one use innertext in js * fix merge, move code to new PreviewViewer * fix checkstyle * fix search highlighting in source editor fix listeners * refactor state manager as parameter move css for highlighting binding for searchResultSize * Get rid of SearchQueryHighlightObservable Use SearchQuery directly TODO: fix updating of search results * update on search * fix checkstyle * try again with checkstyle declaration order * Finally fix the number of search results on multiple libs * fix checkstyle --- src/main/java/org/jabref/gui/BasePanel.java | 3 +- .../java/org/jabref/gui/StateManager.java | 15 +++- .../gui/collab/EntryAddChangeViewModel.java | 3 +- .../collab/EntryDeleteChangeViewModel.java | 3 +- .../jabref/gui/entryeditor/EntryEditor.css | 6 ++ .../jabref/gui/entryeditor/EntryEditor.java | 52 ++++------- .../org/jabref/gui/entryeditor/SourceTab.java | 45 ++++++++-- .../gui/maintable/MainTableDataModel.java | 6 ++ .../gui/openoffice/StyleSelectDialogView.java | 5 +- .../preferences/PreviewPreferencesTab.java | 2 +- .../org/jabref/gui/preview/PreviewPanel.java | 11 +-- .../org/jabref/gui/preview/PreviewViewer.java | 82 ++++++++++++++---- .../jabref/gui/search/GlobalSearchBar.java | 34 +++----- .../org/jabref/gui/search/SearchWorker.java | 68 --------------- .../org/jabref/logic/search/SearchQuery.java | 31 ++++++- .../search/SearchQueryHighlightListener.java | 20 ----- .../SearchQueryHighlightObservable.java | 86 ------------------- .../jabref/gui/entryeditor/SourceTabTest.java | 3 +- .../SearchQueryHighlightObservableTest.java | 59 ------------- .../jabref/logic/search/SearchQueryTest.java | 13 ++- 20 files changed, 205 insertions(+), 342 deletions(-) delete mode 100644 src/main/java/org/jabref/gui/search/SearchWorker.java delete mode 100644 src/main/java/org/jabref/logic/search/SearchQueryHighlightListener.java delete mode 100644 src/main/java/org/jabref/logic/search/SearchQueryHighlightObservable.java delete mode 100644 src/test/java/org/jabref/logic/search/SearchQueryHighlightObservableTest.java diff --git a/src/main/java/org/jabref/gui/BasePanel.java b/src/main/java/org/jabref/gui/BasePanel.java index 932491c4800..d64f2226ff0 100644 --- a/src/main/java/org/jabref/gui/BasePanel.java +++ b/src/main/java/org/jabref/gui/BasePanel.java @@ -182,10 +182,9 @@ public BasePanel(JabRefFrame frame, BasePanelPreferences preferences, BibDatabas this.getDatabase().registerListener(new UpdateTimestampListener(Globals.prefs)); - this.entryEditor = new EntryEditor(this, preferences.getEntryEditorPreferences(), Globals.getFileUpdateMonitor(), dialogService, externalFileTypes, Globals.TASK_EXECUTOR); + this.entryEditor = new EntryEditor(this, preferences.getEntryEditorPreferences(), Globals.getFileUpdateMonitor(), dialogService, externalFileTypes, Globals.TASK_EXECUTOR, Globals.stateManager); this.preview = new PreviewPanel(getBibDatabaseContext(), this, dialogService, externalFileTypes, Globals.getKeyPrefs(), preferences.getPreviewPreferences()); - frame().getGlobalSearchBar().getSearchQueryHighlightObservable().addSearchListener(preview); } @Subscribe diff --git a/src/main/java/org/jabref/gui/StateManager.java b/src/main/java/org/jabref/gui/StateManager.java index 630d5511eb9..f9a0076d70f 100644 --- a/src/main/java/org/jabref/gui/StateManager.java +++ b/src/main/java/org/jabref/gui/StateManager.java @@ -6,6 +6,7 @@ import java.util.stream.Collectors; import javafx.beans.binding.Bindings; +import javafx.beans.property.IntegerProperty; import javafx.beans.property.ReadOnlyListProperty; import javafx.beans.property.ReadOnlyListWrapper; import javafx.collections.FXCollections; @@ -23,9 +24,8 @@ * This class manages the GUI-state of JabRef, including: * - currently selected database * - currently selected group - * Coming soon: - * - open databases * - active search + * - active number of search results */ public class StateManager { @@ -34,6 +34,7 @@ public class StateManager { private final ObservableList selectedEntries = FXCollections.observableArrayList(); private final ObservableMap> selectedGroups = FXCollections.observableHashMap(); private final OptionalObjectProperty activeSearchQuery = OptionalObjectProperty.empty(); + private final ObservableMap searchResultMap = FXCollections.observableHashMap(); public StateManager() { activeGroups.bind(Bindings.valueAt(selectedGroups, activeDatabase.orElse(null))); @@ -47,6 +48,14 @@ public OptionalObjectProperty activeSearchQueryProperty() { return activeSearchQuery; } + public void setActiveSearchResultSize(BibDatabaseContext database, IntegerProperty resultSize) { + searchResultMap.put(database, resultSize); + } + + public IntegerProperty getSearchResultSize() { + return searchResultMap.get(activeDatabase.getValue().orElse(new BibDatabaseContext())); + } + public ReadOnlyListProperty activeGroupProperty() { return activeGroups.getReadOnlyProperty(); } @@ -79,7 +88,7 @@ public Optional getActiveDatabase() { public List getEntriesInCurrentDatabase() { return OptionalUtil.flatMap(activeDatabase.get(), BibDatabaseContext::getEntries) - .collect(Collectors.toList()); + .collect(Collectors.toList()); } public void clearSearchQuery() { diff --git a/src/main/java/org/jabref/gui/collab/EntryAddChangeViewModel.java b/src/main/java/org/jabref/gui/collab/EntryAddChangeViewModel.java index 4fa50ccca9c..45832985b5b 100644 --- a/src/main/java/org/jabref/gui/collab/EntryAddChangeViewModel.java +++ b/src/main/java/org/jabref/gui/collab/EntryAddChangeViewModel.java @@ -2,6 +2,7 @@ import javafx.scene.Node; +import org.jabref.Globals; import org.jabref.JabRefGUI; import org.jabref.gui.preview.PreviewViewer; import org.jabref.gui.undo.NamedCompound; @@ -27,7 +28,7 @@ public void makeChange(BibDatabaseContext database, NamedCompound undoEdit) { @Override public Node description() { - PreviewViewer previewViewer = new PreviewViewer(new BibDatabaseContext(), JabRefGUI.getMainFrame().getDialogService()); + PreviewViewer previewViewer = new PreviewViewer(new BibDatabaseContext(), JabRefGUI.getMainFrame().getDialogService(), Globals.stateManager); previewViewer.setEntry(diskEntry); return previewViewer; } diff --git a/src/main/java/org/jabref/gui/collab/EntryDeleteChangeViewModel.java b/src/main/java/org/jabref/gui/collab/EntryDeleteChangeViewModel.java index f8e2b88a02c..f07dcbe28c9 100644 --- a/src/main/java/org/jabref/gui/collab/EntryDeleteChangeViewModel.java +++ b/src/main/java/org/jabref/gui/collab/EntryDeleteChangeViewModel.java @@ -2,6 +2,7 @@ import javafx.scene.Node; +import org.jabref.Globals; import org.jabref.JabRefGUI; import org.jabref.gui.preview.PreviewViewer; import org.jabref.gui.undo.NamedCompound; @@ -44,7 +45,7 @@ public void makeChange(BibDatabaseContext database, NamedCompound undoEdit) { @Override public Node description() { - PreviewViewer previewViewer = new PreviewViewer(new BibDatabaseContext(), JabRefGUI.getMainFrame().getDialogService()); + PreviewViewer previewViewer = new PreviewViewer(new BibDatabaseContext(), JabRefGUI.getMainFrame().getDialogService(), Globals.stateManager); previewViewer.setEntry(memEntry); return previewViewer; } diff --git a/src/main/java/org/jabref/gui/entryeditor/EntryEditor.css b/src/main/java/org/jabref/gui/entryeditor/EntryEditor.css index 1a1be9d2870..d0a97309716 100644 --- a/src/main/java/org/jabref/gui/entryeditor/EntryEditor.css +++ b/src/main/java/org/jabref/gui/entryeditor/EntryEditor.css @@ -98,4 +98,10 @@ -fx-padding: 20 20 20 20; } +#bibtexSourceCodeArea .search { + -fx-fill: red; +} +.bibtexSourceCodeArea .text { + -fx-fill: -fx-text-background-color; +} \ No newline at end of file diff --git a/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java b/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java index 2629b4d3234..72fdf53f104 100644 --- a/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java +++ b/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java @@ -2,7 +2,6 @@ import java.io.File; import java.nio.file.Path; -import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -27,6 +26,7 @@ import org.jabref.gui.BasePanel; import org.jabref.gui.DialogService; import org.jabref.gui.GUIGlobals; +import org.jabref.gui.StateManager; import org.jabref.gui.bibtexkeypattern.GenerateBibtexKeySingleAction; import org.jabref.gui.entryeditor.fileannotationtab.FileAnnotationTab; import org.jabref.gui.externalfiles.ExternalFilesEntryLinker; @@ -43,7 +43,6 @@ import org.jabref.logic.help.HelpFile; import org.jabref.logic.importer.EntryBasedFetcher; import org.jabref.logic.importer.WebFetchers; -import org.jabref.logic.search.SearchQueryHighlightListener; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; import org.jabref.model.util.FileUpdateMonitor; @@ -71,7 +70,6 @@ public class EntryEditor extends BorderPane { private final BibDatabaseContext databaseContext; private final CountingUndoManager undoManager; private final BasePanel panel; - private final List searchListeners = new ArrayList<>(); private Subscription typeSubscription; private final List tabs; private final FileUpdateMonitor fileMonitor; @@ -90,8 +88,9 @@ public class EntryEditor extends BorderPane { private final DialogService dialogService; private final ExternalFilesEntryLinker fileLinker; private final TaskExecutor taskExecutor; + private final StateManager stateManager; - public EntryEditor(BasePanel panel, EntryEditorPreferences preferences, FileUpdateMonitor fileMonitor, DialogService dialogService, ExternalFileTypes externalFileTypes, TaskExecutor taskExecutor) { + public EntryEditor(BasePanel panel, EntryEditorPreferences preferences, FileUpdateMonitor fileMonitor, DialogService dialogService, ExternalFileTypes externalFileTypes, TaskExecutor taskExecutor, StateManager stateManager) { this.panel = panel; this.databaseContext = panel.getBibDatabaseContext(); this.undoManager = panel.getUndoManager(); @@ -99,6 +98,7 @@ public EntryEditor(BasePanel panel, EntryEditorPreferences preferences, FileUpda this.fileMonitor = fileMonitor; this.dialogService = dialogService; this.taskExecutor = taskExecutor; + this.stateManager = stateManager; fileLinker = new ExternalFilesEntryLinker(externalFileTypes, Globals.prefs.getFilePreferences(), databaseContext); @@ -108,9 +108,9 @@ public EntryEditor(BasePanel panel, EntryEditorPreferences preferences, FileUpda if (GUIGlobals.currentFont != null) { setStyle( - "text-area-background: " + ColorUtil.toHex(GUIGlobals.validFieldBackgroundColor) + ";" - + "text-area-foreground: " + ColorUtil.toHex(GUIGlobals.editorTextColor) + ";" - + "text-area-highlight: " + ColorUtil.toHex(GUIGlobals.activeBackgroundColor) + ";"); + "text-area-background: " + ColorUtil.toHex(GUIGlobals.validFieldBackgroundColor) + ";" + + "text-area-foreground: " + ColorUtil.toHex(GUIGlobals.editorTextColor) + ";" + + "text-area-highlight: " + ColorUtil.toHex(GUIGlobals.activeBackgroundColor) + ";"); } EasyBind.subscribe(tabbed.getSelectionModel().selectedItemProperty(), tab -> { @@ -139,58 +139,46 @@ public EntryEditor(BasePanel panel, EntryEditorPreferences preferences, FileUpda FileDragDropPreferenceType dragDropPreferencesType = Globals.prefs.getEntryEditorFileLinkPreference(); - if (dragDropPreferencesType == FileDragDropPreferenceType.MOVE) - { + if (dragDropPreferencesType == FileDragDropPreferenceType.MOVE) { if (event.getTransferMode() == TransferMode.LINK) //alt on win { LOGGER.debug("Mode LINK"); fileLinker.addFilesToEntry(entry, files); - } - else if (event.getTransferMode() == TransferMode.COPY) //ctrl on win, no modifier on Xubuntu + } else if (event.getTransferMode() == TransferMode.COPY) //ctrl on win, no modifier on Xubuntu { LOGGER.debug("Mode COPY"); fileLinker.copyFilesToFileDirAndAddToEntry(entry, files); - } - else - { + } else { LOGGER.debug("Mode MOVE"); //shift on win or no modifier fileLinker.moveFilesToFileDirAndAddToEntry(entry, files); } } - if (dragDropPreferencesType == FileDragDropPreferenceType.COPY) - { + if (dragDropPreferencesType == FileDragDropPreferenceType.COPY) { if (event.getTransferMode() == TransferMode.COPY) //ctrl on win, no modifier on Xubuntu { LOGGER.debug("Mode MOVE"); fileLinker.moveFilesToFileDirAndAddToEntry(entry, files); - } - else if (event.getTransferMode() == TransferMode.LINK) //alt on win + } else if (event.getTransferMode() == TransferMode.LINK) //alt on win { LOGGER.debug("Mode LINK"); fileLinker.addFilesToEntry(entry, files); - } - else - { + } else { LOGGER.debug("Mode COPY"); //shift on win or no modifier fileLinker.copyFilesToFileDirAndAddToEntry(entry, files); } } - if (dragDropPreferencesType == FileDragDropPreferenceType.LINK) - { + if (dragDropPreferencesType == FileDragDropPreferenceType.LINK) { if (event.getTransferMode() == TransferMode.COPY) //ctrl on win, no modifier on Xubuntu { LOGGER.debug("Mode COPY"); fileLinker.copyFilesToFileDirAndAddToEntry(entry, files); - } - else if (event.getTransferMode() == TransferMode.LINK) //alt on win + } else if (event.getTransferMode() == TransferMode.LINK) //alt on win { LOGGER.debug("Mode MOVE"); fileLinker.moveFilesToFileDirAndAddToEntry(entry, files); - } - else - { + } else { LOGGER.debug("Mode LINK"); //shift on win or no modifier fileLinker.addFilesToEntry(entry, files); } @@ -299,7 +287,7 @@ private List createTabs() { tabs.add(new RelatedArticlesTab(preferences, dialogService)); // Source tab - sourceTab = new SourceTab(databaseContext, undoManager, preferences.getLatexFieldFormatterPreferences(), preferences.getImportFormatPreferences(), fileMonitor, dialogService); + sourceTab = new SourceTab(databaseContext, undoManager, preferences.getLatexFieldFormatterPreferences(), preferences.getImportFormatPreferences(), fileMonitor, dialogService, stateManager); tabs.add(sourceTab); return tabs; } @@ -396,12 +384,6 @@ private void fetchAndMerge(EntryBasedFetcher fetcher) { new FetchAndMergeEntry(panel, taskExecutor).fetchAndMerge(entry, fetcher); } - void addSearchListener(SearchQueryHighlightListener listener) { - // TODO: Highlight search text in entry editors - searchListeners.add(listener); - panel.frame().getGlobalSearchBar().getSearchQueryHighlightObservable().addSearchListener(listener); - } - public void setFocusToField(String fieldName) { DefaultTaskExecutor.runInJavaFXThread(() -> { for (Tab tab : tabbed.getTabs()) { diff --git a/src/main/java/org/jabref/gui/entryeditor/SourceTab.java b/src/main/java/org/jabref/gui/entryeditor/SourceTab.java index 2752103316d..c8fa3c87b37 100644 --- a/src/main/java/org/jabref/gui/entryeditor/SourceTab.java +++ b/src/main/java/org/jabref/gui/entryeditor/SourceTab.java @@ -5,6 +5,9 @@ import java.io.StringWriter; import java.util.Map; import java.util.Objects; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.swing.undo.UndoManager; @@ -16,6 +19,7 @@ import javafx.scene.input.InputMethodRequests; import org.jabref.gui.DialogService; +import org.jabref.gui.StateManager; import org.jabref.gui.icon.IconTheme; import org.jabref.gui.undo.CountingUndoManager; import org.jabref.gui.undo.NamedCompound; @@ -31,6 +35,7 @@ import org.jabref.logic.importer.ParserResult; import org.jabref.logic.importer.fileformat.BibtexParser; import org.jabref.logic.l10n.Localization; +import org.jabref.logic.search.SearchQuery; import org.jabref.model.database.BibDatabase; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.database.BibDatabaseMode; @@ -53,12 +58,16 @@ public class SourceTab extends EntryEditorTab { private final BibDatabaseMode mode; private final UndoManager undoManager; private final ObjectProperty sourceIsValid = new SimpleObjectProperty<>(); - private final ObservableRuleBasedValidator sourceValidator = new ObservableRuleBasedValidator(sourceIsValid); + @SuppressWarnings("unchecked") private final ObservableRuleBasedValidator sourceValidator = new ObservableRuleBasedValidator(sourceIsValid); private final ImportFormatPreferences importFormatPreferences; private final FileUpdateMonitor fileMonitor; private final DialogService dialogService; + private final StateManager stateManager; - public SourceTab(BibDatabaseContext bibDatabaseContext, CountingUndoManager undoManager, LatexFieldFormatterPreferences fieldFormatterPreferences, ImportFormatPreferences importFormatPreferences, FileUpdateMonitor fileMonitor, DialogService dialogService) { + private Optional searchHighlightPattern = Optional.empty(); + private CodeArea codeArea; + + public SourceTab(BibDatabaseContext bibDatabaseContext, CountingUndoManager undoManager, LatexFieldFormatterPreferences fieldFormatterPreferences, ImportFormatPreferences importFormatPreferences, FileUpdateMonitor fileMonitor, DialogService dialogService, StateManager stateManager) { this.mode = bibDatabaseContext.getMode(); this.setText(Localization.lang("%0 source", mode.getFormattedName())); this.setTooltip(new Tooltip(Localization.lang("Show/edit %0 source", mode.getFormattedName()))); @@ -68,9 +77,27 @@ public SourceTab(BibDatabaseContext bibDatabaseContext, CountingUndoManager undo this.importFormatPreferences = importFormatPreferences; this.fileMonitor = fileMonitor; this.dialogService = dialogService; + this.stateManager = stateManager; + + stateManager.activeSearchQueryProperty().addListener((observable, oldValue, newValue) -> { + searchHighlightPattern = newValue.flatMap(SearchQuery::getPatternForWords); + highlightSearchPattern(); + }); } + private void highlightSearchPattern() { + if (searchHighlightPattern.isPresent() && codeArea != null) { + codeArea.setStyleClass(0, codeArea.getLength(), "text"); + Matcher matcher = searchHighlightPattern.get().matcher(codeArea.getText()); + while (matcher.find()) { + for (int i = 0; i <= matcher.groupCount(); i++) { + codeArea.setStyleClass(matcher.start(), matcher.end(), "search"); + } + } + } + } + private static String getSourceString(BibEntry entry, BibDatabaseMode type, LatexFieldFormatterPreferences fieldFormatterPreferences) throws IOException { StringWriter stringWriter = new StringWriter(200); LatexFieldFormatter formatter = LatexFieldFormatter.buildIgnoreHashes(fieldFormatterPreferences); @@ -115,6 +142,7 @@ private CodeArea createSourceEditor() { codeArea.insertText(codeArea.getCaretPosition(), committed); } }); + codeArea.setId("bibtexSourceCodeArea"); return codeArea; } @@ -140,7 +168,7 @@ protected void bindToEntry(BibEntry entry) { } }); this.setContent(codeArea); - + this.codeArea = codeArea; // Store source for on focus out event in the source code (within its text area) // and update source code for every change of entry field values BindingsHelper.bindContentBidirectional(entry.getFieldsObservable(), codeArea.focusedProperty(), onFocus -> { @@ -152,10 +180,12 @@ protected void bindToEntry(BibEntry entry) { codeArea.clear(); try { codeArea.appendText(getSourceString(entry, mode, fieldFormatterPreferences)); + highlightSearchPattern(); + } catch (IOException ex) { codeArea.setEditable(false); codeArea.appendText(ex.getMessage() + "\n\n" + - Localization.lang("Correct the entry, and reopen editor to display/edit source.")); + Localization.lang("Correct the entry, and reopen editor to display/edit source.")); LOGGER.debug("Incorrect entry", ex); } }); @@ -208,8 +238,7 @@ private void storeSource(BibEntry outOfFocusEntry, String text) { String fieldValue = field.getValue(); if (InternalBibtexFields.isDisplayableField(fieldName) && !newEntry.hasField(fieldName)) { - compound.addEdit( - new UndoableFieldChange(outOfFocusEntry, fieldName, fieldValue, null)); + compound.addEdit(new UndoableFieldChange(outOfFocusEntry, fieldName, fieldValue, null)); outOfFocusEntry.clearField(fieldName); } } @@ -221,8 +250,7 @@ private void storeSource(BibEntry outOfFocusEntry, String text) { String newValue = field.getValue(); if (!Objects.equals(oldValue, newValue)) { // Test if the field is legally set. - new LatexFieldFormatter(fieldFormatterPreferences) - .format(newValue, fieldName); + new LatexFieldFormatter(fieldFormatterPreferences).format(newValue, fieldName); compound.addEdit(new UndoableFieldChange(outOfFocusEntry, fieldName, oldValue, newValue)); outOfFocusEntry.setField(fieldName, newValue); @@ -243,4 +271,5 @@ private void storeSource(BibEntry outOfFocusEntry, String text) { LOGGER.debug("Incorrect source", ex); } } + } diff --git a/src/main/java/org/jabref/gui/maintable/MainTableDataModel.java b/src/main/java/org/jabref/gui/maintable/MainTableDataModel.java index 5ef91744ea9..da3c0724790 100644 --- a/src/main/java/org/jabref/gui/maintable/MainTableDataModel.java +++ b/src/main/java/org/jabref/gui/maintable/MainTableDataModel.java @@ -4,6 +4,8 @@ import java.util.Optional; import javafx.beans.binding.Bindings; +import javafx.beans.property.IntegerProperty; +import javafx.beans.property.SimpleIntegerProperty; import javafx.collections.ObservableList; import javafx.collections.transformation.FilteredList; import javafx.collections.transformation.SortedList; @@ -30,8 +32,12 @@ public MainTableDataModel(BibDatabaseContext context) { entriesFiltered.predicateProperty().bind( Bindings.createObjectBinding(() -> this::isMatched, Globals.stateManager.activeGroupProperty(), Globals.stateManager.activeSearchQueryProperty()) + ); + IntegerProperty resultSize = new SimpleIntegerProperty(); + resultSize.bind(Bindings.size(entriesFiltered)); + Globals.stateManager.setActiveSearchResultSize(context, resultSize); // We need to wrap the list since otherwise sorting in the table does not work entriesSorted = new SortedList<>(entriesFiltered); } diff --git a/src/main/java/org/jabref/gui/openoffice/StyleSelectDialogView.java b/src/main/java/org/jabref/gui/openoffice/StyleSelectDialogView.java index cec9e6a9048..778758961f3 100644 --- a/src/main/java/org/jabref/gui/openoffice/StyleSelectDialogView.java +++ b/src/main/java/org/jabref/gui/openoffice/StyleSelectDialogView.java @@ -11,6 +11,7 @@ import javafx.scene.control.TableView; import javafx.scene.layout.VBox; +import org.jabref.Globals; import org.jabref.gui.DialogService; import org.jabref.gui.icon.IconTheme; import org.jabref.gui.preview.PreviewViewer; @@ -68,11 +69,11 @@ public StyleSelectDialogView(StyleLoader loader) { private void initialize() { viewModel = new StyleSelectDialogViewModel(dialogService, loader, preferencesService); - previewArticle = new PreviewViewer(new BibDatabaseContext(), dialogService); + previewArticle = new PreviewViewer(new BibDatabaseContext(), dialogService, Globals.stateManager); previewArticle.setEntry(TestEntry.getTestEntry()); vbox.getChildren().add(previewArticle); - previewBook = new PreviewViewer(new BibDatabaseContext(), dialogService); + previewBook = new PreviewViewer(new BibDatabaseContext(), dialogService, Globals.stateManager); previewBook.setEntry(TestEntry.getTestEntryBook()); vbox.getChildren().add(previewBook); diff --git a/src/main/java/org/jabref/gui/preferences/PreviewPreferencesTab.java b/src/main/java/org/jabref/gui/preferences/PreviewPreferencesTab.java index da23285e2e8..ec4c6348a23 100644 --- a/src/main/java/org/jabref/gui/preferences/PreviewPreferencesTab.java +++ b/src/main/java/org/jabref/gui/preferences/PreviewPreferencesTab.java @@ -118,7 +118,7 @@ private void setupLogic() { btnTest.setOnAction(event -> { try { - PreviewViewer testPane = new PreviewViewer(new BibDatabaseContext(), dialogService); + PreviewViewer testPane = new PreviewViewer(new BibDatabaseContext(), dialogService, Globals.stateManager); testPane.setEntry(TestEntry.getTestEntry()); PreviewLayout layout = chosen.getSelectionModel().getSelectedItem(); diff --git a/src/main/java/org/jabref/gui/preview/PreviewPanel.java b/src/main/java/org/jabref/gui/preview/PreviewPanel.java index 08db01a8a88..790aae4c1d6 100644 --- a/src/main/java/org/jabref/gui/preview/PreviewPanel.java +++ b/src/main/java/org/jabref/gui/preview/PreviewPanel.java @@ -4,7 +4,6 @@ import java.nio.file.Path; import java.util.List; import java.util.Optional; -import java.util.regex.Pattern; import java.util.stream.Collectors; import javafx.scene.control.ContextMenu; @@ -27,7 +26,6 @@ import org.jabref.gui.keyboard.KeyBindingRepository; import org.jabref.logic.citationstyle.PreviewLayout; import org.jabref.logic.l10n.Localization; -import org.jabref.logic.search.SearchQueryHighlightListener; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; import org.jabref.preferences.PreviewPreferences; @@ -35,7 +33,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class PreviewPanel extends VBox implements SearchQueryHighlightListener { +public class PreviewPanel extends VBox { private static final Logger LOGGER = LoggerFactory.getLogger(PreviewPanel.class); @@ -52,7 +50,7 @@ public PreviewPanel(BibDatabaseContext database, BasePanel basePanel, DialogServ this.dialogService = dialogService; fileLinker = new ExternalFilesEntryLinker(externalFileTypes, Globals.prefs.getFilePreferences(), database); - previewView = new PreviewViewer(database, dialogService); + previewView = new PreviewViewer(database, dialogService, Globals.stateManager); previewView.setLayout(preferences.getCurrentPreviewStyle()); previewView.setContextMenu(createPopupMenu()); previewView.setOnDragDetected(event -> { @@ -107,11 +105,6 @@ public void close() { basePanel.closeBottomPane(); } - @Override - public void highlightPattern(Optional newPattern) { - // TODO: Implement that search phrases are highlighted - } - public void updateLayout(PreviewPreferences previewPreferences) { updateLayout(previewPreferences, false); } diff --git a/src/main/java/org/jabref/gui/preview/PreviewViewer.java b/src/main/java/org/jabref/gui/preview/PreviewViewer.java index 6432ef4cc3b..8811d398b88 100644 --- a/src/main/java/org/jabref/gui/preview/PreviewViewer.java +++ b/src/main/java/org/jabref/gui/preview/PreviewViewer.java @@ -2,9 +2,12 @@ import java.util.Objects; import java.util.Optional; +import java.util.regex.Pattern; import javafx.beans.InvalidationListener; import javafx.beans.Observable; +import javafx.beans.value.ChangeListener; +import javafx.concurrent.Worker; import javafx.print.PrinterJob; import javafx.scene.control.ScrollPane; import javafx.scene.input.ClipboardContent; @@ -13,11 +16,13 @@ import org.jabref.Globals; import org.jabref.gui.ClipBoardManager; import org.jabref.gui.DialogService; +import org.jabref.gui.StateManager; import org.jabref.gui.util.BackgroundTask; import org.jabref.gui.util.TaskExecutor; import org.jabref.logic.citationstyle.PreviewLayout; import org.jabref.logic.exporter.ExporterFactory; import org.jabref.logic.l10n.Localization; +import org.jabref.logic.search.SearchQuery; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; @@ -34,22 +39,39 @@ public class PreviewViewer extends ScrollPane implements InvalidationListener { private static final Logger LOGGER = LoggerFactory.getLogger(PreviewViewer.class); + private static final String JS_HIGHLIGHT_FUNCTION = " "; + private final ClipBoardManager clipBoardManager; private final DialogService dialogService; private final TaskExecutor taskExecutor = Globals.TASK_EXECUTOR; private final WebView previewView; private PreviewLayout layout; + /** * The entry currently shown */ private Optional entry = Optional.empty(); + private Optional searchHighlightPattern = Optional.empty(); + private BibDatabaseContext database; + private boolean registered; + + private ChangeListener> listener = (queryObservable, queryOldValue, queryNewValue) -> { + searchHighlightPattern = queryNewValue.flatMap(SearchQuery::getPatternForWords); + highlightSearchPattern(); + }; /** * @param database Used for resolving strings and pdf directories for links. */ - public PreviewViewer(BibDatabaseContext database, DialogService dialogService) { + public PreviewViewer(BibDatabaseContext database, DialogService dialogService, StateManager stateManager) { this.database = Objects.requireNonNull(database); this.dialogService = dialogService; this.clipBoardManager = Globals.clipboardManager; @@ -59,6 +81,27 @@ public PreviewViewer(BibDatabaseContext database, DialogService dialogService) { previewView = new WebView(); setContent(previewView); previewView.setContextMenuEnabled(false); + + previewView.getEngine().getLoadWorker().stateProperty().addListener((observable, oldValue, newValue) -> { + + if (newValue != Worker.State.SUCCEEDED) { + return; + } + if (!registered) { + stateManager.activeSearchQueryProperty().addListener(listener); + registered = true; + } + highlightSearchPattern(); + }); + + } + + private void highlightSearchPattern() { + if (searchHighlightPattern.isPresent()) { + String pattern = searchHighlightPattern.get().pattern().replace("\\Q", "").replace("\\E", ""); + + previewView.getEngine().executeScript("highlight('" + pattern + "');"); + } } public void setLayout(PreviewLayout newLayout) { @@ -80,8 +123,8 @@ public void setEntry(BibEntry newEntry) { for (Observable observable : newEntry.getObservables()) { observable.addListener(this); } - update(); + } private void update() { @@ -93,18 +136,21 @@ private void update() { ExporterFactory.entryNumber = 1; // Set entry number in case that is included in the preview layout. BackgroundTask - .wrap(() -> layout.generatePreview(entry.get(), database.getDatabase())) - .onRunning(() -> setPreviewText("" + Localization.lang("Processing %0", Localization.lang("Citation Style")) + ": " + layout.getName() + " ..." + "")) - .onSuccess(this::setPreviewText) - .onFailure(exception -> { - LOGGER.error("Error while generating citation style", exception); - setPreviewText(Localization.lang("Error while generating citation style")); - }) - .executeWith(taskExecutor); + .wrap(() -> layout.generatePreview(entry.get(), database.getDatabase())) + .onRunning(() -> setPreviewText("" + Localization.lang("Processing %0", Localization.lang("Citation Style")) + ": " + layout.getName() + " ..." + "")) + .onSuccess(this::setPreviewText) + .onFailure(exception -> { + LOGGER.error("Error while generating citation style", exception); + setPreviewText(Localization.lang("Error while generating citation style")); + }) + .executeWith(taskExecutor); } private void setPreviewText(String text) { - previewView.getEngine().loadContent(text); + String myText = JS_HIGHLIGHT_FUNCTION + "
"; + previewView.getEngine().setJavaScriptEnabled(true); + previewView.getEngine().loadContent(myText); + this.setHvalue(0); } @@ -116,13 +162,13 @@ public void print() { } BackgroundTask - .wrap(() -> { - job.getJobSettings().setJobName(entry.flatMap(BibEntry::getCiteKeyOptional).orElse("NO ENTRY")); - previewView.getEngine().print(job); - job.endJob(); - }) - .onFailure(exception -> dialogService.showErrorDialogAndWait(Localization.lang("Could not print preview"), exception)) - .executeWith(taskExecutor); + .wrap(() -> { + job.getJobSettings().setJobName(entry.flatMap(BibEntry::getCiteKeyOptional).orElse("NO ENTRY")); + previewView.getEngine().print(job); + job.endJob(); + }) + .onFailure(exception -> dialogService.showErrorDialogAndWait(Localization.lang("Could not print preview"), exception)) + .executeWith(taskExecutor); } public void copyPreviewToClipBoard() { diff --git a/src/main/java/org/jabref/gui/search/GlobalSearchBar.java b/src/main/java/org/jabref/gui/search/GlobalSearchBar.java index 60a46a783ca..efd2aab5258 100644 --- a/src/main/java/org/jabref/gui/search/GlobalSearchBar.java +++ b/src/main/java/org/jabref/gui/search/GlobalSearchBar.java @@ -44,11 +44,11 @@ import org.jabref.gui.keyboard.KeyBinding; import org.jabref.gui.keyboard.KeyBindingRepository; import org.jabref.gui.maintable.MainTable; +import org.jabref.gui.search.rules.describer.SearchDescribers; import org.jabref.gui.util.DefaultTaskExecutor; import org.jabref.gui.util.TooltipTextUtil; import org.jabref.logic.l10n.Localization; import org.jabref.logic.search.SearchQuery; -import org.jabref.logic.search.SearchQueryHighlightObservable; import org.jabref.model.entry.Author; import org.jabref.preferences.JabRefPreferences; import org.jabref.preferences.SearchPreferences; @@ -77,9 +77,6 @@ public class GlobalSearchBar extends HBox { private final Button searchModeButton = new Button(); private final Label currentResults = new Label(""); private final Tooltip tooltip = new Tooltip(); - private final SearchQueryHighlightObservable searchQueryHighlightObservable = new SearchQueryHighlightObservable(); - private SearchWorker searchWorker; - private SearchDisplayMode searchDisplayMode; public GlobalSearchBar(JabRefFrame frame) { @@ -155,11 +152,16 @@ public GlobalSearchBar(JabRefFrame frame) { } }); - this.getChildren().addAll( - searchField, - currentResults); + this.getChildren().addAll(searchField, currentResults); this.setAlignment(Pos.CENTER_LEFT); + + EasyBind.subscribe(Globals.stateManager.activeSearchQueryProperty(), searchQuery -> { + searchQuery.ifPresent(query -> { + updateResults(Globals.stateManager.getSearchResultSize().intValue(), SearchDescribers.getSearchDescriberFor(query).getDescription(), + query.isGrammarBasedSearch()); + }); + }); } private void toggleSearchModeAndSearch() { @@ -181,7 +183,6 @@ public void endSearch() { clearSearch(); MainTable mainTable = frame.getCurrentBasePanel().getMainTable(); mainTable.requestFocus(); - //SwingUtilities.invokeLater(() -> mainTable.ensureVisible(mainTable.getSelectedRow())); } } @@ -199,8 +200,6 @@ private void clearSearch() { currentResults.setText(""); searchField.setText(""); setHintTooltip(null); - searchQueryHighlightObservable.reset(); - Globals.stateManager.clearSearchQuery(); } @@ -209,11 +208,6 @@ public void performSearch() { if (currentBasePanel == null) { return; } - - if (searchWorker != null) { - searchWorker.cancel(true); - } - // An empty search field should cause the search to be cleared. if (searchField.getText().isEmpty()) { clearSearch(); @@ -228,16 +222,11 @@ public void performSearch() { Globals.stateManager.setSearchQuery(searchQuery); - // TODO: Remove search worker as this is doing the work twice now - searchWorker = new SearchWorker(currentBasePanel, searchQuery, searchDisplayMode); - searchWorker.execute(); } private void informUserAboutInvalidSearchQuery() { searchField.pseudoClassStateChanged(CLASS_NO_RESULTS, true); - searchQueryHighlightObservable.reset(); - Globals.stateManager.clearSearchQuery(); String illegalSearch = Localization.lang("Search failed: illegal search expression"); @@ -270,10 +259,6 @@ private AutoCompletePopup getPopup(AutoCompletionBinding autoCompletio } } - public SearchQueryHighlightObservable getSearchQueryHighlightObservable() { - return searchQueryHighlightObservable; - } - private SearchQuery getSearchQuery() { SearchQuery searchQuery = new SearchQuery(this.searchField.getText(), this.caseSensitive.isSelected(), this.regularExp.isSelected()); this.frame.getCurrentBasePanel().setCurrentSearchQuery(searchQuery); @@ -401,6 +386,7 @@ public AutoCompletePopup getSkinnable() { @Override public void dispose() { + //empty } } } diff --git a/src/main/java/org/jabref/gui/search/SearchWorker.java b/src/main/java/org/jabref/gui/search/SearchWorker.java deleted file mode 100644 index 5e916e63ad6..00000000000 --- a/src/main/java/org/jabref/gui/search/SearchWorker.java +++ /dev/null @@ -1,68 +0,0 @@ -package org.jabref.gui.search; - -import java.util.List; -import java.util.Objects; -import java.util.concurrent.ExecutionException; -import java.util.stream.Collectors; - -import javax.swing.SwingWorker; - -import org.jabref.JabRefGUI; -import org.jabref.gui.BasePanel; -import org.jabref.gui.search.rules.describer.SearchDescribers; -import org.jabref.gui.util.DefaultTaskExecutor; -import org.jabref.logic.search.SearchQuery; -import org.jabref.model.database.BibDatabase; -import org.jabref.model.entry.BibEntry; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Not reusable. Always create a new instance for each search! - */ -class SearchWorker extends SwingWorker, Void> { - - private static final Logger LOGGER = LoggerFactory.getLogger(SearchWorker.class); - - private final BibDatabase database; - - private final SearchQuery searchQuery; - - public SearchWorker(BasePanel basePanel, SearchQuery searchQuery, SearchDisplayMode searchDisplayMode) { - this.database = Objects.requireNonNull(basePanel.getDatabase()); - this.searchQuery = Objects.requireNonNull(searchQuery); - LOGGER.debug("Search (" + searchDisplayMode.getDisplayName() + "): " + this.searchQuery); - } - - @Override - protected List doInBackground() throws Exception { - return database.getEntries().parallelStream() - .filter(searchQuery::isMatch) - .collect(Collectors.toList()); - } - - @Override - protected void done() { - if (isCancelled()) { - return; - } - - try { - updateUIWithSearchResult(get()); - } catch (InterruptedException | ExecutionException e) { - LOGGER.error("something went wrong during the search", e); - } - } - - private void updateUIWithSearchResult(List matchedEntries) { - GlobalSearchBar globalSearchBar = JabRefGUI.getMainFrame().getGlobalSearchBar(); - - DefaultTaskExecutor.runInJavaFXThread(() -> - globalSearchBar.updateResults(matchedEntries.size(), - SearchDescribers.getSearchDescriberFor(searchQuery).getDescription(), - searchQuery.isGrammarBasedSearch())); - globalSearchBar.getSearchQueryHighlightObservable().fireSearchlistenerEvent(searchQuery); - } - -} diff --git a/src/main/java/org/jabref/logic/search/SearchQuery.java b/src/main/java/org/jabref/logic/search/SearchQuery.java index d33fa4f90ff..e6e35486767 100644 --- a/src/main/java/org/jabref/logic/search/SearchQuery.java +++ b/src/main/java/org/jabref/logic/search/SearchQuery.java @@ -3,6 +3,9 @@ import java.util.Collections; import java.util.List; import java.util.Objects; +import java.util.Optional; +import java.util.StringJoiner; +import java.util.regex.Pattern; import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.BibEntry; @@ -63,9 +66,9 @@ private String getRegularExpressionDescription() { public String localize() { return String.format("\"%s\" (%s, %s)", - getQuery(), - getLocalizedCaseSensitiveDescription(), - getLocalizedRegularExpressionDescription()); + getQuery(), + getLocalizedCaseSensitiveDescription(), + getLocalizedRegularExpressionDescription()); } private String getLocalizedCaseSensitiveDescription() { @@ -119,6 +122,28 @@ public List getSearchWords() { } } + // Returns a regular expression pattern in the form (w1)|(w2)| ... wi are escaped if no regular expression search is enabled + public Optional getPatternForWords() { + List words = getSearchWords(); + + if ((words == null) || words.isEmpty() || words.get(0).isEmpty()) { + return Optional.empty(); + } + + // compile the words to a regular expression in the form (w1)|(w2)|(w3) + StringJoiner joiner = new StringJoiner(")|(", "(", ")"); + for (String word : words) { + joiner.add(regularExpression ? word : Pattern.quote(word)); + } + String searchPattern = joiner.toString(); + + if (caseSensitive) { + return Optional.of(Pattern.compile(searchPattern)); + } else { + return Optional.of(Pattern.compile(searchPattern, Pattern.CASE_INSENSITIVE)); + } + } + public SearchRule getRule() { return rule; } diff --git a/src/main/java/org/jabref/logic/search/SearchQueryHighlightListener.java b/src/main/java/org/jabref/logic/search/SearchQueryHighlightListener.java deleted file mode 100644 index 5f88be0ae0a..00000000000 --- a/src/main/java/org/jabref/logic/search/SearchQueryHighlightListener.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.jabref.logic.search; - -import java.util.Optional; -import java.util.regex.Pattern; - -import com.google.common.eventbus.Subscribe; - -/** - * Every Listener that wants to receive events from a search needs to - * implement this interface - */ -@FunctionalInterface -public interface SearchQueryHighlightListener { - - /** - * Pattern with which one can determine what to highlight - */ - @Subscribe - void highlightPattern(Optional highlightPattern); -} diff --git a/src/main/java/org/jabref/logic/search/SearchQueryHighlightObservable.java b/src/main/java/org/jabref/logic/search/SearchQueryHighlightObservable.java deleted file mode 100644 index 8046f442446..00000000000 --- a/src/main/java/org/jabref/logic/search/SearchQueryHighlightObservable.java +++ /dev/null @@ -1,86 +0,0 @@ -package org.jabref.logic.search; - -import java.util.List; -import java.util.Objects; -import java.util.Optional; -import java.util.StringJoiner; -import java.util.regex.Pattern; - -import com.google.common.eventbus.EventBus; - -public class SearchQueryHighlightObservable { - - private final EventBus eventBus = new EventBus(); - - private Optional pattern = Optional.empty(); - - /** - * Adds a SearchQueryHighlightListener to the search bar. The added listener is immediately informed about the current search. - * Subscribers will be notified about searches. - * - * @param newListener SearchQueryHighlightListener to be added - */ - public void addSearchListener(SearchQueryHighlightListener newListener) { - Objects.requireNonNull(newListener); - - eventBus.register(newListener); - newListener.highlightPattern(pattern); - - } - - public void removeSearchListener(SearchQueryHighlightListener listener) { - Objects.requireNonNull(listener); - - try { - eventBus.unregister(listener); - } catch (IllegalArgumentException e) { - // occurs if the event source has not been registered, should not prevent shutdown - } - } - /** - * Fires an event if a search was started (or cleared) - * - * @param searchQuery the search query - */ - - public void fireSearchlistenerEvent(SearchQuery searchQuery) { - Objects.requireNonNull(searchQuery); - - // Parse the search string to words - pattern = getPatternForWords(searchQuery.getSearchWords(), searchQuery.isRegularExpression(), - searchQuery.isCaseSensitive()); - - update(); - } - - public void reset() { - pattern = Optional.empty(); - update(); - } - - private void update() { - // Fire an event for every listener - eventBus.post(pattern); - } - - // Returns a regular expression pattern in the form (w1)|(w2)| ... wi are escaped if no regular expression search is enabled - public static Optional getPatternForWords(List words, boolean useRegex, boolean isCaseSensitive) { - if ((words == null) || words.isEmpty() || words.get(0).isEmpty()) { - return Optional.empty(); - } - - // compile the words to a regular expression in the form (w1)|(w2)|(w3) - StringJoiner joiner = new StringJoiner(")|(", "(", ")"); - for (String word : words) { - joiner.add(useRegex ? word : Pattern.quote(word)); - } - String searchPattern = joiner.toString(); - - if (isCaseSensitive) { - return Optional.of(Pattern.compile(searchPattern)); - } else { - return Optional.of(Pattern.compile(searchPattern, Pattern.CASE_INSENSITIVE)); - } - } - -} diff --git a/src/test/java/org/jabref/gui/entryeditor/SourceTabTest.java b/src/test/java/org/jabref/gui/entryeditor/SourceTabTest.java index c3f50e3c853..20d11612483 100644 --- a/src/test/java/org/jabref/gui/entryeditor/SourceTabTest.java +++ b/src/test/java/org/jabref/gui/entryeditor/SourceTabTest.java @@ -7,6 +7,7 @@ import javafx.stage.Stage; import org.jabref.gui.DialogService; +import org.jabref.gui.StateManager; import org.jabref.gui.undo.CountingUndoManager; import org.jabref.logic.bibtex.LatexFieldFormatterPreferences; import org.jabref.logic.importer.ImportFormatPreferences; @@ -38,7 +39,7 @@ public class SourceTabTest { public void onStart(Stage stage) { area = new CodeArea(); area.appendText("some example\n text to go here\n across a couple of \n lines...."); - sourceTab = new SourceTab(new BibDatabaseContext(), new CountingUndoManager(), new LatexFieldFormatterPreferences(), mock(ImportFormatPreferences.class), new DummyFileUpdateMonitor(), mock(DialogService.class)); + sourceTab = new SourceTab(new BibDatabaseContext(), new CountingUndoManager(), new LatexFieldFormatterPreferences(), mock(ImportFormatPreferences.class), new DummyFileUpdateMonitor(), mock(DialogService.class), mock(StateManager.class)); pane = new TabPane( new Tab("main area", area), new Tab("other tab", new Label("some text")), diff --git a/src/test/java/org/jabref/logic/search/SearchQueryHighlightObservableTest.java b/src/test/java/org/jabref/logic/search/SearchQueryHighlightObservableTest.java deleted file mode 100644 index fbe998e8a85..00000000000 --- a/src/test/java/org/jabref/logic/search/SearchQueryHighlightObservableTest.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.jabref.logic.search; - -import java.util.Optional; -import java.util.regex.Pattern; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.verify; - -class SearchQueryHighlightObservableTest { - - @Captor ArgumentCaptor> captor; - @Mock private SearchQueryHighlightListener listener; - private SearchQueryHighlightObservable observable; - - @BeforeEach - void setUp() throws Exception { - observable = new SearchQueryHighlightObservable(); - MockitoAnnotations.initMocks(this); - } - - @Test - void addSearchListenerNotifiesListenerAboutPreviousPattern() throws Exception { - observable.fireSearchlistenerEvent(new SearchQuery("test", false, false)); - - observable.addSearchListener(listener); - - verify(listener).highlightPattern(captor.capture()); - assertEquals("(\\Qtest\\E)", captor.getValue().get().pattern()); - } - - @Test - void addSearchListenerNotifiesRegisteredListener() throws Exception { - observable.addSearchListener(listener); - - observable.fireSearchlistenerEvent(new SearchQuery("test", false, false)); - - verify(listener, atLeastOnce()).highlightPattern(captor.capture()); - assertEquals("(\\Qtest\\E)", captor.getValue().get().pattern()); - } - - @Test - void addSearchListenerNotifiesRegisteredListenerAboutGrammarBasedSearches() throws Exception { - observable.addSearchListener(listener); - - observable.fireSearchlistenerEvent(new SearchQuery("author=harrer", false, false)); - - verify(listener, atLeastOnce()).highlightPattern(captor.capture()); - // TODO: We would expect "harrer" here - assertEquals("(\\Qauthor=harrer\\E)", captor.getValue().get().pattern()); - } -} diff --git a/src/test/java/org/jabref/logic/search/SearchQueryTest.java b/src/test/java/org/jabref/logic/search/SearchQueryTest.java index e4463f75155..34593c55d85 100644 --- a/src/test/java/org/jabref/logic/search/SearchQueryTest.java +++ b/src/test/java/org/jabref/logic/search/SearchQueryTest.java @@ -1,5 +1,8 @@ package org.jabref.logic.search; +import java.util.Optional; +import java.util.regex.Pattern; + import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.BibtexEntryTypes; import org.jabref.model.entry.FieldName; @@ -189,7 +192,15 @@ public void testSimpleTerm() { String query = "progress"; SearchQuery result = new SearchQuery(query, false, false); - assertFalse(result.isGrammarBasedSearch()); } + + @Test + public void testGetPattern() { + String query = "progress"; + SearchQuery result = new SearchQuery(query, false, false); + Pattern pattern = Pattern.compile("(\\Qprogress\\E)"); + //We can't directly compare the pattern objects + assertEquals(Optional.of(pattern.toString()), result.getPatternForWords().map(Pattern::toString)); + } } From b3993fd272cd230e792f332d75b0c4f6ef283943 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" Date: Fri, 7 Jun 2019 11:11:49 +0200 Subject: [PATCH 017/103] Bump bcprov-jdk15on from 1.61 to 1.62 (#5039) Bumps [bcprov-jdk15on](https://github.com/bcgit/bc-java) from 1.61 to 1.62. - [Release notes](https://github.com/bcgit/bc-java/releases) - [Changelog](https://github.com/bcgit/bc-java/blob/master/docs/releasenotes.html) - [Commits](https://github.com/bcgit/bc-java/commits) Signed-off-by: dependabot-preview[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 15217878163..9b39cf11101 100644 --- a/build.gradle +++ b/build.gradle @@ -97,7 +97,7 @@ dependencies { compile group: 'org.apache.tika', name: 'tika-core', version: '1.21' // required for reading write-protected PDFs - see https://github.com/JabRef/jabref/pull/942#issuecomment-209252635 - compile 'org.bouncycastle:bcprov-jdk15on:1.61' + compile 'org.bouncycastle:bcprov-jdk15on:1.62' compile 'commons-cli:commons-cli:1.4' From 65a7cd34c04d6005b5884399ab85caf947438ab8 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Fri, 7 Jun 2019 11:16:36 +0200 Subject: [PATCH 018/103] Remove "automatic bug report" title (#5040) Right now users often forget to change the title to something reasonable. --- .../jabref/gui/errorconsole/ErrorConsoleViewModel.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/jabref/gui/errorconsole/ErrorConsoleViewModel.java b/src/main/java/org/jabref/gui/errorconsole/ErrorConsoleViewModel.java index d5b25ae7aea..a47ba6f02be 100644 --- a/src/main/java/org/jabref/gui/errorconsole/ErrorConsoleViewModel.java +++ b/src/main/java/org/jabref/gui/errorconsole/ErrorConsoleViewModel.java @@ -91,17 +91,16 @@ public void clearLog() { */ public void reportIssue() { try { - String issueTitle = "Automatic Bug Report - " + dateFormat.format(date); - // system info + // System info String systemInfo = String.format("JabRef %s%n%s %s %s %nJava %s", buildInfo.getVersion(), BuildInfo.OS, BuildInfo.OS_VERSION, BuildInfo.OS_ARCH, BuildInfo.JAVA_VERSION); - // steps to reproduce + // Steps to reproduce String howToReproduce = "Steps to reproduce:\n\n1. ...\n2. ...\n3. ..."; - // log messages + // Log messages String issueDetails = "
\n" + "" + "Detail information:" + "\n\n```\n" + getLogMessagesAsString(allMessagesData) + "\n```\n\n
"; clipBoardManager.setContent(issueDetails); - // bug report body + // Bug report body String issueBody = systemInfo + "\n\n" + howToReproduce + "\n\n" + "Paste your log details here."; dialogService.notify(Localization.lang("Issue on GitHub successfully reported.")); @@ -114,7 +113,6 @@ public void reportIssue() { URIBuilder uriBuilder = new URIBuilder() .setScheme("https").setHost("github.com") .setPath("/JabRef/jabref/issues/new") - .setParameter("title", issueTitle) .setParameter("body", issueBody); JabRefDesktop.openBrowser(uriBuilder.build().toString()); } catch (IOException | URISyntaxException e) { From 427f74ae240effa610ea6569a63be6dad734f46d Mon Sep 17 00:00:00 2001 From: Carl Christian Snethlage Date: Wed, 5 Jun 2019 22:15:27 +0200 Subject: [PATCH 019/103] Refactor PreferenceDialog to MVVM with a split-pane --- .../jabref/gui/preferences/ExternalTab.java | 2 +- .../gui/preferences/PreferencesDialog.css | 4 +- .../gui/preferences/PreferencesDialog.fxml | 51 +++- .../gui/preferences/PreferencesDialog.java | 279 ------------------ .../preferences/PreferencesDialogView.java | 132 +++++++++ .../PreferencesDialogViewModel.java | 168 +++++++++++ .../preferences/ShowPreferencesAction.java | 3 +- 7 files changed, 353 insertions(+), 286 deletions(-) delete mode 100644 src/main/java/org/jabref/gui/preferences/PreferencesDialog.java create mode 100644 src/main/java/org/jabref/gui/preferences/PreferencesDialogView.java create mode 100644 src/main/java/org/jabref/gui/preferences/PreferencesDialogViewModel.java diff --git a/src/main/java/org/jabref/gui/preferences/ExternalTab.java b/src/main/java/org/jabref/gui/preferences/ExternalTab.java index a2bca6c0077..9fa691deb0f 100644 --- a/src/main/java/org/jabref/gui/preferences/ExternalTab.java +++ b/src/main/java/org/jabref/gui/preferences/ExternalTab.java @@ -58,7 +58,7 @@ class ExternalTab implements PrefsTab { private final DialogService dialogService; private final FileDialogConfiguration fileDialogConfiguration = new FileDialogConfiguration.Builder().build(); - public ExternalTab(JabRefFrame frame, PreferencesDialog prefsDiag, JabRefPreferences prefs) { + public ExternalTab(JabRefFrame frame, JabRefPreferences prefs) { this.prefs = prefs; this.frame = frame; dialogService = frame.getDialogService(); diff --git a/src/main/java/org/jabref/gui/preferences/PreferencesDialog.css b/src/main/java/org/jabref/gui/preferences/PreferencesDialog.css index 8933d9096a3..b6b9da0f317 100644 --- a/src/main/java/org/jabref/gui/preferences/PreferencesDialog.css +++ b/src/main/java/org/jabref/gui/preferences/PreferencesDialog.css @@ -1,10 +1,10 @@ -#sideMenu { +#preferenceTabList { -fx-background-color: -fx-control-inner-background; -fx-border-color: -fx-outer-border; -fx-border-width: 1; } -#sideMenu > .virtual-flow > .clipped-container > .sheet > .list-cell { +#preferenceTabList > .virtual-flow > .clipped-container > .sheet > .list-cell { -fx-padding: 8 8 8 8; -fx-background: -fx-control-inner-background; } diff --git a/src/main/java/org/jabref/gui/preferences/PreferencesDialog.fxml b/src/main/java/org/jabref/gui/preferences/PreferencesDialog.fxml index 367768f7cb9..139fd9adc20 100644 --- a/src/main/java/org/jabref/gui/preferences/PreferencesDialog.fxml +++ b/src/main/java/org/jabref/gui/preferences/PreferencesDialog.fxml @@ -1,5 +1,52 @@ - + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - -