diff --git a/CHANGELOG.md b/CHANGELOG.md index f5c6b08442d..54b97114808 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 tools menu. [#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..2317076dae7 100644 --- a/src/main/java/org/jabref/gui/JabRefFrame.java +++ b/src/main/java/org/jabref/gui/JabRefFrame.java @@ -28,13 +28,16 @@ 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.RadioMenuItem; import javafx.scene.control.Separator; import javafx.scene.control.SeparatorMenuItem; import javafx.scene.control.SplitPane; import javafx.scene.control.Tab; import javafx.scene.control.TabPane; import javafx.scene.control.TextInputControl; +import javafx.scene.control.ToggleGroup; import javafx.scene.control.ToolBar; import javafx.scene.control.Tooltip; import javafx.scene.input.DataFormat; @@ -95,7 +98,9 @@ import org.jabref.gui.metadata.PreambleEditor; import org.jabref.gui.preferences.ShowPreferencesAction; import org.jabref.gui.protectedterms.ManageProtectedTermsAction; +import org.jabref.gui.push.PushToApplication; import org.jabref.gui.push.PushToApplicationAction; +import org.jabref.gui.push.PushToApplicationMenuAction; import org.jabref.gui.push.PushToApplicationsManager; import org.jabref.gui.search.GlobalSearchBar; import org.jabref.gui.shared.ConnectToSharedDatabaseCommand; @@ -154,7 +159,7 @@ public class JabRefFrame extends BorderPane { private final CountingUndoManager undoManager; private SidePaneManager sidePaneManager; private TabPane tabbedPane; - private PushToApplicationsManager pushApplications; + private PushToApplicationsManager pushToApplicationsManager; private final DialogService dialogService; private SidePane sidePane; @@ -449,7 +454,7 @@ public boolean quit() { private void initLayout() { setProgressBarVisible(false); - pushApplications = new PushToApplicationsManager(this.getDialogService()); + pushToApplicationsManager = new PushToApplicationsManager(dialogService, stateManager); BorderPane head = new BorderPane(); head.setTop(createMenu()); @@ -520,7 +525,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 +539,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 +767,28 @@ 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 submenu + final Menu pushApplicationsMenu = factory.createSubMenu(StandardActions.SELECT_PUSH_APPLICATION); + final String activePushToApplicationName = Globals.prefs.get(JabRefPreferences.PUSH_TO_APPLICATION); + + final ToggleGroup pushToToggleGroup = new ToggleGroup(); + + for (PushToApplication application : pushToApplicationsManager.getApplications()) { + PushToApplicationMenuAction pushToApplicationMenuAction = new PushToApplicationMenuAction(application, pushToApplicationsManager); + RadioMenuItem pushToApplication = factory.createRadioMenuItem( + pushToApplicationMenuAction.getActionInformation(), + pushToApplicationMenuAction, + application.getApplicationName().equals(activePushToApplicationName)); + + pushApplicationsMenu.getItems().add(pushToApplication); + pushToApplication.setToggleGroup(pushToToggleGroup); + } + + // 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 +805,13 @@ 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), + + new SeparatorMenuItem(), + + pushApplicationsMenu, + pushToApplicationMenuItem, + + new SeparatorMenuItem(), factory.createSubMenu(StandardActions.ABBREVIATE, factory.createMenuItem(StandardActions.ABBREVIATE_ISO, new OldDatabaseCommandWrapper(Actions.ABBREVIATE_ISO, this, stateManager)), @@ -1192,8 +1227,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/actions/ActionFactory.java b/src/main/java/org/jabref/gui/actions/ActionFactory.java index 60625d13a1a..719265be957 100644 --- a/src/main/java/org/jabref/gui/actions/ActionFactory.java +++ b/src/main/java/org/jabref/gui/actions/ActionFactory.java @@ -10,6 +10,7 @@ import javafx.scene.control.Label; import javafx.scene.control.Menu; import javafx.scene.control.MenuItem; +import javafx.scene.control.RadioMenuItem; import javafx.scene.control.Tooltip; import org.jabref.gui.keyboard.KeyBindingRepository; @@ -112,6 +113,14 @@ public CheckMenuItem createCheckMenuItem(Action action, Command command, boolean return checkMenuItem; } + public RadioMenuItem createRadioMenuItem(Action action, Command command, boolean selected) { + RadioMenuItem radioMenuItem = ActionUtils.createRadioMenuItem(new JabRefAction(action, command, keyBindingRepository)); + radioMenuItem.setSelected(selected); + setGraphic(radioMenuItem, action); + + return radioMenuItem; + } + public Menu createMenu(Action action) { Menu menu = ActionUtils.createMenu(new JabRefAction(action, keyBindingRepository)); diff --git a/src/main/java/org/jabref/gui/actions/StandardActions.java b/src/main/java/org/jabref/gui/actions/StandardActions.java index eb4c6508955..03d6e65d98c 100644 --- a/src/main/java/org/jabref/gui/actions/StandardActions.java +++ b/src/main/java/org/jabref/gui/actions/StandardActions.java @@ -92,6 +92,7 @@ public enum StandardActions implements Action { OPEN_CONSOLE(Localization.lang("Open terminal here"), Localization.lang("Open terminal here"), IconTheme.JabRefIcons.CONSOLE, KeyBinding.OPEN_CONSOLE), COPY_LINKED_FILES(Localization.lang("Copy linked files to folder...")), COPY_DOI(Localization.lang("Copy DOI url")), + SELECT_PUSH_APPLICATION(Localization.lang("Select external application")), ABBREVIATE(Localization.lang("Abbreviate journal names")), ABBREVIATE_ISO("ISO", Localization.lang("Abbreviate journal names of the selected entries (ISO abbreviation)"), KeyBinding.ABBREVIATE), ABBREVIATE_MEDLINE("MEDLINE", Localization.lang("Abbreviate journal names of the selected entries (MEDLINE abbreviation)")), diff --git a/src/main/java/org/jabref/gui/preferences/ExternalTab.java b/src/main/java/org/jabref/gui/preferences/ExternalTab.java index afb52861d68..47e98009b42 100644 --- a/src/main/java/org/jabref/gui/preferences/ExternalTab.java +++ b/src/main/java/org/jabref/gui/preferences/ExternalTab.java @@ -149,7 +149,7 @@ public ExternalTab(JabRefFrame frame, PreferencesDialog prefsDiag, JabRefPrefere GridPane butpan = new GridPane(); int index = 0; - for (PushToApplication pushToApplication : frame.getPushApplications().getApplications()) { + for (PushToApplication pushToApplication : frame.getPushToApplicationsManager().getApplications()) { addSettingsButton(pushToApplication, butpan, index); index++; } @@ -198,7 +198,7 @@ public Node getBuilder() { } private void addSettingsButton(final PushToApplication application, GridPane panel, int index) { - PushToApplicationSettings settings = frame.getPushApplications().getSettings(application); + PushToApplicationSettings settings = frame.getPushToApplicationsManager().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)); diff --git a/src/main/java/org/jabref/gui/push/PushToApplicationAction.java b/src/main/java/org/jabref/gui/push/PushToApplicationAction.java index ecfb54763ad..124bc5ada93 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 = pushToApplicationsManager.getActiveApplication(Globals.prefs); 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,13 @@ 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/PushToApplicationMenuAction.java b/src/main/java/org/jabref/gui/push/PushToApplicationMenuAction.java new file mode 100644 index 00000000000..02326cb3bfa --- /dev/null +++ b/src/main/java/org/jabref/gui/push/PushToApplicationMenuAction.java @@ -0,0 +1,78 @@ +package org.jabref.gui.push; + +import java.util.Optional; + +import javafx.scene.control.Button; +import javafx.scene.control.MenuItem; + +import org.jabref.Globals; +import org.jabref.gui.actions.Action; +import org.jabref.gui.actions.ActionFactory; +import org.jabref.gui.actions.SimpleCommand; +import org.jabref.gui.icon.JabRefIcon; +import org.jabref.gui.keyboard.KeyBinding; +import org.jabref.preferences.JabRefPreferences; + +/** + * An Action class representing the process of invoking a PushToApplicationMenu operation. + */ +public class PushToApplicationMenuAction extends SimpleCommand { + + private final PushToApplication application; + private final PushToApplicationsManager manager; + + public PushToApplicationMenuAction(PushToApplication pushToApplication, PushToApplicationsManager manager) { + this.application = pushToApplication; + this.manager = manager; + } + + public Action getActionInformation() { + return new Action() { + + @Override + public Optional getIcon() { + return Optional.of(application.getIcon()); + } + + @Override + public Optional getKeyBinding() { + return Optional.empty(); + } + + @Override + public String getText() { + return application.getApplicationName(); + } + + @Override + public String getDescription() { + return ""; + } + }; + } + + @Override + public void execute() { + final ActionFactory factory = new ActionFactory(Globals.getKeyPrefs()); + final PushToApplicationAction pushToApplicationAction = manager.getPushToApplicationAction(); + final MenuItem menuItem = manager.getMenuItem(); + final Button toolBarButton = manager.getToolBarButton(); + + Globals.prefs.put(JabRefPreferences.PUSH_TO_APPLICATION, application.getApplicationName()); + pushToApplicationAction.updateApplication(application); + + if (menuItem != null) { + factory.configureMenuItem( + pushToApplicationAction.getActionInformation(), + pushToApplicationAction, + menuItem); + } + + if (toolBarButton != null) { + factory.configureIconButton( + pushToApplicationAction.getActionInformation(), + pushToApplicationAction, + toolBarButton); + } + } +} diff --git a/src/main/java/org/jabref/gui/push/PushToApplicationsManager.java b/src/main/java/org/jabref/gui/push/PushToApplicationsManager.java index e7bfaf78b3b..79bb486a411 100644 --- a/src/main/java/org/jabref/gui/push/PushToApplicationsManager.java +++ b/src/main/java/org/jabref/gui/push/PushToApplicationsManager.java @@ -3,7 +3,11 @@ import java.util.ArrayList; import java.util.List; +import javafx.scene.control.Button; +import javafx.scene.control.MenuItem; + import org.jabref.gui.DialogService; +import org.jabref.gui.StateManager; import org.jabref.preferences.JabRefPreferences; public class PushToApplicationsManager { @@ -12,7 +16,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,12 +30,32 @@ 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 MenuItem getMenuItem() { + return menuItem; + } + + public void setToolBarButton(Button toolBarButton) { this.toolBarButton = toolBarButton; } + + public Button getToolBarButton() { + return toolBarButton; + } + public PushToApplicationSettings getSettings(PushToApplication application) { if (application instanceof PushToEmacs) { return new PushToEmacsSettings(dialogService); @@ -40,7 +68,7 @@ public PushToApplicationSettings getSettings(PushToApplication application) { } } - public PushToApplication getLastUsedApplication(JabRefPreferences preferences) { + public PushToApplication getActiveApplication(JabRefPreferences preferences) { String appSelected = preferences.get(JabRefPreferences.PUSH_TO_APPLICATION); return applications.stream() .filter(application -> application.getApplicationName().equals(appSelected)) diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index 58822acd1ce..421cc8d28b0 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -1370,6 +1370,7 @@ Open\ %0\ file=Open %0 file Cannot\ delete\ file=Cannot delete file File\ permission\ error=File permission error +Select\ external\ application=Select external application Push\ to\ %0=Push to %0 Path\ to\ %0=Path to %0 Convert=Convert