diff --git a/CHANGELOG.md b/CHANGELOG.md
index bca01e2d50f..c461952c966 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -53,6 +53,7 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `#
- For automatically created groups, added ability to filter groups by entry type. [#4539](https://github.com/JabRef/jabref/issues/4539)
- We added the ability to add field names from the Preferences Dialog [#4546](https://github.com/JabRef/jabref/issues/4546)
- We added the ability change the column widths directly in the main table. [#4546](https://github.com/JabRef/jabref/issues/4546)
+- We added description of how recommendations where chosen and better error handling to Related Articles tab
- We added the ability to execute default action in dialog by using with Ctrl + Enter combination [#4496](https://github.com/JabRef/jabref/issues/4496)
- We grouped and reordered the Main Menu (File, Edit, Library, Quality, Tools, and View tabs & icons). [#4666](https://github.com/JabRef/jabref/issues/4666) [#4667](https://github.com/JabRef/jabref/issues/4667) [#4668](https://github.com/JabRef/jabref/issues/4668) [#4669](https://github.com/JabRef/jabref/issues/4669) [#4670](https://github.com/JabRef/jabref/issues/4670) [#4671](https://github.com/JabRef/jabref/issues/4671) [#4672](https://github.com/JabRef/jabref/issues/4672) [#4673](https://github.com/JabRef/jabref/issues/4673)
- We added additional modifiers (capitalize, titlecase and sentencecase) to the Bibtex key generator. [#1506](https://github.com/JabRef/jabref/issues/1506)
diff --git a/src/main/java/org/jabref/gui/entryeditor/EntryEditor.css b/src/main/java/org/jabref/gui/entryeditor/EntryEditor.css
index 5d7c406cb2f..799644a9839 100644
--- a/src/main/java/org/jabref/gui/entryeditor/EntryEditor.css
+++ b/src/main/java/org/jabref/gui/entryeditor/EntryEditor.css
@@ -102,10 +102,23 @@
-fx-padding: 20 20 20 20;
}
+.recommendation-heading {
+ -fx-font-size: 14pt;
+ -fx-font-weight: bold;
+}
+
+.recommendation-description {
+ -fx-font-style: italic;
+}
+
+.recommendation-item {
+ -fx-padding: 0 0 0 20;
+}
+
#bibtexSourceCodeArea .search {
-fx-fill: red;
}
.bibtexSourceCodeArea .text {
-fx-fill: -fx-text-background-color;
-}
\ No newline at end of file
+}
diff --git a/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java b/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java
index 72fdf53f104..b7a875655e8 100644
--- a/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java
+++ b/src/main/java/org/jabref/gui/entryeditor/EntryEditor.java
@@ -284,7 +284,7 @@ private List createTabs() {
// Special tabs
tabs.add(new MathSciNetTab());
tabs.add(new FileAnnotationTab(panel.getAnnotationCache()));
- tabs.add(new RelatedArticlesTab(preferences, dialogService));
+ tabs.add(new RelatedArticlesTab(this, preferences, dialogService));
// Source tab
sourceTab = new SourceTab(databaseContext, undoManager, preferences.getLatexFieldFormatterPreferences(), preferences.getImportFormatPreferences(), fileMonitor, dialogService, stateManager);
diff --git a/src/main/java/org/jabref/gui/entryeditor/RelatedArticlesTab.java b/src/main/java/org/jabref/gui/entryeditor/RelatedArticlesTab.java
index 4bd30b7c614..0fbb3d2e08d 100644
--- a/src/main/java/org/jabref/gui/entryeditor/RelatedArticlesTab.java
+++ b/src/main/java/org/jabref/gui/entryeditor/RelatedArticlesTab.java
@@ -36,11 +36,13 @@ public class RelatedArticlesTab extends EntryEditorTab {
private static final Logger LOGGER = LoggerFactory.getLogger(RelatedArticlesTab.class);
private final EntryEditorPreferences preferences;
+ private final EntryEditor entryEditor;
private final DialogService dialogService;
- public RelatedArticlesTab(EntryEditorPreferences preferences, DialogService dialogService) {
+ public RelatedArticlesTab(EntryEditor entryEditor, EntryEditorPreferences preferences, DialogService dialogService) {
setText(Localization.lang("Related articles"));
setTooltip(new Tooltip(Localization.lang("Related articles")));
+ this.entryEditor = entryEditor;
this.preferences = preferences;
this.dialogService = dialogService;
}
@@ -63,7 +65,12 @@ private StackPane getRelatedArticlesPane(BibEntry entry) {
.onRunning(() -> progress.setVisible(true))
.onSuccess(relatedArticles -> {
progress.setVisible(false);
- root.getChildren().add(getRelatedArticleInfo(relatedArticles));
+ root.getChildren().add(getRelatedArticleInfo(relatedArticles, fetcher));
+ })
+ .onFailure(exception -> {
+ LOGGER.error("Error while fetching from Mr. DLib", exception);
+ progress.setVisible(false);
+ root.getChildren().add(getErrorInfo());
})
.executeWith(Globals.TASK_EXECUTOR);
@@ -77,13 +84,25 @@ private StackPane getRelatedArticlesPane(BibEntry entry) {
* @param list List of BibEntries of related articles
* @return VBox of related article descriptions to be displayed in the Related Articles tab
*/
- private VBox getRelatedArticleInfo(List list) {
+ private ScrollPane getRelatedArticleInfo(List list, MrDLibFetcher fetcher) {
+ ScrollPane scrollPane = new ScrollPane();
+
VBox vBox = new VBox();
vBox.setSpacing(20.0);
+ String heading = fetcher.getHeading();
+ Text headingText = new Text(heading);
+ headingText.getStyleClass().add("recommendation-heading");
+ String description = fetcher.getDescription();
+ Text descriptionText = new Text(description);
+ descriptionText.getStyleClass().add("recommendation-description");
+ vBox.getChildren().add(headingText);
+ vBox.getChildren().add(descriptionText);
+
for (BibEntry entry : list) {
HBox hBox = new HBox();
hBox.setSpacing(5.0);
+ hBox.getStyleClass().add("recommendation-item");
String title = entry.getTitle().orElse("");
String journal = entry.getField(FieldName.JOURNAL).orElse("");
@@ -109,7 +128,26 @@ private VBox getRelatedArticleInfo(List list) {
hBox.getChildren().addAll(titleLink, journalText, authorsText, yearText);
vBox.getChildren().add(hBox);
}
- return vBox;
+ scrollPane.setContent(vBox);
+ return scrollPane;
+ }
+
+ /**
+ * Gets a ScrollPane to display error info when recommendations fail.
+ * @return ScrollPane to display in place of recommendations
+ */
+ private ScrollPane getErrorInfo() {
+ ScrollPane scrollPane = new ScrollPane();
+
+ VBox vBox = new VBox();
+ vBox.setSpacing(20.0);
+
+ Text descriptionText = new Text(Localization.lang("No recommendations received from Mr. DLib for this entry."));
+ descriptionText.getStyleClass().add("recommendation-description");
+ vBox.getChildren().add(descriptionText);
+ scrollPane.setContent(vBox);
+
+ return scrollPane;
}
/**
diff --git a/src/main/java/org/jabref/logic/importer/fetcher/MrDLibFetcher.java b/src/main/java/org/jabref/logic/importer/fetcher/MrDLibFetcher.java
index 0e3e30898bd..f09f032cfbb 100644
--- a/src/main/java/org/jabref/logic/importer/fetcher/MrDLibFetcher.java
+++ b/src/main/java/org/jabref/logic/importer/fetcher/MrDLibFetcher.java
@@ -12,6 +12,7 @@
import org.jabref.logic.importer.FetcherException;
import org.jabref.logic.importer.ParserResult;
import org.jabref.logic.importer.fileformat.MrDLibImporter;
+import org.jabref.logic.l10n.Localization;
import org.jabref.logic.net.URLDownload;
import org.jabref.logic.util.Version;
import org.jabref.model.database.BibDatabase;
@@ -30,8 +31,13 @@ public class MrDLibFetcher implements EntryBasedFetcher {
private static final Logger LOGGER = LoggerFactory.getLogger(MrDLibFetcher.class);
private static final String NAME = "MDL_FETCHER";
private static final String MDL_JABREF_PARTNER_ID = "1";
+ private static final String MDL_URL = "api.mr-dlib.org";
+ private static final String DEFAULT_MRDLIB_ERROR_MESSAGE = Localization.lang("Error while fetching recommendations from Mr.DLib.");
private final String LANGUAGE;
private final Version VERSION;
+ private String heading;
+ private String description;
+ private String recommendationSetId;
public MrDLibFetcher(String language, Version version) {
@@ -54,13 +60,13 @@ public List performSearch(BibEntry entry) throws FetcherException {
try {
if (importer.isRecognizedFormat(response)) {
parserResult = importer.importDatabase(response);
+ heading = importer.getRecommendationsHeading();
+ description = importer.getRecommendationsDescription();
+ recommendationSetId = importer.getRecommendationSetId();
} else {
// For displaying An ErrorMessage
- String error = importer.getResponseErrorMessage(response);
- BibEntry errorBibEntry = new BibEntry();
- errorBibEntry.setField("html_representation", error);
+ description = DEFAULT_MRDLIB_ERROR_MESSAGE;
BibDatabase errorBibDataBase = new BibDatabase();
- errorBibDataBase.insertEntry(errorBibEntry);
parserResult = new ParserResult(errorBibDataBase);
}
} catch (IOException e) {
@@ -74,6 +80,14 @@ public List performSearch(BibEntry entry) throws FetcherException {
}
}
+ public String getHeading() {
+ return heading;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
/**
* Contact the server with the title of the selected item
*
@@ -106,7 +120,7 @@ private String constructQuery(String queryWithTitle) {
queryWithTitle = queryWithTitle.replaceAll("/", " ");
URIBuilder builder = new URIBuilder();
builder.setScheme("http");
- builder.setHost(getMdlUrl());
+ builder.setHost(MDL_URL);
builder.setPath("/v2/documents/" + queryWithTitle + "/related_documents");
builder.addParameter("partner_id", MDL_JABREF_PARTNER_ID);
builder.addParameter("app_id", "jabref_desktop");
@@ -132,8 +146,4 @@ private String constructQuery(String queryWithTitle) {
}
return "";
}
-
- private String getMdlUrl() {
- return VERSION.isDevelopmentVersion() ? "api-dev.darwingoliath.com" : "api.mr-dlib.org";
- }
}
diff --git a/src/main/java/org/jabref/logic/importer/fileformat/MrDLibImporter.java b/src/main/java/org/jabref/logic/importer/fileformat/MrDLibImporter.java
index 5bc8af04b8c..b71f5eabf2c 100644
--- a/src/main/java/org/jabref/logic/importer/fileformat/MrDLibImporter.java
+++ b/src/main/java/org/jabref/logic/importer/fileformat/MrDLibImporter.java
@@ -12,13 +12,11 @@
import org.jabref.logic.importer.Importer;
import org.jabref.logic.importer.ParserResult;
-import org.jabref.logic.l10n.Localization;
import org.jabref.logic.util.StandardFileType;
import org.jabref.model.database.BibDatabase;
import org.jabref.model.entry.BibEntry;
import org.jabref.model.entry.FieldName;
-import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
@@ -29,9 +27,11 @@
*/
public class MrDLibImporter extends Importer {
- private static final String DEFAULT_MRDLIB_ERROR_MESSAGE = Localization.lang("Error while fetching from Mr.DLib.");
private static final Logger LOGGER = LoggerFactory.getLogger(MrDLibImporter.class);
public ParserResult parserResult;
+ private String recommendationsHeading;
+ private String recommendationsDescription;
+ private String recommendationSetId;
@SuppressWarnings("unused")
@Override
@@ -111,12 +111,13 @@ private void parse(BufferedReader input) throws IOException {
// The Bibdatabase that gets returned in the ParserResult.
BibDatabase bibDatabase = new BibDatabase();
// The document to parse
- String recommendations = convertToString(input);
+ String recommendationSet = convertToString(input);
+ JSONObject recommendationSetJson = new JSONObject(recommendationSet);
// The sorted BibEntries gets stored here later
List rankedBibEntries = new ArrayList<>();
// Get recommendations from response and populate bib entries
- JSONObject recommendationsJson = new JSONObject(recommendations).getJSONObject("recommendations");
+ JSONObject recommendationsJson = recommendationSetJson.getJSONObject("recommendations");
Iterator keys = recommendationsJson.keys();
while (keys.hasNext()) {
String key = keys.next();
@@ -133,6 +134,11 @@ private void parse(BufferedReader input) throws IOException {
bibDatabase.insertEntry(bibentry);
}
parserResult = new ParserResult(bibDatabase);
+
+ JSONObject label = recommendationSetJson.getJSONObject("label");
+ recommendationsHeading = label.getString("label-text");
+ recommendationsDescription = label.getString("label-description");
+ recommendationSetId = recommendationSetJson.getBigInteger("recommendation_set_id").toString();
}
/**
@@ -144,7 +150,7 @@ private RankedBibEntry populateBibEntry(JSONObject recommendation) {
BibEntry current = new BibEntry();
// parse each of the relevant fields into variables
- String authors = isRecommendationFieldPresent(recommendation, "authors") ? getAuthorsString(recommendation) : "";
+ String authors = isRecommendationFieldPresent(recommendation, "authors") ? recommendation.getString("authors") : "";
String title = isRecommendationFieldPresent(recommendation, "title") ? recommendation.getString("title") : "";
String year = isRecommendationFieldPresent(recommendation, "published_year") ? Integer.toString(recommendation.getInt("published_year")) : "";
String journal = isRecommendationFieldPresent(recommendation, "published_in") ? recommendation.getString("published_in") : "";
@@ -165,43 +171,20 @@ private Boolean isRecommendationFieldPresent(JSONObject recommendation, String f
return recommendation.has(field) && !recommendation.isNull(field);
}
- /**
- * Creates an authors string from a JSON recommendation
- * @param recommendation JSON Object recommendation from Mr. DLib
- * @return A string of all authors, separated by commas and finished with a full stop.
- */
- private String getAuthorsString(JSONObject recommendation) {
- String authorsString = "";
- JSONArray array = recommendation.getJSONArray("authors");
- for (int i = 0; i < array.length(); ++i) {
- authorsString += array.getString(i) + "; ";
- }
- int stringLength = authorsString.length();
- if (stringLength > 2) {
- authorsString = authorsString.substring(0, stringLength - 2) + ".";
- }
- return authorsString;
- }
-
public ParserResult getParserResult() {
return parserResult;
}
- /**
- * Gets the error message to be returned if there has been an error in returning recommendations.
- * Returns default error message if there is no message from Mr. DLib.
- * @param response The response from the MDL server as a string.
- * @return String error message to be shown to the user.
- */
- public String getResponseErrorMessage(String response) {
- try {
- JSONObject jsonObject = new JSONObject(response);
- if (!jsonObject.has("message")) {
- return jsonObject.getString("message");
- }
- } catch (JSONException ex) {
- return DEFAULT_MRDLIB_ERROR_MESSAGE;
- }
- return DEFAULT_MRDLIB_ERROR_MESSAGE;
+ public String getRecommendationsHeading() {
+ return recommendationsHeading;
}
+
+ public String getRecommendationsDescription() {
+ return recommendationsDescription;
+ }
+
+ public String getRecommendationSetId() {
+ return recommendationSetId;
+ }
+
}
diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties
index bae2e82011d..20ed0a4cd14 100644
--- a/src/main/resources/l10n/JabRef_en.properties
+++ b/src/main/resources/l10n/JabRef_en.properties
@@ -334,8 +334,6 @@ Error\ occurred\ when\ parsing\ entry=Error occurred when parsing entry
Error\ opening\ file=Error opening file
-Error\ while\ fetching\ from\ Mr.DLib.=Error while fetching from Mr.DLib.
-
Error\ while\ writing=Error while writing
'%0'\ exists.\ Overwrite\ file?='%0' exists. Overwrite file?
@@ -570,6 +568,10 @@ Move\ up=Move up
Moved\ group\ "%0".=Moved group "%0".
+No\ recommendations\ received\ from\ Mr.\ DLib\ for\ this\ entry.=No recommendations received from Mr. DLib for this entry.
+
+Error\ while\ fetching\ recommendations\ from\ Mr.DLib.=Error while fetching recommendations from Mr.DLib.
+
Name=Name
Name\ formatter=Name formatter
diff --git a/src/test/java/org/jabref/logic/importer/fileformat/MrDLibImporterTest.java b/src/test/java/org/jabref/logic/importer/fileformat/MrDLibImporterTest.java
index 723afd1b6fc..246bee9e3cf 100644
--- a/src/test/java/org/jabref/logic/importer/fileformat/MrDLibImporterTest.java
+++ b/src/test/java/org/jabref/logic/importer/fileformat/MrDLibImporterTest.java
@@ -24,7 +24,7 @@ public class MrDLibImporterTest {
@BeforeEach
public void setUp() {
importer = new MrDLibImporter();
- String testInput = "{ \"label\": { \"label-language\": \"en\", \"label-text\": \"Related Items\" }, \"recommendation-set-id\": \"1\", \"recommendations\": { \"74021358\": { \"abstract\": \"abstract\", \"authors\": [ \"Sajovic, Marija\" ], \"published_year\": \"2006\", \"item_id_original\": \"12088644\", \"keywords\": [ \"visoko\\u0161olski program Geodezija - smer Prostorska informatika\" ], \"language_provided\": \"sl\", \"recommendation_id\": \"1\", \"title\": \"The protection of rural lands with the spatial development strategy on the case of Hrastnik commune\", \"url\": \"http://drugg.fgg.uni-lj.si/701/1/GEV_0199_Sajovic.pdf\" }, \"82005804\": { \"abstract\": \"abstract\", \"year_published\": null, \"item_id_original\": \"30145702\", \"language_provided\": null, \"recommendation_id\": \"2\", \"title\": \"Engagement of the volunteers in the solution to the accidents in the South-Moravia region\" }, \"82149599\": { \"abstract\": \"abstract\", \"year_published\": null, \"item_id_original\": \"97690763\", \"language_provided\": null, \"recommendation_id\": \"3\", \"title\": \"\\\"The only Father's word\\\". The relationship of the Father and the Son in the documents of saint John of the Cross\", \"url\": \"http://www.nusl.cz/ntk/nusl-285711\" }, \"84863921\": { \"abstract\": \"abstract\", \"authors\": [ \"Kaffa, Elena\" ], \"year_published\": null, \"item_id_original\": \"19397104\", \"keywords\": [ \"BX\", \"D111\" ], \"language_provided\": \"en\", \"recommendation_id\": \"4\", \"title\": \"Greek Church of Cyprus, the Morea and Constantinople during the Frankish Era (1196-1303)\" }, \"88950992\": { \"abstract\": \"abstract\", \"authors\": [ \"Yasui, Kono\" ], \"year_published\": null, \"item_id_original\": \"38763657\", \"language_provided\": null, \"recommendation_id\": \"5\", \"title\": \"A Phylogenetic Consideration on the Vascular Plants, Cotyledonary Node Including Hypocotyl Being Taken as the Ancestral Form : A Preliminary Note\" } }}";
+ String testInput = "{\"label\": {\"label-description\": \"The following articles are similar to the document have currently selected.\", \"label-language\": \"en\", \"label-text\": \"Related Articles\"}, \"recommendation_set_id\": \"1\", \"recommendations\": { \"74021358\": { \"abstract\": \"abstract\", \"authors\":\"Sajovic, Marija\", \"published_year\": \"2006\", \"item_id_original\": \"12088644\", \"keywords\": [ \"visoko\\u0161olski program Geodezija - smer Prostorska informatika\" ], \"language_provided\": \"sl\", \"recommendation_id\": \"1\", \"title\": \"The protection of rural lands with the spatial development strategy on the case of Hrastnik commune\", \"url\": \"http://drugg.fgg.uni-lj.si/701/1/GEV_0199_Sajovic.pdf\" }, \"82005804\": { \"abstract\": \"abstract\", \"year_published\": null, \"item_id_original\": \"30145702\", \"language_provided\": null, \"recommendation_id\": \"2\", \"title\": \"Engagement of the volunteers in the solution to the accidents in the South-Moravia region\" }, \"82149599\": { \"abstract\": \"abstract\", \"year_published\": null, \"item_id_original\": \"97690763\", \"language_provided\": null, \"recommendation_id\": \"3\", \"title\": \"\\\"The only Father's word\\\". The relationship of the Father and the Son in the documents of saint John of the Cross\", \"url\": \"http://www.nusl.cz/ntk/nusl-285711\" }, \"84863921\": { \"abstract\": \"abstract\", \"authors\":\"Kaffa, Elena\", \"year_published\": null, \"item_id_original\": \"19397104\", \"keywords\": [ \"BX\", \"D111\" ], \"language_provided\": \"en\", \"recommendation_id\": \"4\", \"title\": \"Greek Church of Cyprus, the Morea and Constantinople during the Frankish Era (1196-1303)\" }, \"88950992\": { \"abstract\": \"abstract\", \"authors\":\"Yasui, Kono\", \"year_published\": null, \"item_id_original\": \"38763657\", \"language_provided\": null, \"recommendation_id\": \"5\", \"title\": \"A Phylogenetic Consideration on the Vascular Plants, Cotyledonary Node Including Hypocotyl Being Taken as the Ancestral Form : A Preliminary Note\" } }}";
input = new BufferedReader(new StringReader(testInput));
}