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

Make entry editor DND behave as specified in settings #5563

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 45 additions & 26 deletions src/main/java/org/jabref/gui/entryeditor/EntryEditor.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import javafx.scene.control.MenuItem;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.input.DataFormat;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.BorderPane;
Expand Down Expand Up @@ -79,6 +78,9 @@ public class EntryEditor extends BorderPane {
private Subscription typeSubscription;
private BibEntry entry; // A reference to the entry this editor works on.
private SourceTab sourceTab;
private List<Path> draggedFiles;
private boolean inDragDropMode = false;
private TransferMode transferMode;
@FXML private TabPane tabbed;
@FXML private Button typeChangeButton;
@FXML private Button fetcherButton;
Expand Down Expand Up @@ -121,41 +123,57 @@ public EntryEditor(BasePanel panel, ExternalFileTypes externalFileTypes) {

this.tabs = createTabs();

this.setOnDragOver(event -> {
if (event.getDragboard().hasFiles()) {
event.acceptTransferModes(TransferMode.COPY, TransferMode.MOVE, TransferMode.LINK);
}
event.consume();
});
this.setOnMouseEntered(event -> {
// When registering using this.setOnDragDetected, the code is never called. Thus, using the workaround on "mouseEntered"
// onMouseEntered is called AFTER onDragDropped. We need it BEFORE. So we do this workaround with inDragDropMode
if (this.inDragDropMode) {
boolean dragDropModifierPressed = event.isAltDown() || event.isShiftDown() || event.isControlDown();

this.setOnDragDropped(event -> {
BibEntry entry = this.getEntry();
boolean success = false;
BibEntry entry = this.getEntry();

if (event.getDragboard().hasContent(DataFormat.FILES)) {
List<Path> files = event.getDragboard().getFiles().stream().map(File::toPath).collect(Collectors.toList());
FileDragDropPreferenceType dragDropPreferencesType = preferencesService.getEntryEditorFileLinkPreference();

if (dragDropPreferencesType == FileDragDropPreferenceType.MOVE) {
LOGGER.debug("Mode MOVE");
fileLinker.moveFilesToFileDirAndAddToEntry(entry, files);
success = true;
// determine transfer mode -- JabRef's preferences are the default; modifier keys override the default
TransferMode determinedTransferMode;
if (dragDropModifierPressed) {
LOGGER.debug("Modifier pressed");
determinedTransferMode = transferMode;
} else {
LOGGER.debug("No modifier pressed");
determinedTransferMode = dragDropPreferencesType.getTransferMode();
}

if (dragDropPreferencesType == FileDragDropPreferenceType.COPY) {
LOGGER.debug("Mode COPY");
fileLinker.copyFilesToFileDirAndAddToEntry(entry, files);
success = true;
// obey the determined transfer mode and take action accordingly
switch (determinedTransferMode) {
case LINK:
LOGGER.debug("Mode LINK");
fileLinker.addFilesToEntry(entry, this.draggedFiles);
break;
case COPY:
LOGGER.debug("Mode COPY");
fileLinker.copyFilesToFileDirAndAddToEntry(entry, this.draggedFiles);
break;
default:
LOGGER.debug("Mode MOVE");
fileLinker.moveFilesToFileDirAndAddToEntry(entry, this.draggedFiles);
break;
}
inDragDropMode = false;
}
});

if (dragDropPreferencesType == FileDragDropPreferenceType.LINK) {
LOGGER.debug("Mode LINK");
fileLinker.addFilesToEntry(entry, files);
success = true;
}
this.setOnDragOver(event -> {
if (event.getDragboard().hasFiles()) {
event.acceptTransferModes(TransferMode.COPY, TransferMode.MOVE, TransferMode.LINK);
this.draggedFiles = event.getDragboard().getFiles().stream().map(File::toPath).collect(Collectors.toList());
this.inDragDropMode = true;
this.transferMode = event.getTransferMode();
}
event.consume();
});

event.setDropCompleted(success);
this.setOnDragDropped(event -> {
event.setDropCompleted(true);
event.consume();
});
}
Expand Down Expand Up @@ -245,6 +263,7 @@ private List<EntryEditorTab> createTabs() {
entryEditorTabs.add(new OtherFieldsTab(databaseContext, panel.getSuggestionProviders(), undoManager, entryEditorPreferences.getCustomTabFieldNames(), dialogService, Globals.prefs, Globals.entryTypesManager, ExternalFileTypes.getInstance(), Globals.TASK_EXECUTOR, Globals.journalAbbreviationLoader));

// General fields from preferences
// Examples: "General", "Abstract", and "Comments"
for (Map.Entry<String, Set<Field>> tab : entryEditorPreferences.getEntryEditorTabList().entrySet()) {
entryEditorTabs.add(new UserDefinedFieldsTab(tab.getKey(), tab.getValue(), databaseContext, panel.getSuggestionProviders(), undoManager, dialogService, Globals.prefs, Globals.entryTypesManager, ExternalFileTypes.getInstance(), Globals.TASK_EXECUTOR, Globals.journalAbbreviationLoader));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -52,7 +53,7 @@ abstract class FieldsEditorTab extends EntryEditorTab {
private final JournalAbbreviationLoader journalAbbreviationLoader;
private PreviewPanel previewPanel;
private UndoManager undoManager;
private Collection<Field> fields = new ArrayList<>();
private Collection<Field> fields = Collections.emptyList();
private GridPane gridPane;

public FieldsEditorTab(boolean compressed, BibDatabaseContext databaseContext, SuggestionProviders suggestionProviders, UndoManager undoManager, DialogService dialogService, JabRefPreferences preferences, ExternalFileTypes externalFileTypes, TaskExecutor taskExecutor, JournalAbbreviationLoader journalAbbreviationLoader) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
package org.jabref.gui.entryeditor;

import javafx.scene.input.TransferMode;

public enum FileDragDropPreferenceType {
COPY(TransferMode.COPY),
LINK(TransferMode.LINK),
MOVE(TransferMode.MOVE);

private final TransferMode transferMode;

/**
* Copy file to default file folder
*/
COPY,
/**
* Link file (without copying)
*/
LINK,
/**
* Copy, rename and link file
* Initializes the enum with the mapping to JavaFX's TransferMode. We use this straight-forward implementation as
* this class resides in `org.jabref.gui` and thus has access to JavaFX classes. The alternative is to use an
* <a hreF="https://docs.oracle.com/javase/8/docs/api/java/util/EnumMap.html">EnumMap</a>.
*
* @param transferMode the JavaFX TransferMode which the enum corresponds to.
*/
MOVE;
FileDragDropPreferenceType(TransferMode transferMode) {
this.transferMode = transferMode;
}

public TransferMode getTransferMode() {
return transferMode;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@

import com.airhacks.afterburner.views.ViewLoader;

/**
* Without customization of JabRef, this contains the "File" field in the "General" tab.
*/
public class LinkedFilesEditor extends HBox implements FieldEditorFX {

@FXML private final LinkedFilesEditorViewModel viewModel;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,5 +63,5 @@
<Label styleClass="sectionHeader" text="%Default drag &amp; drop action"/>
<RadioButton fx:id="dndCopyFile" text="%Copy file to default file folder" toggleGroup="$dnd"/>
<RadioButton fx:id="dndLinkFile" text="%Link file (without copying)" toggleGroup="$dnd"/>
<RadioButton fx:id="dndCopyRenameLinkFile" text="%Copy, rename and link file" toggleGroup="$dnd"/>
<RadioButton fx:id="dndMoveFile" text="%Move file" toggleGroup="$dnd"/>
</fx:root>
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public class EntryEditorTabView extends AbstractPreferenceTabView<EntryEditorTab
@FXML private RadioButton firstNameModeBoth;
@FXML private RadioButton dndCopyFile;
@FXML private RadioButton dndLinkFile;
@FXML private RadioButton dndCopyRenameLinkFile;
@FXML private RadioButton dndMoveFile;

public EntryEditorTabView(JabRefPreferences preferences) {
this.preferences = preferences;
Expand Down Expand Up @@ -60,6 +60,6 @@ public void initialize () {
firstNameModeBoth.selectedProperty().bindBidirectional(viewModel.firstNameModeBothProperty());
dndCopyFile.selectedProperty().bindBidirectional(viewModel.dndCopyFileProperty());
dndLinkFile.selectedProperty().bindBidirectional(viewModel.dndLinkFileProperty());
dndCopyRenameLinkFile.selectedProperty().bindBidirectional(viewModel.dndCopyRenameLinkFileProperty());
dndMoveFile.selectedProperty().bindBidirectional(viewModel.dndMoveFileProperty());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public class EntryEditorTabViewModel implements PreferenceTabViewModel {
private final BooleanProperty firstNameModeBothProperty = new SimpleBooleanProperty();
private final BooleanProperty dndCopyFileProperty = new SimpleBooleanProperty();
private final BooleanProperty dndLinkFileProperty = new SimpleBooleanProperty();
private final BooleanProperty dndCopyRenameLinkFileProperty = new SimpleBooleanProperty();
private final BooleanProperty dndMoveFileProperty = new SimpleBooleanProperty();

private AutoCompletePreferences autoCompletePreferences;

Expand Down Expand Up @@ -80,12 +80,15 @@ public void setValues() {
}

FileDragDropPreferenceType dragDropPreferenceType = preferences.getEntryEditorFileLinkPreference();
if (dragDropPreferenceType == FileDragDropPreferenceType.COPY) {
dndCopyFileProperty.setValue(true);
} else if (dragDropPreferenceType == FileDragDropPreferenceType.LINK) {
dndLinkFileProperty.setValue(true);
} else {
dndCopyRenameLinkFileProperty.setValue(true);
switch (dragDropPreferenceType) {
case COPY:
dndCopyFileProperty.setValue(true);
break;
case LINK:
dndLinkFileProperty.setValue(true);
break;
default:
dndMoveFileProperty.setValue(true);
}
}

Expand All @@ -103,12 +106,10 @@ public void storeSettings() {
if (autoCompleteBothProperty.getValue()) {
autoCompletePreferences.setOnlyCompleteFirstLast(false);
autoCompletePreferences.setOnlyCompleteLastFirst(false);
}
else if (autoCompleteFirstLastProperty.getValue()) {
} else if (autoCompleteFirstLastProperty.getValue()) {
autoCompletePreferences.setOnlyCompleteFirstLast(true);
autoCompletePreferences.setOnlyCompleteLastFirst(false);
}
else {
} else {
autoCompletePreferences.setOnlyCompleteFirstLast(false);
autoCompletePreferences.setOnlyCompleteLastFirst(true);
}
Expand Down Expand Up @@ -142,37 +143,71 @@ public List<String> getRestartWarnings() {
return new ArrayList<>();
}

public BooleanProperty openOnNewEntryProperty() { return openOnNewEntryProperty; }
public BooleanProperty openOnNewEntryProperty() {
return openOnNewEntryProperty;
}

public BooleanProperty defaultSourceProperty() { return defaultSourceProperty; }
public BooleanProperty defaultSourceProperty() {
return defaultSourceProperty;
}

public BooleanProperty enableRelatedArticlesTabProperty() { return enableRelatedArticlesTabProperty; }
public BooleanProperty enableRelatedArticlesTabProperty() {
return enableRelatedArticlesTabProperty;
}

public BooleanProperty acceptRecommendationsProperty() { return acceptRecommendationsProperty; }
public BooleanProperty acceptRecommendationsProperty() {
return acceptRecommendationsProperty;
}

public BooleanProperty enableLatexCitationsTabProperty() { return enableLatexCitationsTabProperty; }
public BooleanProperty enableLatexCitationsTabProperty() {
return enableLatexCitationsTabProperty;
}

public BooleanProperty enableValidationProperty() { return enableValidationProperty; }
public BooleanProperty enableValidationProperty() {
return enableValidationProperty;
}

public BooleanProperty enableAutoCompleteProperty() { return enableAutoCompleteProperty; }
public BooleanProperty enableAutoCompleteProperty() {
return enableAutoCompleteProperty;
}

public StringProperty autoCompleteFieldsProperty() { return autoCompleteFieldsProperty; }
public StringProperty autoCompleteFieldsProperty() {
return autoCompleteFieldsProperty;
}

public BooleanProperty autoCompleteFirstLastProperty() { return autoCompleteFirstLastProperty; }
public BooleanProperty autoCompleteFirstLastProperty() {
return autoCompleteFirstLastProperty;
}

public BooleanProperty autoCompleteLastFirstProperty() { return autoCompleteLastFirstProperty; }
public BooleanProperty autoCompleteLastFirstProperty() {
return autoCompleteLastFirstProperty;
}

public BooleanProperty autoCompleteBothProperty() { return autoCompleteBothProperty; }
public BooleanProperty autoCompleteBothProperty() {
return autoCompleteBothProperty;
}

public BooleanProperty firstNameModeAbbreviatedProperty() { return firstNameModeAbbreviatedProperty; }
public BooleanProperty firstNameModeAbbreviatedProperty() {
return firstNameModeAbbreviatedProperty;
}

public BooleanProperty firstNameModeFullProperty() { return firstNameModeFullProperty; }
public BooleanProperty firstNameModeFullProperty() {
return firstNameModeFullProperty;
}

public BooleanProperty firstNameModeBothProperty() { return firstNameModeBothProperty; }
public BooleanProperty firstNameModeBothProperty() {
return firstNameModeBothProperty;
}

public BooleanProperty dndCopyFileProperty() { return dndCopyFileProperty; }
public BooleanProperty dndCopyFileProperty() {
return dndCopyFileProperty;
}

public BooleanProperty dndLinkFileProperty() { return dndLinkFileProperty; }
public BooleanProperty dndLinkFileProperty() {
return dndLinkFileProperty;
}

public BooleanProperty dndCopyRenameLinkFileProperty() { return dndCopyRenameLinkFileProperty; }
public BooleanProperty dndMoveFileProperty() {
return dndMoveFileProperty;
}
}
4 changes: 2 additions & 2 deletions src/main/java/org/jabref/logic/util/io/FileUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -151,11 +151,11 @@ public static List<String> uniquePathSubstrings(List<String> paths) {
public static boolean copyFile(Path pathToSourceFile, Path pathToDestinationFile, boolean replaceExisting) {
// Check if the file already exists.
if (!Files.exists(pathToSourceFile)) {
LOGGER.error("Path to the source file doesn't exist.");
LOGGER.error("Path {} to the source file doesn't exist.", pathToSourceFile);
return false;
}
if (Files.exists(pathToDestinationFile) && !replaceExisting) {
LOGGER.error("Path to the destination file exists but the file shouldn't be replaced.");
LOGGER.error("Path {} to the destination file exists but the file shouldn't be replaced.", pathToDestinationFile);
return false;
}
try {
Expand Down
1 change: 0 additions & 1 deletion src/main/resources/l10n/JabRef_en.properties
Original file line number Diff line number Diff line change
Expand Up @@ -1963,7 +1963,6 @@ Move\ preprint\ information\ from\ 'URL'\ and\ 'journal'\ field\ to\ the\ 'eprin
Default\ drag\ &\ drop\ action=Default drag & drop action
Copy\ file\ to\ default\ file\ folder=Copy file to default file folder
Link\ file\ (without\ copying)=Link file (without copying)
Copy,\ rename\ and\ link\ file=Copy, rename and link file
Type=Type
Customize\ Export\ Formats=Customize Export Formats
Export\ name=Export name
Expand Down