diff --git a/src/main/java/org/jabref/gui/BasePanel.java b/src/main/java/org/jabref/gui/BasePanel.java index 9c0f31b1358..ff5baf2606d 100644 --- a/src/main/java/org/jabref/gui/BasePanel.java +++ b/src/main/java/org/jabref/gui/BasePanel.java @@ -233,21 +233,6 @@ private void setupActions() { actions.put(Actions.SAVE_SELECTED_AS_PLAIN, saveAction::saveSelectedAsPlain); - // The action for copying selected entries. - actions.put(Actions.COPY, this::copy); - - actions.put(Actions.CUT, this::cut); - - actions.put(Actions.DELETE, () -> delete(false)); - - // The action for pasting entries or cell contents. - // - more robust detection of available content flavors (doesn't only look at first one offered) - // - support for parsing string-flavor clipboard contents which are bibtex entries. - // This allows you to (a) paste entire bibtex entries from a text editor, web browser, etc - // (b) copy and paste entries between multiple instances of JabRef (since - // only the text representation seems to get as far as the X clipboard, at least on my system) - actions.put(Actions.PASTE, this::paste); - actions.put(Actions.SELECT_ALL, mainTable.getSelectionModel()::selectAll); // The action for auto-generating keys. diff --git a/src/main/java/org/jabref/gui/EditAction.java b/src/main/java/org/jabref/gui/EditAction.java new file mode 100644 index 00000000000..52e9a878f2a --- /dev/null +++ b/src/main/java/org/jabref/gui/EditAction.java @@ -0,0 +1,71 @@ +package org.jabref.gui; + +import javafx.scene.control.TextInputControl; + +import org.jabref.gui.actions.SimpleCommand; +import org.jabref.gui.actions.StandardActions; + +/** + * Class for handling general actions; cut, copy and paste. The focused component is kept track of by + * Globals.focusListener, and we call the action stored under the relevant name in its action map. + */ +public class EditAction extends SimpleCommand { + + private final JabRefFrame frame; + private final StandardActions action; + private final StateManager stateManager; + + public EditAction(StandardActions action, JabRefFrame frame, StateManager stateManager) { + this.action = action; + this.frame = frame; + this.stateManager = stateManager; + } + + @Override + public String toString() { + return this.action.toString(); + } + + @Override + public void execute() { + stateManager.getFocusOwner().ifPresent(focusOwner -> { + if (focusOwner instanceof TextInputControl) { + // Focus is on text field -> copy/paste/cut selected text + TextInputControl textInput = (TextInputControl) focusOwner; + switch (action) { + case COPY: + textInput.copy(); + break; + case CUT: + textInput.cut(); + break; + case PASTE: + // handled by FX in TextInputControl#paste + break; + default: + throw new IllegalStateException("Only cut/copy/paste supported in TextInputControl but got " + action); + } + } else { + // Not sure what is selected -> copy/paste/cut selected entries + + // ToDo: Should be handled by BibDatabaseContext instead of BasePanel + switch (action) { + case COPY: + frame.getCurrentBasePanel().copy(); + break; + case CUT: + frame.getCurrentBasePanel().cut(); + break; + case PASTE: + // handled by FX in TextInputControl#paste + break; + case DELETE_ENTRY: + frame.getCurrentBasePanel().delete(false); + break; + default: + throw new IllegalStateException("Only cut/copy/paste supported but got " + action); + } + } + }); + } +} diff --git a/src/main/java/org/jabref/gui/JabRefFrame.java b/src/main/java/org/jabref/gui/JabRefFrame.java index cea1f679a97..e58864a852b 100644 --- a/src/main/java/org/jabref/gui/JabRefFrame.java +++ b/src/main/java/org/jabref/gui/JabRefFrame.java @@ -30,7 +30,6 @@ import javafx.scene.control.SplitPane; import javafx.scene.control.Tab; import javafx.scene.control.TabPane; -import javafx.scene.control.TextInputControl; import javafx.scene.control.ToolBar; import javafx.scene.control.Tooltip; import javafx.scene.control.skin.TabPaneSkin; @@ -487,13 +486,13 @@ private Node createToolbar() { factory.createIconButton(StandardActions.NEW_ARTICLE, new NewEntryAction(this, StandardEntryType.Article, dialogService, Globals.prefs, stateManager)), factory.createIconButton(StandardActions.NEW_ENTRY, new NewEntryAction(this, dialogService, Globals.prefs, stateManager)), factory.createIconButton(StandardActions.NEW_ENTRY_FROM_PLAIN_TEXT, new ExtractBibtexAction(stateManager)), - factory.createIconButton(StandardActions.DELETE_ENTRY, new OldDatabaseCommandWrapper(Actions.DELETE, this, 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.CUT, new OldDatabaseCommandWrapper(Actions.CUT, this, stateManager)), - factory.createIconButton(StandardActions.COPY, new OldDatabaseCommandWrapper(Actions.COPY, this, stateManager)), - factory.createIconButton(StandardActions.PASTE, new OldDatabaseCommandWrapper(Actions.PASTE, this, 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)), @@ -577,6 +576,9 @@ public void init() { } }); + // Wait for the scene to be created, otherwise focusOwnerProperty is not provided + Platform.runLater(() -> stateManager.focusOwnerProperty().bind( + EasyBind.map(mainStage.getScene().focusOwnerProperty(), Optional::ofNullable))); /* * The following state listener makes sure focus is registered with the * correct database when the user switches tabs. Without this, @@ -701,9 +703,9 @@ private MenuBar createMenu() { new SeparatorMenuItem(), - factory.createMenuItem(StandardActions.CUT, new EditAction(Actions.CUT)), + factory.createMenuItem(StandardActions.CUT, new EditAction(StandardActions.CUT, this, stateManager)), - factory.createMenuItem(StandardActions.COPY, new EditAction(Actions.COPY)), + factory.createMenuItem(StandardActions.COPY, new EditAction(StandardActions.COPY, this, stateManager)), factory.createSubMenu(StandardActions.COPY_MORE, factory.createMenuItem(StandardActions.COPY_TITLE, new CopyMoreAction(StandardActions.COPY_TITLE, dialogService, stateManager, Globals.clipboardManager, prefs)), factory.createMenuItem(StandardActions.COPY_KEY, new CopyMoreAction(StandardActions.COPY_KEY, dialogService, stateManager, Globals.clipboardManager, prefs)), @@ -713,7 +715,7 @@ private MenuBar createMenu() { factory.createMenuItem(StandardActions.COPY_CITATION_PREVIEW, new CopyCitationAction(CitationStyleOutputFormat.HTML, dialogService, stateManager, Globals.clipboardManager, prefs.getPreviewPreferences())), factory.createMenuItem(StandardActions.EXPORT_SELECTED_TO_CLIPBOARD, new ExportToClipboardAction(this, dialogService))), - factory.createMenuItem(StandardActions.PASTE, new EditAction(Actions.PASTE)), + factory.createMenuItem(StandardActions.PASTE, new EditAction(StandardActions.PASTE, this, stateManager)), new SeparatorMenuItem(), @@ -743,7 +745,7 @@ private MenuBar createMenu() { library.getItems().addAll( factory.createMenuItem(StandardActions.NEW_ENTRY, new NewEntryAction(this, dialogService, Globals.prefs, stateManager)), factory.createMenuItem(StandardActions.NEW_ENTRY_FROM_PLAIN_TEXT, new ExtractBibtexAction(stateManager)), - factory.createMenuItem(StandardActions.DELETE_ENTRY, new OldDatabaseCommandWrapper(Actions.DELETE, this, stateManager)), + factory.createMenuItem(StandardActions.DELETE_ENTRY, new EditAction(StandardActions.DELETE_ENTRY, this, stateManager)), new SeparatorMenuItem(), @@ -1244,63 +1246,6 @@ public void execute() { } } - /** - * Class for handling general actions; cut, copy and paste. The focused component is kept track of by - * Globals.focusListener, and we call the action stored under the relevant name in its action map. - */ - private class EditAction extends SimpleCommand { - - private final Actions command; - - public EditAction(Actions command) { - this.command = command; - } - - @Override - public String toString() { - return this.command.toString(); - } - - @Override - public void execute() { - Node focusOwner = mainStage.getScene().getFocusOwner(); - if (focusOwner != null) { - if (focusOwner instanceof TextInputControl) { - // Focus is on text field -> copy/paste/cut selected text - TextInputControl textInput = (TextInputControl) focusOwner; - switch (command) { - case COPY: - textInput.copy(); - break; - case CUT: - textInput.cut(); - break; - case PASTE: - // handled by FX in TextInputControl#paste - break; - default: - throw new IllegalStateException("Only cut/copy/paste supported but got " + command); - } - } else { - // Not sure what is selected -> copy/paste/cut selected entries - switch (command) { - case COPY: - getCurrentBasePanel().copy(); - break; - case CUT: - getCurrentBasePanel().cut(); - break; - case PASTE: - // handled by FX in TextInputControl#paste - break; - default: - throw new IllegalStateException("Only cut/copy/paste supported but got " + command); - } - } - } - } - } - private class CloseDatabaseAction extends SimpleCommand { @Override diff --git a/src/main/java/org/jabref/gui/StateManager.java b/src/main/java/org/jabref/gui/StateManager.java index c09f97244f0..19a45f94c71 100644 --- a/src/main/java/org/jabref/gui/StateManager.java +++ b/src/main/java/org/jabref/gui/StateManager.java @@ -13,6 +13,7 @@ import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.collections.ObservableMap; +import javafx.scene.Node; import org.jabref.gui.util.OptionalObjectProperty; import org.jabref.logic.search.SearchQuery; @@ -27,6 +28,7 @@ * - currently selected group * - active search * - active number of search results + * - focus owner */ public class StateManager { @@ -36,6 +38,7 @@ public class StateManager { private final ObservableMap> selectedGroups = FXCollections.observableHashMap(); private final OptionalObjectProperty activeSearchQuery = OptionalObjectProperty.empty(); private final ObservableMap searchResultMap = FXCollections.observableHashMap(); + private final OptionalObjectProperty focusOwner = OptionalObjectProperty.empty(); public StateManager() { activeGroups.bind(Bindings.valueAt(selectedGroups, activeDatabase.orElse(null))); @@ -99,4 +102,8 @@ public void clearSearchQuery() { public void setSearchQuery(SearchQuery searchQuery) { activeSearchQuery.setValue(Optional.of(searchQuery)); } + + public OptionalObjectProperty focusOwnerProperty() { return focusOwner; } + + public Optional getFocusOwner() { return focusOwner.get(); } } diff --git a/src/main/java/org/jabref/gui/actions/Actions.java b/src/main/java/org/jabref/gui/actions/Actions.java index 905b487cb02..f606eec20a1 100644 --- a/src/main/java/org/jabref/gui/actions/Actions.java +++ b/src/main/java/org/jabref/gui/actions/Actions.java @@ -10,9 +10,6 @@ public enum Actions { ABBREVIATE_SHORTEST_UNIQUE, ADD_FILE_LINK, CLEANUP, - COPY, - CUT, - DELETE, DOWNLOAD_FULL_TEXT, EDIT, EDIT_PREAMBLE, @@ -21,7 +18,6 @@ public enum Actions { MAKE_KEY, MANAGE_SELECTORS, MERGE_DATABASE, - PASTE, PULL_CHANGES_FROM_SHARED_DATABASE, REDO, REPLACE_ALL, diff --git a/src/main/java/org/jabref/gui/actions/JabRefAction.java b/src/main/java/org/jabref/gui/actions/JabRefAction.java index f04deb1157c..dfdc35330b2 100644 --- a/src/main/java/org/jabref/gui/actions/JabRefAction.java +++ b/src/main/java/org/jabref/gui/actions/JabRefAction.java @@ -58,7 +58,10 @@ private String getActionName(Action action, Command command) { return action.getText(); } else { String commandName = command.getClass().getSimpleName(); - if ((command instanceof OldDatabaseCommandWrapper) || (command instanceof OldCommandWrapper) || commandName.contains("EditAction")) { + if ((command instanceof OldDatabaseCommandWrapper) + || commandName.contains("EditAction") + || commandName.contains("CopyMoreAction") + || commandName.contains("CopyCitationAction")) { return command.toString(); } else { return commandName; diff --git a/src/main/java/org/jabref/gui/actions/OldCommandWrapper.java b/src/main/java/org/jabref/gui/actions/OldCommandWrapper.java deleted file mode 100644 index 028e0b153bb..00000000000 --- a/src/main/java/org/jabref/gui/actions/OldCommandWrapper.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.jabref.gui.actions; - -import javafx.beans.property.ReadOnlyDoubleProperty; - -import org.jabref.gui.BasePanel; -import org.jabref.gui.util.BindingsHelper; - -import de.saxsys.mvvmfx.utils.commands.CommandBase; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This wraps the old Swing commands so that they fit into the new infrastructure. - * In the long term, this class should be removed. - */ -@Deprecated -public class OldCommandWrapper extends CommandBase { - - private static final Logger LOGGER = LoggerFactory.getLogger(OldCommandWrapper.class); - - private final Actions command; - private final BasePanel panel; - - public OldCommandWrapper(Actions command, BasePanel panel) { - this.command = command; - this.panel = panel; - } - - @Override - public void execute() { - try { - panel.runCommand(command); - } catch (Throwable ex) { - LOGGER.debug("Cannot execute command " + command + ".", ex); - } - } - - @Override - public double getProgress() { - return 0; - } - - @Override - public ReadOnlyDoubleProperty progressProperty() { - return null; - } - - public void setExecutable(boolean executable) { - this.executable.bind(BindingsHelper.constantOf(executable)); - } - - @Override - public String toString() { - return this.command.toString(); - } -} diff --git a/src/main/java/org/jabref/gui/maintable/RightClickMenu.java b/src/main/java/org/jabref/gui/maintable/RightClickMenu.java index feb59dcfb93..441c1698ed4 100644 --- a/src/main/java/org/jabref/gui/maintable/RightClickMenu.java +++ b/src/main/java/org/jabref/gui/maintable/RightClickMenu.java @@ -7,11 +7,10 @@ import org.jabref.Globals; import org.jabref.gui.BasePanel; import org.jabref.gui.DialogService; +import org.jabref.gui.EditAction; import org.jabref.gui.SendAsEMailAction; import org.jabref.gui.StateManager; import org.jabref.gui.actions.ActionFactory; -import org.jabref.gui.actions.Actions; -import org.jabref.gui.actions.OldCommandWrapper; import org.jabref.gui.actions.StandardActions; import org.jabref.gui.edit.CopyMoreAction; import org.jabref.gui.exporter.ExportToClipboardAction; @@ -36,11 +35,11 @@ public static ContextMenu create(BibEntryTableViewModel entry, KeyBindingReposit ContextMenu contextMenu = new ContextMenu(); ActionFactory factory = new ActionFactory(keyBindingRepository); - contextMenu.getItems().add(factory.createMenuItem(StandardActions.COPY, new OldCommandWrapper(Actions.COPY, panel))); + contextMenu.getItems().add(factory.createMenuItem(StandardActions.COPY, new EditAction(StandardActions.COPY, panel.frame(), stateManager))); contextMenu.getItems().add(createCopySubMenu(panel, factory, dialogService, stateManager, preferencesService)); - contextMenu.getItems().add(factory.createMenuItem(StandardActions.PASTE, new OldCommandWrapper(Actions.PASTE, panel))); - contextMenu.getItems().add(factory.createMenuItem(StandardActions.CUT, new OldCommandWrapper(Actions.CUT, panel))); - contextMenu.getItems().add(factory.createMenuItem(StandardActions.DELETE, new OldCommandWrapper(Actions.DELETE, panel))); + contextMenu.getItems().add(factory.createMenuItem(StandardActions.PASTE, new EditAction(StandardActions.PASTE, panel.frame(), stateManager))); + contextMenu.getItems().add(factory.createMenuItem(StandardActions.CUT, new EditAction(StandardActions.CUT, panel.frame(), stateManager))); + contextMenu.getItems().add(factory.createMenuItem(StandardActions.DELETE_ENTRY, new EditAction(StandardActions.DELETE_ENTRY, panel.frame(), stateManager))); contextMenu.getItems().add(new SeparatorMenuItem());