Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Copy to option #12374

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
9 changes: 9 additions & 0 deletions src/main/java/org/jabref/gui/actions/ActionFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,15 @@ public MenuItem createMenuItem(Action action, Command command) {
return menuItem;
}

public MenuItem createCustomMenuItem(Action action, Command command, String text) {
MenuItem menuItem = new MenuItem();
configureMenuItem(action, command, menuItem);
menuItem.textProperty().unbind();
menuItem.setText(text);

return menuItem;
}

public CheckMenuItem createCheckMenuItem(Action action, Command command, boolean selected) {
CheckMenuItem checkMenuItem = ActionUtils.createCheckMenuItem(new JabRefAction(action, command, keyBindingRepository));
checkMenuItem.setSelected(selected);
Expand Down
1 change: 1 addition & 0 deletions src/main/java/org/jabref/gui/actions/StandardActions.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

public enum StandardActions implements Action {

COPY_TO(Localization.lang("Copy to")),
COPY_MORE(Localization.lang("Copy") + "..."),
COPY_TITLE(Localization.lang("Copy title"), KeyBinding.COPY_TITLE),
COPY_KEY(Localization.lang("Copy citation key"), KeyBinding.COPY_CITATION_KEY),
Expand Down
72 changes: 72 additions & 0 deletions src/main/java/org/jabref/gui/edit/CopyTo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package org.jabref.gui.edit;

import java.util.List;

import org.jabref.gui.DialogService;
import org.jabref.gui.LibraryTab;
import org.jabref.gui.StateManager;
import org.jabref.gui.actions.ActionHelper;
import org.jabref.gui.actions.SimpleCommand;
import org.jabref.logic.l10n.Localization;
import org.jabref.model.database.BibDatabaseContext;
import org.jabref.model.entry.BibEntry;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class CopyTo extends SimpleCommand {

private static final Logger LOGGER = LoggerFactory.getLogger(CopyMoreAction.class);

private final DialogService dialogService;
private final StateManager stateManager;
private final CopyToPreferences copyToPreferences;
private final LibraryTab libraryTab;
private final BibDatabaseContext sourceDatabaseContext;
private final BibDatabaseContext targetDatabaseContext;

public CopyTo(DialogService dialogService,
StateManager stateManager,
CopyToPreferences copyToPreferences,
LibraryTab libraryTab,
BibDatabaseContext sourceDatabaseContext,
BibDatabaseContext targetDatabaseContext) {
this.dialogService = dialogService;
this.stateManager = stateManager;
this.copyToPreferences = copyToPreferences;
this.libraryTab = libraryTab;
this.sourceDatabaseContext = sourceDatabaseContext;
this.targetDatabaseContext = targetDatabaseContext;

this.executable.bind(ActionHelper.needsEntriesSelected(stateManager));
}

@Override
public void execute() {
boolean includeCrossReferences = askForCrossReferencedEntries();
copyToPreferences.setShouldIncludeCrossReferences(includeCrossReferences);

copyEntryToAnotherLibrary(sourceDatabaseContext, targetDatabaseContext);
}

public void copyEntryToAnotherLibrary(BibDatabaseContext sourceDatabaseContext, BibDatabaseContext targetDatabaseContext) {
List<BibEntry> selectedEntries = stateManager.getSelectedEntries();

targetDatabaseContext.getDatabase().insertEntries(selectedEntries);
}

private boolean askForCrossReferencedEntries() {
if (copyToPreferences.getShouldAskForIncludingCrossReferences()) {
return dialogService.showConfirmationDialogWithOptOutAndWait(
Localization.lang("Include or exclude cross-referenced entries"),
Localization.lang("Would you like to include cross-reference entries in the current operation?"),
Localization.lang("Include"),
Localization.lang("Exclude"),
Localization.lang("Do not ask again"),
optOut -> copyToPreferences.setShouldAskForIncludingCrossReferences(!optOut)
);
} else {
return copyToPreferences.getShouldIncludeCrossReferences();
}
}
}
32 changes: 32 additions & 0 deletions src/main/java/org/jabref/gui/edit/CopyToPreferences.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.jabref.gui.edit;

import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;

public class CopyToPreferences {
private final BooleanProperty shouldIncludeCrossReferences = new SimpleBooleanProperty();
private final BooleanProperty shouldAskForIncludingCrossReferences = new SimpleBooleanProperty();

public CopyToPreferences(boolean shouldAskForIncludingCrossReferences,
boolean shouldIncludeCrossReferences
) {
this.shouldIncludeCrossReferences.set(shouldIncludeCrossReferences);
this.shouldAskForIncludingCrossReferences.set(shouldAskForIncludingCrossReferences);
}

public boolean getShouldIncludeCrossReferences() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about shouldIncludeCrossReferences? It reads better.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it in line 17 or 14?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method name. It is a nitpick so feel free to ignore.

return shouldIncludeCrossReferences.get();
}

public void setShouldIncludeCrossReferences(boolean decision) {
this.shouldIncludeCrossReferences.set(decision);
}

public boolean getShouldAskForIncludingCrossReferences() {
return shouldAskForIncludingCrossReferences.get();
}

public void setShouldAskForIncludingCrossReferences(boolean decision) {
this.shouldAskForIncludingCrossReferences.set(decision);
}
}
54 changes: 54 additions & 0 deletions src/main/java/org/jabref/gui/maintable/RightClickMenu.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package org.jabref.gui.maintable;

import java.nio.file.Path;
import java.util.Optional;

import javax.swing.undo.UndoManager;

import javafx.collections.ObservableList;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuItem;
Expand All @@ -14,6 +18,7 @@
import org.jabref.gui.actions.ActionFactory;
import org.jabref.gui.actions.StandardActions;
import org.jabref.gui.edit.CopyMoreAction;
import org.jabref.gui.edit.CopyTo;
import org.jabref.gui.edit.EditAction;
import org.jabref.gui.exporter.ExportToClipboardAction;
import org.jabref.gui.frame.SendAsKindleEmailAction;
Expand All @@ -31,7 +36,11 @@
import org.jabref.logic.citationstyle.CitationStyleOutputFormat;
import org.jabref.logic.citationstyle.CitationStylePreviewLayout;
import org.jabref.logic.journals.JournalAbbreviationRepository;
import org.jabref.logic.l10n.Localization;
import org.jabref.logic.shared.DatabaseLocation;
import org.jabref.logic.util.TaskExecutor;
import org.jabref.logic.util.io.FileUtil;
import org.jabref.model.database.BibDatabaseContext;
import org.jabref.model.entry.BibEntryTypesManager;
import org.jabref.model.entry.field.SpecialField;

Expand Down Expand Up @@ -61,6 +70,7 @@ public static ContextMenu create(BibEntryTableViewModel entry,
contextMenu.getItems().addAll(
factory.createMenuItem(StandardActions.COPY, new EditAction(StandardActions.COPY, () -> libraryTab, stateManager, undoManager)),
createCopySubMenu(factory, dialogService, stateManager, preferences, clipBoardManager, abbreviationRepository, taskExecutor),
createCopyToMenu(factory, dialogService, stateManager, preferences, libraryTab),
factory.createMenuItem(StandardActions.PASTE, new EditAction(StandardActions.PASTE, () -> libraryTab, stateManager, undoManager)),
factory.createMenuItem(StandardActions.CUT, new EditAction(StandardActions.CUT, () -> libraryTab, stateManager, undoManager)),
factory.createMenuItem(StandardActions.MERGE_ENTRIES, new MergeEntriesAction(dialogService, stateManager, undoManager, preferences)),
Expand Down Expand Up @@ -103,6 +113,50 @@ public static ContextMenu create(BibEntryTableViewModel entry,
return contextMenu;
}

private static Menu createCopyToMenu(ActionFactory factory,
DialogService dialogService,
StateManager stateManager,
GuiPreferences preferences,
LibraryTab libraryTab
) {
Menu copyToMenu = factory.createMenu(StandardActions.COPY_TO);

ObservableList<BibDatabaseContext> openDatabases = stateManager.getOpenDatabases();

BibDatabaseContext sourceDatabaseContext = libraryTab.getBibDatabaseContext();

Optional<Path> sourcePath = libraryTab.getBibDatabaseContext().getDatabasePath();
String sourceDatabaseName = FileUtil.getUniquePathFragment(stateManager.collectAllDatabasePaths(), sourcePath.get()).get();

if (!openDatabases.isEmpty()) {
openDatabases.forEach(bibDatabaseContext -> {
Optional<Path> destinationPath = Optional.empty();
String destinationDatabaseName = " ";

if (bibDatabaseContext.getDatabasePath().isPresent()) {
destinationPath = bibDatabaseContext.getDatabasePath();
String uniquePathName = FileUtil.getUniquePathFragment(stateManager.collectAllDatabasePaths(), destinationPath.get()).get();
if (uniquePathName.equals(sourceDatabaseName)) {
return;
}
destinationDatabaseName = uniquePathName;
} else if (bibDatabaseContext.getLocation() == DatabaseLocation.SHARED) {
destinationDatabaseName = bibDatabaseContext.getDBMSSynchronizer().getDBName() + " [" + Localization.lang("shared") + "]";
}

copyToMenu.getItems().addAll(
factory.createCustomMenuItem(
StandardActions.COPY_TO,
new CopyTo(dialogService, stateManager, preferences.getCopyToPreferences(), libraryTab, sourceDatabaseContext, bibDatabaseContext),
destinationDatabaseName
)
);
});
}

return copyToMenu;
}

private static Menu createCopySubMenu(ActionFactory factory,
DialogService dialogService,
StateManager stateManager,
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/org/jabref/gui/preferences/GuiPreferences.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import org.jabref.gui.CoreGuiPreferences;
import org.jabref.gui.WorkspacePreferences;
import org.jabref.gui.autocompleter.AutoCompletePreferences;
import org.jabref.gui.edit.CopyToPreferences;
import org.jabref.gui.entryeditor.EntryEditorPreferences;
import org.jabref.gui.externalfiles.UnlinkedFilesDialogPreferences;
import org.jabref.gui.frame.ExternalApplicationsPreferences;
Expand All @@ -19,6 +20,8 @@
import org.jabref.logic.preferences.CliPreferences;

public interface GuiPreferences extends CliPreferences {
CopyToPreferences getCopyToPreferences();

EntryEditorPreferences getEntryEditorPreferences();

MergeDialogPreferences getMergeDialogPreferences();
Expand Down
19 changes: 19 additions & 0 deletions src/main/java/org/jabref/gui/preferences/JabRefGuiPreferences.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.jabref.gui.autocompleter.AutoCompletePreferences;
import org.jabref.gui.desktop.os.NativeDesktop;
import org.jabref.gui.duplicationFinder.DuplicateResolverDialog;
import org.jabref.gui.edit.CopyToPreferences;
import org.jabref.gui.entryeditor.EntryEditorPreferences;
import org.jabref.gui.externalfiles.UnlinkedFilesDialogPreferences;
import org.jabref.gui.externalfiletype.ExternalFileType;
Expand Down Expand Up @@ -213,6 +214,9 @@ public class JabRefGuiPreferences extends JabRefCliPreferences implements GuiPre
private static final String UNLINKED_FILES_SELECTED_DATE_RANGE = "unlinkedFilesSelectedDateRange";
private static final String UNLINKED_FILES_SELECTED_SORT = "unlinkedFilesSelectedSort";

private static final String INCLUDE_CROSS_REFERENCES = "includeCrossReferences";
private static final String ASK_FOR_INCLUDING_CROSS_REFERENCES = "askForIncludingCrossReferences";

private static JabRefGuiPreferences singleton;

private EntryEditorPreferences entryEditorPreferences;
Expand All @@ -232,6 +236,7 @@ public class JabRefGuiPreferences extends JabRefCliPreferences implements GuiPre
private ColumnPreferences mainTableColumnPreferences;
private ColumnPreferences searchDialogColumnPreferences;
private KeyBindingRepository keyBindingRepository;
private CopyToPreferences copyToPreferences;

private JabRefGuiPreferences() {
super();
Expand Down Expand Up @@ -394,6 +399,9 @@ private JabRefGuiPreferences() {
// By default disable "Fit table horizontally on the screen"
defaults.put(AUTO_RESIZE_MODE, Boolean.FALSE);
// endregion

defaults.put(ASK_FOR_INCLUDING_CROSS_REFERENCES, Boolean.TRUE);
defaults.put(INCLUDE_CROSS_REFERENCES, Boolean.FALSE);
}

/**
Expand All @@ -409,6 +417,17 @@ public static JabRefGuiPreferences getInstance() {
return JabRefGuiPreferences.singleton;
}

public CopyToPreferences getCopyToPreferences() {
if (copyToPreferences != null) {
return copyToPreferences;
}
copyToPreferences = new CopyToPreferences(
getBoolean(ASK_FOR_INCLUDING_CROSS_REFERENCES),
getBoolean(INCLUDE_CROSS_REFERENCES)
);
return copyToPreferences;
}

// region EntryEditorPreferences
public EntryEditorPreferences getEntryEditorPreferences() {
if (entryEditorPreferences != null) {
Expand Down
6 changes: 6 additions & 0 deletions src/main/resources/l10n/JabRef_en.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2820,3 +2820,9 @@ Citation\ Entry=Citation Entry

File\ Move\ Errors=File Move Errors
Could\ not\ move\ file\ %0.\ Please\ close\ this\ file\ and\ retry.=Could not move file %0. Please close this file and retry.

Copy\ to=Copy to
Include=Include
Exclude=Exclude
Include\ or\ exclude\ cross-referenced\ entries=Include or exclude cross-referenced entries
Would\ you\ like\ to\ include\ cross-reference\ entries\ in\ the\ current\ operation?=Would you like to include cross-reference entries in the current operation?
Loading