Skip to content

Commit

Permalink
Merge pull request #5482 from JabRef/issue-2389
Browse files Browse the repository at this point in the history
Add X11 Primary Selection clipboard support
  • Loading branch information
koppor authored Oct 27, 2019
2 parents 2180f75 + 554e45b commit 0fef38f
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 17 deletions.
4 changes: 1 addition & 3 deletions src/main/java/org/jabref/Globals.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,11 @@ public class Globals {
/**
* Manager for the state of the GUI.
*/

public static ClipBoardManager clipboardManager = new ClipBoardManager();

public static StateManager stateManager = new StateManager();
public static ExporterFactory exportFactory;
public static CountingUndoManager undoManager = new CountingUndoManager();
public static BibEntryTypesManager entryTypesManager = new BibEntryTypesManager();
public static ClipBoardManager clipboardManager = new ClipBoardManager();
// Key binding preferences
private static KeyBindingRepository keyBindingRepository;
private static DefaultFileUpdateMonitor fileUpdateMonitor;
Expand Down
91 changes: 77 additions & 14 deletions src/main/java/org/jabref/gui/ClipBoardManager.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
package org.jabref.gui;

import java.awt.Toolkit;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

import javafx.scene.control.TextInputControl;
import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.DataFormat;
import javafx.scene.input.MouseButton;

import org.jabref.Globals;
import org.jabref.logic.bibtex.BibEntryWriter;
Expand All @@ -30,53 +37,108 @@
import org.slf4j.LoggerFactory;

public class ClipBoardManager {

public static final DataFormat XML = new DataFormat("application/xml");

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

private final Clipboard clipboard;
private final ImportFormatReader importFormatReader;
private static Clipboard clipboard;
private static java.awt.datatransfer.Clipboard primary;
private static ImportFormatReader importFormatReader;

public ClipBoardManager() {
this(Clipboard.getSystemClipboard(), Globals.IMPORT_FORMAT_READER);
public ClipBoardManager(Clipboard clipboard, java.awt.datatransfer.Clipboard primary, ImportFormatReader importFormatReader) {
ClipBoardManager.clipboard = clipboard;
ClipBoardManager.primary = primary;
ClipBoardManager.importFormatReader = importFormatReader;
}

public ClipBoardManager(Clipboard clipboard, ImportFormatReader importFormatReader) {
this.clipboard = clipboard;
this.importFormatReader = importFormatReader;
public ClipBoardManager() {
this(Clipboard.getSystemClipboard(), Toolkit.getDefaultToolkit().getSystemSelection(), Globals.IMPORT_FORMAT_READER);
}

/**
* Puts content onto the clipboard.
* Add X11 clipboard support to a text input control.
* It is necessary to call this method in every input where you want to use it:
* {@code ClipBoardManager.addX11Support(TextInputControl input);}.
*
* @param input the TextInputControl (e.g., TextField, TextArea, and children) where adding this functionality.
* @see <a href="https://www.uninformativ.de/blog/postings/2017-04-02/0/POSTING-en.html">Short summary for X11 clipboards</a>
* @see <a href="https://unix.stackexchange.com/questions/139191/whats-the-difference-between-primary-selection-and-clipboard-buffer/139193#139193">Longer text over clipboards</a>
*/
public void setContent(ClipboardContent content) {
clipboard.setContent(content);
public static void addX11Support(TextInputControl input) {
input.selectedTextProperty().addListener((observable, oldValue, newValue) -> {
if (!newValue.isEmpty()) {
primary.setContents(new StringSelection(newValue), null);
}
});
input.setOnMouseClicked(event -> {
if (event.getButton() == MouseButton.MIDDLE) {
input.insertText(input.getCaretPosition(), getContentsPrimary());
}
});
}

/**
* Get the String residing on the clipboard.
* Get the String residing on the system clipboard.
*
* @return any text found on the Clipboard; if none found, return an
* empty String.
* @return any text found on the Clipboard; if none found, return an empty String.
*/
public String getContents() {
public static String getContents() {
String result = clipboard.getString();
if (result == null) {
return "";
}
return result;
}

/**
* Get the String residing on the primary clipboard.
*
* @return any text found on the primary Clipboard; if none found, try with the system clipboard.
*/
public static String getContentsPrimary() {
Transferable contents = primary.getContents(null);
if (contents != null && contents.isDataFlavorSupported(DataFlavor.stringFlavor)) {
try {
return (String) contents.getTransferData(DataFlavor.stringFlavor);
} catch (UnsupportedFlavorException | IOException e) {
LOGGER.warn(e.getMessage());
}
}
return getContents();
}

/**
* Puts content onto the system clipboard.
*
* @param content the ClipboardContent to set as current value of the system clipboard.
*/
public void setContent(ClipboardContent content) {
clipboard.setContent(content);
setPrimaryClipboardContent(content);
}

/**
* Puts content onto the primary clipboard.
*
* @param content the ClipboardContent to set as current value of the primary clipboard.
*/
public void setPrimaryClipboardContent(ClipboardContent content) {
primary.setContents(new StringSelection(content.getString()), null);
}

public void setHtmlContent(String html) {
final ClipboardContent content = new ClipboardContent();
content.putHtml(html);
clipboard.setContent(content);
setPrimaryClipboardContent(content);
}

public void setContent(String string) {
final ClipboardContent content = new ClipboardContent();
content.putString(string);
clipboard.setContent(content);
setPrimaryClipboardContent(content);
}

public void setContent(List<BibEntry> entries) throws IOException {
Expand All @@ -86,6 +148,7 @@ public void setContent(List<BibEntry> entries) throws IOException {
content.put(DragAndDropDataFormats.ENTRIES, serializedEntries);
content.putString(serializedEntries);
clipboard.setContent(content);
setPrimaryClipboardContent(content);
}

public List<BibEntry> extractData() {
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/org/jabref/gui/fieldeditors/EditorTextArea.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;

import org.jabref.gui.ClipBoardManager;

public class EditorTextArea extends javafx.scene.control.TextArea implements Initializable, ContextMenuAddable {

private final ContextMenu contextMenu = new ContextMenu();
Expand All @@ -29,6 +31,8 @@ public EditorTextArea(final String text) {

// Hide horizontal scrollbar and always wrap text
setWrapText(true);

ClipBoardManager.addX11Support(this);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;

import org.jabref.gui.ClipBoardManager;

public class EditorTextField extends javafx.scene.control.TextField implements Initializable, ContextMenuAddable {

private final ContextMenu contextMenu = new ContextMenu();
Expand All @@ -25,6 +27,8 @@ public EditorTextField(final String text) {
// Always fill out all the available space
setPrefHeight(Double.POSITIVE_INFINITY);
HBox.setHgrow(this, Priority.ALWAYS);

ClipBoardManager.addX11Support(this);
}

@Override
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/org/jabref/gui/search/GlobalSearchBar.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@

import org.jabref.Globals;
import org.jabref.gui.BasePanel;
import org.jabref.gui.ClipBoardManager;
import org.jabref.gui.JabRefFrame;
import org.jabref.gui.StateManager;
import org.jabref.gui.autocompleter.AppendPersonNamesStrategy;
Expand Down Expand Up @@ -111,6 +112,8 @@ public GlobalSearchBar(JabRefFrame frame, StateManager stateManager) {
}
});

ClipBoardManager.addX11Support(searchField);

regularExp = IconTheme.JabRefIcons.REG_EX.asToggleButton();
regularExp.setSelected(searchPreferences.isRegularExpression());
regularExp.setTooltip(new Tooltip(Localization.lang("regular expression")));
Expand Down

0 comments on commit 0fef38f

Please sign in to comment.