From 3d24714deb07978972b921025551d5328faff039 Mon Sep 17 00:00:00 2001 From: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com> Date: Fri, 6 Mar 2020 15:31:23 +0100 Subject: [PATCH] [WIP] Remove BaseAction from JabRefFrame (#6056) * Added UndoRedoAction * Refactored AppendDatabaseAction * Refactored ReplaceStringAction and GenerateBibtexKeyAction * Refactored CleanupAction * Added OpenEntryEditorAction, fixed bug about selected entries without open database * Refactored AbbreviateAction, merged UnabbreviateAction, removed unused Actions * Refactored DownloadFullTextAction * Added PullChangesFromSharedAction * Added SaveAction, removed remaining deprecated OldDatabaseCommandWrapper, BaseAction and Actions * Added UndoRedoAction * Refactored AppendDatabaseAction * Refactored ReplaceStringAction and GenerateBibtexKeyAction * Refactored CleanupAction * Added OpenEntryEditorAction, fixed bug about selected entries without open database * Refactored AbbreviateAction, merged UnabbreviateAction, removed unused Actions * Refactored DownloadFullTextAction * Added PullChangesFromSharedAction * Added SaveAction, removed remaining deprecated OldDatabaseCommandWrapper, BaseAction and Actions * Removed test, added default case for codacy compliance * Removed test for notifications --- src/main/java/org/jabref/gui/BasePanel.java | 131 +----------------- src/main/java/org/jabref/gui/JabRefFrame.java | 72 +++++----- .../java/org/jabref/gui/actions/Actions.java | 31 ----- .../org/jabref/gui/actions/BaseAction.java | 15 -- .../org/jabref/gui/actions/JabRefAction.java | 7 +- .../actions/OldDatabaseCommandWrapper.java | 63 --------- .../GenerateBibtexKeyAction.java | 70 +++++----- .../org/jabref/gui/cleanup/CleanupAction.java | 116 ++++++++-------- .../jabref/gui/edit/ReplaceStringAction.java | 14 +- .../entryeditor/OpenEntryEditorAction.java | 25 ++++ .../org/jabref/gui/exporter/SaveAction.java | 52 +++++++ .../jabref/gui/exporter/SaveAllAction.java | 9 +- .../externalfiles/DownloadFullTextAction.java | 73 ++++++---- .../actions/AppendDatabaseAction.java | 56 +++++--- .../jabref/gui/journals/AbbreviateAction.java | 112 ++++++++++++--- .../gui/journals/UnabbreviateAction.java | 51 ------- .../shared/PullChangesFromSharedAction.java | 24 ++++ .../org/jabref/gui/undo/UndoRedoAction.java | 62 +++++++++ .../preferences/PreferencesService.java | 8 ++ .../gui/exporter/SaveAllActionTest.java | 77 ---------- 20 files changed, 499 insertions(+), 569 deletions(-) delete mode 100644 src/main/java/org/jabref/gui/actions/Actions.java delete mode 100644 src/main/java/org/jabref/gui/actions/BaseAction.java delete mode 100644 src/main/java/org/jabref/gui/actions/OldDatabaseCommandWrapper.java create mode 100644 src/main/java/org/jabref/gui/entryeditor/OpenEntryEditorAction.java create mode 100644 src/main/java/org/jabref/gui/exporter/SaveAction.java delete mode 100644 src/main/java/org/jabref/gui/journals/UnabbreviateAction.java create mode 100644 src/main/java/org/jabref/gui/shared/PullChangesFromSharedAction.java create mode 100644 src/main/java/org/jabref/gui/undo/UndoRedoAction.java delete mode 100644 src/test/java/org/jabref/gui/exporter/SaveAllActionTest.java diff --git a/src/main/java/org/jabref/gui/BasePanel.java b/src/main/java/org/jabref/gui/BasePanel.java index ff5baf2606d..65bfb60f56a 100644 --- a/src/main/java/org/jabref/gui/BasePanel.java +++ b/src/main/java/org/jabref/gui/BasePanel.java @@ -2,15 +2,10 @@ import java.nio.file.Path; import java.util.Collections; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.Optional; -import javax.swing.undo.CannotRedoException; -import javax.swing.undo.CannotUndoException; - import javafx.application.Platform; import javafx.beans.binding.Bindings; import javafx.geometry.Orientation; @@ -20,25 +15,14 @@ import org.jabref.Globals; import org.jabref.JabRefExecutorService; -import org.jabref.gui.actions.Actions; -import org.jabref.gui.actions.BaseAction; import org.jabref.gui.autocompleter.AutoCompletePreferences; import org.jabref.gui.autocompleter.AutoCompleteUpdater; import org.jabref.gui.autocompleter.PersonNameSuggestionProvider; import org.jabref.gui.autocompleter.SuggestionProviders; -import org.jabref.gui.bibtexkeypattern.GenerateBibtexKeyAction; -import org.jabref.gui.cleanup.CleanupAction; import org.jabref.gui.collab.DatabaseChangeMonitor; import org.jabref.gui.collab.DatabaseChangePane; -import org.jabref.gui.edit.ReplaceStringAction; import org.jabref.gui.entryeditor.EntryEditor; -import org.jabref.gui.exporter.SaveDatabaseAction; -import org.jabref.gui.externalfiles.DownloadFullTextAction; import org.jabref.gui.externalfiletype.ExternalFileTypes; -import org.jabref.gui.importer.actions.AppendDatabaseAction; -import org.jabref.gui.journals.AbbreviateAction; -import org.jabref.gui.journals.AbbreviationType; -import org.jabref.gui.journals.UnabbreviateAction; import org.jabref.gui.maintable.MainTable; import org.jabref.gui.maintable.MainTableDataModel; import org.jabref.gui.specialfields.SpecialFieldDatabaseChangeListener; @@ -62,7 +46,6 @@ import org.jabref.model.database.event.EntriesAddedEvent; import org.jabref.model.database.event.EntriesRemovedEvent; import org.jabref.model.database.shared.DatabaseLocation; -import org.jabref.model.database.shared.DatabaseSynchronizer; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.event.EntriesEventSource; import org.jabref.model.entry.event.EntryChangedEvent; @@ -88,11 +71,8 @@ public class BasePanel extends StackPane { private final JabRefFrame frame; // The undo manager. - private final UndoAction undoAction = new UndoAction(); - private final RedoAction redoAction = new RedoAction(); private final CountingUndoManager undoManager; - // Keeps track of the string dialog if it is open. - private final Map actions = new HashMap<>(); + private final SidePaneManager sidePaneManager; private final ExternalFileTypes externalFileTypes; @@ -139,8 +119,6 @@ public BasePanel(JabRefFrame frame, BasePanelPreferences preferences, BibDatabas setupMainPanel(); - setupActions(); - this.getDatabase().registerListener(new SearchListener()); this.getDatabase().registerListener(new EntriesRemovedListener()); @@ -153,7 +131,7 @@ public BasePanel(JabRefFrame frame, BasePanelPreferences preferences, BibDatabas this.entryEditor = new EntryEditor(this, externalFileTypes); // Open entry editor for first entry on start up. - Platform.runLater(() -> clearAndSelectFirst()); + Platform.runLater(this::clearAndSelectFirst); } @Subscribe @@ -216,48 +194,6 @@ public void output(String s) { dialogService.notify(s); } - private void setupActions() { - SaveDatabaseAction saveAction = new SaveDatabaseAction(this, Globals.prefs, Globals.entryTypesManager); - CleanupAction cleanUpAction = new CleanupAction(this, Globals.prefs, Globals.TASK_EXECUTOR); - - actions.put(Actions.UNDO, undoAction); - actions.put(Actions.REDO, redoAction); - - // The action for opening an entry editor. - actions.put(Actions.EDIT, this::showAndEdit); - - // The action for saving a database. - actions.put(Actions.SAVE, saveAction::save); - - actions.put(Actions.SAVE_AS, saveAction::saveAs); - - actions.put(Actions.SAVE_SELECTED_AS_PLAIN, saveAction::saveSelectedAsPlain); - - actions.put(Actions.SELECT_ALL, mainTable.getSelectionModel()::selectAll); - - // The action for auto-generating keys. - actions.put(Actions.MAKE_KEY, new GenerateBibtexKeyAction(this, frame.getDialogService())); - - // The action for cleaning up entry. - actions.put(Actions.CLEANUP, cleanUpAction); - - actions.put(Actions.MERGE_DATABASE, new AppendDatabaseAction(frame, this)); - - actions.put(Actions.PULL_CHANGES_FROM_SHARED_DATABASE, () -> { - DatabaseSynchronizer dbmsSynchronizer = frame.getCurrentBasePanel().getBibDatabaseContext().getDBMSSynchronizer(); - dbmsSynchronizer.pullChanges(); - }); - - actions.put(Actions.REPLACE_ALL, () -> (new ReplaceStringAction(this)).execute()); - - actions.put(Actions.ABBREVIATE_DEFAULT, new AbbreviateAction(this, AbbreviationType.DEFAULT)); - actions.put(Actions.ABBREVIATE_MEDLINE, new AbbreviateAction(this, AbbreviationType.MEDLINE)); - actions.put(Actions.ABBREVIATE_SHORTEST_UNIQUE, new AbbreviateAction(this, AbbreviationType.SHORTEST_UNIQUE)); - actions.put(Actions.UNABBREVIATE, new UnabbreviateAction(this)); - - actions.put(Actions.DOWNLOAD_FULL_TEXT, new DownloadFullTextAction(this)::execute); - } - /** * Removes the selected entries from the database * @@ -297,26 +233,6 @@ public void delete(BibEntry entry) { delete(false, Collections.singletonList(entry)); } - /** - * This method is called from JabRefFrame if a database specific action is requested by the user. Runs the command - * if it is defined, or prints an error message to the standard error stream. - * - * @param command The name of the command to run. - */ - public void runCommand(final Actions command) { - if (!actions.containsKey(command)) { - LOGGER.info("No action defined for '" + command + '\''); - return; - } - - BaseAction action = actions.get(command); - try { - action.action(); - } catch (Throwable ex) { - LOGGER.error("runCommand error: " + ex.getMessage(), ex); - } - } - public void registerUndoableChanges(List changes) { NamedCompound ce = new NamedCompound(Localization.lang("Save actions")); for (FieldChange change : changes) { @@ -567,12 +483,6 @@ private void showBottomPane(BasePanelMode newMode) { adjustSplitter(); } - private void showAndEdit() { - if (!mainTable.getSelectedEntries().isEmpty()) { - showAndEdit(mainTable.getSelectedEntries().get(0)); - } - } - /** * Removes the bottom component. */ @@ -594,7 +504,7 @@ public void clearAndSelect(final BibEntry bibEntry) { */ private void clearAndSelectFirst() { mainTable.clearAndSelectFirst(); - showAndEdit(); + showAndEdit(mainTable.getSelectedEntries().get(0)); } public void selectPreviousEntry() { @@ -645,7 +555,7 @@ public void markNonUndoableBaseChanged() { markBaseChanged(); } - private synchronized void markChangedOrUnChanged() { + public synchronized void markChangedOrUnChanged() { if (getUndoManager().hasChanged()) { if (!baseChanged) { markBaseChanged(); @@ -864,37 +774,4 @@ public void listen(EntriesRemovedEvent removedEntriesEvent) { DefaultTaskExecutor.runInJavaFXThread(() -> frame.getGlobalSearchBar().performSearch()); } } - - private class UndoAction implements BaseAction { - - @Override - public void action() { - try { - getUndoManager().undo(); - markBaseChanged(); - output(Localization.lang("Undo")); - } catch (CannotUndoException ex) { - LOGGER.warn("Nothing to undo", ex); - output(Localization.lang("Nothing to undo") + '.'); - } - - markChangedOrUnChanged(); - } - } - - private class RedoAction implements BaseAction { - - @Override - public void action() { - try { - getUndoManager().redo(); - markBaseChanged(); - output(Localization.lang("Redo")); - } catch (CannotRedoException ex) { - output(Localization.lang("Nothing to redo") + '.'); - } - - markChangedOrUnChanged(); - } - } } diff --git a/src/main/java/org/jabref/gui/JabRefFrame.java b/src/main/java/org/jabref/gui/JabRefFrame.java index 63e7b72edbb..b097b875c92 100644 --- a/src/main/java/org/jabref/gui/JabRefFrame.java +++ b/src/main/java/org/jabref/gui/JabRefFrame.java @@ -5,6 +5,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -45,13 +46,13 @@ import org.jabref.Globals; import org.jabref.JabRefExecutorService; import org.jabref.gui.actions.ActionFactory; -import org.jabref.gui.actions.Actions; -import org.jabref.gui.actions.OldDatabaseCommandWrapper; import org.jabref.gui.actions.SimpleCommand; import org.jabref.gui.actions.StandardActions; import org.jabref.gui.auximport.NewSubLibraryAction; import org.jabref.gui.bibtexextractor.ExtractBibtexAction; import org.jabref.gui.bibtexkeypattern.BibtexKeyPatternAction; +import org.jabref.gui.bibtexkeypattern.GenerateBibtexKeyAction; +import org.jabref.gui.cleanup.CleanupAction; import org.jabref.gui.contentselector.ManageContentSelectorAction; import org.jabref.gui.copyfiles.CopyFilesAction; import org.jabref.gui.customentrytypes.CustomizeEntryAction; @@ -64,14 +65,18 @@ import org.jabref.gui.edit.ManageKeywordsAction; import org.jabref.gui.edit.MassSetFieldsAction; import org.jabref.gui.edit.OpenBrowserAction; +import org.jabref.gui.edit.ReplaceStringAction; +import org.jabref.gui.entryeditor.OpenEntryEditorAction; import org.jabref.gui.entryeditor.PreviewSwitchAction; import org.jabref.gui.exporter.ExportCommand; import org.jabref.gui.exporter.ExportToClipboardAction; import org.jabref.gui.exporter.ManageCustomExportsAction; +import org.jabref.gui.exporter.SaveAction; import org.jabref.gui.exporter.SaveAllAction; import org.jabref.gui.exporter.SaveDatabaseAction; import org.jabref.gui.exporter.WriteXMPAction; import org.jabref.gui.externalfiles.AutoLinkFilesAction; +import org.jabref.gui.externalfiles.DownloadFullTextAction; import org.jabref.gui.externalfiles.FindUnlinkedFilesAction; import org.jabref.gui.externalfiletype.EditExternalFileTypesAction; import org.jabref.gui.externalfiletype.ExternalFileTypes; @@ -84,9 +89,11 @@ import org.jabref.gui.importer.ManageCustomImportsAction; import org.jabref.gui.importer.NewDatabaseAction; import org.jabref.gui.importer.NewEntryAction; +import org.jabref.gui.importer.actions.AppendDatabaseAction; import org.jabref.gui.importer.actions.OpenDatabaseAction; import org.jabref.gui.importer.fetcher.LookupIdentifierAction; import org.jabref.gui.integrity.IntegrityCheckAction; +import org.jabref.gui.journals.AbbreviateAction; import org.jabref.gui.journals.ManageJournalsAction; import org.jabref.gui.keyboard.CustomizeKeyBindingAction; import org.jabref.gui.keyboard.KeyBinding; @@ -102,9 +109,11 @@ import org.jabref.gui.push.PushToApplicationsManager; import org.jabref.gui.search.GlobalSearchBar; import org.jabref.gui.shared.ConnectToSharedDatabaseCommand; +import org.jabref.gui.shared.PullChangesFromSharedAction; import org.jabref.gui.specialfields.SpecialFieldMenuItemFactory; import org.jabref.gui.texparser.ParseLatexAction; import org.jabref.gui.undo.CountingUndoManager; +import org.jabref.gui.undo.UndoRedoAction; import org.jabref.gui.util.BackgroundTask; import org.jabref.gui.util.DefaultTaskExecutor; import org.jabref.logic.autosaveandbackup.AutosaveManager; @@ -421,7 +430,7 @@ private void initLayout() { splitPane.getItems().addAll(sidePane, tabbedPane); // We need to wait with setting the divider since it gets reset a few times during the initial set-up - mainStage.showingProperty().addListener(new ChangeListener() { + mainStage.showingProperty().addListener(new ChangeListener<>() { @Override public void changed(ObservableValue observable, Boolean oldValue, Boolean showing) { @@ -475,7 +484,7 @@ private Node createToolbar() { HBox leftSide = new HBox( newLibrary, factory.createIconButton(StandardActions.OPEN_LIBRARY, new OpenDatabaseAction(this)), - factory.createIconButton(StandardActions.SAVE_LIBRARY, new OldDatabaseCommandWrapper(Actions.SAVE, this, stateManager)), + factory.createIconButton(StandardActions.SAVE_LIBRARY, new SaveAction(SaveAction.SaveMethod.SAVE, this, stateManager)), leftSpacer ); @@ -489,15 +498,15 @@ private Node createToolbar() { factory.createIconButton(StandardActions.NEW_ENTRY_FROM_PLAIN_TEXT, new ExtractBibtexAction(stateManager)), factory.createIconButton(StandardActions.DELETE_ENTRY, new EditAction(StandardActions.DELETE_ENTRY, this, stateManager)), new Separator(Orientation.VERTICAL), - factory.createIconButton(StandardActions.UNDO, new OldDatabaseCommandWrapper(Actions.UNDO, this, stateManager)), - factory.createIconButton(StandardActions.REDO, new OldDatabaseCommandWrapper(Actions.REDO, this, stateManager)), + factory.createIconButton(StandardActions.UNDO, new UndoRedoAction(StandardActions.UNDO, this, dialogService, stateManager)), + factory.createIconButton(StandardActions.REDO, new UndoRedoAction(StandardActions.REDO, this, dialogService, stateManager)), factory.createIconButton(StandardActions.CUT, new EditAction(StandardActions.CUT,this, stateManager)), factory.createIconButton(StandardActions.COPY, new EditAction(StandardActions.COPY,this, stateManager)), factory.createIconButton(StandardActions.PASTE, new EditAction(StandardActions.PASTE,this, stateManager)), new Separator(Orientation.VERTICAL), 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)), + factory.createIconButton(StandardActions.GENERATE_CITE_KEYS, new GenerateBibtexKeyAction(this, dialogService, stateManager)), + factory.createIconButton(StandardActions.CLEANUP_ENTRIES, new CleanupAction(this, prefs, dialogService, stateManager)), new Separator(Orientation.VERTICAL), factory.createIconButton(StandardActions.OPEN_GITHUB, new OpenBrowserAction("https://github.com/JabRef/jabref")), factory.createIconButton(StandardActions.OPEN_FACEBOOK, new OpenBrowserAction("https://www.facebook.com/JabRef/")), @@ -587,6 +596,7 @@ public void init() { */ EasyBind.subscribe(tabbedPane.getSelectionModel().selectedItemProperty(), tab -> { if (tab == null) { + stateManager.setSelectedEntries(Collections.emptyList()); return; } @@ -674,27 +684,27 @@ private MenuBar createMenu() { factory.createMenuItem(StandardActions.OPEN_LIBRARY, getOpenDatabaseAction()), fileHistory, - factory.createMenuItem(StandardActions.SAVE_LIBRARY, new OldDatabaseCommandWrapper(Actions.SAVE, this, stateManager)), - factory.createMenuItem(StandardActions.SAVE_LIBRARY_AS, new OldDatabaseCommandWrapper(Actions.SAVE_AS, this, stateManager)), + factory.createMenuItem(StandardActions.SAVE_LIBRARY, new SaveAction(SaveAction.SaveMethod.SAVE, this, stateManager)), + factory.createMenuItem(StandardActions.SAVE_LIBRARY_AS, new SaveAction(SaveAction.SaveMethod.SAVE_AS, this, stateManager)), factory.createMenuItem(StandardActions.SAVE_ALL, new SaveAllAction(this)), new SeparatorMenuItem(), factory.createSubMenu(StandardActions.IMPORT, - factory.createMenuItem(StandardActions.MERGE_DATABASE, new OldDatabaseCommandWrapper(Actions.MERGE_DATABASE, this, stateManager)), // TODO: merge with import + factory.createMenuItem(StandardActions.MERGE_DATABASE, new AppendDatabaseAction(this, dialogService, stateManager)), // TODO: merge with import factory.createMenuItem(StandardActions.IMPORT_INTO_CURRENT_LIBRARY, new ImportCommand(this, false, stateManager)), factory.createMenuItem(StandardActions.IMPORT_INTO_NEW_LIBRARY, new ImportCommand(this, true, stateManager))), factory.createSubMenu(StandardActions.EXPORT, factory.createMenuItem(StandardActions.EXPORT_ALL, new ExportCommand(this, false, Globals.prefs)), factory.createMenuItem(StandardActions.EXPORT_SELECTED, new ExportCommand(this, true, Globals.prefs)), - factory.createMenuItem(StandardActions.SAVE_SELECTED_AS_PLAIN_BIBTEX, new OldDatabaseCommandWrapper(Actions.SAVE_SELECTED_AS_PLAIN, this, stateManager))), + factory.createMenuItem(StandardActions.SAVE_SELECTED_AS_PLAIN_BIBTEX, new SaveAction(SaveAction.SaveMethod.SAVE_SELECTED, this, stateManager))), new SeparatorMenuItem(), factory.createSubMenu(StandardActions.REMOTE_DB, factory.createMenuItem(StandardActions.CONNECT_TO_SHARED_DB, new ConnectToSharedDatabaseCommand(this)), - factory.createMenuItem(StandardActions.PULL_CHANGES_FROM_SHARED_DB, new OldDatabaseCommandWrapper(Actions.PULL_CHANGES_FROM_SHARED_DATABASE, this, stateManager)) + factory.createMenuItem(StandardActions.PULL_CHANGES_FROM_SHARED_DB, new PullChangesFromSharedAction(stateManager)) ), new SeparatorMenuItem(), @@ -704,8 +714,8 @@ private MenuBar createMenu() { ); edit.getItems().addAll( - factory.createMenuItem(StandardActions.UNDO, new OldDatabaseCommandWrapper(Actions.UNDO, this, stateManager)), - factory.createMenuItem(StandardActions.REDO, new OldDatabaseCommandWrapper(Actions.REDO, this, stateManager)), + factory.createMenuItem(StandardActions.UNDO, new UndoRedoAction(StandardActions.UNDO, this, dialogService, stateManager)), + factory.createMenuItem(StandardActions.REDO, new UndoRedoAction(StandardActions.REDO, this, dialogService, stateManager)), new SeparatorMenuItem(), @@ -725,8 +735,8 @@ private MenuBar createMenu() { new SeparatorMenuItem(), - factory.createMenuItem(StandardActions.REPLACE_ALL, new OldDatabaseCommandWrapper(Actions.REPLACE_ALL, this, stateManager)), - factory.createMenuItem(StandardActions.GENERATE_CITE_KEYS, new OldDatabaseCommandWrapper(Actions.MAKE_KEY, this, stateManager)), + factory.createMenuItem(StandardActions.REPLACE_ALL, new ReplaceStringAction( this, stateManager)), + factory.createMenuItem(StandardActions.GENERATE_CITE_KEYS, new GenerateBibtexKeyAction(this, dialogService, stateManager)), new SeparatorMenuItem(), @@ -762,17 +772,11 @@ private MenuBar createMenu() { factory.createMenuItem(StandardActions.MASS_SET_FIELDS, new MassSetFieldsAction(stateManager, dialogService, undoManager)) ); - Menu lookupIdentifiers = factory.createSubMenu(StandardActions.LOOKUP_DOC_IDENTIFIER); - for (IdFetcher fetcher : WebFetchers.getIdFetchers(Globals.prefs.getImportFormatPreferences())) { - LookupIdentifierAction identifierAction = new LookupIdentifierAction<>(this, fetcher, stateManager, undoManager); - lookupIdentifiers.getItems().add(factory.createMenuItem(identifierAction.getAction(), identifierAction)); - } - quality.getItems().addAll( factory.createMenuItem(StandardActions.FIND_DUPLICATES, new DuplicateSearch(this, dialogService, stateManager)), factory.createMenuItem(StandardActions.MERGE_ENTRIES, new MergeEntriesAction(this, dialogService, stateManager)), factory.createMenuItem(StandardActions.CHECK_INTEGRITY, new IntegrityCheckAction(this, stateManager, Globals.TASK_EXECUTOR)), - factory.createMenuItem(StandardActions.CLEANUP_ENTRIES, new OldDatabaseCommandWrapper(Actions.CLEANUP, this, stateManager)), + factory.createMenuItem(StandardActions.CLEANUP_ENTRIES, new CleanupAction(this, this.prefs, dialogService, stateManager)), new SeparatorMenuItem(), @@ -781,17 +785,23 @@ private MenuBar createMenu() { new SeparatorMenuItem(), factory.createSubMenu(StandardActions.ABBREVIATE, - factory.createMenuItem(StandardActions.ABBREVIATE_DEFAULT, new OldDatabaseCommandWrapper(Actions.ABBREVIATE_DEFAULT, this, stateManager)), - factory.createMenuItem(StandardActions.ABBREVIATE_MEDLINE, new OldDatabaseCommandWrapper(Actions.ABBREVIATE_MEDLINE, this, stateManager)), - factory.createMenuItem(StandardActions.ABBREVIATE_SHORTEST_UNIQUE, new OldDatabaseCommandWrapper(Actions.ABBREVIATE_SHORTEST_UNIQUE, this, stateManager))), + factory.createMenuItem(StandardActions.ABBREVIATE_DEFAULT, new AbbreviateAction(StandardActions.ABBREVIATE_DEFAULT, this, dialogService, stateManager, prefs)), + factory.createMenuItem(StandardActions.ABBREVIATE_MEDLINE, new AbbreviateAction(StandardActions.ABBREVIATE_MEDLINE, this, dialogService, stateManager, prefs)), + factory.createMenuItem(StandardActions.ABBREVIATE_SHORTEST_UNIQUE, new AbbreviateAction(StandardActions.ABBREVIATE_SHORTEST_UNIQUE, this, dialogService, stateManager, prefs))), - factory.createMenuItem(StandardActions.UNABBREVIATE, new OldDatabaseCommandWrapper(Actions.UNABBREVIATE, this, stateManager)) + factory.createMenuItem(StandardActions.UNABBREVIATE, new AbbreviateAction(StandardActions.UNABBREVIATE, this, dialogService, stateManager, prefs)) ); lookup.getItems().addAll( factory.createMenuItem(StandardActions.FIND_DUPLICATES, new DuplicateSearch(this, dialogService, stateManager)) ); + Menu lookupIdentifiers = factory.createSubMenu(StandardActions.LOOKUP_DOC_IDENTIFIER); + for (IdFetcher fetcher : WebFetchers.getIdFetchers(Globals.prefs.getImportFormatPreferences())) { + LookupIdentifierAction identifierAction = new LookupIdentifierAction<>(this, fetcher, stateManager, undoManager); + lookupIdentifiers.getItems().add(factory.createMenuItem(identifierAction.getAction(), identifierAction)); + } + // PushToApplication final PushToApplicationAction pushToApplicationAction = pushToApplicationsManager.getPushToApplicationAction(); final MenuItem pushToApplicationMenuItem = factory.createMenuItem(pushToApplicationAction.getActionInformation(), pushToApplicationAction); @@ -810,7 +820,7 @@ private MenuBar createMenu() { new SeparatorMenuItem(), lookupIdentifiers, - factory.createMenuItem(StandardActions.DOWNLOAD_FULL_TEXT, new OldDatabaseCommandWrapper(Actions.DOWNLOAD_FULL_TEXT, this, stateManager)), + factory.createMenuItem(StandardActions.DOWNLOAD_FULL_TEXT, new DownloadFullTextAction(dialogService, stateManager, prefs)), new SeparatorMenuItem(), @@ -838,7 +848,7 @@ private MenuBar createMenu() { new SeparatorMenuItem(), factory.createMenuItem(StandardActions.SHOW_PDF_VIEWER, new ShowDocumentViewerAction()), - factory.createMenuItem(StandardActions.EDIT_ENTRY, new OldDatabaseCommandWrapper(Actions.EDIT, this, stateManager)), + factory.createMenuItem(StandardActions.EDIT_ENTRY, new OpenEntryEditorAction(this, stateManager)), factory.createMenuItem(StandardActions.OPEN_CONSOLE, new OpenConsoleAction(stateManager)) ); }); @@ -1152,7 +1162,7 @@ private boolean confirmClose(BasePanel panel) { // Save was cancelled or an error occurred. return false; } - return !response.isPresent() || !response.get().equals(cancel); + return response.isEmpty() || !response.get().equals(cancel); } private void closeTab(BasePanel panel) { diff --git a/src/main/java/org/jabref/gui/actions/Actions.java b/src/main/java/org/jabref/gui/actions/Actions.java deleted file mode 100644 index f606eec20a1..00000000000 --- a/src/main/java/org/jabref/gui/actions/Actions.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.jabref.gui.actions; - -/** - * Global String constants for GUI actions - */ -@Deprecated -public enum Actions { - ABBREVIATE_DEFAULT, - ABBREVIATE_MEDLINE, - ABBREVIATE_SHORTEST_UNIQUE, - ADD_FILE_LINK, - CLEANUP, - DOWNLOAD_FULL_TEXT, - EDIT, - EDIT_PREAMBLE, - EDIT_STRINGS, - EXPORT_TO_CLIPBOARD, - MAKE_KEY, - MANAGE_SELECTORS, - MERGE_DATABASE, - PULL_CHANGES_FROM_SHARED_DATABASE, - REDO, - REPLACE_ALL, - SAVE, - SAVE_AS, - SAVE_SELECTED_AS_PLAIN, - SELECT_ALL, - TOGGLE_GROUPS, - UNABBREVIATE, - UNDO -} diff --git a/src/main/java/org/jabref/gui/actions/BaseAction.java b/src/main/java/org/jabref/gui/actions/BaseAction.java deleted file mode 100644 index 0af963e1a30..00000000000 --- a/src/main/java/org/jabref/gui/actions/BaseAction.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.jabref.gui.actions; - -/** - * BaseAction is used to define actions that are called from the - * base frame through runCommand(). runCommand() finds the - * appropriate BaseAction object, and runs its action() method. - * - * @deprecated use {@link SimpleCommand} instead - */ -@FunctionalInterface -@Deprecated -public interface BaseAction { - - void action() throws Exception; -} diff --git a/src/main/java/org/jabref/gui/actions/JabRefAction.java b/src/main/java/org/jabref/gui/actions/JabRefAction.java index dfdc35330b2..aba36dfe2e9 100644 --- a/src/main/java/org/jabref/gui/actions/JabRefAction.java +++ b/src/main/java/org/jabref/gui/actions/JabRefAction.java @@ -58,10 +58,11 @@ private String getActionName(Action action, Command command) { return action.getText(); } else { String commandName = command.getClass().getSimpleName(); - if ((command instanceof OldDatabaseCommandWrapper) - || commandName.contains("EditAction") + if ( commandName.contains("EditAction") || commandName.contains("CopyMoreAction") - || commandName.contains("CopyCitationAction")) { + || commandName.contains("CopyCitationAction") + || commandName.contains("PreviewSwitchAction") + || commandName.contains("SaveAction")) { return command.toString(); } else { return commandName; diff --git a/src/main/java/org/jabref/gui/actions/OldDatabaseCommandWrapper.java b/src/main/java/org/jabref/gui/actions/OldDatabaseCommandWrapper.java deleted file mode 100644 index bcd8301d690..00000000000 --- a/src/main/java/org/jabref/gui/actions/OldDatabaseCommandWrapper.java +++ /dev/null @@ -1,63 +0,0 @@ -package org.jabref.gui.actions; - -import java.util.Optional; - -import javafx.beans.property.ReadOnlyDoubleProperty; - -import org.jabref.gui.JabRefFrame; -import org.jabref.gui.StateManager; - -import de.saxsys.mvvmfx.utils.commands.CommandBase; -import org.fxmisc.easybind.EasyBind; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * A command that is only executable if a database is open. - * Deprecated use instead - * @see org.jabref.gui.actions.SimpleCommand - */ -@Deprecated -public class OldDatabaseCommandWrapper extends CommandBase { - - private static final Logger LOGGER = LoggerFactory.getLogger(OldDatabaseCommandWrapper.class); - - private final Actions command; - private final JabRefFrame frame; - - public OldDatabaseCommandWrapper(Actions command, JabRefFrame frame, StateManager stateManager) { - this.command = command; - this.frame = frame; - - this.executable.bind( - EasyBind.map(stateManager.activeDatabaseProperty(), Optional::isPresent)); - } - - @Override - public void execute() { - if (frame.getTabbedPane().getTabs().size() > 0) { - try { - frame.getCurrentBasePanel().runCommand(command); - } catch (Throwable ex) { - LOGGER.error("Problem with executing command: " + command, ex); - } - } else { - LOGGER.info("Action '" + command + "' must be disabled when no database is open."); - } - } - - @Override - public double getProgress() { - return 0; - } - - @Override - public String toString() { - return this.command.toString(); - } - - @Override - public ReadOnlyDoubleProperty progressProperty() { - return null; - } -} diff --git a/src/main/java/org/jabref/gui/bibtexkeypattern/GenerateBibtexKeyAction.java b/src/main/java/org/jabref/gui/bibtexkeypattern/GenerateBibtexKeyAction.java index d11de1046b7..d0697b31c6a 100644 --- a/src/main/java/org/jabref/gui/bibtexkeypattern/GenerateBibtexKeyAction.java +++ b/src/main/java/org/jabref/gui/bibtexkeypattern/GenerateBibtexKeyAction.java @@ -3,9 +3,11 @@ import java.util.List; import org.jabref.Globals; -import org.jabref.gui.BasePanel; import org.jabref.gui.DialogService; -import org.jabref.gui.actions.BaseAction; +import org.jabref.gui.JabRefFrame; +import org.jabref.gui.StateManager; +import org.jabref.gui.actions.ActionHelper; +import org.jabref.gui.actions.SimpleCommand; import org.jabref.gui.undo.NamedCompound; import org.jabref.gui.undo.UndoableKeyChange; import org.jabref.gui.util.BackgroundTask; @@ -14,27 +16,38 @@ import org.jabref.model.entry.BibEntry; import org.jabref.preferences.JabRefPreferences; -public class GenerateBibtexKeyAction implements BaseAction { +public class GenerateBibtexKeyAction extends SimpleCommand { + private final JabRefFrame frame; private final DialogService dialogService; - private final BasePanel basePanel; + private final StateManager stateManager; + private List entries; private boolean isCanceled; - public GenerateBibtexKeyAction(BasePanel basePanel, DialogService dialogService) { - this.basePanel = basePanel; + public GenerateBibtexKeyAction(JabRefFrame frame, DialogService dialogService, StateManager stateManager) { + this.frame = frame; this.dialogService = dialogService; + this.stateManager = stateManager; + + this.executable.bind(ActionHelper.needsEntriesSelected(stateManager)); } - public void init() { - entries = basePanel.getSelectedEntries(); + @Override + public void execute() { + entries = stateManager.getSelectedEntries(); if (entries.isEmpty()) { dialogService.showWarningDialogAndWait(Localization.lang("Autogenerate BibTeX keys"), - Localization.lang("First select the entries you want keys to be generated for.")); + Localization.lang("First select the entries you want keys to be generated for.")); return; } dialogService.notify(formatOutputMessage(Localization.lang("Generating BibTeX key for"), entries.size())); + + checkOverwriteKeysChosen(); + + BackgroundTask.wrap(this::generateKeys) + .executeWith(Globals.TASK_EXECUTOR); } public static boolean confirmOverwriteKeys(DialogService dialogService) { @@ -73,34 +86,29 @@ private void generateKeys() { if (isCanceled) { return; } - // generate the new cite keys for each entry - final NamedCompound compound = new NamedCompound(Localization.lang("Autogenerate BibTeX keys")); - BibtexKeyGenerator keyGenerator = new BibtexKeyGenerator(basePanel.getBibDatabaseContext(), Globals.prefs.getBibtexKeyPatternPreferences()); - for (BibEntry entry : entries) { - keyGenerator.generateAndSetKey(entry) - .ifPresent(fieldChange -> compound.addEdit(new UndoableKeyChange(fieldChange))); - } - compound.end(); - // register the undo event only if new cite keys were generated - if (compound.hasEdits()) { - basePanel.getUndoManager().addEdit(compound); - } + stateManager.getActiveDatabase().ifPresent(databaseContext -> { + // generate the new cite keys for each entry + final NamedCompound compound = new NamedCompound(Localization.lang("Autogenerate BibTeX keys")); + BibtexKeyGenerator keyGenerator = new BibtexKeyGenerator(databaseContext, Globals.prefs.getBibtexKeyPatternPreferences()); + for (BibEntry entry : entries) { + keyGenerator.generateAndSetKey(entry) + .ifPresent(fieldChange -> compound.addEdit(new UndoableKeyChange(fieldChange))); + } + compound.end(); + + // register the undo event only if new cite keys were generated + if (compound.hasEdits()) { + frame.getUndoManager().addEdit(compound); + } - basePanel.markBaseChanged(); - dialogService.notify(formatOutputMessage(Localization.lang("Generated BibTeX key for"), entries.size())); + frame.getCurrentBasePanel().markBaseChanged(); + dialogService.notify(formatOutputMessage(Localization.lang("Generated BibTeX key for"), entries.size())); + }); } private String formatOutputMessage(String start, int count) { return String.format("%s %d %s.", start, count, (count > 1 ? Localization.lang("entries") : Localization.lang("entry"))); } - - @Override - public void action() { - init(); - checkOverwriteKeysChosen(); - BackgroundTask.wrap(this::generateKeys) - .executeWith(Globals.TASK_EXECUTOR); - } } diff --git a/src/main/java/org/jabref/gui/cleanup/CleanupAction.java b/src/main/java/org/jabref/gui/cleanup/CleanupAction.java index ee47ea19ce4..8f71abc2c1a 100644 --- a/src/main/java/org/jabref/gui/cleanup/CleanupAction.java +++ b/src/main/java/org/jabref/gui/cleanup/CleanupAction.java @@ -4,49 +4,66 @@ import java.util.Optional; import org.jabref.Globals; -import org.jabref.gui.BasePanel; import org.jabref.gui.DialogService; -import org.jabref.gui.actions.BaseAction; +import org.jabref.gui.JabRefFrame; +import org.jabref.gui.StateManager; +import org.jabref.gui.actions.ActionHelper; +import org.jabref.gui.actions.SimpleCommand; import org.jabref.gui.undo.NamedCompound; import org.jabref.gui.undo.UndoableFieldChange; import org.jabref.gui.util.BackgroundTask; -import org.jabref.gui.util.TaskExecutor; import org.jabref.logic.cleanup.CleanupPreset; import org.jabref.logic.cleanup.CleanupWorker; import org.jabref.logic.l10n.Localization; import org.jabref.model.FieldChange; +import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; import org.jabref.preferences.JabRefPreferences; +import org.jabref.preferences.PreferencesService; -public class CleanupAction implements BaseAction { +public class CleanupAction extends SimpleCommand { - private final BasePanel panel; + private final JabRefFrame frame; + private final PreferencesService preferences; private final DialogService dialogService; - private final TaskExecutor taskExecutor; + private final StateManager stateManager; private boolean isCanceled; private int modifiedEntriesCount; - private final JabRefPreferences preferences; - public CleanupAction(BasePanel panel, JabRefPreferences preferences, TaskExecutor taskExecutor) { - this.panel = panel; + public CleanupAction(JabRefFrame frame, JabRefPreferences preferences, DialogService dialogService, StateManager stateManager) { + this.frame = frame; this.preferences = preferences; - this.dialogService = panel.frame().getDialogService(); - this.taskExecutor = taskExecutor; + this.dialogService = dialogService; + this.stateManager = stateManager; + + this.executable.bind(ActionHelper.needsEntriesSelected(stateManager)); } @Override - public void action() { - init(); - if (isCanceled) { + public void execute() { + if (stateManager.getActiveDatabase().isEmpty()) { return; } - CleanupDialog cleanupDialog = new CleanupDialog(panel.getBibDatabaseContext(), preferences.getCleanupPreset(), preferences.getFilePreferences()); - Optional chosenPreset = cleanupDialog.showAndWait(); + if (stateManager.getSelectedEntries().isEmpty()) { // None selected. Inform the user to select entries first. + dialogService.showInformationDialogAndWait(Localization.lang("Cleanup entry"), Localization.lang("First select entries to clean up.")); + return; + } + + dialogService.notify(Localization.lang("Doing a cleanup for %0 entries...", + Integer.toString(stateManager.getSelectedEntries().size()))); - if (chosenPreset.isPresent()) { - if (chosenPreset.get().isRenamePDFActive() && preferences.getBoolean(JabRefPreferences.ASK_AUTO_NAMING_PDFS_AGAIN)) { + isCanceled = false; + modifiedEntriesCount = 0; + + Optional chosenPreset = new CleanupDialog( + stateManager.getActiveDatabase().get(), + preferences.getCleanupPreset(), + preferences.getFilePreferences()).showAndWait(); + + chosenPreset.ifPresent(preset -> { + if (preset.isRenamePDFActive() && Globals.prefs.getBoolean(JabRefPreferences.ASK_AUTO_NAMING_PDFS_AGAIN)) { boolean confirmed = dialogService.showConfirmationDialogWithOptOutAndWait(Localization.lang("Autogenerate PDF Names"), Localization.lang("Auto-generating PDF-Names does not support undo. Continue?"), Localization.lang("Autogenerate PDF Names"), @@ -60,38 +77,24 @@ public void action() { } } - preferences.setCleanupPreset(chosenPreset.get()); + preferences.setCleanupPreset(preset); - BackgroundTask.wrap(() -> cleanup(chosenPreset.get())) + BackgroundTask.wrap(() -> cleanup(stateManager.getActiveDatabase().get(), preset)) .onSuccess(result -> showResults()) - .executeWith(taskExecutor); - } - } - - public void init() { - isCanceled = false; - modifiedEntriesCount = 0; - if (panel.getSelectedEntries().isEmpty()) { // None selected. Inform the user to select entries first. - dialogService.showInformationDialogAndWait(Localization.lang("Cleanup entry"), Localization.lang("First select entries to clean up.")); - isCanceled = true; - return; - } - dialogService.notify(Localization.lang("Doing a cleanup for %0 entries...", - Integer.toString(panel.getSelectedEntries().size()))); + .executeWith(Globals.TASK_EXECUTOR); + }); } /** * Runs the cleanup on the entry and records the change. */ - private void doCleanup(CleanupPreset preset, BibEntry entry, NamedCompound ce) { + private void doCleanup(BibDatabaseContext databaseContext, CleanupPreset preset, BibEntry entry, NamedCompound ce) { // Create and run cleaner - CleanupWorker cleaner = new CleanupWorker(panel.getBibDatabaseContext(), preferences.getCleanupPreferences( - Globals.journalAbbreviationLoader)); - List changes = cleaner.cleanup(preset, entry); + CleanupWorker cleaner = new CleanupWorker( + databaseContext, + preferences.getCleanupPreferences(Globals.journalAbbreviationLoader)); - if (changes.isEmpty()) { - return; - } + List changes = cleaner.cleanup(preset, entry); // Register undo action for (FieldChange change : changes) { @@ -105,37 +108,32 @@ private void showResults() { } if (modifiedEntriesCount > 0) { - panel.updateEntryEditorIfShowing(); - panel.markBaseChanged(); + frame.getCurrentBasePanel().updateEntryEditorIfShowing(); + frame.getCurrentBasePanel().markBaseChanged(); } - String message; - switch (modifiedEntriesCount) { - case 0: - message = Localization.lang("No entry needed a clean up"); - break; - case 1: - message = Localization.lang("One entry needed a clean up"); - break; - default: - message = Localization.lang("%0 entries needed a clean up", Integer.toString(modifiedEntriesCount)); - break; + + if (modifiedEntriesCount == 0) { + dialogService.notify(Localization.lang("No entry needed a clean up")); + } else if (modifiedEntriesCount == 1) { + dialogService.notify(Localization.lang("One entry needed a clean up")); + } else { + dialogService.notify(Localization.lang("%0 entries needed a clean up", Integer.toString(modifiedEntriesCount))); } - dialogService.notify(message); } - private void cleanup(CleanupPreset cleanupPreset) { + private void cleanup(BibDatabaseContext databaseContext, CleanupPreset cleanupPreset) { preferences.setCleanupPreset(cleanupPreset); - for (BibEntry entry : panel.getSelectedEntries()) { + for (BibEntry entry : stateManager.getSelectedEntries()) { // undo granularity is on entry level NamedCompound ce = new NamedCompound(Localization.lang("Cleanup entry")); - doCleanup(cleanupPreset, entry, ce); + doCleanup(databaseContext, cleanupPreset, entry, ce); ce.end(); if (ce.hasEdits()) { modifiedEntriesCount++; - panel.getUndoManager().addEdit(ce); + frame.getUndoManager().addEdit(ce); } } } diff --git a/src/main/java/org/jabref/gui/edit/ReplaceStringAction.java b/src/main/java/org/jabref/gui/edit/ReplaceStringAction.java index ae759a01648..a903d812514 100644 --- a/src/main/java/org/jabref/gui/edit/ReplaceStringAction.java +++ b/src/main/java/org/jabref/gui/edit/ReplaceStringAction.java @@ -1,19 +1,23 @@ package org.jabref.gui.edit; -import org.jabref.gui.BasePanel; +import org.jabref.gui.JabRefFrame; +import org.jabref.gui.StateManager; +import org.jabref.gui.actions.ActionHelper; import org.jabref.gui.actions.SimpleCommand; public class ReplaceStringAction extends SimpleCommand { - private BasePanel basePanel; + private final JabRefFrame frame; - public ReplaceStringAction(BasePanel basePanel) { - this.basePanel = basePanel; + public ReplaceStringAction(JabRefFrame frame, StateManager stateManager) { + this.frame = frame; + + this.executable.bind(ActionHelper.needsDatabase(stateManager)); } @Override public void execute() { - ReplaceStringView dialog = new ReplaceStringView(basePanel); + ReplaceStringView dialog = new ReplaceStringView(frame.getCurrentBasePanel()); dialog.showAndWait(); } } diff --git a/src/main/java/org/jabref/gui/entryeditor/OpenEntryEditorAction.java b/src/main/java/org/jabref/gui/entryeditor/OpenEntryEditorAction.java new file mode 100644 index 00000000000..e6e759880e7 --- /dev/null +++ b/src/main/java/org/jabref/gui/entryeditor/OpenEntryEditorAction.java @@ -0,0 +1,25 @@ +package org.jabref.gui.entryeditor; + +import org.jabref.gui.JabRefFrame; +import org.jabref.gui.StateManager; +import org.jabref.gui.actions.ActionHelper; +import org.jabref.gui.actions.SimpleCommand; + +public class OpenEntryEditorAction extends SimpleCommand { + + private final JabRefFrame frame; + private final StateManager stateManager; + + public OpenEntryEditorAction(JabRefFrame frame, StateManager stateManager) { + this.frame = frame; + this.stateManager = stateManager; + + this.executable.bind(ActionHelper.needsEntriesSelected(stateManager)); + } + + public void execute() { + if (!stateManager.getSelectedEntries().isEmpty()) { + frame.getCurrentBasePanel().showAndEdit(stateManager.getSelectedEntries().get(0)); + } + } +} diff --git a/src/main/java/org/jabref/gui/exporter/SaveAction.java b/src/main/java/org/jabref/gui/exporter/SaveAction.java new file mode 100644 index 00000000000..4684cc17954 --- /dev/null +++ b/src/main/java/org/jabref/gui/exporter/SaveAction.java @@ -0,0 +1,52 @@ +package org.jabref.gui.exporter; + +import org.jabref.Globals; +import org.jabref.gui.JabRefFrame; +import org.jabref.gui.StateManager; +import org.jabref.gui.actions.ActionHelper; +import org.jabref.gui.actions.SimpleCommand; + +/** + * This class is just a simple wrapper for the soon to be refactored SaveDatabaseAction. + */ +public class SaveAction extends SimpleCommand { + + public enum SaveMethod { SAVE, SAVE_AS, SAVE_SELECTED } + + private final SaveMethod saveMethod; + private final JabRefFrame frame; + + public SaveAction(SaveMethod saveMethod, JabRefFrame frame, StateManager stateManager) { + this.saveMethod = saveMethod; + this.frame = frame; + + + if (saveMethod == SaveMethod.SAVE_SELECTED) { + this.executable.bind(ActionHelper.needsEntriesSelected(stateManager)); + } else { + this.executable.bind(ActionHelper.needsDatabase(stateManager)); + } + } + + @Override + public void execute() { + SaveDatabaseAction saveDatabaseAction = new SaveDatabaseAction( + frame.getCurrentBasePanel(), + Globals.prefs, + Globals.entryTypesManager); + + switch (saveMethod) { + case SAVE: + saveDatabaseAction.save(); + break; + case SAVE_AS: + saveDatabaseAction.saveAs(); + break; + case SAVE_SELECTED: + saveDatabaseAction.saveSelectedAsPlain(); + break; + default: + // Never happens + } + } +} diff --git a/src/main/java/org/jabref/gui/exporter/SaveAllAction.java b/src/main/java/org/jabref/gui/exporter/SaveAllAction.java index 4ac5618f991..c1d74faf00e 100644 --- a/src/main/java/org/jabref/gui/exporter/SaveAllAction.java +++ b/src/main/java/org/jabref/gui/exporter/SaveAllAction.java @@ -1,9 +1,9 @@ package org.jabref.gui.exporter; +import org.jabref.Globals; import org.jabref.gui.BasePanel; import org.jabref.gui.DialogService; import org.jabref.gui.JabRefFrame; -import org.jabref.gui.actions.Actions; import org.jabref.gui.actions.SimpleCommand; import org.jabref.logic.l10n.Localization; @@ -22,11 +22,12 @@ public void execute() { dialogService.notify(Localization.lang("Saving all libraries...")); for (BasePanel panel : frame.getBasePanelList()) { - if (!panel.getBibDatabaseContext().getDatabasePath().isPresent()) { + SaveDatabaseAction saveDatabaseAction = new SaveDatabaseAction(panel, Globals.prefs, Globals.entryTypesManager); + if (panel.getBibDatabaseContext().getDatabasePath().isEmpty()) { //It will ask a path before saving. - panel.runCommand(Actions.SAVE_AS); + saveDatabaseAction.saveAs(); } else { - panel.runCommand(Actions.SAVE); + saveDatabaseAction.save(); // TODO: can we find out whether the save was actually done or not? } } diff --git a/src/main/java/org/jabref/gui/externalfiles/DownloadFullTextAction.java b/src/main/java/org/jabref/gui/externalfiles/DownloadFullTextAction.java index ea8b661957c..52002cba4dd 100644 --- a/src/main/java/org/jabref/gui/externalfiles/DownloadFullTextAction.java +++ b/src/main/java/org/jabref/gui/externalfiles/DownloadFullTextAction.java @@ -3,6 +3,7 @@ import java.net.MalformedURLException; import java.net.URL; import java.nio.file.Path; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; @@ -10,8 +11,9 @@ import javafx.concurrent.Task; import org.jabref.Globals; -import org.jabref.gui.BasePanel; import org.jabref.gui.DialogService; +import org.jabref.gui.StateManager; +import org.jabref.gui.actions.ActionHelper; import org.jabref.gui.actions.SimpleCommand; import org.jabref.gui.externalfiletype.ExternalFileTypes; import org.jabref.gui.fieldeditors.LinkedFileViewModel; @@ -20,9 +22,10 @@ import org.jabref.logic.importer.FulltextFetchers; import org.jabref.logic.l10n.Localization; import org.jabref.logic.net.URLDownload; +import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.LinkedFile; -import org.jabref.preferences.JabRefPreferences; +import org.jabref.preferences.PreferencesService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,28 +39,38 @@ public class DownloadFullTextAction extends SimpleCommand { // The minimum number of selected entries to ask the user for confirmation private static final int WARNING_LIMIT = 5; - private final BasePanel basePanel; private final DialogService dialogService; + private final StateManager stateManager; + private final PreferencesService preferences; - public DownloadFullTextAction(BasePanel basePanel) { - this.basePanel = basePanel; - this.dialogService = basePanel.frame().getDialogService(); + public DownloadFullTextAction(DialogService dialogService, StateManager stateManager, PreferencesService preferences) { + this.dialogService = dialogService; + this.stateManager = stateManager; + this.preferences = preferences; + + this.executable.bind(ActionHelper.needsEntriesSelected(stateManager)); } @Override public void execute() { - if (!basePanel.getSelectedEntries().isEmpty()) { - basePanel.output(Localization.lang("Looking for full text document...")); - } else { + if (stateManager.getActiveDatabase().isEmpty()) { + return; + } + + List entries = stateManager.getSelectedEntries(); + if (entries.isEmpty()) { LOGGER.debug("No entry selected for fulltext download."); + return; } - if (basePanel.getSelectedEntries().size() >= WARNING_LIMIT) { + dialogService.notify(Localization.lang("Looking for full text document...")); + + if (entries.size() >= WARNING_LIMIT) { boolean confirmDownload = dialogService.showConfirmationDialogAndWait( Localization.lang("Download full text documents"), Localization.lang( "You are about to download full text documents for %0 entries.", - String.valueOf(basePanel.getSelectedEntries().size())) + "\n" + String.valueOf(stateManager.getSelectedEntries().size())) + "\n" + Localization.lang("JabRef will send at least one request per entry to a publisher.") + "\n" + Localization.lang("Do you still want to continue?"), @@ -65,26 +78,27 @@ public void execute() { Localization.lang("Cancel")); if (!confirmDownload) { - basePanel.output(Localization.lang("Operation canceled.")); + dialogService.notify(Localization.lang("Operation canceled.")); return; } } - Task>> findFullTextsTask = new Task>>() { + Task>> findFullTextsTask = new Task<>() { @Override protected Map> call() { Map> downloads = new ConcurrentHashMap<>(); int count = 0; - for (BibEntry entry : basePanel.getSelectedEntries()) { - FulltextFetchers fetchers = new FulltextFetchers(Globals.prefs.getImportFormatPreferences()); + for (BibEntry entry : entries) { + FulltextFetchers fetchers = new FulltextFetchers(preferences.getImportFormatPreferences()); downloads.put(entry, fetchers.findFullTextPDF(entry)); - updateProgress(++count, basePanel.getSelectedEntries().size()); + updateProgress(++count, entries.size()); } return downloads; } }; - findFullTextsTask.setOnSucceeded(value -> downloadFullTexts(findFullTextsTask.getValue())); + findFullTextsTask.setOnSucceeded(value -> + downloadFullTexts(findFullTextsTask.getValue(), stateManager.getActiveDatabase().get())); dialogService.showProgressDialogAndWait( Localization.lang("Download full text documents"), @@ -94,21 +108,22 @@ protected Map> call() { Globals.TASK_EXECUTOR.execute(findFullTextsTask); } - private void downloadFullTexts(Map> downloads) { + private void downloadFullTexts(Map> downloads, BibDatabaseContext databaseContext) { for (Map.Entry> download : downloads.entrySet()) { BibEntry entry = download.getKey(); Optional result = download.getValue(); if (result.isPresent()) { - Optional dir = basePanel.getBibDatabaseContext().getFirstExistingFileDir(Globals.prefs.getFilePreferences()); + Optional dir = databaseContext.getFirstExistingFileDir(Globals.prefs.getFilePreferences()); if (dir.isEmpty()) { dialogService.showErrorDialogAndWait(Localization.lang("Directory not found"), - Localization.lang("Main file directory not set!") + " " + Localization.lang("Preferences") + Localization.lang("Main file directory not set!") + " " + + Localization.lang("Preferences") + " -> " + Localization.lang("File")); return; } // Download and link full text - addLinkedFileFromURL(result.get(), entry, dir.get()); + addLinkedFileFromURL(databaseContext, result.get(), entry, dir.get()); } else { dialogService.notify(Localization.lang("No full text document found for entry %0.", entry.getCiteKeyOptional().orElse(Localization.lang("undefined")))); @@ -120,22 +135,23 @@ private void downloadFullTexts(Map> downloads) { * This method attaches a linked file from a URL (if not already linked) to an entry using the key and value pair * from the findFullTexts map and then downloads the file into the given targetDirectory * - * @param url the url "key" - * @param entry the entry "value" + * @param databaseContext the active database + * @param url the url "key" + * @param entry the entry "value" * @param targetDirectory the target directory for the downloaded file */ - private void addLinkedFileFromURL(URL url, BibEntry entry, Path targetDirectory) { + private void addLinkedFileFromURL(BibDatabaseContext databaseContext, URL url, BibEntry entry, Path targetDirectory) { LinkedFile newLinkedFile = new LinkedFile(url, ""); if (!entry.getFiles().contains(newLinkedFile)) { LinkedFileViewModel onlineFile = new LinkedFileViewModel( newLinkedFile, entry, - basePanel.getBibDatabaseContext(), + databaseContext, Globals.TASK_EXECUTOR, dialogService, - JabRefPreferences.getInstance().getXMPPreferences(), - JabRefPreferences.getInstance().getFilePreferences(), + preferences.getXMPPreferences(), + preferences.getFilePreferences(), ExternalFileTypes.getInstance()); try { @@ -144,7 +160,8 @@ private void addLinkedFileFromURL(URL url, BibEntry entry, Path targetDirectory) downloadTask.onSuccess(destination -> { LinkedFile downloadedFile = LinkedFilesEditorViewModel.fromFile( destination, - basePanel.getBibDatabaseContext().getFileDirectoriesAsPaths(JabRefPreferences.getInstance().getFilePreferences()), ExternalFileTypes.getInstance()); + databaseContext.getFileDirectoriesAsPaths(preferences.getFilePreferences()), + ExternalFileTypes.getInstance()); entry.addFile(downloadedFile); dialogService.notify(Localization.lang("Finished downloading full text document for entry %0.", entry.getCiteKeyOptional().orElse(Localization.lang("undefined")))); diff --git a/src/main/java/org/jabref/gui/importer/actions/AppendDatabaseAction.java b/src/main/java/org/jabref/gui/importer/actions/AppendDatabaseAction.java index e2f60a56aa5..60feebd3548 100644 --- a/src/main/java/org/jabref/gui/importer/actions/AppendDatabaseAction.java +++ b/src/main/java/org/jabref/gui/importer/actions/AppendDatabaseAction.java @@ -12,7 +12,9 @@ import org.jabref.gui.BasePanel; import org.jabref.gui.DialogService; import org.jabref.gui.JabRefFrame; -import org.jabref.gui.actions.BaseAction; +import org.jabref.gui.StateManager; +import org.jabref.gui.actions.ActionHelper; +import org.jabref.gui.actions.SimpleCommand; import org.jabref.gui.importer.AppendDatabaseDialog; import org.jabref.gui.undo.NamedCompound; import org.jabref.gui.undo.UndoableInsertEntries; @@ -41,18 +43,22 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class AppendDatabaseAction implements BaseAction { +public class AppendDatabaseAction extends SimpleCommand { private static final Logger LOGGER = LoggerFactory.getLogger(AppendDatabaseAction.class); - private final BasePanel panel; + private final JabRefFrame frame; + private final DialogService dialogService; + private final StateManager stateManager; private final List filesToOpen = new ArrayList<>(); - private final DialogService dialogService; - public AppendDatabaseAction(JabRefFrame frame, BasePanel panel) { - this.panel = panel; - dialogService = frame.getDialogService(); + public AppendDatabaseAction(JabRefFrame frame, DialogService dialogService, StateManager stateManager) { + this.frame = frame; + this.dialogService = dialogService; + this.stateManager = stateManager; + + this.executable.bind(ActionHelper.needsDatabase(stateManager)); } private static void mergeFromBibtex(BasePanel panel, ParserResult parserResult, boolean importEntries, @@ -131,9 +137,9 @@ private static void addGroups(GroupTreeNode newGroups, CompoundEdit ce) { } Globals.stateManager.getActiveDatabase() - .map(BibDatabaseContext::getMetaData) - .flatMap(MetaData::getGroups) - .ifPresent(newGroups::moveTo); + .map(BibDatabaseContext::getMetaData) + .flatMap(MetaData::getGroups) + .ifPresent(newGroups::moveTo); //UndoableAddOrRemoveGroup undo = new UndoableAddOrRemoveGroup(groupsRoot, // new GroupTreeNodeViewModel(newGroups), UndoableAddOrRemoveGroup.ADD_NODE); @@ -141,7 +147,13 @@ private static void addGroups(GroupTreeNode newGroups, CompoundEdit ce) { } @Override - public void action() { + public void execute() { + if (stateManager.getActiveDatabase().isEmpty()) { + return; + } + + BasePanel panel = frame.getCurrentBasePanel(); + filesToOpen.clear(); final AppendDatabaseDialog dialog = new AppendDatabaseDialog(); Optional response = dialog.showAndWait(); @@ -163,25 +175,25 @@ public void action() { for (Path file : filesToOpen) { // Run the actual open in a thread to prevent the program locking until the file is loaded. - BackgroundTask.wrap(() -> openIt(file, dialog.importEntries(), dialog.importStrings(), dialog.importGroups(), dialog.importSelectorWords())) + BackgroundTask.wrap(() -> openIt(panel, file, dialog.importEntries(), dialog.importStrings(), dialog.importGroups(), dialog.importSelectorWords())) .onSuccess(fileName -> dialogService.notify(Localization.lang("Imported from library") + " '" + fileName + "'")) .onFailure(exception -> { LOGGER.warn("Could not open database", exception); - dialogService.showErrorDialogAndWait(Localization.lang("Open library"), exception);}) + dialogService.showErrorDialogAndWait(Localization.lang("Open library"), exception); + }) .executeWith(Globals.TASK_EXECUTOR); } } } - private String openIt(Path file, boolean importEntries, boolean importStrings, boolean importGroups, - boolean importSelectorWords) throws IOException, KeyCollisionException { - Globals.prefs.put(JabRefPreferences.WORKING_DIRECTORY, file.getParent().toString()); - // Should this be done _after_ we know it was successfully opened? + private String openIt(BasePanel panel, Path file, boolean importEntries, boolean importStrings, boolean importGroups, + boolean importSelectorWords) throws IOException, KeyCollisionException { + Globals.prefs.put(JabRefPreferences.WORKING_DIRECTORY, file.getParent().toString()); + // Should this be done _after_ we know it was successfully opened? ParserResult parserResult = OpenDatabase.loadDatabase(file, - Globals.prefs.getImportFormatPreferences(), Globals.getFileUpdateMonitor()); - AppendDatabaseAction.mergeFromBibtex(panel, parserResult, importEntries, importStrings, importGroups, - importSelectorWords); - return file.toString(); + Globals.prefs.getImportFormatPreferences(), Globals.getFileUpdateMonitor()); + AppendDatabaseAction.mergeFromBibtex(panel, parserResult, importEntries, importStrings, importGroups, + importSelectorWords); + return file.toString(); } - } diff --git a/src/main/java/org/jabref/gui/journals/AbbreviateAction.java b/src/main/java/org/jabref/gui/journals/AbbreviateAction.java index 6fe009928cd..b28ea1e9680 100644 --- a/src/main/java/org/jabref/gui/journals/AbbreviateAction.java +++ b/src/main/java/org/jabref/gui/journals/AbbreviateAction.java @@ -9,13 +9,19 @@ import org.jabref.Globals; import org.jabref.JabRefExecutorService; -import org.jabref.gui.BasePanel; -import org.jabref.gui.actions.BaseAction; +import org.jabref.gui.DialogService; +import org.jabref.gui.JabRefFrame; +import org.jabref.gui.StateManager; +import org.jabref.gui.actions.ActionHelper; +import org.jabref.gui.actions.SimpleCommand; +import org.jabref.gui.actions.StandardActions; import org.jabref.gui.undo.NamedCompound; import org.jabref.gui.util.BackgroundTask; import org.jabref.logic.l10n.Localization; +import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.field.FieldFactory; +import org.jabref.preferences.PreferencesService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -23,38 +29,83 @@ /** * Converts journal full names to either iso or medline abbreviations for all selected entries. */ -public class AbbreviateAction implements BaseAction { +public class AbbreviateAction extends SimpleCommand { private static final Logger LOGGER = LoggerFactory.getLogger(AbbreviateAction.class); - private final BasePanel panel; - private final AbbreviationType abbreviationType; - public AbbreviateAction(BasePanel panel, AbbreviationType abbreviationType) { - this.panel = panel; - this.abbreviationType = abbreviationType; + private final StandardActions action; + private final JabRefFrame frame; + private final DialogService dialogService; + private final StateManager stateManager; + private final PreferencesService preferences; + + private AbbreviationType abbreviationType; + + public AbbreviateAction(StandardActions action, + JabRefFrame frame, + DialogService dialogService, + StateManager stateManager, + PreferencesService preferences) { + + this.action = action; + this.frame = frame; + this.dialogService = dialogService; + this.stateManager = stateManager; + this.preferences = preferences; + + switch (action) { + case ABBREVIATE_DEFAULT: + abbreviationType = AbbreviationType.DEFAULT; + break; + case ABBREVIATE_MEDLINE: + abbreviationType = AbbreviationType.MEDLINE; + break; + case ABBREVIATE_SHORTEST_UNIQUE: + abbreviationType = AbbreviationType.SHORTEST_UNIQUE; + break; + default: + LOGGER.debug("Unknown action: " + action.name()); + break; + } + + this.executable.bind(ActionHelper.needsEntriesSelected(stateManager)); } @Override - public void action() { - panel.output(Localization.lang("Abbreviating...")); - BackgroundTask.wrap(this::abbreviate) - .onSuccess(panel::output) - .executeWith(Globals.TASK_EXECUTOR); + public void execute() { + + if (action == StandardActions.ABBREVIATE_DEFAULT + || action == StandardActions.ABBREVIATE_MEDLINE + || action == StandardActions.ABBREVIATE_SHORTEST_UNIQUE) { + + dialogService.notify(Localization.lang("Abbreviating...")); + stateManager.getActiveDatabase().ifPresent(databaseContext -> + BackgroundTask.wrap(() -> abbreviate(stateManager.getActiveDatabase().get(), stateManager.getSelectedEntries())) + .onSuccess(dialogService::notify) + .executeWith(Globals.TASK_EXECUTOR)); + } else if (action == StandardActions.UNABBREVIATE) { + + dialogService.notify(Localization.lang("Unabbreviating...")); + stateManager.getActiveDatabase().ifPresent(databaseContext -> + BackgroundTask.wrap(() -> unabbreviate(stateManager.getActiveDatabase().get(), stateManager.getSelectedEntries())) + .onSuccess(dialogService::notify) + .executeWith(Globals.TASK_EXECUTOR)); + } else { + LOGGER.debug("Unknown action: " + action.name()); + } } - private String abbreviate() { - List entries = panel.getSelectedEntries(); + private String abbreviate(BibDatabaseContext databaseContext, List entries) { UndoableAbbreviator undoableAbbreviator = new UndoableAbbreviator( - Globals.journalAbbreviationLoader.getRepository(Globals.prefs.getJournalAbbreviationPreferences()), + Globals.journalAbbreviationLoader.getRepository(preferences.getJournalAbbreviationPreferences()), abbreviationType); NamedCompound ce = new NamedCompound(Localization.lang("Abbreviate journal names")); // Collect all callables to execute in one collection. - Set> tasks = entries.stream() - .>map(entry -> () -> - FieldFactory.getJournalNameFields().stream().anyMatch(journalField -> - undoableAbbreviator.abbreviate(panel.getDatabase(), entry, journalField, ce))) + Set> tasks = entries.stream().>map(entry -> () -> + FieldFactory.getJournalNameFields().stream().anyMatch(journalField -> + undoableAbbreviator.abbreviate(databaseContext.getDatabase(), entry, journalField, ce))) .collect(Collectors.toSet()); // Execute the callables and wait for the results. @@ -72,10 +123,27 @@ private String abbreviate() { if (count > 0) { ce.end(); - panel.getUndoManager().addEdit(ce); - panel.markBaseChanged(); + frame.getUndoManager().addEdit(ce); + frame.getCurrentBasePanel().markBaseChanged(); return Localization.lang("Abbreviated %0 journal names.", String.valueOf(count)); } return Localization.lang("No journal names could be abbreviated."); } + + private String unabbreviate(BibDatabaseContext databaseContext, List entries) { + UndoableUnabbreviator undoableAbbreviator = new UndoableUnabbreviator(Globals.journalAbbreviationLoader + .getRepository(Globals.prefs.getJournalAbbreviationPreferences())); + + NamedCompound ce = new NamedCompound(Localization.lang("Unabbreviate journal names")); + int count = entries.stream().mapToInt(entry -> + (int) FieldFactory.getJournalNameFields().stream().filter(journalField -> + undoableAbbreviator.unabbreviate(databaseContext.getDatabase(), entry, journalField, ce)).count()).sum(); + if (count > 0) { + ce.end(); + frame.getUndoManager().addEdit(ce); + frame.getCurrentBasePanel().markBaseChanged(); + return Localization.lang("Unabbreviated %0 journal names.", String.valueOf(count)); + } + return Localization.lang("No journal names could be unabbreviated."); + } } diff --git a/src/main/java/org/jabref/gui/journals/UnabbreviateAction.java b/src/main/java/org/jabref/gui/journals/UnabbreviateAction.java deleted file mode 100644 index a67fb8eb4bf..00000000000 --- a/src/main/java/org/jabref/gui/journals/UnabbreviateAction.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.jabref.gui.journals; - -import java.util.List; - -import org.jabref.Globals; -import org.jabref.gui.BasePanel; -import org.jabref.gui.actions.BaseAction; -import org.jabref.gui.undo.NamedCompound; -import org.jabref.gui.util.BackgroundTask; -import org.jabref.logic.l10n.Localization; -import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.field.FieldFactory; - -/** - * Converts journal abbreviations back to full name for all selected entries. - */ -public class UnabbreviateAction implements BaseAction { - - private final BasePanel panel; - - public UnabbreviateAction(BasePanel panel) { - this.panel = panel; - } - - @Override - public void action() { - panel.output(Localization.lang("Unabbreviating...")); - BackgroundTask.wrap(this::unabbreviate) - .onSuccess(panel::output) - .executeWith(Globals.TASK_EXECUTOR); - } - - private String unabbreviate() { - List entries = panel.getSelectedEntries(); // Never null - - UndoableUnabbreviator undoableAbbreviator = new UndoableUnabbreviator(Globals.journalAbbreviationLoader - .getRepository(Globals.prefs.getJournalAbbreviationPreferences())); - - NamedCompound ce = new NamedCompound(Localization.lang("Unabbreviate journal names")); - int count = entries.stream().mapToInt(entry -> - (int) FieldFactory.getJournalNameFields().stream().filter(journalField -> - undoableAbbreviator.unabbreviate(panel.getDatabase(), entry, journalField, ce)).count()).sum(); - if (count > 0) { - ce.end(); - panel.getUndoManager().addEdit(ce); - panel.markBaseChanged(); - return Localization.lang("Unabbreviated %0 journal names.", String.valueOf(count)); - } - return Localization.lang("No journal names could be unabbreviated."); - } -} diff --git a/src/main/java/org/jabref/gui/shared/PullChangesFromSharedAction.java b/src/main/java/org/jabref/gui/shared/PullChangesFromSharedAction.java new file mode 100644 index 00000000000..72bf0e9c129 --- /dev/null +++ b/src/main/java/org/jabref/gui/shared/PullChangesFromSharedAction.java @@ -0,0 +1,24 @@ +package org.jabref.gui.shared; + +import org.jabref.gui.StateManager; +import org.jabref.gui.actions.ActionHelper; +import org.jabref.gui.actions.SimpleCommand; +import org.jabref.model.database.shared.DatabaseSynchronizer; + +public class PullChangesFromSharedAction extends SimpleCommand { + + private final StateManager stateManager; + + public PullChangesFromSharedAction(StateManager stateManager) { + this.stateManager = stateManager; + + this.executable.bind(ActionHelper.needsDatabase(stateManager)); + } + + public void execute() { + stateManager.getActiveDatabase().ifPresent(databaseContext -> { + DatabaseSynchronizer dbmsSynchronizer = databaseContext.getDBMSSynchronizer(); + dbmsSynchronizer.pullChanges(); + }); + } +} diff --git a/src/main/java/org/jabref/gui/undo/UndoRedoAction.java b/src/main/java/org/jabref/gui/undo/UndoRedoAction.java new file mode 100644 index 00000000000..eb2e7e7cf50 --- /dev/null +++ b/src/main/java/org/jabref/gui/undo/UndoRedoAction.java @@ -0,0 +1,62 @@ +package org.jabref.gui.undo; + +import javax.swing.undo.CannotRedoException; +import javax.swing.undo.CannotUndoException; + +import org.jabref.gui.BasePanel; +import org.jabref.gui.DialogService; +import org.jabref.gui.JabRefFrame; +import org.jabref.gui.StateManager; +import org.jabref.gui.actions.ActionHelper; +import org.jabref.gui.actions.SimpleCommand; +import org.jabref.gui.actions.StandardActions; +import org.jabref.logic.l10n.Localization; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class UndoRedoAction extends SimpleCommand { + + private static final Logger LOGGER = LoggerFactory.getLogger(UndoRedoAction.class); + + private final StandardActions action; + private final JabRefFrame frame; + private DialogService dialogService; + + public UndoRedoAction(StandardActions action, JabRefFrame frame, DialogService dialogService, StateManager stateManager) { + this.action = action; + this.frame = frame; + this.dialogService = dialogService; + + // ToDo: Rework the UndoManager to something like the following, if it had a property. + // this.executable.bind(frame.getCurrentBasePanel().getUndoManager().canUndo()) + this.executable.bind(ActionHelper.needsDatabase(stateManager)); + } + + @Override + public void execute() { + BasePanel panel = frame.getCurrentBasePanel(); + if (action == StandardActions.UNDO) { + try { + panel.getUndoManager().undo(); + panel.markBaseChanged(); + dialogService.notify(Localization.lang("Undo")); + } catch (CannotUndoException ex) { + dialogService.notify(Localization.lang("Nothing to undo") + '.'); + } + frame.getCurrentBasePanel().markChangedOrUnChanged(); + } else if (action == StandardActions.REDO) { + try { + panel.getUndoManager().redo(); + panel.markBaseChanged(); + dialogService.notify(Localization.lang("Redo")); + } catch (CannotRedoException ex) { + dialogService.notify(Localization.lang("Nothing to redo") + '.'); + } + + panel.markChangedOrUnChanged(); + } else { + LOGGER.debug("No undo/redo action: " + action.name()); + } + } +} diff --git a/src/main/java/org/jabref/preferences/PreferencesService.java b/src/main/java/org/jabref/preferences/PreferencesService.java index b8456acc59b..39dbb37ea1d 100644 --- a/src/main/java/org/jabref/preferences/PreferencesService.java +++ b/src/main/java/org/jabref/preferences/PreferencesService.java @@ -8,6 +8,8 @@ import org.jabref.gui.entryeditor.EntryEditorPreferences; import org.jabref.gui.keyboard.KeyBindingRepository; +import org.jabref.logic.cleanup.CleanupPreferences; +import org.jabref.logic.cleanup.CleanupPreset; import org.jabref.logic.exporter.SavePreferences; import org.jabref.logic.exporter.TemplateExporter; import org.jabref.logic.importer.ImportFormatPreferences; @@ -108,4 +110,10 @@ public interface PreferencesService { EntryEditorPreferences getEntryEditorPreferences(); List loadBibEntryTypes(BibDatabaseMode mode); + + CleanupPreferences getCleanupPreferences(JournalAbbreviationLoader journalAbbreviationLoader); + + CleanupPreset getCleanupPreset(); + + void setCleanupPreset(CleanupPreset cleanupPreset); } diff --git a/src/test/java/org/jabref/gui/exporter/SaveAllActionTest.java b/src/test/java/org/jabref/gui/exporter/SaveAllActionTest.java deleted file mode 100644 index e7a9d50c235..00000000000 --- a/src/test/java/org/jabref/gui/exporter/SaveAllActionTest.java +++ /dev/null @@ -1,77 +0,0 @@ -package org.jabref.gui.exporter; - -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Arrays; -import java.util.Optional; - -import org.jabref.gui.BasePanel; -import org.jabref.gui.DialogService; -import org.jabref.gui.JabRefFrame; -import org.jabref.gui.actions.Actions; -import org.jabref.logic.l10n.Localization; -import org.jabref.model.database.BibDatabaseContext; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import static org.mockito.Mockito.anyString; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class SaveAllActionTest { - - private BasePanel firstPanel = mock(BasePanel.class); - private BasePanel secondPanel = mock(BasePanel.class); - private JabRefFrame jabRefFrame = mock(JabRefFrame.class); - private DialogService dialogService = mock(DialogService.class); - private BibDatabaseContext bibDatabaseContext = mock(BibDatabaseContext.class); - private Optional databasePath = Optional.of(Paths.get("C:\\Users\\John_Doe\\Jabref")); - private SaveAllAction saveAllAction; - - @BeforeEach - public void setUp() { - when(firstPanel.getBibDatabaseContext()).thenReturn(bibDatabaseContext); - when(secondPanel.getBibDatabaseContext()).thenReturn(bibDatabaseContext); - when(bibDatabaseContext.getDatabasePath()).thenReturn(databasePath); - - when(jabRefFrame.getBasePanelList()).thenReturn(Arrays.asList(firstPanel, secondPanel)); - when(jabRefFrame.getDialogService()).thenReturn(dialogService); - - saveAllAction = new SaveAllAction(jabRefFrame); - } - - @Test - public void executeShouldRunSaveCommandInEveryPanel() { - doNothing().when(dialogService).notify(anyString()); - - saveAllAction.execute(); - - verify(firstPanel, times(1)).runCommand(Actions.SAVE); - verify(secondPanel, times(1)).runCommand(Actions.SAVE); - } - - @Test - public void executeShouldNotifyAboutSavingProcess() { - when(bibDatabaseContext.getDatabasePath()).thenReturn(databasePath); - - saveAllAction.execute(); - - verify(dialogService, times(1)).notify(Localization.lang("Saving all libraries...")); - verify(dialogService, times(1)).notify(Localization.lang("Save all finished.")); - } - - @Test - public void executeShouldShowSaveAsWindowIfDatabaseNotSelected() { - when(bibDatabaseContext.getDatabasePath()).thenReturn(Optional.empty()); - doNothing().when(dialogService).notify(anyString()); - - saveAllAction.execute(); - - verify(firstPanel, times(1)).runCommand(Actions.SAVE_AS); - verify(secondPanel, times(1)).runCommand(Actions.SAVE_AS); - } -}