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

Enable drag'n'drop from maintable to external application #11846

Merged
merged 5 commits into from
Sep 29, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
Create ClipboardContentGenerator out of CopyCitationAction
  • Loading branch information
koppor committed Sep 28, 2024
commit f2ffbda5e4dca2e1d50b2f5f48e398dad81162f5
136 changes: 136 additions & 0 deletions src/main/java/org/jabref/gui/preview/ClipboardContentGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package org.jabref.gui.preview;

import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;

import javafx.scene.input.ClipboardContent;

import org.jabref.logic.citationstyle.CitationStyleGenerator;
import org.jabref.logic.citationstyle.CitationStyleOutputFormat;
import org.jabref.logic.citationstyle.CitationStylePreviewLayout;
import org.jabref.logic.journals.JournalAbbreviationRepository;
import org.jabref.logic.layout.Layout;
import org.jabref.logic.layout.LayoutFormatterPreferences;
import org.jabref.logic.layout.LayoutHelper;
import org.jabref.logic.layout.TextBasedPreviewLayout;
import org.jabref.logic.os.OS;
import org.jabref.logic.preview.PreviewLayout;
import org.jabref.model.database.BibDatabaseContext;
import org.jabref.model.entry.BibEntry;
import org.jabref.model.entry.BibEntryTypesManager;

import com.airhacks.afterburner.injection.Injector;
import com.google.common.annotations.VisibleForTesting;

public class ClipboardContentGenerator {

private PreviewPreferences previewPreferences;
private final LayoutFormatterPreferences layoutFormatterPreferences;
private final JournalAbbreviationRepository abbreviationRepository;

public ClipboardContentGenerator(PreviewPreferences previewPreferences,
LayoutFormatterPreferences layoutFormatterPreferences,
JournalAbbreviationRepository abbreviationRepository) {
this.previewPreferences = previewPreferences;
this.layoutFormatterPreferences = layoutFormatterPreferences;
this.abbreviationRepository = abbreviationRepository;
}

public ClipboardContent generateCitation(List<BibEntry> selectedEntries, CitationStyleOutputFormat outputFormat, BibDatabaseContext bibDatabaseContext) throws IOException {
List<String> citations = generateCitations(selectedEntries, outputFormat, bibDatabaseContext);
PreviewLayout previewLayout = previewPreferences.getSelectedPreviewLayout();

// if it is not a citation style take care of the preview
if (!(previewLayout instanceof CitationStylePreviewLayout)) {
return processPreview(citations);
} else {
// if it's generated by a citation style take care of each output format
ClipboardContent content;
return switch (outputFormat) {
case HTML -> processHtml(citations);
case TEXT -> processText(citations);
};
}
}

private List<String> generateCitations(List<BibEntry> selectedEntries, CitationStyleOutputFormat outputFormat, BibDatabaseContext bibDatabaseContext) throws IOException {
// This worker stored the style as filename. The CSLAdapter and the CitationStyleCache store the source of the
// style. Therefore, we extract the style source from the file.
String styleSource = null;
PreviewLayout previewLayout = previewPreferences.getSelectedPreviewLayout();

if (previewLayout instanceof CitationStylePreviewLayout citationStyleLayout) {
styleSource = citationStyleLayout.getText();
}

if (styleSource != null) {
return CitationStyleGenerator.generateBibliographies(
selectedEntries,
styleSource,
outputFormat,
bibDatabaseContext,
Injector.instantiateModelOrService(BibEntryTypesManager.class));
} else {
return generateTextBasedPreviewLayoutCitations(selectedEntries, bibDatabaseContext);
}
}

/**
* Generates a plain text string out of the preview (based on {@link org.jabref.logic.layout.TextBasedPreviewLayout} or {@link org.jabref.logic.bst.BstPreviewLayout})
* and copies it additionally to the html to the clipboard (WYSIWYG Editors use the HTML, plain text editors the text)
*/
@VisibleForTesting
static ClipboardContent processPreview(List<String> citations) {
ClipboardContent content = new ClipboardContent();
content.putHtml(String.join(CitationStyleOutputFormat.HTML.getLineSeparator(), citations));
content.putString(String.join(CitationStyleOutputFormat.HTML.getLineSeparator(), citations));
return content;
}

/**
* Joins every citation with a newline and returns it.
*/
@VisibleForTesting
static ClipboardContent processText(List<String> citations) {
ClipboardContent content = new ClipboardContent();
content.putString(String.join(CitationStyleOutputFormat.TEXT.getLineSeparator(), citations));
return content;
}

/**
* Inserts each citation into a HTML body and copies it to the clipboard.
* The given preview is based on {@link org.jabref.logic.citationstyle.CitationStylePreviewLayout}.
*/
@VisibleForTesting
static ClipboardContent processHtml(List<String> citations) {
String result = "<!DOCTYPE html>" + OS.NEWLINE +
"<html>" + OS.NEWLINE +
" <head>" + OS.NEWLINE +
" <meta charset=\"utf-8\">" + OS.NEWLINE +
" </head>" + OS.NEWLINE +
" <body>" + OS.NEWLINE + OS.NEWLINE;

result += String.join(CitationStyleOutputFormat.HTML.getLineSeparator(), citations);
result += OS.NEWLINE +
" </body>" + OS.NEWLINE +
"</html>" + OS.NEWLINE;

ClipboardContent content = new ClipboardContent();
content.putString(result);
content.putHtml(result);
return content;
}

private List<String> generateTextBasedPreviewLayoutCitations(List<BibEntry> selectedEntries, BibDatabaseContext bibDatabaseContext) throws IOException {
TextBasedPreviewLayout customPreviewLayout = previewPreferences.getCustomPreviewLayout();
StringReader customLayoutReader = new StringReader(customPreviewLayout.getText().replace("__NEWLINE__", "\n"));
Layout layout = new LayoutHelper(customLayoutReader, layoutFormatterPreferences, abbreviationRepository).getLayoutFromText();
List<String> citations = new ArrayList<>(selectedEntries.size());
for (BibEntry entry : selectedEntries) {
citations.add(layout.doLayout(entry, bibDatabaseContext.getDatabase()));
}
return citations;
}
}
120 changes: 6 additions & 114 deletions src/main/java/org/jabref/gui/preview/CopyCitationAction.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package org.jabref.gui.preview;

import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javafx.scene.input.ClipboardContent;
Expand All @@ -14,22 +11,13 @@
import org.jabref.gui.actions.ActionHelper;
import org.jabref.gui.actions.SimpleCommand;
import org.jabref.gui.preferences.GuiPreferences;
import org.jabref.logic.citationstyle.CitationStyleGenerator;
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.layout.Layout;
import org.jabref.logic.layout.LayoutHelper;
import org.jabref.logic.layout.TextBasedPreviewLayout;
import org.jabref.logic.os.OS;
import org.jabref.logic.preview.PreviewLayout;
import org.jabref.logic.util.BackgroundTask;
import org.jabref.logic.util.TaskExecutor;
import org.jabref.model.entry.BibEntry;
import org.jabref.model.entry.BibEntryTypesManager;

import com.airhacks.afterburner.injection.Injector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -47,8 +35,7 @@ public class CopyCitationAction extends SimpleCommand {
private final DialogService dialogService;
private final ClipBoardManager clipBoardManager;
private final TaskExecutor taskExecutor;
private final GuiPreferences preferences;
private final JournalAbbreviationRepository abbreviationRepository;
private final ClipboardContentGenerator clipboardContentGenerator;

public CopyCitationAction(CitationStyleOutputFormat outputFormat,
DialogService dialogService,
Expand All @@ -63,8 +50,7 @@ public CopyCitationAction(CitationStyleOutputFormat outputFormat,
this.selectedEntries = stateManager.getSelectedEntries();
this.clipBoardManager = clipBoardManager;
this.taskExecutor = taskExecutor;
this.preferences = preferences;
this.abbreviationRepository = abbreviationRepository;
this.clipboardContentGenerator = new ClipboardContentGenerator(preferences.getPreviewPreferences(), preferences.getLayoutFormatterPreferences(), abbreviationRepository);

this.executable.bind(ActionHelper.needsEntriesSelected(stateManager));
}
Expand All @@ -77,106 +63,12 @@ public void execute() {
.executeWith(taskExecutor);
}

private List<String> generateCitations() throws IOException {
// This worker stored the style as filename. The CSLAdapter and the CitationStyleCache store the source of the
// style. Therefore, we extract the style source from the file.
String styleSource = null;
PreviewLayout previewLayout = preferences.getPreviewPreferences().getSelectedPreviewLayout();

if (previewLayout instanceof CitationStylePreviewLayout citationStyleLayout) {
styleSource = citationStyleLayout.getText();
}

if (styleSource != null) {
return CitationStyleGenerator.generateBibliographies(
selectedEntries,
styleSource,
outputFormat,
stateManager.getActiveDatabase().get(),
Injector.instantiateModelOrService(BibEntryTypesManager.class));
} else {
return generateTextBasedPreviewLayoutCitations();
}
}

private List<String> generateTextBasedPreviewLayoutCitations() throws IOException {
if (stateManager.getActiveDatabase().isEmpty()) {
return Collections.emptyList();
}

TextBasedPreviewLayout customPreviewLayout = preferences.getPreviewPreferences().getCustomPreviewLayout();
StringReader customLayoutReader = new StringReader(customPreviewLayout.getText().replace("__NEWLINE__", "\n"));
Layout layout = new LayoutHelper(customLayoutReader, preferences.getLayoutFormatterPreferences(), abbreviationRepository)
.getLayoutFromText();

List<String> citations = new ArrayList<>(selectedEntries.size());
for (BibEntry entry : selectedEntries) {
citations.add(layout.doLayout(entry, stateManager.getActiveDatabase().get().getDatabase()));
}
return citations;
}

/**
* Generates a plain text string out of the preview and copies it additionally to the html to the clipboard (WYSIWYG Editors use the HTML, plain text editors the text)
*/
protected static ClipboardContent processPreview(List<String> citations) {
ClipboardContent content = new ClipboardContent();
content.putHtml(String.join(CitationStyleOutputFormat.HTML.getLineSeparator(), citations));
content.putString(String.join(CitationStyleOutputFormat.HTML.getLineSeparator(), citations));
return content;
private ClipboardContent generateCitations() throws IOException {
return clipboardContentGenerator.generateCitation(selectedEntries, outputFormat, stateManager.getActiveDatabase().get());
}

/**
* Joins every citation with a newline and returns it.
*/
protected static ClipboardContent processText(List<String> citations) {
ClipboardContent content = new ClipboardContent();
content.putString(String.join(CitationStyleOutputFormat.TEXT.getLineSeparator(), citations));
return content;
}

/**
* Inserts each citation into a HTML body and copies it to the clipboard
*/
protected static ClipboardContent processHtml(List<String> citations) {
String result = "<!DOCTYPE html>" + OS.NEWLINE +
"<html>" + OS.NEWLINE +
" <head>" + OS.NEWLINE +
" <meta charset=\"utf-8\">" + OS.NEWLINE +
" </head>" + OS.NEWLINE +
" <body>" + OS.NEWLINE + OS.NEWLINE;

result += String.join(CitationStyleOutputFormat.HTML.getLineSeparator(), citations);
result += OS.NEWLINE +
" </body>" + OS.NEWLINE +
"</html>" + OS.NEWLINE;

ClipboardContent content = new ClipboardContent();
content.putString(result);
content.putHtml(result);
return content;
}

private void setClipBoardContent(List<String> citations) {
PreviewLayout previewLayout = preferences.getPreviewPreferences().getSelectedPreviewLayout();

// if it's not a citation style take care of the preview
if (!(previewLayout instanceof CitationStylePreviewLayout)) {
clipBoardManager.setContent(processPreview(citations));
} else {
// if it's generated by a citation style take care of each output format
ClipboardContent content;
switch (outputFormat) {
case HTML -> content = processHtml(citations);
case TEXT -> content = processText(citations);
default -> {
LOGGER.warn("unknown output format: '{}', processing it via the default.", outputFormat);
content = processText(citations);
}
}
clipBoardManager.setContent(content);
}

private void setClipBoardContent(ClipboardContent clipBoardContent) {
clipBoardManager.setContent(clipBoardContent);
dialogService.notify(Localization.lang("Copied %0 citations.", String.valueOf(selectedEntries.size())));
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.jabref.gui.preview;

import java.util.Arrays;
import java.util.List;

import javafx.scene.input.ClipboardContent;

Expand All @@ -10,7 +11,7 @@

import static org.junit.jupiter.api.Assertions.assertEquals;

class CopyCitationActionTest {
class ClipboardContentGeneratorTest {

@Test
void processPreviewText() throws Exception {
Expand Down Expand Up @@ -38,7 +39,7 @@ void processPreviewText() throws Exception {
OS.NEWLINE +
"Abstract: This entry describes a test scenario which may be useful in JabRef. By providing a test entry it is possible to see how certain things will look in this graphical BIB-file mananger. ";

ClipboardContent clipboardContent = CopyCitationAction.processPreview(Arrays.asList(citation, citation));
ClipboardContent clipboardContent = ClipboardContentGenerator.processPreview(List.of(citation, citation));
String actual = clipboardContent.getString();

assertEquals(expected, actual);
Expand Down Expand Up @@ -91,7 +92,7 @@ void processPreviewHtml() throws Exception {
"</dd>" + OS.NEWLINE +
"<p></p></font>";

ClipboardContent clipboardContent = CopyCitationAction.processPreview(Arrays.asList(citation, citation));
ClipboardContent clipboardContent = ClipboardContentGenerator.processPreview(Arrays.asList(citation, citation));
String actual = clipboardContent.getString();
assertEquals(expected, actual);
}
Expand All @@ -102,7 +103,7 @@ void processText() throws Exception {
"[1]B. Smith, B. Jones, and J. Williams, “Title of the test entry,” BibTeX Journal, vol. 34, no. 3, pp. 45–67, Jul. 2016." + OS.NEWLINE;

String citation = "[1]B. Smith, B. Jones, and J. Williams, “Title of the test entry,” BibTeX Journal, vol. 34, no. 3, pp. 45–67, Jul. 2016." + OS.NEWLINE;
ClipboardContent textTransferable = CopyCitationAction.processText(Arrays.asList(citation, citation));
ClipboardContent textTransferable = ClipboardContentGenerator.processText(Arrays.asList(citation, citation));

String actual = textTransferable.getString();
assertEquals(expected, actual);
Expand Down Expand Up @@ -132,7 +133,7 @@ void processHtmlAsHtml() throws Exception {
String citation = " <div class=\"csl-entry\">" + OS.NEWLINE +
" <div class=\"csl-left-margin\">[1]</div><div class=\"csl-right-inline\">B. Smith, B. Jones, and J. Williams, “Title of the test entry,” <i>BibTeX Journal</i>, vol. 34, no. 3, pp. 45–67, Jul. 2016.</div>" + OS.NEWLINE +
" </div>" + OS.NEWLINE;
ClipboardContent htmlTransferable = CopyCitationAction.processHtml(Arrays.asList(citation, citation));
ClipboardContent htmlTransferable = ClipboardContentGenerator.processHtml(Arrays.asList(citation, citation));

Object actual = htmlTransferable.getHtml();
assertEquals(expected, actual);
Expand Down