From 6d6423c8ae9f578cc85956cb51046014c5e39d5d Mon Sep 17 00:00:00 2001 From: GNAQ <41422940+GNAQ@users.noreply.github.com> Date: Tue, 19 Jul 2022 02:48:11 +0800 Subject: [PATCH 1/4] Fixes koppor/jabref#521 - Allow to drag&drop selected bib entries to other library tabs (#8982) Co-authored-by: Cain --- CHANGELOG.md | 1 + src/main/java/org/jabref/gui/JabRefFrame.java | 48 +++++++++++++++++++ src/main/java/org/jabref/gui/LibraryTab.java | 9 ++++ .../org/jabref/gui/maintable/MainTable.java | 9 +++- 4 files changed, 66 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 59545f15c4e..30f70513fe9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve - We added an extra option in the 'Find Unlinked Files' dialog view to ignore unnecessary files like Thumbs.db, DS_Store, etc. [koppor#373](https://github.com/koppor/jabref/issues/373) - JabRef now writes log files. Linux: `$home/.cache/jabref/logs/version`, Windows: `%APPDATA%\..\Local\harawata\jabref\version\logs`, Mac: `Users/.../Library/Logs/jabref/version` - We added an importer for Citavi backup files, support ".ctv5bak" and ".ctv6bak" file formats. [#8322](https://github.com/JabRef/jabref/issues/8322) +- We added a feature to drag selected entries and drop them to other opened inactive library tabs [koppor521](https://github.com/koppor/jabref/issues/521). ### Changed diff --git a/src/main/java/org/jabref/gui/JabRefFrame.java b/src/main/java/org/jabref/gui/JabRefFrame.java index 91d074e7e7c..ba86aa068b8 100644 --- a/src/main/java/org/jabref/gui/JabRefFrame.java +++ b/src/main/java/org/jabref/gui/JabRefFrame.java @@ -222,6 +222,54 @@ private void initDragAndDrop() { } else { tabbedPane.getTabs().remove(dndIndicator); } + // Accept drag entries from MainTable + if (event.getDragboard().hasContent(DragAndDropDataFormats.ENTRIES)) { + event.acceptTransferModes(TransferMode.COPY); + event.consume(); + } + }); + + this.getScene().setOnDragEntered(event -> { + // It is necessary to setOnDragOver for newly opened tabs + // drag'n'drop on tabs covered dnd on tabbedPane, so dnd on tabs should contain all dnds on tabbedPane + tabbedPane.lookupAll(".tab").forEach(t -> { + t.setOnDragOver(tabDragEvent -> { + if (DragAndDropHelper.hasBibFiles(tabDragEvent.getDragboard())) { + tabDragEvent.acceptTransferModes(TransferMode.ANY); + if (!tabbedPane.getTabs().contains(dndIndicator)) { + tabbedPane.getTabs().add(dndIndicator); + } + event.consume(); + } else { + tabbedPane.getTabs().remove(dndIndicator); + } + + if (tabDragEvent.getDragboard().hasContent(DragAndDropDataFormats.ENTRIES)) { + tabDragEvent.acceptTransferModes(TransferMode.COPY); + tabDragEvent.consume(); + } + }); + t.setOnDragExited(event1 -> tabbedPane.getTabs().remove(dndIndicator)); + t.setOnDragDropped(tabDragEvent -> { + if (DragAndDropHelper.hasBibFiles(tabDragEvent.getDragboard())) { + tabbedPane.getTabs().remove(dndIndicator); + List bibFiles = DragAndDropHelper.getBibFiles(tabDragEvent.getDragboard()); + OpenDatabaseAction openDatabaseAction = this.getOpenDatabaseAction(); + openDatabaseAction.openFiles(bibFiles, true); + tabDragEvent.setDropCompleted(true); + tabDragEvent.consume(); + } else { + for (Tab libraryTab : tabbedPane.getTabs()) { + if (libraryTab.getId().equals(t.getId()) && + !tabbedPane.getSelectionModel().getSelectedItem().equals(libraryTab)) { + ((LibraryTab) libraryTab).dropEntry(stateManager.getLocalDragboard().getBibEntries()); + } + } + tabDragEvent.consume(); + } + }); + }); + event.consume(); }); this.getScene().setOnDragExited(event -> tabbedPane.getTabs().remove(dndIndicator)); diff --git a/src/main/java/org/jabref/gui/LibraryTab.java b/src/main/java/org/jabref/gui/LibraryTab.java index 31e64458016..139cdf31fd0 100644 --- a/src/main/java/org/jabref/gui/LibraryTab.java +++ b/src/main/java/org/jabref/gui/LibraryTab.java @@ -7,6 +7,7 @@ import java.util.List; import java.util.Objects; import java.util.Optional; +import java.util.Random; import javafx.animation.PauseTransition; import javafx.application.Platform; @@ -153,6 +154,10 @@ public LibraryTab(JabRefFrame frame, this.entryEditor = new EntryEditor(this, externalFileTypes); + // set LibraryTab ID for drag'n'drop + // ID content doesn't matter, we only need different tabs to have different ID + this.setId(Long.valueOf(new Random().nextLong()).toString()); + Platform.runLater(() -> { EasyBind.subscribe(changedProperty, this::updateTabTitle); stateManager.getOpenDatabases().addListener((ListChangeListener) c -> @@ -758,6 +763,10 @@ public void paste() { mainTable.paste(); } + public void dropEntry(List entriesToAdd) { + mainTable.dropEntry(entriesToAdd); + } + public void cut() { mainTable.cut(); } diff --git a/src/main/java/org/jabref/gui/maintable/MainTable.java b/src/main/java/org/jabref/gui/maintable/MainTable.java index 91720b42823..32a80afb754 100644 --- a/src/main/java/org/jabref/gui/maintable/MainTable.java +++ b/src/main/java/org/jabref/gui/maintable/MainTable.java @@ -315,6 +315,12 @@ public void paste() { } } + public void dropEntry(List entriesToAdd) { + for (BibEntry entry : entriesToAdd) { + importHandler.importEntryWithDuplicateCheck(database, (BibEntry) entry.clone()); + } + } + private void handleOnDragOver(TableRow row, BibEntryTableViewModel item, DragEvent event) { if (event.getDragboard().hasFiles()) { event.acceptTransferModes(TransferMode.ANY); @@ -351,8 +357,9 @@ private void handleOnDragDetected(TableRow row, BibEntry // The following is necesary to initiate the drag and drop in javafx, although we don't need the contents // It doesn't work without + // Drag'n'drop to other tabs use COPY TransferMode, drop to group sidepane use MOVE ClipboardContent content = new ClipboardContent(); - Dragboard dragboard = startDragAndDrop(TransferMode.MOVE); + Dragboard dragboard = startDragAndDrop(TransferMode.COPY_OR_MOVE); content.put(DragAndDropDataFormats.ENTRIES, ""); dragboard.setContent(content); From 126c1c330cc591814ba43aa6d939f26fc983059f Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Mon, 18 Jul 2022 20:51:57 +0200 Subject: [PATCH 2/4] Fix RfcFetcherTest (#8988) Co-authored-by: Christoph Co-authored-by: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com> Co-authored-by: Benedikt Tutzer --- .../jabref/logic/importer/fetcher/CiteSeerTest.java | 1 + .../logic/importer/fetcher/JstorFetcherTest.java | 12 ++++++++++-- .../logic/importer/fetcher/RfcFetcherTest.java | 2 +- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/test/java/org/jabref/logic/importer/fetcher/CiteSeerTest.java b/src/test/java/org/jabref/logic/importer/fetcher/CiteSeerTest.java index e2f6f2951a1..d8f30866596 100644 --- a/src/test/java/org/jabref/logic/importer/fetcher/CiteSeerTest.java +++ b/src/test/java/org/jabref/logic/importer/fetcher/CiteSeerTest.java @@ -14,6 +14,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; @FetcherTest +@Disabled("CiteSeer is down as of 2022-07-18") class CiteSeerTest { private CiteSeer fetcher = new CiteSeer(); diff --git a/src/test/java/org/jabref/logic/importer/fetcher/JstorFetcherTest.java b/src/test/java/org/jabref/logic/importer/fetcher/JstorFetcherTest.java index 1bd77942c35..37eec705059 100644 --- a/src/test/java/org/jabref/logic/importer/fetcher/JstorFetcherTest.java +++ b/src/test/java/org/jabref/logic/importer/fetcher/JstorFetcherTest.java @@ -2,6 +2,8 @@ import java.io.IOException; import java.net.URL; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; import java.util.Collections; import java.util.List; import java.util.Optional; @@ -63,13 +65,19 @@ void searchByTitle() throws Exception { } @Test - void searchById() throws FetcherException { + void searchById() throws Exception { + bibEntry.setField(StandardField.URLDATE, LocalDate.now().format(DateTimeFormatter.ISO_DATE)); assertEquals(Optional.of(bibEntry), fetcher.performSearchById("90002164")); + } + + @Test + void searchByUrlUsingId() throws Exception { + doiEntry.setField(StandardField.URLDATE, LocalDate.now().format(DateTimeFormatter.ISO_DATE)); assertEquals(Optional.of(doiEntry), fetcher.performSearchById("https://www.jstor.org/stable/10.1086/501484?seq=1")); } @Test - void fetchPDF() throws IOException, FetcherException { + void fetchPDF() throws Exception { Optional url = fetcher.findFullText(bibEntry); assertEquals(Optional.of(new URL("https://www.jstor.org/stable/pdf/90002164.pdf")), url); } diff --git a/src/test/java/org/jabref/logic/importer/fetcher/RfcFetcherTest.java b/src/test/java/org/jabref/logic/importer/fetcher/RfcFetcherTest.java index 63db56f9a81..66f36912554 100644 --- a/src/test/java/org/jabref/logic/importer/fetcher/RfcFetcherTest.java +++ b/src/test/java/org/jabref/logic/importer/fetcher/RfcFetcherTest.java @@ -63,7 +63,7 @@ public void performSearchByIdFindsEntryWithDraftIdentifier() throws Exception { bibDraftEntry.setField(StandardField.PUBLISHER, "Internet Engineering Task Force"); bibDraftEntry.setField(StandardField.TITLE, "{Hypertext Transfer Protocol -- HTTP/1.0}"); bibDraftEntry.setField(StandardField.TYPE, "Internet-Draft"); - bibDraftEntry.setField(StandardField.URL, "https://datatracker.ietf.org/doc/html/draft-fielding-http-spec-01"); + bibDraftEntry.setField(StandardField.URL, "https://datatracker.ietf.org/doc/draft-fielding-http-spec/01/"); bibDraftEntry.setField(StandardField.YEAR, "1994"); bibDraftEntry.setField(StandardField.ABSTRACT, "The Hypertext Transfer Protocol (HTTP) is an application-level protocol with the lightness and speed necessary for distributed, collaborative, hypermedia information systems. It is a generic, stateless, object-oriented protocol which can be used for many tasks, such as name servers and distributed object management systems, through extension of its request methods (commands). A feature of HTTP is the typing and negotiation of data representation, allowing systems to be built independently of the data being transferred. HTTP has been in use by the World-Wide Web global information initiative since 1990. This specification reflects preferred usage of the protocol referred to as 'HTTP/1.0', and is compatible with the most commonly used HTTP server and client programs implemented prior to November 1994."); bibDraftEntry.setCommentsBeforeEntry("%% You should probably cite draft-ietf-http-v10-spec instead of this I-D.\n"); From 3beb9af6484230649a52d60cb0641c388c2c8fc5 Mon Sep 17 00:00:00 2001 From: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com> Date: Mon, 18 Jul 2022 21:11:49 +0200 Subject: [PATCH 3/4] Fixed checkstyle (#8990) --- .../org/jabref/logic/importer/fetcher/JstorFetcherTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/test/java/org/jabref/logic/importer/fetcher/JstorFetcherTest.java b/src/test/java/org/jabref/logic/importer/fetcher/JstorFetcherTest.java index 37eec705059..1f1b0a521f7 100644 --- a/src/test/java/org/jabref/logic/importer/fetcher/JstorFetcherTest.java +++ b/src/test/java/org/jabref/logic/importer/fetcher/JstorFetcherTest.java @@ -1,6 +1,5 @@ package org.jabref.logic.importer.fetcher; -import java.io.IOException; import java.net.URL; import java.time.LocalDate; import java.time.format.DateTimeFormatter; @@ -8,7 +7,6 @@ import java.util.List; import java.util.Optional; -import org.jabref.logic.importer.FetcherException; import org.jabref.logic.importer.ImportFormatPreferences; import org.jabref.logic.importer.SearchBasedFetcher; import org.jabref.model.entry.BibEntry; From be4a7c55c669dae4279bea6562a6c9795adada37 Mon Sep 17 00:00:00 2001 From: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com> Date: Mon, 18 Jul 2022 21:13:55 +0200 Subject: [PATCH 4/4] Reworded t in pr (#8989) --- src/main/java/org/jabref/gui/JabRefFrame.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/jabref/gui/JabRefFrame.java b/src/main/java/org/jabref/gui/JabRefFrame.java index ba86aa068b8..834f7beb325 100644 --- a/src/main/java/org/jabref/gui/JabRefFrame.java +++ b/src/main/java/org/jabref/gui/JabRefFrame.java @@ -232,8 +232,8 @@ private void initDragAndDrop() { this.getScene().setOnDragEntered(event -> { // It is necessary to setOnDragOver for newly opened tabs // drag'n'drop on tabs covered dnd on tabbedPane, so dnd on tabs should contain all dnds on tabbedPane - tabbedPane.lookupAll(".tab").forEach(t -> { - t.setOnDragOver(tabDragEvent -> { + tabbedPane.lookupAll(".tab").forEach(tab -> { + tab.setOnDragOver(tabDragEvent -> { if (DragAndDropHelper.hasBibFiles(tabDragEvent.getDragboard())) { tabDragEvent.acceptTransferModes(TransferMode.ANY); if (!tabbedPane.getTabs().contains(dndIndicator)) { @@ -249,8 +249,8 @@ private void initDragAndDrop() { tabDragEvent.consume(); } }); - t.setOnDragExited(event1 -> tabbedPane.getTabs().remove(dndIndicator)); - t.setOnDragDropped(tabDragEvent -> { + tab.setOnDragExited(event1 -> tabbedPane.getTabs().remove(dndIndicator)); + tab.setOnDragDropped(tabDragEvent -> { if (DragAndDropHelper.hasBibFiles(tabDragEvent.getDragboard())) { tabbedPane.getTabs().remove(dndIndicator); List bibFiles = DragAndDropHelper.getBibFiles(tabDragEvent.getDragboard()); @@ -260,7 +260,7 @@ private void initDragAndDrop() { tabDragEvent.consume(); } else { for (Tab libraryTab : tabbedPane.getTabs()) { - if (libraryTab.getId().equals(t.getId()) && + if (libraryTab.getId().equals(tab.getId()) && !tabbedPane.getSelectionModel().getSelectedItem().equals(libraryTab)) { ((LibraryTab) libraryTab).dropEntry(stateManager.getLocalDragboard().getBibEntries()); }