diff --git a/jabsrv/src/main/java/module-info.java b/jabsrv/src/main/java/module-info.java index 65af0874cd8..0e7d6b2a521 100644 --- a/jabsrv/src/main/java/module-info.java +++ b/jabsrv/src/main/java/module-info.java @@ -2,10 +2,11 @@ exports org.jabref.http.server; exports org.jabref.http.dto to com.google.gson, org.glassfish.hk2.locator; + exports org.jabref.http.dto.cayw to com.google.gson; opens org.jabref.http.server to org.glassfish.hk2.utilities, org.glassfish.hk2.locator; exports org.jabref.http.server.cayw; - opens org.jabref.http.server.cayw to org.glassfish.hk2.locator, org.glassfish.hk2.utilities; + opens org.jabref.http.server.cayw to com.google.gson, org.glassfish.hk2.locator, org.glassfish.hk2.utilities; // For ServiceLocatorUtilities.createAndPopulateServiceLocator() requires org.glassfish.hk2.locator; diff --git a/jabsrv/src/main/java/org/jabref/http/dto/cayw/SimpleJson.java b/jabsrv/src/main/java/org/jabref/http/dto/cayw/SimpleJson.java new file mode 100644 index 00000000000..ba33658de6a --- /dev/null +++ b/jabsrv/src/main/java/org/jabref/http/dto/cayw/SimpleJson.java @@ -0,0 +1,27 @@ +package org.jabref.http.dto.cayw; + +import java.nio.charset.StandardCharsets; + +import org.jabref.model.entry.BibEntry; + +import com.google.common.hash.Hashing; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public record SimpleJson( + long id, + String citationKey) { + + private static final Logger LOGGER = LoggerFactory.getLogger(SimpleJson.class); + + public static SimpleJson fromBibEntry(BibEntry bibEntry) { + if (bibEntry.getCitationKey().isEmpty()) { + LOGGER.warn("BibEntry has no citation key: {}", bibEntry); + return new SimpleJson(0, ""); + } + + long id = Hashing.sha256().hashString(bibEntry.getCitationKey().get(), StandardCharsets.UTF_8).asLong(); + String citationKey = bibEntry.getCitationKey().get(); + return new SimpleJson(id, citationKey); + } +} diff --git a/jabsrv/src/main/java/org/jabref/http/server/LibraryResource.java b/jabsrv/src/main/java/org/jabref/http/server/LibraryResource.java index 32b7b67f4bc..3eae56cf22d 100644 --- a/jabsrv/src/main/java/org/jabref/http/server/LibraryResource.java +++ b/jabsrv/src/main/java/org/jabref/http/server/LibraryResource.java @@ -39,7 +39,7 @@ @Path("libraries/{id}") public class LibraryResource { - public static final Logger LOGGER = LoggerFactory.getLogger(LibraryResource.class); + private static final Logger LOGGER = LoggerFactory.getLogger(LibraryResource.class); @Inject CliPreferences preferences; diff --git a/jabsrv/src/main/java/org/jabref/http/server/Server.java b/jabsrv/src/main/java/org/jabref/http/server/Server.java index be7f21a73d0..5ce92b99771 100644 --- a/jabsrv/src/main/java/org/jabref/http/server/Server.java +++ b/jabsrv/src/main/java/org/jabref/http/server/Server.java @@ -10,6 +10,7 @@ import org.jabref.http.dto.GlobalExceptionMapper; import org.jabref.http.dto.GsonFactory; import org.jabref.http.server.cayw.CAYWResource; +import org.jabref.http.server.cayw.format.FormatterService; import org.jabref.http.server.services.FilesToServe; import org.jabref.logic.os.OS; @@ -71,6 +72,7 @@ private HttpServer startServer(FilesToServe filesToServe, URI uri) { ServiceLocator serviceLocator = ServiceLocatorUtilities.createAndPopulateServiceLocator(); ServiceLocatorUtilities.addFactoryConstants(serviceLocator, new GsonFactory()); ServiceLocatorUtilities.addFactoryConstants(serviceLocator, new PreferencesFactory()); + ServiceLocatorUtilities.addOneConstant(serviceLocator, new FormatterService()); ServiceLocatorUtilities.addOneConstant(serviceLocator, filesToServe); final HttpServer httpServer = startServer(serviceLocator, uri); diff --git a/jabsrv/src/main/java/org/jabref/http/server/cayw/CAYWQueryParams.java b/jabsrv/src/main/java/org/jabref/http/server/cayw/CAYWQueryParams.java new file mode 100644 index 00000000000..d62bb572d53 --- /dev/null +++ b/jabsrv/src/main/java/org/jabref/http/server/cayw/CAYWQueryParams.java @@ -0,0 +1,76 @@ +package org.jabref.http.server.cayw; + +import java.util.Optional; + +import jakarta.ws.rs.DefaultValue; +import jakarta.ws.rs.QueryParam; + +public class CAYWQueryParams { + + /// See documentation here https://retorque.re/zotero-better-bibtex/citing/cayw/index.html#diy + + @QueryParam("probe") + private String probe; + + @QueryParam("format") + @DefaultValue("biblatex") + private String format; + + @QueryParam("clipboard") + private String clipboard; + + @QueryParam("command") + @DefaultValue("autocite") + private String command; + + @QueryParam("minimize") + private String minimize; + + @QueryParam("texstudio") + private String texstudio; + + @QueryParam("selected") + private String selected; + + @QueryParam("select") + private String select; + + @QueryParam("librarypath") + private String libraryPath; + + public String getCommand() { + return command; + } + + public boolean isClipboard() { + return clipboard != null; + } + + public boolean isTexstudio() { + return texstudio != null; + } + + public boolean isSelected() { + return selected != null; + } + + public boolean isSelect() { + return select != null && select.equalsIgnoreCase("true"); + } + + public boolean isProbe() { + return probe != null; + } + + public boolean isMinimize() { + return minimize != null; + } + + public String getFormat() { + return format; + } + + public Optional getLibraryPath() { + return Optional.ofNullable(libraryPath); + } +} diff --git a/jabsrv/src/main/java/org/jabref/http/server/cayw/CAYWResource.java b/jabsrv/src/main/java/org/jabref/http/server/cayw/CAYWResource.java index f664b2a8e69..512b25d0c0c 100644 --- a/jabsrv/src/main/java/org/jabref/http/server/cayw/CAYWResource.java +++ b/jabsrv/src/main/java/org/jabref/http/server/cayw/CAYWResource.java @@ -1,5 +1,8 @@ package org.jabref.http.server.cayw; +import java.awt.Toolkit; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.StringSelection; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; @@ -8,18 +11,17 @@ import java.nio.file.Files; import java.util.ArrayList; import java.util.List; -import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import javafx.application.Platform; +import org.jabref.http.server.cayw.format.FormatterService; import org.jabref.http.server.cayw.gui.CAYWEntry; import org.jabref.http.server.cayw.gui.SearchDialog; import org.jabref.logic.importer.fileformat.BibtexImporter; import org.jabref.logic.preferences.CliPreferences; -import org.jabref.logic.preferences.JabRefCliPreferences; import org.jabref.model.database.BibDatabase; import org.jabref.model.database.BibDatabaseContext; import org.jabref.model.entry.BibEntry; @@ -28,11 +30,10 @@ import com.google.gson.Gson; import jakarta.inject.Inject; -import jakarta.ws.rs.DefaultValue; +import jakarta.ws.rs.BeanParam; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; -import jakarta.ws.rs.QueryParam; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import org.jspecify.annotations.Nullable; @@ -41,7 +42,7 @@ @Path("better-bibtex/cayw") public class CAYWResource { - public static final Logger LOGGER = LoggerFactory.getLogger(CAYWResource.class); + private static final Logger LOGGER = LoggerFactory.getLogger(CAYWResource.class); private static final String CHOCOLATEBIB_PATH = "/Chocolate.bib"; private static boolean initialized = false; @@ -51,23 +52,29 @@ public class CAYWResource { @Inject private Gson gson; + @Inject + private FormatterService formatterService; + @GET @Produces(MediaType.TEXT_PLAIN) public Response getCitation( - @QueryParam("probe") String probe, - @QueryParam("format") @DefaultValue("latex") String format, - @QueryParam("clipboard") String clipboard, - @QueryParam("minimize") String minimize, - @QueryParam("texstudio") String texstudio, - @QueryParam("selected") String selected, - @QueryParam("select") String select, - @QueryParam("librarypath") String libraryPath + @BeanParam CAYWQueryParams queryParams ) throws IOException, ExecutionException, InterruptedException { - if (probe != null && !probe.isEmpty()) { + if (queryParams.isProbe()) { return Response.ok("ready").build(); } - BibDatabaseContext databaseContext = getBibDatabaseContext(libraryPath); + BibDatabaseContext databaseContext; + + // handle library path parameter + if (queryParams.getLibraryPath().isPresent() && queryParams.getLibraryPath().get().equalsIgnoreCase("demo")) { + databaseContext = getDatabaseContextFromStream(getChocolateBibAsStream()); + } else if (queryParams.getLibraryPath().isPresent()) { + InputStream inputStream = getDatabaseStreamFromPath(java.nio.file.Path.of(queryParams.getLibraryPath().get())); + databaseContext = getDatabaseContextFromStream(inputStream); + } else { + databaseContext = getDatabaseContextFromStream(getLatestDatabaseStream()); + } /* unused until DatabaseSearcher is fixed PostgreServer postgreServer = new PostgreServer(); @@ -79,71 +86,76 @@ public Response getCitation( postgreServer); */ - List> entries = databaseContext.getEntries() + List entries = databaseContext.getEntries() .stream() .map(this::createCAYWEntry) .toList(); initializeGUI(); - CompletableFuture> future = new CompletableFuture<>(); + CompletableFuture> future = new CompletableFuture<>(); Platform.runLater(() -> { - SearchDialog dialog = new SearchDialog<>(); + SearchDialog dialog = new SearchDialog(); // TODO: Using the DatabaseSearcher directly here results in a lot of exceptions being thrown, so we use an alternative for now until we have a nice way of using the DatabaseSearcher class. // searchDialog.set(new SearchDialog<>(s -> searcher.getMatches(new SearchQuery(s)), entries)); - List results = dialog.show(searchQuery -> - entries.stream() - .filter(bibEntryCAYWEntry -> matches(bibEntryCAYWEntry, searchQuery)) - .map(CAYWEntry::getValue) - .toList(), + List results = dialog.show(searchQuery -> + entries.stream().filter(caywEntry -> matches(caywEntry, searchQuery)).toList(), entries); future.complete(results); }); - List citationKeys = future.get().stream() - .map(BibEntry::getCitationKey) - .filter(Optional::isPresent) - .map(Optional::get) - .toList(); + List searchResults = future.get(); - if (citationKeys.isEmpty()) { + if (searchResults.isEmpty()) { return Response.noContent().build(); } - return Response.ok(gson.toJson(citationKeys)).build(); + // Format parameter handling + String response = formatterService.format(queryParams, searchResults); + + // Clipboard parameter handling + if (queryParams.isClipboard()) { + Toolkit toolkit = Toolkit.getDefaultToolkit(); + Clipboard systemClipboard = toolkit.getSystemClipboard(); + StringSelection strSel = new StringSelection(response); + systemClipboard.setContents(strSel, null); + } + + return Response.ok(response).build(); } - private BibDatabaseContext getBibDatabaseContext(String libraryPath) throws IOException { + private InputStream getLatestDatabaseStream() throws IOException { InputStream libraryStream; - if (libraryPath != null && !libraryPath.isEmpty()) { - java.nio.file.Path path = java.nio.file.Path.of(libraryPath); - if (!Files.exists(path)) { - LOGGER.error("Library path does not exist, using the default chocolate.bib: {}", libraryPath); - libraryStream = getChocolateBibAsStream(); - } else { - libraryStream = Files.newInputStream(path); - } + // Use the latest opened library as the default library + final List lastOpenedLibraries = new ArrayList<>(preferences.getLastFilesOpenedPreferences().getLastFilesOpened()); + if (lastOpenedLibraries.isEmpty()) { + LOGGER.warn("No library path provided and no last opened libraries found, using the default chocolate.bib."); + libraryStream = getChocolateBibAsStream(); } else { - // Use the latest opened library as the default library - final List lastOpenedLibraries = new ArrayList<>(JabRefCliPreferences.getInstance().getLastFilesOpenedPreferences().getLastFilesOpened()); - if (lastOpenedLibraries.isEmpty()) { - LOGGER.warn("No library path provided and no last opened libraries found, using the default chocolate.bib."); + java.nio.file.Path lastOpenedLibrary = lastOpenedLibraries.getFirst(); + if (!Files.exists(lastOpenedLibrary)) { + LOGGER.error("Last opened library does not exist, using the default chocolate.bib: {}", lastOpenedLibrary); libraryStream = getChocolateBibAsStream(); } else { - java.nio.file.Path lastOpenedLibrary = lastOpenedLibraries.getFirst(); - if (!Files.exists(lastOpenedLibrary)) { - LOGGER.error("Last opened library does not exist, using the default chocolate.bib: {}", lastOpenedLibrary); - libraryStream = getChocolateBibAsStream(); - } else { - libraryStream = Files.newInputStream(lastOpenedLibrary); - } + libraryStream = Files.newInputStream(lastOpenedLibrary); } } + return libraryStream; + } + + private InputStream getDatabaseStreamFromPath(java.nio.file.Path path) throws IOException { + if (!Files.exists(path)) { + LOGGER.warn("The provided library path does not exist: {}. Using the default chocolate.bib.", path); + return getChocolateBibAsStream(); + } + return Files.newInputStream(path); + } + private BibDatabaseContext getDatabaseContextFromStream(InputStream inputStream) throws IOException { BibtexImporter bibtexImporter = new BibtexImporter(preferences.getImportFormatPreferences(), new DummyFileUpdateMonitor()); BibDatabaseContext databaseContext; - try (BufferedReader reader = new BufferedReader(new InputStreamReader(libraryStream, StandardCharsets.UTF_8))) { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) { databaseContext = bibtexImporter.importDatabase(reader).getDatabaseContext(); } return databaseContext; @@ -172,14 +184,14 @@ private synchronized void initializeGUI() { return BibDatabase.class.getResourceAsStream(CHOCOLATEBIB_PATH); } - private CAYWEntry createCAYWEntry(BibEntry entry) { + private CAYWEntry createCAYWEntry(BibEntry entry) { String label = entry.getCitationKey().orElse(""); String shortLabel = label; String description = entry.getField(StandardField.TITLE).orElse(entry.getAuthorTitleYear()); - return new CAYWEntry<>(entry, label, shortLabel, description); + return new CAYWEntry(entry, label, shortLabel, description); } - private boolean matches(CAYWEntry entry, String searchText) { + private boolean matches(CAYWEntry entry, String searchText) { if (searchText == null || searchText.isEmpty()) { return true; } diff --git a/jabsrv/src/main/java/org/jabref/http/server/cayw/format/BibLatexFormatter.java b/jabsrv/src/main/java/org/jabref/http/server/cayw/format/BibLatexFormatter.java new file mode 100644 index 00000000000..6e0018948d0 --- /dev/null +++ b/jabsrv/src/main/java/org/jabref/http/server/cayw/format/BibLatexFormatter.java @@ -0,0 +1,33 @@ +package org.jabref.http.server.cayw.format; + +import java.util.List; +import java.util.stream.Collectors; + +import org.jabref.http.server.cayw.CAYWQueryParams; +import org.jabref.http.server.cayw.gui.CAYWEntry; +import org.jabref.model.entry.BibEntry; + +import org.jvnet.hk2.annotations.Service; + +@Service +public class BibLatexFormatter implements CAYWFormatter { + + @Override + public String getFormatName() { + return "biblatex"; + } + + @Override + public String format(CAYWQueryParams queryParams, List caywEntries) { + String command = queryParams.getCommand(); + + List bibEntries = caywEntries.stream() + .map(CAYWEntry::getBibEntry) + .toList(); + + return String.format("\\%s{%s}", command, + bibEntries.stream() + .map(entry -> entry.getCitationKey().orElse("")) + .collect(Collectors.joining(","))); + } +} diff --git a/jabsrv/src/main/java/org/jabref/http/server/cayw/format/CAYWFormatter.java b/jabsrv/src/main/java/org/jabref/http/server/cayw/format/CAYWFormatter.java new file mode 100644 index 00000000000..bd96dc657af --- /dev/null +++ b/jabsrv/src/main/java/org/jabref/http/server/cayw/format/CAYWFormatter.java @@ -0,0 +1,13 @@ +package org.jabref.http.server.cayw.format; + +import java.util.List; + +import org.jabref.http.server.cayw.CAYWQueryParams; +import org.jabref.http.server.cayw.gui.CAYWEntry; + +public interface CAYWFormatter { + + String getFormatName(); + + String format(CAYWQueryParams caywQueryParams, List caywEntries); +} diff --git a/jabsrv/src/main/java/org/jabref/http/server/cayw/format/FormatterService.java b/jabsrv/src/main/java/org/jabref/http/server/cayw/format/FormatterService.java new file mode 100644 index 00000000000..c014141242f --- /dev/null +++ b/jabsrv/src/main/java/org/jabref/http/server/cayw/format/FormatterService.java @@ -0,0 +1,31 @@ +package org.jabref.http.server.cayw.format; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.jabref.http.server.cayw.CAYWQueryParams; +import org.jabref.http.server.cayw.gui.CAYWEntry; + +import org.jvnet.hk2.annotations.Service; + +@Service +public class FormatterService { + + private final Map formatters; + + public FormatterService() { + this.formatters = new HashMap<>(); + registerFormatter(new SimpleJsonFormatter()); + registerFormatter(new BibLatexFormatter()); + } + + public void registerFormatter(CAYWFormatter formatter) { + formatters.putIfAbsent(formatter.getFormatName(), formatter); + } + + public String format(CAYWQueryParams queryParams, List caywEntries) throws IllegalArgumentException { + CAYWFormatter formatter = formatters.get(queryParams.getFormat().toLowerCase()); + return formatter.format(queryParams, caywEntries); + } +} diff --git a/jabsrv/src/main/java/org/jabref/http/server/cayw/format/SimpleJsonFormatter.java b/jabsrv/src/main/java/org/jabref/http/server/cayw/format/SimpleJsonFormatter.java new file mode 100644 index 00000000000..b4ac28e75b3 --- /dev/null +++ b/jabsrv/src/main/java/org/jabref/http/server/cayw/format/SimpleJsonFormatter.java @@ -0,0 +1,34 @@ +package org.jabref.http.server.cayw.format; + +import java.util.List; + +import org.jabref.http.dto.GsonFactory; +import org.jabref.http.dto.cayw.SimpleJson; +import org.jabref.http.server.cayw.CAYWQueryParams; +import org.jabref.http.server.cayw.gui.CAYWEntry; + +import com.google.gson.Gson; +import org.jvnet.hk2.annotations.Service; + +@Service +public class SimpleJsonFormatter implements CAYWFormatter { + + private final Gson gson; + + public SimpleJsonFormatter() { + this.gson = new GsonFactory().provide(); + } + + @Override + public String getFormatName() { + return "simple-json"; + } + + @Override + public String format(CAYWQueryParams queryParams, List caywEntries) { + List simpleJsons = caywEntries.stream() + .map(caywEntry -> SimpleJson.fromBibEntry(caywEntry.getBibEntry())) + .toList(); + return gson.toJson(simpleJsons); + } +} diff --git a/jabsrv/src/main/java/org/jabref/http/server/cayw/gui/CAYWEntry.java b/jabsrv/src/main/java/org/jabref/http/server/cayw/gui/CAYWEntry.java index 59e3a2b8942..32593961221 100644 --- a/jabsrv/src/main/java/org/jabref/http/server/cayw/gui/CAYWEntry.java +++ b/jabsrv/src/main/java/org/jabref/http/server/cayw/gui/CAYWEntry.java @@ -1,11 +1,15 @@ package org.jabref.http.server.cayw.gui; +import java.util.Objects; + import javafx.event.ActionEvent; import javafx.event.EventHandler; -public class CAYWEntry { +import org.jabref.model.entry.BibEntry; + +public class CAYWEntry { - private final T value; + private final BibEntry bibEntry; // Used on the buttons ("chips") private final String shortLabel; @@ -18,15 +22,15 @@ public class CAYWEntry { private EventHandler onClick; - public CAYWEntry(T value, String label, String shortLabel, String description) { - this.value = value; + public CAYWEntry(BibEntry bibEntry, String label, String shortLabel, String description) { + this.bibEntry = bibEntry; this.label = label; this.shortLabel = shortLabel; this.description = description; } - public T getValue() { - return value; + public BibEntry getBibEntry() { + return bibEntry; } public String getLabel() { @@ -48,4 +52,19 @@ public EventHandler getOnClick() { public void setOnClick(EventHandler onClick) { this.onClick = onClick; } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) { + return false; + } + + CAYWEntry caywEntry = (CAYWEntry) o; + return Objects.equals(getBibEntry(), caywEntry.getBibEntry()); + } + + @Override + public int hashCode() { + return Objects.hashCode(getBibEntry()); + } } diff --git a/jabsrv/src/main/java/org/jabref/http/server/cayw/gui/SearchDialog.java b/jabsrv/src/main/java/org/jabref/http/server/cayw/gui/SearchDialog.java index d4a48d3e06b..55207f92e15 100644 --- a/jabsrv/src/main/java/org/jabref/http/server/cayw/gui/SearchDialog.java +++ b/jabsrv/src/main/java/org/jabref/http/server/cayw/gui/SearchDialog.java @@ -26,7 +26,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class SearchDialog { +public class SearchDialog { public static final Logger LOGGER = LoggerFactory.getLogger(SearchDialog.class); @@ -34,12 +34,12 @@ public class SearchDialog { private static final double DIALOG_HEIGHT_RATIO = 0.4; private static final int PREF_HEIGHT = 150; - private final ObservableList> selectedItems = FXCollections.observableArrayList(); + private final ObservableList selectedItems = FXCollections.observableArrayList(); private Stage dialogStage; - public List show(Function> searchFunction, List> entries) { - FilteredList> searchResults = new FilteredList<>(FXCollections.observableArrayList(entries)); + public List show(Function> searchFunction, List entries) { + FilteredList searchResults = new FilteredList<>(FXCollections.observableArrayList(entries)); selectedItems.clear(); dialogStage = new Stage(); @@ -56,10 +56,10 @@ public List show(Function> searchFunction, List> mainLayout.setPadding(new Insets(15)); mainLayout.setAlignment(Pos.TOP_CENTER); - SearchField searchField = new SearchField<>(searchResults, searchFunction); + SearchField searchField = new SearchField(searchResults, searchFunction); searchField.setMaxWidth(Double.MAX_VALUE); - SearchResultContainer resultContainer = new SearchResultContainer<>(searchResults, selectedItems); + SearchResultContainer resultContainer = new SearchResultContainer(searchResults, selectedItems); resultContainer.setPrefHeight(PREF_HEIGHT); ScrollPane scrollPane = new ScrollPane(resultContainer); @@ -67,7 +67,7 @@ public List show(Function> searchFunction, List> scrollPane.setFitToHeight(true); VBox.setVgrow(scrollPane, Priority.ALWAYS); - SelectedItemsContainer selectedContainer = new SelectedItemsContainer<>(selectedItems); + SelectedItemsContainer selectedContainer = new SelectedItemsContainer(selectedItems); Button finishButton = new Button(Localization.lang("Cite")); finishButton.setOnAction(event -> { @@ -105,7 +105,7 @@ public List show(Function> searchFunction, List> dialogStage.showAndWait(); - return selectedItems.stream().map(CAYWEntry::getValue).toList(); + return selectedItems; } public void close() { diff --git a/jabsrv/src/main/java/org/jabref/http/server/cayw/gui/SearchField.java b/jabsrv/src/main/java/org/jabref/http/server/cayw/gui/SearchField.java index a442d124e84..09feed635f2 100644 --- a/jabsrv/src/main/java/org/jabref/http/server/cayw/gui/SearchField.java +++ b/jabsrv/src/main/java/org/jabref/http/server/cayw/gui/SearchField.java @@ -10,16 +10,16 @@ import javafx.scene.control.TextField; import javafx.util.Duration; -public class SearchField extends TextField { +public class SearchField extends TextField { private static final int DELAY_IN_MS = 100; - public SearchField(FilteredList> filteredEntries, Function> filter) { + public SearchField(FilteredList filteredEntries, Function> filter) { PauseTransition pause = new PauseTransition(Duration.millis(DELAY_IN_MS)); textProperty().addListener((_, _, newValue) -> { pause.setOnFinished(event -> { - Set currentEntries = new HashSet<>(filter.apply(newValue)); - filteredEntries.setPredicate(entry -> currentEntries.contains(entry.getValue())); + Set currentEntries = new HashSet<>(filter.apply(newValue)); + filteredEntries.setPredicate(currentEntries::contains); }); pause.playFromStart(); }); diff --git a/jabsrv/src/main/java/org/jabref/http/server/cayw/gui/SearchResultContainer.java b/jabsrv/src/main/java/org/jabref/http/server/cayw/gui/SearchResultContainer.java index 4826fa23c07..4b2b17b9ed5 100644 --- a/jabsrv/src/main/java/org/jabref/http/server/cayw/gui/SearchResultContainer.java +++ b/jabsrv/src/main/java/org/jabref/http/server/cayw/gui/SearchResultContainer.java @@ -13,16 +13,16 @@ import org.jabref.logic.os.OS; import org.jabref.model.strings.StringUtil; -public class SearchResultContainer extends ListView> { +public class SearchResultContainer extends ListView { private final static int MAX_LINES = 3; private final static int ESTIMATED_CHARS_PER_LINE = 80; private final static int TOOLTIP_WIDTH = 400; private final static double PREF_WIDTH = 300; - private ObservableList> selectedEntries = javafx.collections.FXCollections.observableArrayList(); + private ObservableList selectedEntries = javafx.collections.FXCollections.observableArrayList(); - public SearchResultContainer(ObservableList> entries, ObservableList> selectedEntries) { + public SearchResultContainer(ObservableList entries, ObservableList selectedEntries) { super(entries); this.selectedEntries = selectedEntries; setup(); @@ -30,7 +30,7 @@ public SearchResultContainer(ObservableList> entries, ObservableLis private void setup() { this.setCellFactory(listView -> { - SearchResultCell searchResultCell = new SearchResultCell(); + SearchResultCell searchResultCell = new SearchResultCell(); searchResultCell.setOnMouseClicked(event -> { if (searchResultCell.getItem() == null || selectedEntries.contains(searchResultCell.getItem())) { return; @@ -50,7 +50,7 @@ private void setup() { }, parentProperty())); } - private static class SearchResultCell extends ListCell> { + private static class SearchResultCell extends ListCell { private final VBox content; private final Text labelText; private final Text descriptionText; @@ -74,7 +74,7 @@ public SearchResultCell() { } @Override - protected void updateItem(CAYWEntry item, boolean empty) { + protected void updateItem(CAYWEntry item, boolean empty) { super.updateItem(item, empty); if (empty || item == null) { diff --git a/jabsrv/src/main/java/org/jabref/http/server/cayw/gui/SelectedItemsContainer.java b/jabsrv/src/main/java/org/jabref/http/server/cayw/gui/SelectedItemsContainer.java index ea8f71271aa..e36724d2918 100644 --- a/jabsrv/src/main/java/org/jabref/http/server/cayw/gui/SelectedItemsContainer.java +++ b/jabsrv/src/main/java/org/jabref/http/server/cayw/gui/SelectedItemsContainer.java @@ -10,11 +10,11 @@ import javafx.scene.layout.FlowPane; import javafx.scene.layout.HBox; -public class SelectedItemsContainer extends FlowPane { +public class SelectedItemsContainer extends FlowPane { - private final ObservableList> items; + private final ObservableList items; - public SelectedItemsContainer(ObservableList> items) { + public SelectedItemsContainer(ObservableList items) { this.items = items; setup(); } @@ -26,7 +26,7 @@ private void setup() { items.forEach(this::addChip); - items.addListener((ListChangeListener>) change -> { + items.addListener((ListChangeListener) change -> { while (change.next()) { if (change.wasAdded()) { change.getAddedSubList().forEach(this::addChip); @@ -38,24 +38,24 @@ private void setup() { }); } - private void addChip(CAYWEntry entry) { - Chip chip = new Chip<>(entry, items); + private void addChip(CAYWEntry entry) { + Chip chip = new Chip(entry, items); getChildren().add(chip); } - private void removeChip(CAYWEntry entry) { + private void removeChip(CAYWEntry entry) { getChildren().removeIf(node -> { - if (node instanceof SelectedItemsContainer.Chip chip) { + if (node instanceof SelectedItemsContainer.Chip chip) { return chip.getEntry().equals(entry); } return false; }); } - private static class Chip extends HBox { - private final CAYWEntry entry; + private static class Chip extends HBox { + private final CAYWEntry entry; - public Chip(CAYWEntry entry, ObservableList> parentList) { + public Chip(CAYWEntry entry, ObservableList parentList) { this.entry = entry; this.setAlignment(Pos.CENTER_LEFT); @@ -83,7 +83,7 @@ public Chip(CAYWEntry entry, ObservableList> parentList) { }); } - public CAYWEntry getEntry() { + public CAYWEntry getEntry() { return entry; } } diff --git a/jabsrv/src/test/cayw.http b/jabsrv/src/test/cayw.http index 477ccee1ab6..b4cf112fe60 100644 --- a/jabsrv/src/test/cayw.http +++ b/jabsrv/src/test/cayw.http @@ -1,7 +1,23 @@ -#### Serve chocolate.bib +#### Serve the latest opened library GET http://localhost:23119/better-bibtex/cayw -#### Serve a library specified using the URL param +#### Serve a demo library specified by the URL param -GET http://localhost:6050/better-bibtex/cayw?librarypath=C%3A%5CUsers%5CDEMO%5CDownloads%5CChocolate.bib +GET http://localhost:23119/better-bibtex/cayw?librarypath=demo + +#### Use simple-json format for the response + +GET http://localhost:23119/better-bibtex/cayw?librarypath=demo&format=simple-json + +#### Use biblatex format for the response + +GET http://localhost:23119/better-bibtex/cayw?librarypath=demo&format=biblatex + +#### Use biblatex format with a custom command for the response + +GET http://localhost:23119/better-bibtex/cayw?librarypath=demo&format=biblatex&command=cite + +#### Serve a library specified by its path using the URL param + +GET http://localhost:23119/better-bibtex/cayw?librarypath=C%3A%5CUsers%5CDEMO%5CDownloads%5CChocolate.bib \ No newline at end of file