From 4172fcdbcb83b0aedb836598463cc405b56e28c7 Mon Sep 17 00:00:00 2001 From: dimitra-karadima Date: Sun, 29 Mar 2020 17:41:30 +0300 Subject: [PATCH 01/25] Add tooltips for all entry types for #6074 Change: Add tooltips in the "Select entry type" dialog. You can see the tooltip when hovering a button of an entry type. --- .../java/org/jabref/gui/EntryTypeView.java | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/src/main/java/org/jabref/gui/EntryTypeView.java b/src/main/java/org/jabref/gui/EntryTypeView.java index d7d45501a8e..d9aa1b66b67 100644 --- a/src/main/java/org/jabref/gui/EntryTypeView.java +++ b/src/main/java/org/jabref/gui/EntryTypeView.java @@ -12,6 +12,7 @@ import javafx.scene.control.ComboBox; import javafx.scene.control.TextField; import javafx.scene.control.TitledPane; +import javafx.scene.control.Tooltip; import javafx.scene.layout.FlowPane; import org.jabref.Globals; @@ -26,6 +27,8 @@ import org.jabref.model.entry.types.BibtexEntryTypeDefinitions; import org.jabref.model.entry.types.EntryType; import org.jabref.model.entry.types.IEEETranEntryTypeDefinitions; +import org.jabref.model.entry.types.StandardEntryType; +import org.jabref.model.strings.StringUtil; import org.jabref.preferences.JabRefPreferences; import com.airhacks.afterburner.views.ViewLoader; @@ -92,6 +95,13 @@ private void addEntriesToPane(FlowPane pane, Collection entryButton.setUserData(entryType); entryButton.setOnAction(event -> setEntryTypeForReturnAndClose(Optional.of(entryType))); pane.getChildren().add(entryButton); + + String description = getDescription(entryType); + if (StringUtil.isNotBlank(description)) { + Tooltip tooltip = new Tooltip(); + tooltip.setText(description); + entryButton.setTooltip(tooltip); + } } } @@ -168,4 +178,82 @@ private void setEntryTypeForReturnAndClose(Optional entryType) { viewModel.stopFetching(); this.close(); } + + public String getDescription(BibEntryType selectedType) { + EntryType entryType = selectedType.getType(); + try { + StandardEntryType entry = (StandardEntryType) entryType; + switch (entry) { + case Article: + return Localization.lang("An article from a journal or magazine."); + case Book: + return Localization.lang("A book with an explicit publisher."); + case Booklet: + return Localization.lang("A work that is printed and bound, but without a named publisher orsponsoring institution."); + case Collection: + return Localization.lang("A single-volume collection with multiple, self-contained contributions by distinct authors which have their own title. The work as a whole has no overall author but it will usually have an editor."); + case Conference: + return Localization.lang("The same as Inproceedings, included for Scribe compatibility."); + case InBook: + return Localization.lang("A part of a book, which may be a chapter(or section or whatever) and/or a range of pages."); + case InCollection: + return Localization.lang("A part of a book having its own title."); + case InProceedings: + return Localization.lang("An article in a conference proceedings."); + case Manual: + return Localization.lang("Technical documentation."); + case MastersThesis: + return Localization.lang("A Master’s thesis."); + case Misc: + return Localization.lang("Use this type when nothing else fits"); + case PhdThesis: + return Localization.lang("A PhD thesis."); + case Proceedings: + return Localization.lang("The proceedings of a conference."); + case TechReport: + return Localization.lang("A report published by a school or other institution, usually numbered within a series."); + case Unpublished: + return Localization.lang("A document having an author and title, but not formally published."); + case BookInBook: + return Localization.lang("This type is similar to inbook but intended for works originally published as astand-alone book."); + case InReference: + return Localization.lang("An article in a work of reference."); + case MvBook: + return Localization.lang("A multi-volume book."); + case MvCollection: + return Localization.lang("A multi-volume collection."); + case MvProceedings: + return Localization.lang("A multi-volume proceedings entry."); + case MvReference: + return Localization.lang("A multi-volume reference entry. The standard styles will treat this entry typeas an alias for mvcollection."); + case Online: + return Localization.lang("This entry type is intended for sources such as web sites which are intrinsically online resources."); + case Reference: + return Localization.lang("A single-volume work of reference such as an encyclopedia or a dictionary."); + case Report: + return Localization.lang("A technical report, research report, or white paper published by a university or someother institution."); + case Set: + return Localization.lang("An entry set is a group of entries which are cited as a single reference and listed as a single item in the bibliography."); + case SuppBook: + return Localization.lang("Supplemental material in a book. This type is provided for elements such as prefaces, introductions, forewords, afterwords, etc. which often have a generic title only."); + case SuppCollection: + return Localization.lang("Supplemental material in a collection."); + case SuppPeriodical: + return Localization.lang("Supplemental material in a periodical. This type may be useful when referring to items such as regular columns, obituaries, letters to the editor, etc. which only have a generic title."); + case Thesis: + return Localization.lang("A thesis written for an educational institution to satisfy the requirements for a degree."); + case WWW: + return Localization.lang("An alias for online, provided for jurabib compatibility."); + case Software: + return Localization.lang("Computer software. The standard styles will treat this entry type as an alias for misc."); + case DATESET: + return Localization.lang("A data set or a similar collection of (mostly) raw data."); + } + return ""; + } catch (Exception e) { + return ""; + } + + } + } From 073a60cd8d8b83d2bad236f53c5d082ed4e891be Mon Sep 17 00:00:00 2001 From: dimitra-karadima Date: Mon, 30 Mar 2020 20:31:17 +0300 Subject: [PATCH 02/25] Change the tooltips' description for #6074 Add the following changes: -tooltips' description comes from biblatex documentation -comment about the biblatex manual -description to the english localization file --- .../java/org/jabref/gui/EntryTypeView.java | 137 +++++++++++------- src/main/resources/l10n/JabRef_en.properties | 33 +++++ 2 files changed, 120 insertions(+), 50 deletions(-) diff --git a/src/main/java/org/jabref/gui/EntryTypeView.java b/src/main/java/org/jabref/gui/EntryTypeView.java index d9aa1b66b67..5bc6aea6c82 100644 --- a/src/main/java/org/jabref/gui/EntryTypeView.java +++ b/src/main/java/org/jabref/gui/EntryTypeView.java @@ -179,77 +179,114 @@ private void setEntryTypeForReturnAndClose(Optional entryType) { this.close(); } + //The description is coming from biblatex manual chapter 2 + //Biblatex documentation is favored over the bibtex, + //since bibtex is a subset of biblatex and biblatex is better documented. public String getDescription(BibEntryType selectedType) { EntryType entryType = selectedType.getType(); try { StandardEntryType entry = (StandardEntryType) entryType; switch (entry) { - case Article: - return Localization.lang("An article from a journal or magazine."); - case Book: - return Localization.lang("A book with an explicit publisher."); - case Booklet: - return Localization.lang("A work that is printed and bound, but without a named publisher orsponsoring institution."); - case Collection: + case Article -> { + return Localization.lang("An article in a journal, magazine, newspaper, or other periodical which forms a self-contained unit with its own title."); + } + case Book -> { + return Localization.lang("A single-volume book with one or more authors where the authors share credit for the work as a whole."); + } + case Booklet -> { + return Localization.lang("A book-like work without a formal publisher or sponsoring institution."); + } + case Collection -> { return Localization.lang("A single-volume collection with multiple, self-contained contributions by distinct authors which have their own title. The work as a whole has no overall author but it will usually have an editor."); - case Conference: - return Localization.lang("The same as Inproceedings, included for Scribe compatibility."); - case InBook: - return Localization.lang("A part of a book, which may be a chapter(or section or whatever) and/or a range of pages."); - case InCollection: - return Localization.lang("A part of a book having its own title."); - case InProceedings: + } + case Conference -> { + return Localization.lang("A legacy alias for inproceedings."); + } + case InBook -> { + return Localization.lang("A part of a book which forms a self-contained unit with its own title."); + } + case InCollection -> { + return Localization.lang("A contribution to a collection which forms a self-contained unit with a distinct author and title."); + } + case InProceedings -> { return Localization.lang("An article in a conference proceedings."); - case Manual: - return Localization.lang("Technical documentation."); - case MastersThesis: - return Localization.lang("A Master’s thesis."); - case Misc: - return Localization.lang("Use this type when nothing else fits"); - case PhdThesis: - return Localization.lang("A PhD thesis."); - case Proceedings: - return Localization.lang("The proceedings of a conference."); - case TechReport: - return Localization.lang("A report published by a school or other institution, usually numbered within a series."); - case Unpublished: - return Localization.lang("A document having an author and title, but not formally published."); - case BookInBook: - return Localization.lang("This type is similar to inbook but intended for works originally published as astand-alone book."); - case InReference: - return Localization.lang("An article in a work of reference."); - case MvBook: + } + case Manual -> { + return Localization.lang("Technical or other documentation, not necessarily in printed form."); + } + case MastersThesis -> { + return Localization.lang("Similar to thesis except that the type field is optional and defaults to the localised term Master's thesis."); + } + case Misc -> { + return Localization.lang("A fallback type for entries which do not fit into any other category."); + } + case PhdThesis -> { + return Localization.lang("Similar to thesis except that the type field is optional and defaults to the localised term PhD thesis."); + } + case Proceedings -> { + return Localization.lang("A single-volume conference proceedings. This type is very similar to collection."); + } + case TechReport -> { + return Localization.lang("Similar to report except that the type field is optional and defaults to the localised term technical report."); + } + case Unpublished -> { + return Localization.lang("A work with an author and a title which has not been formally published, such as a manuscript or the script of a talk."); + } + case BookInBook -> { + return Localization.lang("This type is similar to inbook but intended for works originally published as a stand-alone book."); + } + case InReference -> { + return Localization.lang("An article in a work of reference. This is a more specific variant of the generic incollection entry type."); + } + case MvBook -> { return Localization.lang("A multi-volume book."); - case MvCollection: + } + case MvCollection -> { return Localization.lang("A multi-volume collection."); - case MvProceedings: + } + case MvProceedings -> { return Localization.lang("A multi-volume proceedings entry."); - case MvReference: - return Localization.lang("A multi-volume reference entry. The standard styles will treat this entry typeas an alias for mvcollection."); - case Online: + } + case MvReference -> { + return Localization.lang("A multi-volume reference entry. The standard styles will treat this entry type as an alias for mvcollection."); + } + case Online -> { return Localization.lang("This entry type is intended for sources such as web sites which are intrinsically online resources."); - case Reference: + } + case Reference -> { return Localization.lang("A single-volume work of reference such as an encyclopedia or a dictionary."); - case Report: - return Localization.lang("A technical report, research report, or white paper published by a university or someother institution."); - case Set: + } + case Report -> { + return Localization.lang("A technical report, research report, or white paper published by a university or some other institution."); + } + case Set -> { return Localization.lang("An entry set is a group of entries which are cited as a single reference and listed as a single item in the bibliography."); - case SuppBook: + } + case SuppBook -> { return Localization.lang("Supplemental material in a book. This type is provided for elements such as prefaces, introductions, forewords, afterwords, etc. which often have a generic title only."); - case SuppCollection: + } + case SuppCollection -> { return Localization.lang("Supplemental material in a collection."); - case SuppPeriodical: + } + case SuppPeriodical -> { return Localization.lang("Supplemental material in a periodical. This type may be useful when referring to items such as regular columns, obituaries, letters to the editor, etc. which only have a generic title."); - case Thesis: + } + case Thesis -> { return Localization.lang("A thesis written for an educational institution to satisfy the requirements for a degree."); - case WWW: + } + case WWW -> { return Localization.lang("An alias for online, provided for jurabib compatibility."); - case Software: + } + case Software -> { return Localization.lang("Computer software. The standard styles will treat this entry type as an alias for misc."); - case DATESET: + } + case DATESET -> { return Localization.lang("A data set or a similar collection of (mostly) raw data."); + } + default -> { + return ""; + } } - return ""; } catch (Exception e) { return ""; } diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index 125b07a0806..f28279d40fd 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -2169,3 +2169,36 @@ Year\ of\ publication.=Year of publication. Remove\ formatter\ for\ %0=Remove formatter for %0 Remove\ formatter\ '%0'=Remove formatter '%0' + +An\ article\ in\ a\ journal,\ magazine,\ newspaper,\ or\ other\ periodical\ which\ forms\ a\ self-contained\ unit\ with\ its\ own\ title.=An article in a journal, magazine, newspaper, or other periodical which forms aself-contained unit with its own title. +A\ single-volume\ book\ with\ one\ or\ more\ authors\ where\ the\ authors\ share\ credit\ for\ the\ work\ as\ a\ whole.=A single-volume book with one or more authors where the authors share credit for the work as a whole. +A\ book-like\ work\ without\ a\ formal\ publisher\ or\ sponsoring\ institution.=A book-like work without a formal publisher or sponsoring institution. +A\ single-volume\ collection\ with\ multiple,\ self-contained\ contributions\ by\ distinct\ authors\ which\ have\ their\ own\ title.\ The\ work\ as\ a\ whole\ has\ no\ overall\ author\ but\ it\ will\ usually\ have\ an\ editor.=A single-volume collection with multiple, self-contained contributions by distinct authors which have their own title. The work as a whole has no overall author but it will usually have an editor. +A\ legacy\ alias\ for\ inproceedings.=A legacy alias for inproceedings. +A\ part\ of\ a\ book\ which\ forms\ a\ self-contained\ unit\ with\ its\ own\ title.=A part of a book which forms a self-contained unit with its own title. +A\ contribution\ to\ a\ collection\ which\ forms\ a\ self-contained\ unit\ with\ a\ distinct\ author\ and\ title.=A contribution to a collection which forms a self-contained unit with a distinct author and title. +An\ article\ in\ a\ conference\ proceedings.=An article in a conference proceedings. +Technical\ or\ other\ documentation,\ not\ necessarily\ in\ printed\ form.=Technical or other documentation, not necessarily in printed form. +Similar\ to\ thesis\ except\ that\ the\ type\ field\ is\ optional\ and\ defaults\ to\ the\ localised\ term\ Master's\ thesis.=Similar to thesis except that the type field is optional and defaults to the localised term Master's thesis. +A\ fallback\ type\ for\ entries\ which\ do\ not\ fit\ into\ any\ other\ category.=A fallback type for entries which do not fit into any other category. +Similar\ to\ thesis\ except\ that\ the\ type\ field\ is\ optional\ and\ defaults\ to\ the\ localised\ term\ PhD\ thesis.=Similar to thesis except that the type field is optional and defaults to the localised term PhD thesis. +A\ single-volume\ conference\ proceedings.\ This\ type\ is\ very\ similar\ to\ collection.=A single-volume conference proceedings. This type is very similar to collection. +Similar\ to\ report\ except\ that\ the\ type\ field\ is\ optional\ and\ defaults\ to\ the\ localised\ term\ technical\ report.=Similar to report except that the type field is optional and defaults to the localised term technical report. +A\ work\ with\ an\ author\ and\ a\ title\ which\ has\ not\ been\ formally\ published,\ such\ as\ a\ manuscript\ or\ the\ script\ of\ a\ talk.=A work with an author and a title which has not been formally published, such as a manuscript or the script of a talk. +This\ type\ is\ similar\ to\ inbook\ but\ intended\ for\ works\ originally\ published\ as\ a\ stand-alone\ book.=This type is similar to inbook but intended for works originally published as a stand-alone book. +An\ article\ in\ a\ work\ of\ reference.\ This\ is\ a\ more\ specific\ variant\ of\ the\ generic\ incollection\ entry\ type.=An article in a work of reference. This is a more specific variant of the generic incollection entry type. +A\ multi-volume\ book.=A multi-volume book. +A\ multi-volume\ collection.=A multi-volume collection. +A\ multi-volume\ proceedings\ entry.=A multi-volume proceedings entry. +A\ multi-volume\ reference\ entry.\ The\ standard\ styles\ will\ treat\ this\ entry\ type\ as\ an\ alias\ for\ mvcollection.=A multi-volume reference entry. The standard styles will treat this entry type as an alias for mvcollection. +This\ entry\ type\ is\ intended\ for\ sources\ such\ as\ web\ sites\ which\ are\ intrinsically\ online\ resources.=This entry type is intended for sources such as web sites which are intrinsically online resources. +A\ single-volume\ work\ of\ reference\ such\ as\ an\ encyclopedia\ or\ a\ dictionary.=A single-volume work of reference such as an encyclopedia or a dictionary. +A\ technical\ report,\ research\ report,\ or\ white\ paper\ published\ by\ a\ university\ or\ some\ other\ institution.=A technical report, research report, or white paper published by a university or some other institution. +An\ entry\ set\ is\ a\ group\ of\ entries\ which\ are\ cited\ as\ a\ single\ reference\ and\ listed\ as\ a\ single\ item\ in\ the\ bibliography.=An entry set is a group of entries which are cited as a single reference and listed as a single item in the bibliography. +Supplemental\ material\ in\ a\ book.\ This\ type\ is\ provided\ for\ elements\ such\ as\ prefaces,\ introductions,\ forewords,\ afterwords,\ etc.\ which\ often\ have\ a\ generic\ title\ only.=Supplemental material in a book. This type is provided for elements such as prefaces, introductions, forewords, afterwords, etc. which often have a generic title only. +Supplemental\ material\ in\ a\ collection.=Supplemental material in a collection. +Supplemental\ material\ in\ a\ periodical.\ This\ type\ may\ be\ useful\ when\ referring\ to\ items\ such\ as\ regular\ columns,\ obituaries,\ letters\ to\ the\ editor,\ etc.\ which\ only\ have\ a\ generic\ title.=Supplemental material in a periodical. This type may be useful when referring to items such as regular columns, obituaries, letters to the editor, etc. which only have a generic title. +A\ thesis\ written\ for\ an\ educational\ institution\ to\ satisfy\ the\ requirements\ for\ a\ degree.=A thesis written for an educational institution to satisfy the requirements for a degree. +An\ alias\ for\ online,\ provided\ for\ jurabib\ compatibility.=An alias for online, provided for jurabib compatibility. +Computer\ software.\ The\ standard\ styles\ will\ treat\ this\ entry\ type\ as\ an\ alias\ for\ misc.=Computer software. The standard styles will treat this entry type as an alias for misc. +A\ data\ set\ or\ a\ similar\ collection\ of\ (mostly)\ raw\ data.=A data set or a similar collection of (mostly) raw data. From a546c32c8acb9a7ae6237e971c4bb777c7c910c3 Mon Sep 17 00:00:00 2001 From: dimitra-karadima Date: Sat, 4 Apr 2020 14:46:48 +0300 Subject: [PATCH 03/25] Refactor tooltip for #6074 Add the following changes: -refactor the tooltip to prevent display issues -check if the entry type is StandardEntryType with instance of -use quotes to describe another entry type in the tooltip's description --- .../java/org/jabref/gui/EntryTypeView.java | 46 ++++++++++--------- src/main/resources/l10n/JabRef_en.properties | 32 ++++++------- 2 files changed, 40 insertions(+), 38 deletions(-) diff --git a/src/main/java/org/jabref/gui/EntryTypeView.java b/src/main/java/org/jabref/gui/EntryTypeView.java index 5bc6aea6c82..cd8297a0bdb 100644 --- a/src/main/java/org/jabref/gui/EntryTypeView.java +++ b/src/main/java/org/jabref/gui/EntryTypeView.java @@ -14,6 +14,7 @@ import javafx.scene.control.TitledPane; import javafx.scene.control.Tooltip; import javafx.scene.layout.FlowPane; +import javafx.stage.Screen; import org.jabref.Globals; import org.jabref.gui.util.BaseDialog; @@ -98,8 +99,11 @@ private void addEntriesToPane(FlowPane pane, Collection String description = getDescription(entryType); if (StringUtil.isNotBlank(description)) { - Tooltip tooltip = new Tooltip(); - tooltip.setText(description); + Screen currentScreen = Screen.getPrimary(); + double maxWidth = currentScreen.getBounds().getWidth(); + Tooltip tooltip = new Tooltip(description); + tooltip.setMaxWidth((maxWidth * 2) / 3); + tooltip.setWrapText(true); entryButton.setTooltip(tooltip); } } @@ -184,8 +188,7 @@ private void setEntryTypeForReturnAndClose(Optional entryType) { //since bibtex is a subset of biblatex and biblatex is better documented. public String getDescription(BibEntryType selectedType) { EntryType entryType = selectedType.getType(); - try { - StandardEntryType entry = (StandardEntryType) entryType; + if (entryType instanceof StandardEntryType entry) { switch (entry) { case Article -> { return Localization.lang("An article in a journal, magazine, newspaper, or other periodical which forms a self-contained unit with its own title."); @@ -200,7 +203,7 @@ public String getDescription(BibEntryType selectedType) { return Localization.lang("A single-volume collection with multiple, self-contained contributions by distinct authors which have their own title. The work as a whole has no overall author but it will usually have an editor."); } case Conference -> { - return Localization.lang("A legacy alias for inproceedings."); + return Localization.lang("A legacy alias for \"InProceedings\"."); } case InBook -> { return Localization.lang("A part of a book which forms a self-contained unit with its own title."); @@ -215,40 +218,40 @@ public String getDescription(BibEntryType selectedType) { return Localization.lang("Technical or other documentation, not necessarily in printed form."); } case MastersThesis -> { - return Localization.lang("Similar to thesis except that the type field is optional and defaults to the localised term Master's thesis."); + return Localization.lang("Similar to \"Thesis\" except that the type field is optional and defaults to the localised term Master's thesis."); } case Misc -> { return Localization.lang("A fallback type for entries which do not fit into any other category."); } case PhdThesis -> { - return Localization.lang("Similar to thesis except that the type field is optional and defaults to the localised term PhD thesis."); + return Localization.lang("Similar to \"Thesis\" except that the type field is optional and defaults to the localised term PhD thesis."); } case Proceedings -> { - return Localization.lang("A single-volume conference proceedings. This type is very similar to collection."); + return Localization.lang("A single-volume conference proceedings. This type is very similar to \"Collection\"."); } case TechReport -> { - return Localization.lang("Similar to report except that the type field is optional and defaults to the localised term technical report."); + return Localization.lang("Similar to \"Report\" except that the type field is optional and defaults to the localised term technical report."); } case Unpublished -> { return Localization.lang("A work with an author and a title which has not been formally published, such as a manuscript or the script of a talk."); } case BookInBook -> { - return Localization.lang("This type is similar to inbook but intended for works originally published as a stand-alone book."); + return Localization.lang("This type is similar to \"InBook\" but intended for works originally published as a stand-alone book."); } case InReference -> { - return Localization.lang("An article in a work of reference. This is a more specific variant of the generic incollection entry type."); + return Localization.lang("An article in a work of reference. This is a more specific variant of the generic \"InCollection\" entry type."); } case MvBook -> { - return Localization.lang("A multi-volume book."); + return Localization.lang("A multi-volume \"Book\"."); } case MvCollection -> { - return Localization.lang("A multi-volume collection."); + return Localization.lang("A multi-volume \"Collection\"."); } case MvProceedings -> { - return Localization.lang("A multi-volume proceedings entry."); + return Localization.lang("A multi-volume \"Proceedings\" entry."); } case MvReference -> { - return Localization.lang("A multi-volume reference entry. The standard styles will treat this entry type as an alias for mvcollection."); + return Localization.lang("A multi-volume \"Reference\" entry. The standard styles will treat this entry type as an alias for \"MvCollection\"."); } case Online -> { return Localization.lang("This entry type is intended for sources such as web sites which are intrinsically online resources."); @@ -263,22 +266,22 @@ public String getDescription(BibEntryType selectedType) { return Localization.lang("An entry set is a group of entries which are cited as a single reference and listed as a single item in the bibliography."); } case SuppBook -> { - return Localization.lang("Supplemental material in a book. This type is provided for elements such as prefaces, introductions, forewords, afterwords, etc. which often have a generic title only."); + return Localization.lang("Supplemental material in a \"Book\". This type is provided for elements such as prefaces, introductions, forewords, afterwords, etc. which often have a generic title only."); } case SuppCollection -> { - return Localization.lang("Supplemental material in a collection."); + return Localization.lang("Supplemental material in a \"Collection\"."); } case SuppPeriodical -> { - return Localization.lang("Supplemental material in a periodical. This type may be useful when referring to items such as regular columns, obituaries, letters to the editor, etc. which only have a generic title."); + return Localization.lang("Supplemental material in a \"Periodical\". This type may be useful when referring to items such as regular columns, obituaries, letters to the editor, etc. which only have a generic title."); } case Thesis -> { return Localization.lang("A thesis written for an educational institution to satisfy the requirements for a degree."); } case WWW -> { - return Localization.lang("An alias for online, provided for jurabib compatibility."); + return Localization.lang("An alias for \"Online\", provided for jurabib compatibility."); } case Software -> { - return Localization.lang("Computer software. The standard styles will treat this entry type as an alias for misc."); + return Localization.lang("Computer software. The standard styles will treat this entry type as an alias for \"Misc\"."); } case DATESET -> { return Localization.lang("A data set or a similar collection of (mostly) raw data."); @@ -287,10 +290,9 @@ public String getDescription(BibEntryType selectedType) { return ""; } } - } catch (Exception e) { + } else { return ""; } - } } diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index f28279d40fd..6def139723d 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -2174,31 +2174,31 @@ An\ article\ in\ a\ journal,\ magazine,\ newspaper,\ or\ other\ periodical\ whic A\ single-volume\ book\ with\ one\ or\ more\ authors\ where\ the\ authors\ share\ credit\ for\ the\ work\ as\ a\ whole.=A single-volume book with one or more authors where the authors share credit for the work as a whole. A\ book-like\ work\ without\ a\ formal\ publisher\ or\ sponsoring\ institution.=A book-like work without a formal publisher or sponsoring institution. A\ single-volume\ collection\ with\ multiple,\ self-contained\ contributions\ by\ distinct\ authors\ which\ have\ their\ own\ title.\ The\ work\ as\ a\ whole\ has\ no\ overall\ author\ but\ it\ will\ usually\ have\ an\ editor.=A single-volume collection with multiple, self-contained contributions by distinct authors which have their own title. The work as a whole has no overall author but it will usually have an editor. -A\ legacy\ alias\ for\ inproceedings.=A legacy alias for inproceedings. +A\ legacy\ alias\ for\ "InProceedings".=A legacy alias for "InProceedings". A\ part\ of\ a\ book\ which\ forms\ a\ self-contained\ unit\ with\ its\ own\ title.=A part of a book which forms a self-contained unit with its own title. A\ contribution\ to\ a\ collection\ which\ forms\ a\ self-contained\ unit\ with\ a\ distinct\ author\ and\ title.=A contribution to a collection which forms a self-contained unit with a distinct author and title. An\ article\ in\ a\ conference\ proceedings.=An article in a conference proceedings. Technical\ or\ other\ documentation,\ not\ necessarily\ in\ printed\ form.=Technical or other documentation, not necessarily in printed form. -Similar\ to\ thesis\ except\ that\ the\ type\ field\ is\ optional\ and\ defaults\ to\ the\ localised\ term\ Master's\ thesis.=Similar to thesis except that the type field is optional and defaults to the localised term Master's thesis. +Similar\ to\ "Thesis"\ except\ that\ the\ type\ field\ is\ optional\ and\ defaults\ to\ the\ localised\ term\ Master's\ thesis.=Similar to "Thesis" except that the type field is optional and defaults to the localised term Master's thesis. A\ fallback\ type\ for\ entries\ which\ do\ not\ fit\ into\ any\ other\ category.=A fallback type for entries which do not fit into any other category. -Similar\ to\ thesis\ except\ that\ the\ type\ field\ is\ optional\ and\ defaults\ to\ the\ localised\ term\ PhD\ thesis.=Similar to thesis except that the type field is optional and defaults to the localised term PhD thesis. -A\ single-volume\ conference\ proceedings.\ This\ type\ is\ very\ similar\ to\ collection.=A single-volume conference proceedings. This type is very similar to collection. -Similar\ to\ report\ except\ that\ the\ type\ field\ is\ optional\ and\ defaults\ to\ the\ localised\ term\ technical\ report.=Similar to report except that the type field is optional and defaults to the localised term technical report. +Similar\ to\ "Thesis"\ except\ that\ the\ type\ field\ is\ optional\ and\ defaults\ to\ the\ localised\ term\ PhD\ thesis.=Similar to "Thesis" except that the type field is optional and defaults to the localised term PhD thesis. +A\ single-volume\ conference\ proceedings.\ This\ type\ is\ very\ similar\ to\ "Collection".=A single-volume conference proceedings. This type is very similar to "Collection". +Similar\ to\ "Report"\ except\ that\ the\ type\ field\ is\ optional\ and\ defaults\ to\ the\ localised\ term\ technical\ report.=Similar to "Report" except that the type field is optional and defaults to the localised term technical report. A\ work\ with\ an\ author\ and\ a\ title\ which\ has\ not\ been\ formally\ published,\ such\ as\ a\ manuscript\ or\ the\ script\ of\ a\ talk.=A work with an author and a title which has not been formally published, such as a manuscript or the script of a talk. -This\ type\ is\ similar\ to\ inbook\ but\ intended\ for\ works\ originally\ published\ as\ a\ stand-alone\ book.=This type is similar to inbook but intended for works originally published as a stand-alone book. -An\ article\ in\ a\ work\ of\ reference.\ This\ is\ a\ more\ specific\ variant\ of\ the\ generic\ incollection\ entry\ type.=An article in a work of reference. This is a more specific variant of the generic incollection entry type. -A\ multi-volume\ book.=A multi-volume book. -A\ multi-volume\ collection.=A multi-volume collection. -A\ multi-volume\ proceedings\ entry.=A multi-volume proceedings entry. -A\ multi-volume\ reference\ entry.\ The\ standard\ styles\ will\ treat\ this\ entry\ type\ as\ an\ alias\ for\ mvcollection.=A multi-volume reference entry. The standard styles will treat this entry type as an alias for mvcollection. +This\ type\ is\ similar\ to\ "InBook"\ but\ intended\ for\ works\ originally\ published\ as\ a\ stand-alone\ book.=This type is similar to "InBook" but intended for works originally published as a stand-alone book. +An\ article\ in\ a\ work\ of\ reference.\ This\ is\ a\ more\ specific\ variant\ of\ the\ generic\ "InCollection"\ entry\ type.=An article in a work of reference. This is a more specific variant of the generic "InCollection" entry type. +A\ multi-volume\ "Book".=A multi-volume "Book". +A\ multi-volume\ "Collection".=A multi-volume "Collection". +A\ multi-volume\ "Proceedings"\ entry.=A multi-volume "Proceedings" entry. +A\ multi-volume\ "Reference"\ entry.\ The\ standard\ styles\ will\ treat\ this\ entry\ type\ as\ an\ alias\ for\ "MvCollection".=A multi-volume "Reference" entry. The standard styles will treat this entry type as an alias for "MvCollection". This\ entry\ type\ is\ intended\ for\ sources\ such\ as\ web\ sites\ which\ are\ intrinsically\ online\ resources.=This entry type is intended for sources such as web sites which are intrinsically online resources. A\ single-volume\ work\ of\ reference\ such\ as\ an\ encyclopedia\ or\ a\ dictionary.=A single-volume work of reference such as an encyclopedia or a dictionary. A\ technical\ report,\ research\ report,\ or\ white\ paper\ published\ by\ a\ university\ or\ some\ other\ institution.=A technical report, research report, or white paper published by a university or some other institution. An\ entry\ set\ is\ a\ group\ of\ entries\ which\ are\ cited\ as\ a\ single\ reference\ and\ listed\ as\ a\ single\ item\ in\ the\ bibliography.=An entry set is a group of entries which are cited as a single reference and listed as a single item in the bibliography. -Supplemental\ material\ in\ a\ book.\ This\ type\ is\ provided\ for\ elements\ such\ as\ prefaces,\ introductions,\ forewords,\ afterwords,\ etc.\ which\ often\ have\ a\ generic\ title\ only.=Supplemental material in a book. This type is provided for elements such as prefaces, introductions, forewords, afterwords, etc. which often have a generic title only. -Supplemental\ material\ in\ a\ collection.=Supplemental material in a collection. -Supplemental\ material\ in\ a\ periodical.\ This\ type\ may\ be\ useful\ when\ referring\ to\ items\ such\ as\ regular\ columns,\ obituaries,\ letters\ to\ the\ editor,\ etc.\ which\ only\ have\ a\ generic\ title.=Supplemental material in a periodical. This type may be useful when referring to items such as regular columns, obituaries, letters to the editor, etc. which only have a generic title. +Supplemental\ material\ in\ a\ "Book".\ This\ type\ is\ provided\ for\ elements\ such\ as\ prefaces,\ introductions,\ forewords,\ afterwords,\ etc.\ which\ often\ have\ a\ generic\ title\ only.=Supplemental material in a "Book". This type is provided for elements such as prefaces, introductions, forewords, afterwords, etc. which often have a generic title only. +Supplemental\ material\ in\ a\ "Collection".=Supplemental material in a "Collection". +Supplemental\ material\ in\ a\ "Periodical".\ This\ type\ may\ be\ useful\ when\ referring\ to\ items\ such\ as\ regular\ columns,\ obituaries,\ letters\ to\ the\ editor,\ etc.\ which\ only\ have\ a\ generic\ title.=Supplemental material in a "Periodical". This type may be useful when referring to items such as regular columns, obituaries, letters to the editor, etc. which only have a generic title. A\ thesis\ written\ for\ an\ educational\ institution\ to\ satisfy\ the\ requirements\ for\ a\ degree.=A thesis written for an educational institution to satisfy the requirements for a degree. -An\ alias\ for\ online,\ provided\ for\ jurabib\ compatibility.=An alias for online, provided for jurabib compatibility. -Computer\ software.\ The\ standard\ styles\ will\ treat\ this\ entry\ type\ as\ an\ alias\ for\ misc.=Computer software. The standard styles will treat this entry type as an alias for misc. +An\ alias\ for\ "Online",\ provided\ for\ jurabib\ compatibility.=An alias for "Online", provided for jurabib compatibility. +Computer\ software.\ The\ standard\ styles\ will\ treat\ this\ entry\ type\ as\ an\ alias\ for\ "Misc".=Computer software. The standard styles will treat this entry type as an alias for "Misc". A\ data\ set\ or\ a\ similar\ collection\ of\ (mostly)\ raw\ data.=A data set or a similar collection of (mostly) raw data. From dff1c164ce94000d6e7cce3692b3f1fc1bcec2a0 Mon Sep 17 00:00:00 2001 From: dimitra-karadima Date: Tue, 7 Apr 2020 20:48:16 +0300 Subject: [PATCH 04/25] Add tooltips when changing the entry type Add the following changes: -Add tooltips in the left side of the entry editor when you click the entry type you have already selected or the Change entry type button. -Add tooltips in the main table when you right click and choose "Change entry type" --- .../jabref/gui/menus/ChangeEntryTypeMenu.java | 124 +++++++++++++++++- 1 file changed, 123 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/menus/ChangeEntryTypeMenu.java b/src/main/java/org/jabref/gui/menus/ChangeEntryTypeMenu.java index bf574cf411a..c64001495a9 100644 --- a/src/main/java/org/jabref/gui/menus/ChangeEntryTypeMenu.java +++ b/src/main/java/org/jabref/gui/menus/ChangeEntryTypeMenu.java @@ -7,9 +7,12 @@ import javafx.collections.ObservableList; import javafx.scene.control.ContextMenu; +import javafx.scene.control.CustomMenuItem; +import javafx.scene.control.Label; import javafx.scene.control.Menu; import javafx.scene.control.MenuItem; import javafx.scene.control.SeparatorMenuItem; +import javafx.scene.control.Tooltip; import org.jabref.Globals; import org.jabref.gui.undo.CountingUndoManager; @@ -23,6 +26,8 @@ import org.jabref.model.entry.types.BibtexEntryTypeDefinitions; import org.jabref.model.entry.types.EntryType; import org.jabref.model.entry.types.IEEETranEntryTypeDefinitions; +import org.jabref.model.entry.types.StandardEntryType; +import org.jabref.model.strings.StringUtil; public class ChangeEntryTypeMenu { @@ -31,13 +36,18 @@ public ChangeEntryTypeMenu() { } public static MenuItem createMenuItem(EntryType type, BibEntry entry, UndoManager undoManager) { - MenuItem menuItem = new MenuItem(type.getDisplayName()); + CustomMenuItem menuItem = new CustomMenuItem(new Label(type.getDisplayName())); menuItem.setOnAction(event -> { NamedCompound compound = new NamedCompound(Localization.lang("Change entry type")); entry.setType(type) .ifPresent(change -> compound.addEdit(new UndoableChangeType(change))); undoManager.addEdit(compound); }); + String description = getDescription(type); + if (StringUtil.isNotBlank(description)) { + Tooltip tooltip = new Tooltip(description); + Tooltip.install(menuItem.getContent(), tooltip); + } return menuItem; } @@ -92,4 +102,116 @@ private void populate(ObservableList items, Collection t private void populate(Menu menu, Collection types, BibEntry entry, UndoManager undoManager) { populate(menu.getItems(), types, entry, undoManager); } + + //The description is coming from biblatex manual chapter 2 + //Biblatex documentation is favored over the bibtex, + //since bibtex is a subset of biblatex and biblatex is better documented. + public static String getDescription(EntryType entryType) { + if (entryType instanceof StandardEntryType entry) { + switch (entry) { + case Article -> { + return Localization.lang("An article in a journal, magazine, newspaper, or other periodical which forms a self-contained unit with its own title."); + } + case Book -> { + return Localization.lang("A single-volume book with one or more authors where the authors share credit for the work as a whole."); + } + case Booklet -> { + return Localization.lang("A book-like work without a formal publisher or sponsoring institution."); + } + case Collection -> { + return Localization.lang("A single-volume collection with multiple, self-contained contributions by distinct authors which have their own title. The work as a whole has no overall author but it will usually have an editor."); + } + case Conference -> { + return Localization.lang("A legacy alias for \"InProceedings\"."); + } + case InBook -> { + return Localization.lang("A part of a book which forms a self-contained unit with its own title."); + } + case InCollection -> { + return Localization.lang("A contribution to a collection which forms a self-contained unit with a distinct author and title."); + } + case InProceedings -> { + return Localization.lang("An article in a conference proceedings."); + } + case Manual -> { + return Localization.lang("Technical or other documentation, not necessarily in printed form."); + } + case MastersThesis -> { + return Localization.lang("Similar to \"Thesis\" except that the type field is optional and defaults to the localised term Master's thesis."); + } + case Misc -> { + return Localization.lang("A fallback type for entries which do not fit into any other category."); + } + case PhdThesis -> { + return Localization.lang("Similar to \"Thesis\" except that the type field is optional and defaults to the localised term PhD thesis."); + } + case Proceedings -> { + return Localization.lang("A single-volume conference proceedings. This type is very similar to \"Collection\"."); + } + case TechReport -> { + return Localization.lang("Similar to \"Report\" except that the type field is optional and defaults to the localised term technical report."); + } + case Unpublished -> { + return Localization.lang("A work with an author and a title which has not been formally published, such as a manuscript or the script of a talk."); + } + case BookInBook -> { + return Localization.lang("This type is similar to \"InBook\" but intended for works originally published as a stand-alone book."); + } + case InReference -> { + return Localization.lang("An article in a work of reference. This is a more specific variant of the generic \"InCollection\" entry type."); + } + case MvBook -> { + return Localization.lang("A multi-volume \"Book\"."); + } + case MvCollection -> { + return Localization.lang("A multi-volume \"Collection\"."); + } + case MvProceedings -> { + return Localization.lang("A multi-volume \"Proceedings\" entry."); + } + case MvReference -> { + return Localization.lang("A multi-volume \"Reference\" entry. The standard styles will treat this entry type as an alias for \"MvCollection\"."); + } + case Online -> { + return Localization.lang("This entry type is intended for sources such as web sites which are intrinsically online resources."); + } + case Reference -> { + return Localization.lang("A single-volume work of reference such as an encyclopedia or a dictionary."); + } + case Report -> { + return Localization.lang("A technical report, research report, or white paper published by a university or some other institution."); + } + case Set -> { + return Localization.lang("An entry set is a group of entries which are cited as a single reference and listed as a single item in the bibliography."); + } + case SuppBook -> { + return Localization.lang("Supplemental material in a \"Book\". This type is provided for elements such as prefaces, introductions, forewords, afterwords, etc. which often have a generic title only."); + } + case SuppCollection -> { + return Localization.lang("Supplemental material in a \"Collection\"."); + } + case SuppPeriodical -> { + return Localization.lang("Supplemental material in a \"Periodical\". This type may be useful when referring to items such as regular columns, obituaries, letters to the editor, etc. which only have a generic title."); + } + case Thesis -> { + return Localization.lang("A thesis written for an educational institution to satisfy the requirements for a degree."); + } + case WWW -> { + return Localization.lang("An alias for \"Online\", provided for jurabib compatibility."); + } + case Software -> { + return Localization.lang("Computer software. The standard styles will treat this entry type as an alias for \"Misc\"."); + } + case DATESET -> { + return Localization.lang("A data set or a similar collection of (mostly) raw data."); + } + default -> { + return ""; + } + } + } else { + return ""; + } + } + } From fe14e5490c7f9d7b687052f6492a88dd0f609f7a Mon Sep 17 00:00:00 2001 From: dimitra-karadima Date: Wed, 8 Apr 2020 12:38:23 +0300 Subject: [PATCH 05/25] Fix some issues Change DATESET standard entry type to Dataset Remove getDescription() from ChangeEntryTypeMenu.java --- .../java/org/jabref/gui/EntryTypeView.java | 10 +- .../jabref/gui/menus/ChangeEntryTypeMenu.java | 115 +----------------- .../types/BiblatexEntryTypeDefinitions.java | 2 +- .../model/entry/types/StandardEntryType.java | 2 +- 4 files changed, 9 insertions(+), 120 deletions(-) diff --git a/src/main/java/org/jabref/gui/EntryTypeView.java b/src/main/java/org/jabref/gui/EntryTypeView.java index cd8297a0bdb..266bd3b7e41 100644 --- a/src/main/java/org/jabref/gui/EntryTypeView.java +++ b/src/main/java/org/jabref/gui/EntryTypeView.java @@ -97,7 +97,8 @@ private void addEntriesToPane(FlowPane pane, Collection entryButton.setOnAction(event -> setEntryTypeForReturnAndClose(Optional.of(entryType))); pane.getChildren().add(entryButton); - String description = getDescription(entryType); + EntryType selectedType = entryType.getType(); + String description = getDescription(selectedType); if (StringUtil.isNotBlank(description)) { Screen currentScreen = Screen.getPrimary(); double maxWidth = currentScreen.getBounds().getWidth(); @@ -186,9 +187,8 @@ private void setEntryTypeForReturnAndClose(Optional entryType) { //The description is coming from biblatex manual chapter 2 //Biblatex documentation is favored over the bibtex, //since bibtex is a subset of biblatex and biblatex is better documented. - public String getDescription(BibEntryType selectedType) { - EntryType entryType = selectedType.getType(); - if (entryType instanceof StandardEntryType entry) { + public static String getDescription(EntryType selectedType) { + if (selectedType instanceof StandardEntryType entry) { switch (entry) { case Article -> { return Localization.lang("An article in a journal, magazine, newspaper, or other periodical which forms a self-contained unit with its own title."); @@ -283,7 +283,7 @@ public String getDescription(BibEntryType selectedType) { case Software -> { return Localization.lang("Computer software. The standard styles will treat this entry type as an alias for \"Misc\"."); } - case DATESET -> { + case Dataset -> { return Localization.lang("A data set or a similar collection of (mostly) raw data."); } default -> { diff --git a/src/main/java/org/jabref/gui/menus/ChangeEntryTypeMenu.java b/src/main/java/org/jabref/gui/menus/ChangeEntryTypeMenu.java index c64001495a9..e5625178f81 100644 --- a/src/main/java/org/jabref/gui/menus/ChangeEntryTypeMenu.java +++ b/src/main/java/org/jabref/gui/menus/ChangeEntryTypeMenu.java @@ -15,6 +15,7 @@ import javafx.scene.control.Tooltip; import org.jabref.Globals; +import org.jabref.gui.EntryTypeView; import org.jabref.gui.undo.CountingUndoManager; import org.jabref.gui.undo.NamedCompound; import org.jabref.gui.undo.UndoableChangeType; @@ -26,7 +27,6 @@ import org.jabref.model.entry.types.BibtexEntryTypeDefinitions; import org.jabref.model.entry.types.EntryType; import org.jabref.model.entry.types.IEEETranEntryTypeDefinitions; -import org.jabref.model.entry.types.StandardEntryType; import org.jabref.model.strings.StringUtil; public class ChangeEntryTypeMenu { @@ -43,7 +43,7 @@ public static MenuItem createMenuItem(EntryType type, BibEntry entry, UndoManage .ifPresent(change -> compound.addEdit(new UndoableChangeType(change))); undoManager.addEdit(compound); }); - String description = getDescription(type); + String description = EntryTypeView.getDescription(type); if (StringUtil.isNotBlank(description)) { Tooltip tooltip = new Tooltip(description); Tooltip.install(menuItem.getContent(), tooltip); @@ -103,115 +103,4 @@ private void populate(Menu menu, Collection types, BibEntry entry, populate(menu.getItems(), types, entry, undoManager); } - //The description is coming from biblatex manual chapter 2 - //Biblatex documentation is favored over the bibtex, - //since bibtex is a subset of biblatex and biblatex is better documented. - public static String getDescription(EntryType entryType) { - if (entryType instanceof StandardEntryType entry) { - switch (entry) { - case Article -> { - return Localization.lang("An article in a journal, magazine, newspaper, or other periodical which forms a self-contained unit with its own title."); - } - case Book -> { - return Localization.lang("A single-volume book with one or more authors where the authors share credit for the work as a whole."); - } - case Booklet -> { - return Localization.lang("A book-like work without a formal publisher or sponsoring institution."); - } - case Collection -> { - return Localization.lang("A single-volume collection with multiple, self-contained contributions by distinct authors which have their own title. The work as a whole has no overall author but it will usually have an editor."); - } - case Conference -> { - return Localization.lang("A legacy alias for \"InProceedings\"."); - } - case InBook -> { - return Localization.lang("A part of a book which forms a self-contained unit with its own title."); - } - case InCollection -> { - return Localization.lang("A contribution to a collection which forms a self-contained unit with a distinct author and title."); - } - case InProceedings -> { - return Localization.lang("An article in a conference proceedings."); - } - case Manual -> { - return Localization.lang("Technical or other documentation, not necessarily in printed form."); - } - case MastersThesis -> { - return Localization.lang("Similar to \"Thesis\" except that the type field is optional and defaults to the localised term Master's thesis."); - } - case Misc -> { - return Localization.lang("A fallback type for entries which do not fit into any other category."); - } - case PhdThesis -> { - return Localization.lang("Similar to \"Thesis\" except that the type field is optional and defaults to the localised term PhD thesis."); - } - case Proceedings -> { - return Localization.lang("A single-volume conference proceedings. This type is very similar to \"Collection\"."); - } - case TechReport -> { - return Localization.lang("Similar to \"Report\" except that the type field is optional and defaults to the localised term technical report."); - } - case Unpublished -> { - return Localization.lang("A work with an author and a title which has not been formally published, such as a manuscript or the script of a talk."); - } - case BookInBook -> { - return Localization.lang("This type is similar to \"InBook\" but intended for works originally published as a stand-alone book."); - } - case InReference -> { - return Localization.lang("An article in a work of reference. This is a more specific variant of the generic \"InCollection\" entry type."); - } - case MvBook -> { - return Localization.lang("A multi-volume \"Book\"."); - } - case MvCollection -> { - return Localization.lang("A multi-volume \"Collection\"."); - } - case MvProceedings -> { - return Localization.lang("A multi-volume \"Proceedings\" entry."); - } - case MvReference -> { - return Localization.lang("A multi-volume \"Reference\" entry. The standard styles will treat this entry type as an alias for \"MvCollection\"."); - } - case Online -> { - return Localization.lang("This entry type is intended for sources such as web sites which are intrinsically online resources."); - } - case Reference -> { - return Localization.lang("A single-volume work of reference such as an encyclopedia or a dictionary."); - } - case Report -> { - return Localization.lang("A technical report, research report, or white paper published by a university or some other institution."); - } - case Set -> { - return Localization.lang("An entry set is a group of entries which are cited as a single reference and listed as a single item in the bibliography."); - } - case SuppBook -> { - return Localization.lang("Supplemental material in a \"Book\". This type is provided for elements such as prefaces, introductions, forewords, afterwords, etc. which often have a generic title only."); - } - case SuppCollection -> { - return Localization.lang("Supplemental material in a \"Collection\"."); - } - case SuppPeriodical -> { - return Localization.lang("Supplemental material in a \"Periodical\". This type may be useful when referring to items such as regular columns, obituaries, letters to the editor, etc. which only have a generic title."); - } - case Thesis -> { - return Localization.lang("A thesis written for an educational institution to satisfy the requirements for a degree."); - } - case WWW -> { - return Localization.lang("An alias for \"Online\", provided for jurabib compatibility."); - } - case Software -> { - return Localization.lang("Computer software. The standard styles will treat this entry type as an alias for \"Misc\"."); - } - case DATESET -> { - return Localization.lang("A data set or a similar collection of (mostly) raw data."); - } - default -> { - return ""; - } - } - } else { - return ""; - } - } - } diff --git a/src/main/java/org/jabref/model/entry/types/BiblatexEntryTypeDefinitions.java b/src/main/java/org/jabref/model/entry/types/BiblatexEntryTypeDefinitions.java index 9344c2faff4..08e3ac006dc 100644 --- a/src/main/java/org/jabref/model/entry/types/BiblatexEntryTypeDefinitions.java +++ b/src/main/java/org/jabref/model/entry/types/BiblatexEntryTypeDefinitions.java @@ -427,7 +427,7 @@ public class BiblatexEntryTypeDefinitions { .build(); private static final BibEntryType DATASET = new BibEntryTypeBuilder() - .withType(StandardEntryType.DATESET) + .withType(StandardEntryType.Dataset) .withImportantFields( StandardField.SUBTITLE, StandardField.TITLEADDON, StandardField.HOWPUBLISHED, StandardField.LOCATION, StandardField.DOI, StandardField.EPRINT, StandardField.EPRINTCLASS, StandardField.EPRINTTYPE, StandardField.URL, StandardField.URLDATE) diff --git a/src/main/java/org/jabref/model/entry/types/StandardEntryType.java b/src/main/java/org/jabref/model/entry/types/StandardEntryType.java index 9b2f87d1674..8a01a87cb32 100644 --- a/src/main/java/org/jabref/model/entry/types/StandardEntryType.java +++ b/src/main/java/org/jabref/model/entry/types/StandardEntryType.java @@ -36,7 +36,7 @@ public enum StandardEntryType implements EntryType { Thesis("Thesis"), WWW("WWW"), Software("Software"), - DATESET("DataSet"); + Dataset("Dataset"); From 91578d73957650c89abf7c0b0f4c1a39dd36eb13 Mon Sep 17 00:00:00 2001 From: github actions Date: Tue, 14 Apr 2020 11:25:55 +0000 Subject: [PATCH 06/25] Squashed 'src/main/resources/csl-styles/' changes from db54e5655d..c31d9ca05a MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit c31d9ca05a Create tagungsberichte-der-historischen-kommission-fur-ost-und-westpr… (#4700) 34220d34ad Change apa-fr-provost.csl to fr-CA locale (#4701) bbdc9c4719 Update to better match RMIT Easy Cite (#4697) 7c506d9d33 Create Anatomia Histologia Embryologia csl file (#4688) 61f3dc5525 Update pravnik.csl, masarykova-univerzita-pravnicka-fakulta.csl and iso690-full-note-cs.csl (#4705) 449eaec040 add DOI to mdpi.csl back (#4695) 642002eee4 Create muni-law.csl (#4691) 483d04aa78 Create iso690-author-date-pt (#4694) 505c006cc1 Update pravnik.csl (#4690) eb260efe1f Update instituto-brasileiro-de-informacao-em-ciencia-e-tecnologia-abn… (#4692) 9279f0dd31 Update instituto-brasileiro-de-informacao-em-ciencia-e-tecnologia-abn… (#4693) 70f7be6952 Create iso690-full-note-cs-pravnik.csl (#4686) git-subtree-dir: src/main/resources/csl-styles git-subtree-split: c31d9ca05a507b44517a193237b60336e15198d9 --- apa-fr-provost.csl | 18 +- apa-tr.csl | 2 +- dependent/anatomia-histologia-embryologia.csl | 22 + ...-em-ciencia-e-tecnologia-abnt-initials.csl | 72 +- ...nformacao-em-ciencia-e-tecnologia-abnt.csl | 72 +- iso690-author-date-pt-br.csl | 576 ++++++++++++++++ iso690-full-note-cs.csl | 211 +++--- masarykova-univerzita-pravnicka-fakulta.csl | 642 ++++++++++++++++++ ...ciplinary-digital-publishing-institute.csl | 3 + pravnik.csl | 586 ++++++++++++++++ rmit-university-harvard.csl | 35 +- ...st-und-westpreussische-landesforschung.csl | 238 +++++++ 12 files changed, 2303 insertions(+), 174 deletions(-) create mode 100644 dependent/anatomia-histologia-embryologia.csl create mode 100644 iso690-author-date-pt-br.csl create mode 100644 masarykova-univerzita-pravnicka-fakulta.csl create mode 100644 pravnik.csl create mode 100644 tagungsberichte-der-historischen-kommission-fur-ost-und-westpreussische-landesforschung.csl diff --git a/apa-fr-provost.csl b/apa-fr-provost.csl index f48c3ac9379..237cf67409e 100644 --- a/apa-fr-provost.csl +++ b/apa-fr-provost.csl @@ -1,8 +1,8 @@ - diff --git a/instituto-brasileiro-de-informacao-em-ciencia-e-tecnologia-abnt-initials.csl b/instituto-brasileiro-de-informacao-em-ciencia-e-tecnologia-abnt-initials.csl index b01dad805cd..7ca74716cac 100644 --- a/instituto-brasileiro-de-informacao-em-ciencia-e-tecnologia-abnt-initials.csl +++ b/instituto-brasileiro-de-informacao-em-ciencia-e-tecnologia-abnt-initials.csl @@ -26,7 +26,7 @@ The Brazilian Standard Style by IBICT - 2020-04-09T14:37:00+00:00 + 2020-04-11T15:24:32+00:00 This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License @@ -87,7 +87,7 @@ - + @@ -155,33 +155,29 @@ - + - - - - - - - - + - + - - + + + + + + + + + - - - - - + @@ -306,18 +302,19 @@ - + - + - + + @@ -333,7 +330,7 @@ - + @@ -392,7 +389,7 @@ - + @@ -442,7 +439,7 @@ - + @@ -483,15 +480,16 @@ - + + - - + + @@ -505,9 +503,9 @@ - - - + + + @@ -524,7 +522,7 @@ - + @@ -532,9 +530,9 @@ - - + + @@ -545,8 +543,8 @@ - - + + @@ -560,7 +558,7 @@ - + diff --git a/instituto-brasileiro-de-informacao-em-ciencia-e-tecnologia-abnt.csl b/instituto-brasileiro-de-informacao-em-ciencia-e-tecnologia-abnt.csl index c6226cb1ff9..536ca319594 100644 --- a/instituto-brasileiro-de-informacao-em-ciencia-e-tecnologia-abnt.csl +++ b/instituto-brasileiro-de-informacao-em-ciencia-e-tecnologia-abnt.csl @@ -26,7 +26,7 @@ The Brazilian Standard Style by IBICT - 2020-04-09T14:38:00+00:00 + 2020-04-11T15:20:00+00:00 This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License @@ -87,7 +87,7 @@ - + @@ -155,33 +155,29 @@ - + - - - - - - - - + - + - - + + + + + + + + + - - - - - + @@ -306,18 +302,19 @@ - + - + - + + @@ -333,7 +330,7 @@ - + @@ -392,7 +389,7 @@ - + @@ -442,7 +439,7 @@ - + @@ -483,15 +480,16 @@ - + + - - + + @@ -505,9 +503,9 @@ - - - + + + @@ -524,7 +522,7 @@ - + @@ -532,9 +530,9 @@ - - + + @@ -545,8 +543,8 @@ - - + + @@ -560,7 +558,7 @@ - + diff --git a/iso690-author-date-pt-br.csl b/iso690-author-date-pt-br.csl new file mode 100644 index 00000000000..c95e9474ed8 --- /dev/null +++ b/iso690-author-date-pt-br.csl @@ -0,0 +1,576 @@ + + diff --git a/iso690-full-note-cs.csl b/iso690-full-note-cs.csl index f7adf459017..5a774d3c967 100644 --- a/iso690-full-note-cs.csl +++ b/iso690-full-note-cs.csl @@ -2,26 +2,19 @@ diff --git a/multidisciplinary-digital-publishing-institute.csl b/multidisciplinary-digital-publishing-institute.csl index c4823a3dc84..d50ab1ea0e4 100644 --- a/multidisciplinary-digital-publishing-institute.csl +++ b/multidisciplinary-digital-publishing-institute.csl @@ -94,6 +94,9 @@ + + + diff --git a/pravnik.csl b/pravnik.csl new file mode 100644 index 00000000000..a77f4b9a362 --- /dev/null +++ b/pravnik.csl @@ -0,0 +1,586 @@ + + diff --git a/rmit-university-harvard.csl b/rmit-university-harvard.csl index cc6ce25f919..1e19a8031fa 100644 --- a/rmit-university-harvard.csl +++ b/rmit-university-harvard.csl @@ -12,7 +12,7 @@ - 2020-01-13T00:52:05+00:00 + 2020-04-13T04:40:00+00:00 This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License @@ -86,7 +86,7 @@ - + @@ -98,6 +98,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + @@ -148,14 +173,14 @@ - + - + @@ -210,6 +235,8 @@ + + diff --git a/tagungsberichte-der-historischen-kommission-fur-ost-und-westpreussische-landesforschung.csl b/tagungsberichte-der-historischen-kommission-fur-ost-und-westpreussische-landesforschung.csl new file mode 100644 index 00000000000..c5c78739a40 --- /dev/null +++ b/tagungsberichte-der-historischen-kommission-fur-ost-und-westpreussische-landesforschung.csl @@ -0,0 +1,238 @@ + + From d0a86e91449f2cf3f2800653b135cd8e54eca901 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Tue, 14 Apr 2020 14:02:45 +0200 Subject: [PATCH 07/25] Add checkstyle screenshot (and lint guidelines-...md) --- ...elines-for-setting-up-a-local-workspace.md | 68 +++++++++--------- docs/images/intellij-checkstyle-settings.png | Bin 0 -> 33804 bytes 2 files changed, 35 insertions(+), 33 deletions(-) create mode 100644 docs/images/intellij-checkstyle-settings.png diff --git a/docs/guidelines-for-setting-up-a-local-workspace.md b/docs/guidelines-for-setting-up-a-local-workspace.md index 431d4aa410c..b04a13fb208 100644 --- a/docs/guidelines-for-setting-up-a-local-workspace.md +++ b/docs/guidelines-for-setting-up-a-local-workspace.md @@ -29,9 +29,9 @@ If you do not yet have a GitHub account, please [create one](https://github.com/ Proposals for account names: -- Login similar to your university account. Example: `koppor` -- Use your last name prefixed by the first letter of your first name. Example: `okopp` -- Use `firstname.lastname`. Example: `oliver.kopp` +* Login similar to your university account. Example: `koppor` +* Use your last name prefixed by the first letter of your first name. Example: `okopp` +* Use `firstname.lastname`. Example: `oliver.kopp` You can hide your email adress by following the recommendations at . @@ -41,9 +41,9 @@ That account then be used for develoment mailing lists, mail exchange with other Examples: -- Same login as in GitHub (see above). Example: `koppor@gmail.com` -- "`it`" in the name. Example: `kopp.it@gmail.com` -- Use the university login. Example: `st342435@stud.uni-stuttgart.de` +* Same login as in GitHub (see above). Example: `koppor@gmail.com` +* "`it`" in the name. Example: `kopp.it@gmail.com` +* Use the university login. Example: `st342435@stud.uni-stuttgart.de` ### git @@ -172,15 +172,18 @@ Contributions to JabRef's source code need to have a code formatting that is con 2. Close the settings afterwards and restart IntelliJ * Go to **File \| Settings \| Editor \| Code Style** * Click on the settings wheel \(next to the scheme chooser\), then click "Import Scheme" -* Select the IntelliJ configuration file `config/IntelliJ Code Style.xml`. +* Select the IntelliJ configuration file `config/IntelliJ Code Style.xml` * Go to **File \| Settings \| Checkstyle \| Configuration File** 1. Import the CheckStyle configuration file by clicking the \[+\] button - 2. For the description provide e.g. "JabRef" + 2. For the description provide "JabRef" 3. Click "Browse" and choose `config/checkstyle/checkstyle.xml` 4. Check "Store relative to project location" 5. Click "Next" and "Finish" 6. Activate the CheckStyle configuration file by ticking it in the list - 7. Save settings by clicking "OK" + 7. Ensure that CheckStyle version 8.31 (or higher) is selected + 8. Save settings by clicking "OK" + +![checkstyle settings](images/intellij-checkstyle-settings.png) #### Troubleshooting when using both IDEA and Eclipse @@ -200,7 +203,7 @@ For Eclipse 2020-03 you need to install [jdk14 support](https://marketplace.ecli 1. Run `./gradlew run` to generate all resources and to check if JabRef runs. * The JabRef GUI should finally appear. * This step is only required once. -2. Run `./gradlew eclipse` +2. Run `./gradlew eclipse` * **This must always be executed, when there are new upstream changes.** 3. Copy the file `Log4jPlugins.java` from `build/generated/sources/annotationProcessor/java/main/org/jabref/gui/logging/plugins` to `src/main/java/org/jabref/gui/logging/plugins/` * Usually, the folder `plugins` must be created for that. @@ -210,29 +213,28 @@ For Eclipse 2020-03 you need to install [jdk14 support](https://marketplace.ecli 5. Create a run/debug configuration for the main class `org.jabref.JabRefLauncher` and/or for `org.jabref.JabRefMain` \(both can be used equivalently\) * In the tab "Arguments" of the run/debug configuration, enter the following runtime VM arguments: - * Set "VM Arguments" to: - - ```text - --patch-module test=fastparse_2.12-1.0.0.jar - --patch-module test2=fastparse-utils_2.12-1.0.0.jar - --patch-module test3=sourcecode_2.12-0.1.4.jar - --add-exports javafx.controls/com.sun.javafx.scene.control=org.jabref - --add-exports org.controlsfx.controls/impl.org.controlsfx.skin=org.jabref - --add-exports javafx.graphics/com.sun.javafx.scene=org.controlsfx.controls - --add-exports javafx.graphics/com.sun.javafx.scene.traversal=org.controlsfx.controls - --add-exports javafx.graphics/com.sun.javafx.css=org.controlsfx.controls - --add-exports javafx.controls/com.sun.javafx.scene.control.behavior=org.controlsfx.controls - --add-exports javafx.controls/com.sun.javafx.scene.control=org.controlsfx.controls - --add-exports javafx.controls/com.sun.javafx.scene.control.inputmap=org.controlsfx.controls - --add-exports javafx.base/com.sun.javafx.event=org.controlsfx.controls - --add-exports javafx.base/com.sun.javafx.collections=org.controlsfx.controls - --add-exports javafx.base/com.sun.javafx.runtime=org.controlsfx.controls - --add-exports javafx.web/com.sun.webkit=org.controlsfx.controls - --add-exports javafx.graphics/com.sun.javafx.css=org.controlsfx.controls - --add-exports javafx.controls/com.sun.javafx.scene.control.behavior=com.jfoenix - --add-exports com.oracle.truffle.regex/com.oracle.truffle.regex=org.graalvm.truffle - --patch-module org.jabref=build\resources\main - ``` + ```text + --patch-module test=fastparse_2.12-1.0.0.jar + --patch-module test2=fastparse-utils_2.12-1.0.0.jar + --patch-module test3=sourcecode_2.12-0.1.4.jar + --add-exports javafx.controls/com.sun.javafx.scene.control=org.jabref + --add-exports org.controlsfx.controls/impl.org.controlsfx.skin=org.jabref + --add-exports javafx.graphics/com.sun.javafx.scene=org.controlsfx.controls + --add-exports javafx.graphics/com.sun.javafx.scene.traversal=org.controlsfx.controls + --add-exports javafx.graphics/com.sun.javafx.css=org.controlsfx.controls + --add-exports javafx.controls/com.sun.javafx.scene.control.behavior=org.controlsfx.controls + --add-exports javafx.controls/com.sun.javafx.scene.control=org.controlsfx.controls + --add-exports javafx.controls/com.sun.javafx.scene.control.inputmap=org.controlsfx.controls + --add-exports javafx.base/com.sun.javafx.event=org.controlsfx.controls + --add-exports javafx.base/com.sun.javafx.collections=org.controlsfx.controls + --add-exports javafx.base/com.sun.javafx.runtime=org.controlsfx.controls + --add-exports javafx.web/com.sun.webkit=org.controlsfx.controls + --add-exports javafx.graphics/com.sun.javafx.css=org.controlsfx.controls + --add-exports javafx.controls/com.sun.javafx.scene.control.behavior=com.jfoenix + --add-exports com.oracle.truffle.regex/com.oracle.truffle.regex=org.graalvm.truffle + --patch-module org.jabref=build\resources\main + ``` + 6. Optional: Install the [e\(fx\)clipse plugin](http://www.eclipse.org/efxclipse/index.html) from the Eclipse marketplace: 1. Help -> Eclipse Marketplace... -> Search tab 2. Enter "e\(fx\)clipse" in the search dialogue 3. Click "Go" 4. Click "Install" button next to the plugin 5. Click "Finish" 7. Now you can build and run/debug the application by either using "JabRefLauncher" or "JabRefMain". This is the recommended way, since the application starts quite fast. diff --git a/docs/images/intellij-checkstyle-settings.png b/docs/images/intellij-checkstyle-settings.png new file mode 100644 index 0000000000000000000000000000000000000000..c605c04cd20d1e7ae21fa9338aafef3dc655ce05 GIT binary patch literal 33804 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 Date: Tue, 14 Apr 2020 16:55:56 +0200 Subject: [PATCH 08/25] Fix XmpExporterTest (#6289) --- .../jabref/logic/exporter/XmpExporter.java | 15 +++++++++------ .../logic/exporter/XmpExporterTest.java | 19 ++++++++++--------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/jabref/logic/exporter/XmpExporter.java b/src/main/java/org/jabref/logic/exporter/XmpExporter.java index 9a045f8ebc8..59f7c445b6b 100644 --- a/src/main/java/org/jabref/logic/exporter/XmpExporter.java +++ b/src/main/java/org/jabref/logic/exporter/XmpExporter.java @@ -24,7 +24,7 @@ */ public class XmpExporter extends Exporter { - private static final String XMP_SPLIT_PATTERN = "split"; + public static final String XMP_SPLIT_DIRECTORY_INDICATOR = "split"; private final XmpPreferences xmpPreferences; @@ -33,6 +33,12 @@ public XmpExporter(XmpPreferences xmpPreferences) { this.xmpPreferences = xmpPreferences; } + /** + * @param databaseContext the database to export from + * @param file the file to write to. If it contains "split", then the output is split into different files + * @param encoding the encoding to use + * @param entries a list containing all entries that should be exported + */ @Override public void export(BibDatabaseContext databaseContext, Path file, Charset encoding, List entries) throws Exception { Objects.requireNonNull(databaseContext); @@ -45,18 +51,16 @@ public void export(BibDatabaseContext databaseContext, Path file, Charset encodi // This is a distinction between writing all entries from the supplied list to a single .xmp file, // or write every entry to a separate file. - if (file.getFileName().toString().trim().equals(XMP_SPLIT_PATTERN)) { - + if (file.getFileName().toString().trim().equals(XMP_SPLIT_DIRECTORY_INDICATOR)) { for (BibEntry entry : entries) { // Avoid situations, where two cite keys are null Path entryFile; - String suffix = entry.getId() + "_" + entry.getField(InternalField.KEY_FIELD).orElse("") + ".xmp"; + String suffix = entry.getId() + "_" + entry.getField(InternalField.KEY_FIELD).orElse("null") + ".xmp"; if (file.getParent() == null) { entryFile = Paths.get(suffix); } else { entryFile = Paths.get(file.getParent().toString() + "/" + suffix); } - this.writeBibToXmp(entryFile, Collections.singletonList(entry), encoding); } } else { @@ -66,7 +70,6 @@ public void export(BibDatabaseContext databaseContext, Path file, Charset encodi private void writeBibToXmp(Path file, List entries, Charset encoding) throws IOException { String xmpContent = XmpUtilWriter.generateXmpStringWithoutXmpDeclaration(entries, this.xmpPreferences); - try (BufferedWriter writer = Files.newBufferedWriter(file, encoding)) { writer.write(xmpContent); writer.flush(); diff --git a/src/test/java/org/jabref/logic/exporter/XmpExporterTest.java b/src/test/java/org/jabref/logic/exporter/XmpExporterTest.java index d102c01aa39..120d27f8638 100644 --- a/src/test/java/org/jabref/logic/exporter/XmpExporterTest.java +++ b/src/test/java/org/jabref/logic/exporter/XmpExporterTest.java @@ -119,22 +119,23 @@ public void writeMultipleEntriesInASingleFile(@TempDir Path testFolder) throws E @Test public void writeMultipleEntriesInDifferentFiles(@TempDir Path testFolder) throws Exception { - Path file = testFolder.resolve("split"); + // set path to the one where the exporter produces several files + Path file = testFolder.resolve(XmpExporter.XMP_SPLIT_DIRECTORY_INDICATOR); Files.createFile(file); - BibEntry entryTuring = new BibEntry(); - entryTuring.setField(StandardField.AUTHOR, "Alan Turing"); + BibEntry entryTuring = new BibEntry() + .withField(StandardField.AUTHOR, "Alan Turing"); - BibEntry entryArmbrust = new BibEntry(); - entryArmbrust.setField(StandardField.AUTHOR, "Michael Armbrust"); - entryArmbrust.setCiteKey("Armbrust2010"); + BibEntry entryArmbrust = new BibEntry() + .withField(StandardField.AUTHOR, "Michael Armbrust") + .withCiteKey("Armbrust2010"); - exporter.export(databaseContext, file, encoding, Arrays.asList(entryTuring, entryArmbrust)); + exporter.export(databaseContext, file, encoding, List.of(entryTuring, entryArmbrust)); List lines = Files.readAllLines(file); assertEquals(Collections.emptyList(), lines); - Path fileTuring = Paths.get(file.getParent().toString() + "/" + entryTuring.getId() + "_null.xmp"); + Path fileTuring = Paths.get(file.getParent().toString(), entryTuring.getId() + "_null.xmp"); String actualTuring = String.join("\n", Files.readAllLines(fileTuring)); // we are using \n to join, so we need it in the expected string as well, \r\n would fail String expectedTuring = " \n" + @@ -155,7 +156,7 @@ public void writeMultipleEntriesInDifferentFiles(@TempDir Path testFolder) throw assertEquals(expectedTuring, actualTuring); - Path fileArmbrust = Paths.get(file.getParent().toString() + "/" + entryArmbrust.getId() + "_Armbrust2010.xmp"); + Path fileArmbrust = Paths.get(file.getParent().toString(), entryArmbrust.getId() + "_Armbrust2010.xmp"); String actualArmbrust = String.join("\n", Files.readAllLines(fileArmbrust)); // we are using \n to join, so we need it in the expected string as well, \r\n would fail String expectedArmbrust = " \n" + From 4a441d9768b7ca3e0df83449297bb2e1b5bf75ea Mon Sep 17 00:00:00 2001 From: dimitra-karadima <44123133+dimitra-karadima@users.noreply.github.com> Date: Tue, 14 Apr 2020 18:32:22 +0300 Subject: [PATCH 09/25] Change to the old school format Necessary change because the new pattern is only available preview in the compiler Co-Authored-By: Christoph --- src/main/java/org/jabref/gui/EntryTypeView.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/jabref/gui/EntryTypeView.java b/src/main/java/org/jabref/gui/EntryTypeView.java index a6324f5c5b7..74ea068625d 100644 --- a/src/main/java/org/jabref/gui/EntryTypeView.java +++ b/src/main/java/org/jabref/gui/EntryTypeView.java @@ -188,7 +188,9 @@ private void setEntryTypeForReturnAndClose(Optional entryType) { //Biblatex documentation is favored over the bibtex, //since bibtex is a subset of biblatex and biblatex is better documented. public static String getDescription(EntryType selectedType) { - if (selectedType instanceof StandardEntryType entry) { + if (selectedType instanceof StandardEntryType ) { + { + var entry = (StandardEntryType) selectedType; switch (entry) { case Article -> { return Localization.lang("An article in a journal, magazine, newspaper, or other periodical which forms a self-contained unit with its own title."); From a3050cde7cbfd03a9b180c33bc357624d64e8d0d Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Tue, 14 Apr 2020 18:19:50 +0200 Subject: [PATCH 10/25] Update EntryTypeView.java --- src/main/java/org/jabref/gui/EntryTypeView.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/jabref/gui/EntryTypeView.java b/src/main/java/org/jabref/gui/EntryTypeView.java index 74ea068625d..52dac1b4bfe 100644 --- a/src/main/java/org/jabref/gui/EntryTypeView.java +++ b/src/main/java/org/jabref/gui/EntryTypeView.java @@ -188,10 +188,8 @@ private void setEntryTypeForReturnAndClose(Optional entryType) { //Biblatex documentation is favored over the bibtex, //since bibtex is a subset of biblatex and biblatex is better documented. public static String getDescription(EntryType selectedType) { - if (selectedType instanceof StandardEntryType ) { - { - var entry = (StandardEntryType) selectedType; - switch (entry) { + if (selectedType instanceof StandardEntryType) { + switch ((StandardEntryType) selectedType) { case Article -> { return Localization.lang("An article in a journal, magazine, newspaper, or other periodical which forms a self-contained unit with its own title."); } From e86d415cccba1ad754818c39d8a23bd09e712496 Mon Sep 17 00:00:00 2001 From: Gennadiy Date: Tue, 14 Apr 2020 23:12:44 +0300 Subject: [PATCH 11/25] RIS import takes the wrong date and duplicates abstract (#6272) * Fixed a bug when "The abstract field is the concatenation of the AB and N2 fields." * Added test * Ouch, now I understand the testing system for importing. * Removed unnecessary imports --- CHANGELOG.md | 1 + .../importer/fileformat/RisImporter.java | 2 +- .../importer/fileformat/RisImporterTest9.bib | 18 +++++++++++++++ .../importer/fileformat/RisImporterTest9.ris | 23 +++++++++++++++++++ 4 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 src/test/resources/org/jabref/logic/importer/fileformat/RisImporterTest9.bib create mode 100644 src/test/resources/org/jabref/logic/importer/fileformat/RisImporterTest9.ris diff --git a/CHANGELOG.md b/CHANGELOG.md index 89324b0615c..b228a40986e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -86,6 +86,7 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve - We fixed an issue where citation styles except the default "Preview" could not be used. [#56220](https://github.com/JabRef/jabref/issues/5622) - We fixed an issue where a warning was displayed when the title content is made up of two sentences. [#5832](https://github.com/JabRef/jabref/issues/5832) - We fixed an issue where an exception was thrown when adding a save action without a selected formatter in the library properties [#6069](https://github.com/JabRef/jabref/issues/6069) +- We fixed an issue when an "Abstract field" was duplicating text, when importing from RIS file (Neurons) [#6065](https://github.com/JabRef/jabref/issues/6065) ### Removed diff --git a/src/main/java/org/jabref/logic/importer/fileformat/RisImporter.java b/src/main/java/org/jabref/logic/importer/fileformat/RisImporter.java index 59b896a2242..35e84f9296b 100644 --- a/src/main/java/org/jabref/logic/importer/fileformat/RisImporter.java +++ b/src/main/java/org/jabref/logic/importer/fileformat/RisImporter.java @@ -199,7 +199,7 @@ public ParserResult importDatabase(BufferedReader reader) throws IOException { String oldAb = fields.get(StandardField.ABSTRACT); if (oldAb == null) { fields.put(StandardField.ABSTRACT, value); - } else { + } else if (!oldAb.equals(value) && !value.isEmpty()) { fields.put(StandardField.ABSTRACT, oldAb + OS.NEWLINE + value); } } else if ("UR".equals(tag) || "L2".equals(tag) || "LK".equals(tag)) { diff --git a/src/test/resources/org/jabref/logic/importer/fileformat/RisImporterTest9.bib b/src/test/resources/org/jabref/logic/importer/fileformat/RisImporterTest9.bib new file mode 100644 index 00000000000..7555e5422d1 --- /dev/null +++ b/src/test/resources/org/jabref/logic/importer/fileformat/RisImporterTest9.bib @@ -0,0 +1,18 @@ +% Encoding: UTF-8 + +@Article{, + author = {Kriegeskorte, Nikolaus and Storrs, Katherine R.}, + title = {Grid Cells for Conceptual Spaces?}, + doi = {10.1016/j.neuron.2016.10.006}, + issn = {0896-6273}, + number = {2}, + pages = {280--284}, + url = {https://doi.org/10.1016/j.neuron.2016.10.006}, + volume = {92}, + abstract = {location and direction of movement in 2D physical environments via regularly repeating receptive fields.}, + comment = {doi: 10.1016/j.neuron.2016.10.006}, + journal = {Neuron}, + month = oct, + publisher = {Elsevier}, + year = {2016}, +} diff --git a/src/test/resources/org/jabref/logic/importer/fileformat/RisImporterTest9.ris b/src/test/resources/org/jabref/logic/importer/fileformat/RisImporterTest9.ris new file mode 100644 index 00000000000..496e17caa88 --- /dev/null +++ b/src/test/resources/org/jabref/logic/importer/fileformat/RisImporterTest9.ris @@ -0,0 +1,23 @@ +TY - JOUR +T1 - Grid Cells for Conceptual Spaces? +AU - Kriegeskorte, Nikolaus +AU - Storrs, Katherine R. +Y1 - 2016/10/19 +PY - 2016 +N1 - doi: 10.1016/j.neuron.2016.10.006 +DO - 10.1016/j.neuron.2016.10.006 +T2 - Neuron +JF - Neuron +SP - 280 +EP - 284 +VL - 92 +IS - 2 +PB - Elsevier +N2 - location and direction of movement in 2D physical environments via regularly repeating receptive fields. +AB - location and direction of movement in 2D physical environments via regularly repeating receptive fields. +SN - 0896-6273 +M3 - doi: 10.1016/j.neuron.2016.10.006 +UR - https://doi.org/10.1016/j.neuron.2016.10.006 +Y2 - 2020/03/04 +ER - + From 760cc0555743ccfd318703d0e3560f1b75376d5a Mon Sep 17 00:00:00 2001 From: dimitra-karadima <44123133+dimitra-karadima@users.noreply.github.com> Date: Tue, 14 Apr 2020 23:46:12 +0300 Subject: [PATCH 12/25] Fix errors Add the following change because some tests were failing. --- src/main/resources/l10n/JabRef_en.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index da4a8e29b55..9b28f876e25 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -2200,7 +2200,7 @@ User-specific\ relevance\ flag,\ in\ case\ the\ entry\ is\ relevant.=User-specif Remove\ formatter\ for\ %0=Remove formatter for %0 Remove\ formatter\ '%0'=Remove formatter '%0' -An\ article\ in\ a\ journal,\ magazine,\ newspaper,\ or\ other\ periodical\ which\ forms\ a\ self-contained\ unit\ with\ its\ own\ title.=An article in a journal, magazine, newspaper, or other periodical which forms aself-contained unit with its own title. +An\ article\ in\ a\ journal,\ magazine,\ newspaper,\ or\ other\ periodical\ which\ forms\ a\ self-contained\ unit\ with\ its\ own\ title.=An article in a journal, magazine, newspaper, or other periodical which forms a self-contained unit with its own title. A\ single-volume\ book\ with\ one\ or\ more\ authors\ where\ the\ authors\ share\ credit\ for\ the\ work\ as\ a\ whole.=A single-volume book with one or more authors where the authors share credit for the work as a whole. A\ book-like\ work\ without\ a\ formal\ publisher\ or\ sponsoring\ institution.=A book-like work without a formal publisher or sponsoring institution. A\ single-volume\ collection\ with\ multiple,\ self-contained\ contributions\ by\ distinct\ authors\ which\ have\ their\ own\ title.\ The\ work\ as\ a\ whole\ has\ no\ overall\ author\ but\ it\ will\ usually\ have\ an\ editor.=A single-volume collection with multiple, self-contained contributions by distinct authors which have their own title. The work as a whole has no overall author but it will usually have an editor. @@ -2209,7 +2209,7 @@ A\ part\ of\ a\ book\ which\ forms\ a\ self-contained\ unit\ with\ its\ own\ tit A\ contribution\ to\ a\ collection\ which\ forms\ a\ self-contained\ unit\ with\ a\ distinct\ author\ and\ title.=A contribution to a collection which forms a self-contained unit with a distinct author and title. An\ article\ in\ a\ conference\ proceedings.=An article in a conference proceedings. Technical\ or\ other\ documentation,\ not\ necessarily\ in\ printed\ form.=Technical or other documentation, not necessarily in printed form. -Similar\ to\ "Thesis"\ except\ that\ the\ type\ field\ is\ optional\ and\ defaults\ to\ the\ localised\ term\ Master's\ thesis.=Similar to "Thesis" except that the type field is optional and defaults to the localised term Master's thesis. +Similar\ to\ "Thesis"\ except\ that\ the\ type\ field\ is\ optional\ and\ defaults\ to\ the\ localised\ term\ Master's\ thesis.=Similar to "Thesis" except that the type field is optional and defaults to the localised term Master's thesis. A\ fallback\ type\ for\ entries\ which\ do\ not\ fit\ into\ any\ other\ category.=A fallback type for entries which do not fit into any other category. Similar\ to\ "Thesis"\ except\ that\ the\ type\ field\ is\ optional\ and\ defaults\ to\ the\ localised\ term\ PhD\ thesis.=Similar to "Thesis" except that the type field is optional and defaults to the localised term PhD thesis. A\ single-volume\ conference\ proceedings.\ This\ type\ is\ very\ similar\ to\ "Collection".=A single-volume conference proceedings. This type is very similar to "Collection". From d2df6f7227f886a784993bfc02a2b121f946406c Mon Sep 17 00:00:00 2001 From: dimitra-karadima <44123133+dimitra-karadima@users.noreply.github.com> Date: Wed, 15 Apr 2020 00:25:17 +0300 Subject: [PATCH 13/25] Add one more change Failing unit tests should stop. --- src/main/resources/l10n/JabRef_en.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index 9b28f876e25..e50db980f55 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -2209,7 +2209,7 @@ A\ part\ of\ a\ book\ which\ forms\ a\ self-contained\ unit\ with\ its\ own\ tit A\ contribution\ to\ a\ collection\ which\ forms\ a\ self-contained\ unit\ with\ a\ distinct\ author\ and\ title.=A contribution to a collection which forms a self-contained unit with a distinct author and title. An\ article\ in\ a\ conference\ proceedings.=An article in a conference proceedings. Technical\ or\ other\ documentation,\ not\ necessarily\ in\ printed\ form.=Technical or other documentation, not necessarily in printed form. -Similar\ to\ "Thesis"\ except\ that\ the\ type\ field\ is\ optional\ and\ defaults\ to\ the\ localised\ term\ Master's\ thesis.=Similar to "Thesis" except that the type field is optional and defaults to the localised term Master's thesis. +Similar\ to\ "Thesis"\ except\ that\ the type\ field\ is\ optional\ and\ defaults\ to\ the\ localised\ term\ Master's\ thesis.=Similar to "Thesis" except that the type field is optional and defaults to the localised term Master's thesis. A\ fallback\ type\ for\ entries\ which\ do\ not\ fit\ into\ any\ other\ category.=A fallback type for entries which do not fit into any other category. Similar\ to\ "Thesis"\ except\ that\ the\ type\ field\ is\ optional\ and\ defaults\ to\ the\ localised\ term\ PhD\ thesis.=Similar to "Thesis" except that the type field is optional and defaults to the localised term PhD thesis. A\ single-volume\ conference\ proceedings.\ This\ type\ is\ very\ similar\ to\ "Collection".=A single-volume conference proceedings. This type is very similar to "Collection". From 2ea22fba0e77a4af426704b7625f322729f40804 Mon Sep 17 00:00:00 2001 From: dimitra-karadima <44123133+dimitra-karadima@users.noreply.github.com> Date: Wed, 15 Apr 2020 01:44:04 +0300 Subject: [PATCH 14/25] Resolve unit test from failing --- src/main/resources/l10n/JabRef_en.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index e50db980f55..bf85dc26e6d 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -2209,7 +2209,7 @@ A\ part\ of\ a\ book\ which\ forms\ a\ self-contained\ unit\ with\ its\ own\ tit A\ contribution\ to\ a\ collection\ which\ forms\ a\ self-contained\ unit\ with\ a\ distinct\ author\ and\ title.=A contribution to a collection which forms a self-contained unit with a distinct author and title. An\ article\ in\ a\ conference\ proceedings.=An article in a conference proceedings. Technical\ or\ other\ documentation,\ not\ necessarily\ in\ printed\ form.=Technical or other documentation, not necessarily in printed form. -Similar\ to\ "Thesis"\ except\ that\ the type\ field\ is\ optional\ and\ defaults\ to\ the\ localised\ term\ Master's\ thesis.=Similar to "Thesis" except that the type field is optional and defaults to the localised term Master's thesis. +Similar\ to\ "Thesis"\ except\ that\ the type\ field\ is\ optional\ and\ defaults\ to\ the\ localised\ term\ Master\ thesis.=Similar to "Thesis" except that the type field is optional and defaults to the localised term Master thesis. A\ fallback\ type\ for\ entries\ which\ do\ not\ fit\ into\ any\ other\ category.=A fallback type for entries which do not fit into any other category. Similar\ to\ "Thesis"\ except\ that\ the\ type\ field\ is\ optional\ and\ defaults\ to\ the\ localised\ term\ PhD\ thesis.=Similar to "Thesis" except that the type field is optional and defaults to the localised term PhD thesis. A\ single-volume\ conference\ proceedings.\ This\ type\ is\ very\ similar\ to\ "Collection".=A single-volume conference proceedings. This type is very similar to "Collection". From 10c4a4aeb83a942377a6d2c3ec690e09867707fd Mon Sep 17 00:00:00 2001 From: github actions Date: Wed, 15 Apr 2020 02:06:44 +0000 Subject: [PATCH 15/25] Squashed 'src/main/resources/csl-styles/' changes from c31d9ca05a..c1793d2fe0 c1793d2fe0 Create isnad-metinici.csl (#4704) 099f4a15af Create isnad-dipnotlu.csl (#4703) 8e8639e079 Update norois.csl (#4706) 62f622181b Create amsterdam-university-press.csl (#4699) git-subtree-dir: src/main/resources/csl-styles git-subtree-split: c1793d2fe0d534c82b1e6125ad1d75d83536ffcc --- amsterdam-university-press-academic.csl | 459 ++++++ isnad-dipnotlu.csl | 1819 +++++++++++++++++++++++ isnad-metinici.csl | 1277 ++++++++++++++++ norois.csl | 26 +- 4 files changed, 3567 insertions(+), 14 deletions(-) create mode 100644 amsterdam-university-press-academic.csl create mode 100644 isnad-dipnotlu.csl create mode 100644 isnad-metinici.csl diff --git a/amsterdam-university-press-academic.csl b/amsterdam-university-press-academic.csl new file mode 100644 index 00000000000..7a302c202af --- /dev/null +++ b/amsterdam-university-press-academic.csl @@ -0,0 +1,459 @@ + + diff --git a/isnad-dipnotlu.csl b/isnad-dipnotlu.csl new file mode 100644 index 00000000000..03ac1faaaba --- /dev/null +++ b/isnad-dipnotlu.csl @@ -0,0 +1,1819 @@ + + diff --git a/isnad-metinici.csl b/isnad-metinici.csl new file mode 100644 index 00000000000..f8c478ffd93 --- /dev/null +++ b/isnad-metinici.csl @@ -0,0 +1,1277 @@ + + diff --git a/norois.csl b/norois.csl index 829dcacc9a8..01f793c4c9c 100644 --- a/norois.csl +++ b/norois.csl @@ -13,7 +13,7 @@ 0029-182X 1760-8546 - 2020-04-06T09:41:00+00:00 + 2020-04-14T10:19:50+00:00 This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License @@ -32,7 +32,7 @@ - + @@ -52,7 +52,7 @@ - + - + @@ -508,8 +504,10 @@ - - + + + + From 02d4022627fb26b6f1e04b69149c76688e46c4be Mon Sep 17 00:00:00 2001 From: dimitra-karadima <44123133+dimitra-karadima@users.noreply.github.com> Date: Wed, 15 Apr 2020 09:38:07 +0300 Subject: [PATCH 16/25] Change one more line Trying to stop failing unit tests --- src/main/resources/l10n/JabRef_en.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index bf85dc26e6d..0dba12d4e08 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -2209,7 +2209,7 @@ A\ part\ of\ a\ book\ which\ forms\ a\ self-contained\ unit\ with\ its\ own\ tit A\ contribution\ to\ a\ collection\ which\ forms\ a\ self-contained\ unit\ with\ a\ distinct\ author\ and\ title.=A contribution to a collection which forms a self-contained unit with a distinct author and title. An\ article\ in\ a\ conference\ proceedings.=An article in a conference proceedings. Technical\ or\ other\ documentation,\ not\ necessarily\ in\ printed\ form.=Technical or other documentation, not necessarily in printed form. -Similar\ to\ "Thesis"\ except\ that\ the type\ field\ is\ optional\ and\ defaults\ to\ the\ localised\ term\ Master\ thesis.=Similar to "Thesis" except that the type field is optional and defaults to the localised term Master thesis. +Similar\ to\ "Thesis"\ except\ that\ the\ type\ field\ is\ optional\ and\ defaults\ to\ the\ localised\ term\ Master\ thesis.=Similar to "Thesis" except that the type field is optional and defaults to the localised term Master thesis. A\ fallback\ type\ for\ entries\ which\ do\ not\ fit\ into\ any\ other\ category.=A fallback type for entries which do not fit into any other category. Similar\ to\ "Thesis"\ except\ that\ the\ type\ field\ is\ optional\ and\ defaults\ to\ the\ localised\ term\ PhD\ thesis.=Similar to "Thesis" except that the type field is optional and defaults to the localised term PhD thesis. A\ single-volume\ conference\ proceedings.\ This\ type\ is\ very\ similar\ to\ "Collection".=A single-volume conference proceedings. This type is very similar to "Collection". From 6635ecea8dcd878a429d7727740e5a14c9afa585 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Wed, 15 Apr 2020 11:32:38 +0200 Subject: [PATCH 17/25] Fix labels for outdated dependency issue --- .github/outdatedDependencies.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/outdatedDependencies.md b/.github/outdatedDependencies.md index c750c81fb06..62b87165631 100644 --- a/.github/outdatedDependencies.md +++ b/.github/outdatedDependencies.md @@ -1,5 +1,5 @@ --- title: Outdated dependencies -labels: code-quality, dependencies +labels: t: dependencies --- [There are outdated dependencies!](https://github.com/JabRef/jabref/actions?query=is%3Afailure+workflow%3A%22Check+dependencies%22) From de7deb29914041187b4e25398140311fcb3c3129 Mon Sep 17 00:00:00 2001 From: Tianjian lei Date: Wed, 15 Apr 2020 20:15:01 +0800 Subject: [PATCH 18/25] Showing correct icon on main table linked files column (#6264) * Showing correct icon on main table linked files column * Showing correct icon on both main table and linked files column * Showing correct icon on both main table and linked file editor list * delete the TODO comments * add record in CHANGELOG.md --- CHANGELOG.md | 2 +- .../jabref/gui/externalfiletype/ExternalFileTypes.java | 2 +- .../org/jabref/gui/fieldeditors/LinkedFileViewModel.java | 8 +++----- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b228a40986e..ff6295cde77 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,7 +37,7 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve - We fixed an issue when importing into current library an erroneous message "import cancelled" is displayed even though import is successful. [#6266](https://github.com/JabRef/jabref/issues/6266) - We fixed an issue where custom jstyles for Open/LibreOffice where not saved correctly. [#6170](https://github.com/JabRef/jabref/issues/6170) - We fixed an issue where the INSPIRE fetcher was no longer working [#6229](https://github.com/JabRef/jabref/issues/6229) - +- We fixed the display of icon both in the main table and linked file editor. [#6169](https://github.com/JabRef/jabref/issues/6169) ### Removed diff --git a/src/main/java/org/jabref/gui/externalfiletype/ExternalFileTypes.java b/src/main/java/org/jabref/gui/externalfiletype/ExternalFileTypes.java index 1c24f739ffd..ed26d3d8373 100644 --- a/src/main/java/org/jabref/gui/externalfiletype/ExternalFileTypes.java +++ b/src/main/java/org/jabref/gui/externalfiletype/ExternalFileTypes.java @@ -56,7 +56,7 @@ public Set getExternalFileTypeSelection() { * @return The ExternalFileType registered, or null if none. */ public Optional getExternalFileTypeByName(String name) { - Optional externalFileType = externalFileTypes.stream().filter(type -> type.getExtension().equals(name)).findFirst(); + Optional externalFileType = externalFileTypes.stream().filter(type -> type.getName().equals(name)).findFirst(); if (externalFileType.isPresent()) { return externalFileType; } diff --git a/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java index e57513db0b7..43233afc802 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java @@ -136,12 +136,10 @@ public Optional findIn(List directories) { return linkedFile.findIn(directories); } - /** - * TODO: Be a bit smarter and try to infer correct icon, for example using {@link - * org.jabref.gui.externalfiletype.ExternalFileTypes#getExternalFileTypeByName(String)} - */ public JabRefIcon getTypeIcon() { - return IconTheme.JabRefIcons.PDF_FILE; + return externalFileTypes.fromLinkedFile(linkedFile, false) + .map(ExternalFileType::getIcon) + .orElse(IconTheme.JabRefIcons.FILE); } public void markAsAutomaticallyFound() { From 01189efd96c7f9691789248e0f519a2083cb8181 Mon Sep 17 00:00:00 2001 From: Oliver Kopp Date: Wed, 15 Apr 2020 21:32:01 +0200 Subject: [PATCH 19/25] Try to minimize CodeCov "wrong metrics" --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 001004798d3..572c836fe90 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -205,7 +205,7 @@ jobs: if: ${{ steps.checksecrets.outputs.secretspresent }} run: xvfb-run --auto-servernum ./gradlew jacocoTestReport && bash <(curl -s https://codecov.io/bash); env: - CI: "false" # we pretend to run locally - even if tests fail on the CI, they count towards test coverage + CI: "true" CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} DBMS: "postgresql" # This is https://github.com/marketplace/actions/gradle-wrapper-validation From 3e517e0e1cbdec794b01540d44ededc027b0d880 Mon Sep 17 00:00:00 2001 From: Siedlerchr Date: Thu, 16 Apr 2020 08:51:59 +0200 Subject: [PATCH 20/25] fix l10n --- src/main/resources/l10n/JabRef_en.properties | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index 0dba12d4e08..c81ad5f95b3 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -2209,7 +2209,6 @@ A\ part\ of\ a\ book\ which\ forms\ a\ self-contained\ unit\ with\ its\ own\ tit A\ contribution\ to\ a\ collection\ which\ forms\ a\ self-contained\ unit\ with\ a\ distinct\ author\ and\ title.=A contribution to a collection which forms a self-contained unit with a distinct author and title. An\ article\ in\ a\ conference\ proceedings.=An article in a conference proceedings. Technical\ or\ other\ documentation,\ not\ necessarily\ in\ printed\ form.=Technical or other documentation, not necessarily in printed form. -Similar\ to\ "Thesis"\ except\ that\ the\ type\ field\ is\ optional\ and\ defaults\ to\ the\ localised\ term\ Master\ thesis.=Similar to "Thesis" except that the type field is optional and defaults to the localised term Master thesis. A\ fallback\ type\ for\ entries\ which\ do\ not\ fit\ into\ any\ other\ category.=A fallback type for entries which do not fit into any other category. Similar\ to\ "Thesis"\ except\ that\ the\ type\ field\ is\ optional\ and\ defaults\ to\ the\ localised\ term\ PhD\ thesis.=Similar to "Thesis" except that the type field is optional and defaults to the localised term PhD thesis. A\ single-volume\ conference\ proceedings.\ This\ type\ is\ very\ similar\ to\ "Collection".=A single-volume conference proceedings. This type is very similar to "Collection". From bf01f0bcfd6a9bd5ec40ef26f54fc1891f1f0db1 Mon Sep 17 00:00:00 2001 From: Siedlerchr Date: Thu, 16 Apr 2020 09:01:10 +0200 Subject: [PATCH 21/25] fix checkstyle --- config/checkstyle/checkstyle.xml | 2 +- src/main/java/org/jabref/gui/EntryTypeView.java | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index d57f19c6853..2de4703981a 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -12,7 +12,7 @@ - + diff --git a/src/main/java/org/jabref/gui/EntryTypeView.java b/src/main/java/org/jabref/gui/EntryTypeView.java index 52dac1b4bfe..657fe4b20f0 100644 --- a/src/main/java/org/jabref/gui/EntryTypeView.java +++ b/src/main/java/org/jabref/gui/EntryTypeView.java @@ -188,6 +188,7 @@ private void setEntryTypeForReturnAndClose(Optional entryType) { //Biblatex documentation is favored over the bibtex, //since bibtex is a subset of biblatex and biblatex is better documented. public static String getDescription(EntryType selectedType) { + //CHECKSTYLE:OFF if (selectedType instanceof StandardEntryType) { switch ((StandardEntryType) selectedType) { case Article -> { @@ -293,6 +294,8 @@ public static String getDescription(EntryType selectedType) { } else { return ""; } + //CHECKSTYLE:ON + } } From 410f8ba4abaad4ff07afcfb8ab12ea62ef2553e2 Mon Sep 17 00:00:00 2001 From: Siedlerchr Date: Thu, 16 Apr 2020 09:19:52 +0200 Subject: [PATCH 22/25] fix l10n again --- src/main/resources/l10n/JabRef_en.properties | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index c81ad5f95b3..28f5f56b5af 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -2210,6 +2210,7 @@ A\ contribution\ to\ a\ collection\ which\ forms\ a\ self-contained\ unit\ with\ An\ article\ in\ a\ conference\ proceedings.=An article in a conference proceedings. Technical\ or\ other\ documentation,\ not\ necessarily\ in\ printed\ form.=Technical or other documentation, not necessarily in printed form. A\ fallback\ type\ for\ entries\ which\ do\ not\ fit\ into\ any\ other\ category.=A fallback type for entries which do not fit into any other category. +Similar\ to\ "Thesis"\ except\ that\ the\ type\ field\ is\ optional\ and\ defaults\ to\ the\ localised\ term\ \ Master's\ thesis.=Similar to "Thesis" except that the type field is optional and defaults to the localised term Master's thesis. Similar\ to\ "Thesis"\ except\ that\ the\ type\ field\ is\ optional\ and\ defaults\ to\ the\ localised\ term\ PhD\ thesis.=Similar to "Thesis" except that the type field is optional and defaults to the localised term PhD thesis. A\ single-volume\ conference\ proceedings.\ This\ type\ is\ very\ similar\ to\ "Collection".=A single-volume conference proceedings. This type is very similar to "Collection". Similar\ to\ "Report"\ except\ that\ the\ type\ field\ is\ optional\ and\ defaults\ to\ the\ localised\ term\ technical\ report.=Similar to "Report" except that the type field is optional and defaults to the localised term technical report. From 4a9247b68c4c20a2cac7331778dbcc4741d6903c Mon Sep 17 00:00:00 2001 From: Matthias Mayr Date: Thu, 16 Apr 2020 22:12:02 +0200 Subject: [PATCH 23/25] Add missing abbreviated journal names (#6292) --- src/main/resources/journals/journalList.csv | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/resources/journals/journalList.csv b/src/main/resources/journals/journalList.csv index 993a4650bc5..0ebc39f583d 100644 --- a/src/main/resources/journals/journalList.csv +++ b/src/main/resources/journals/journalList.csv @@ -450,6 +450,7 @@ Advanced Materials;Adv. Mater.;; Advanced Materials and Processes;Adv. Mater. Processes;; Advanced Materials for Optics and Electronics;Adv. Mater. Opt. Electron.;; Advanced Materials Forum;Adv. Mater. Forum;; +Advanced Modeling and Simulation in Engineering Sciences;Adv. Model. Simul. Eng. Sci.;; Advanced Optical Materials;Adv. Opt. Mater.;; Advanced Powder Technology;Adv. Powder Technol.;; Advanced Practice Nursing Quarterly;Adv. Pract. Nurs. Q.;; @@ -1345,6 +1346,7 @@ Appled Entomology and Zoology;Appl. Entomol. Zool.;; Applicable Algebra in Engineering, Communication and Computing;Appl. Algebra Eng. Commun. Comput.;; Applications and Applied Mathematics;Appl. Appl. Math.;; Applications in Plant Sciences;Appl. Plant Sci.;; +Applications of Mathematics;Appl. Math.;; Applied Accoustics;Appl. Acoust.;; Applied Adhesion Science;Appl. Adhes. Sci.;; Applied and Computational Harmonic Analysis;Appl. Comput. Harmon. Anal.;; @@ -3308,7 +3310,7 @@ Climate Dynamics;Climate Dyn.;; Climate of the Past;Clim. Past;; Climate of the Past Discussion;Clim. Past Discuss.;; Climate Risk Management;Clim. Risk Manage.;; -Climatic Change;Climatic Change;; +Climatic Change;Clim. Change;; Climatological Bulletin;Climatol. Bull.;; Clinic;Clinic (Paris);; Clinic Odontologia;Clin. Odontol.;; @@ -3645,6 +3647,7 @@ Computational Condensed Matter;Comput. Condens. Matter;; Computational Geometry: Theory and Applications;Comput. Geom. Theory Appl.;; Computational Geosciences;Comput. Geosci.;; Computational Intelligence;Comput. Intell.;; +Computational Materials Science;Comput. Mater. Sci.;; Computational Mathematics and Mathematical Physics;Comput. Math. Math. Phys.;; Computational Mathematics and Modeling;Comput. Math. Model.;; Computational Mechanics;Comput. Mech.;; @@ -4576,6 +4579,7 @@ Engineering Analysis with Boundary Elements;Eng. Anal. Boundary Elem.;; Engineering and Mining Journal;Eng. Min. J.;; Engineering and Mining Journal Press;Eng. Min. J. Press;; Engineering Applications of Artificial Intelligence;Eng. Appl. Artif. Intell.;; +Engineering Computations;Eng. Comput.;; Engineering Failure Analysis;Eng. Fail. Anal.;; Engineering Fracture Mechanics;Eng. Fract. Mech.;; Engineering Geology;Eng. Geol.;; @@ -6352,6 +6356,7 @@ Instruments and Experiment Techniques;Instrum. Exp. Tech.;; Integrated Environmental Assessment and Management;Integr. Environ. Assess. Manage.;; Integrated Ferroelectrics;Integr. Ferroelectr.;; Integrated Healthcare Report;Integr. Healthc. Rep.;; +Integrating Materials and Manufacturing Innovation;Integr. Mater. Manuf. Innov.;; Integrative and Comparative Biology;Integr. Comp. Biol.;; Integrative Biology;Integr. Biol.;; Integrative Cancer Therapies;Integr. Cancer Ther.;; @@ -7701,6 +7706,7 @@ Journal of Computational Electronics;J. Comput. Electron.;; Journal of Computational Methods in Science and Engineering;J. Comput. Methods Sci. Eng.;; Journal of Computational Neuroscience;J. Comput. Neurosci.;; Journal of Computational Physics;J. Comput. Phys.;; +Journal of Computational Science;J. Comput. Sci.;; Journal of Computed Tomography;J. Comput. Tomogr.;; Journal of Computer and System Sciences International;J. Comput. Syst. Sci. Int.;; Journal of Computer Assisted Tomography;J. Comput. Assisted Tomogr.;; @@ -10524,7 +10530,7 @@ MRS Internet Journal of Nitride Semiconductor Research;MRS Internet J. Nitride S MSDA Journal;MSDA J.;; Mucopolysaccharides Biochimica et Biophysica Acta, Specialized Section on Mucoproteins and Mucopolysaccharides;Biochim. Biophys. Acta, Spec. Sect. Mucoproteins;BBASFB; Mull und Abfall;Mull Abfall;; -Multibody System Dynamics;Multibody Sys.Dyn.;; +Multibody System Dynamics;Multibody Sys. Dyn.;; Multidimensional Systems and Signal Processing;Multidimension. Syst. Signal Process.;; Multiple Sclerosis;Mult. Scler.;; Multis;Multis;; @@ -11112,6 +11118,7 @@ Nukleonika;Nukleonika;; Numerical Analysis and Applications;Numer. Anal. Appl.;; Numerical Heat Transfer Part A;Numer. Heat Transfer, Part A;; Numerical Heat Transfer Part B;Numer. Heat Transfer, Part B;; +Numerical Linear Algebra with Applications;Numer. Linear Algebra Appl.;; Nuntius Radiologicus;Nunt. Radiol.;; Nuova Rivista di Neurologia;Nuova Riv. Neurol.;; Nuovi Annali d'Igiene e Microbiologia;Nuovi Ann. Ig. Microbiol.;; @@ -13660,6 +13667,7 @@ SIAM Journal on Mathematical Analysis;SIAM J. Math. Anal.;; SIAM Journal on Matrix Analysis and Applications;SIAM J. Matrix Anal. Appl.;; SIAM Journal on Numerical Analysis;SIAM J. Numer. Anal.;; SIAM Journal on Optimization;SIAM J. Optim.;; +SIAM Journal on Scientific and Statistical Computing;SIAM J. Sci. Stat. Comput.;; SIAM Review;SIAM Rev.;; Sichuan Da Xue Xue Bao. Yi Xue Ban (Journal of Sichuan University. Medical Science Edition);Sichuan Da Xue Xue Bao Yi Xue Ban;; Sichuan Yi Xue Yuan Xue Bao (Acta Academiae Medicinae Sichuan);Sichuan Yi Xue Yuan Xue Bao;; From accd387297c8044a13b1fed924ab004a5acf0627 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Fri, 17 Apr 2020 16:18:04 +0200 Subject: [PATCH 24/25] Reduce memory footprint (#6298) * Improve performance - Cache latex free field values for display in the main table - Only access preferences once for how to display names (instead of for every entry again) - Update search async only after 400ms without typing * Fix tests * Reduce memory footprint by removing some caching of ids and keys in databases --- .../bibtexkeypattern/BibtexKeyGenerator.java | 4 +- .../BibtexKeyDuplicationChecker.java | 8 +- .../jabref/model/database/BibDatabase.java | 49 ++++---- .../model/database/DuplicationChecker.java | 107 ------------------ .../model/database/BibDatabaseTest.java | 80 ++++++------- .../database/DuplicationCheckerTest.java | 52 ++++----- 6 files changed, 95 insertions(+), 205 deletions(-) delete mode 100644 src/main/java/org/jabref/model/database/DuplicationChecker.java diff --git a/src/main/java/org/jabref/logic/bibtexkeypattern/BibtexKeyGenerator.java b/src/main/java/org/jabref/logic/bibtexkeypattern/BibtexKeyGenerator.java index d887ac16a15..63279fcfece 100644 --- a/src/main/java/org/jabref/logic/bibtexkeypattern/BibtexKeyGenerator.java +++ b/src/main/java/org/jabref/logic/bibtexkeypattern/BibtexKeyGenerator.java @@ -157,7 +157,7 @@ public String generateKey(BibEntry entry) { } String oldKey = entry.getCiteKeyOptional().orElse(null); - int occurrences = database.getDuplicationChecker().getNumberOfKeyOccurrences(key); + long occurrences = database.getNumberOfKeyOccurrences(key); if (Objects.equals(oldKey, key)) { occurrences--; // No change, so we can accept one dupe. @@ -178,7 +178,7 @@ public String generateKey(BibEntry entry) { moddedKey = key + getAppendix(number); number++; - occurrences = database.getDuplicationChecker().getNumberOfKeyOccurrences(moddedKey); + occurrences = database.getNumberOfKeyOccurrences(moddedKey); // only happens if #getAddition() is buggy if (Objects.equals(oldKey, moddedKey)) { occurrences--; diff --git a/src/main/java/org/jabref/logic/integrity/BibtexKeyDuplicationChecker.java b/src/main/java/org/jabref/logic/integrity/BibtexKeyDuplicationChecker.java index 3448e799d08..7112653709e 100644 --- a/src/main/java/org/jabref/logic/integrity/BibtexKeyDuplicationChecker.java +++ b/src/main/java/org/jabref/logic/integrity/BibtexKeyDuplicationChecker.java @@ -3,6 +3,7 @@ import java.util.Collections; import java.util.List; import java.util.Objects; +import java.util.Optional; import org.jabref.logic.integrity.IntegrityCheck.Checker; import org.jabref.logic.l10n.Localization; @@ -20,7 +21,12 @@ public BibtexKeyDuplicationChecker(BibDatabase database) { @Override public List check(BibEntry entry) { - boolean isDuplicate = database.getDuplicationChecker().isDuplicateCiteKeyExisting(entry); + Optional citeKey = entry.getCiteKeyOptional(); + if (citeKey.isEmpty()) { + return Collections.emptyList(); + } + + boolean isDuplicate = database.isDuplicateCiteKeyExisting(citeKey.get()); if (isDuplicate) { return Collections.singletonList( new IntegrityMessage(Localization.lang("Duplicate BibTeX key"), entry, StandardField.KEY)); diff --git a/src/main/java/org/jabref/model/database/BibDatabase.java b/src/main/java/org/jabref/model/database/BibDatabase.java index 814925ee55f..6496283130a 100644 --- a/src/main/java/org/jabref/model/database/BibDatabase.java +++ b/src/main/java/org/jabref/model/database/BibDatabase.java @@ -53,16 +53,6 @@ public class BibDatabase { private final ObservableList entries = FXCollections.synchronizedObservableList(FXCollections.observableArrayList(BibEntry::getObservables)); private Map bibtexStrings = new ConcurrentHashMap<>(); - /** - * this is kept in sync with the database (upon adding/removing an entry, it is updated as well) - */ - private final DuplicationChecker duplicationChecker = new DuplicationChecker(); - - /** - * contains all entry.getID() of the current database - */ - private final Set internalIDs = new HashSet<>(); - private final EventBus eventBus = new EventBus(); private String preamble; @@ -72,7 +62,6 @@ public class BibDatabase { private String sharedDatabaseID; public BibDatabase() { - this.eventBus.register(duplicationChecker); this.registerListener(new KeyChangeListener(this)); } @@ -125,7 +114,7 @@ public synchronized List getEntriesSorted(Comparator compara * Returns whether an entry with the given ID exists (-> entry_type + hashcode). */ public boolean containsEntryWithId(String id) { - return internalIDs.contains(id); + return entries.stream().anyMatch(entry -> entry.getId().equals(id)); } public ObservableList getEntries() { @@ -179,16 +168,6 @@ public synchronized List getEntriesByKey(String key) { return result; } - /** - * Finds the entry with a specified ID. - * - * @param id - * @return The entry that has the given id - */ - public synchronized Optional getEntryById(String id) { - return entries.stream().filter(entry -> entry.getId().equals(id)).findFirst(); - } - /** * Inserts the entry, given that its ID is not already in use. * use Util.createId(...) to make up a unique ID for an entry. @@ -211,7 +190,7 @@ public synchronized boolean insertEntry(BibEntry entry) throws KeyCollisionExcep */ public synchronized boolean insertEntry(BibEntry entry, EntriesEventSource eventSource) throws KeyCollisionException { insertEntries(Collections.singletonList(entry), eventSource); - return duplicationChecker.isDuplicateCiteKeyExisting(entry); + return entry.getCiteKeyOptional().map(this::isDuplicateCiteKeyExisting).orElse(false); } public synchronized void insertEntries(BibEntry... entries) throws KeyCollisionException { @@ -230,7 +209,6 @@ public synchronized void insertEntries(List newEntries, EntriesEventSo throw new KeyCollisionException("ID is already in use, please choose another", id); } - internalIDs.add(id); entry.registerListener(this); } if (newEntries.isEmpty()) { @@ -251,7 +229,8 @@ public synchronized void removeEntry(BibEntry bibEntry, EntriesEventSource event /** * Removes the given entries. - * The entries removed based on the id {@link BibEntry#id} + * The entries removed based on the id {@link BibEntry#getId()} + * * @param toBeDeleted Entries to delete */ public synchronized void removeEntries(List toBeDeleted) { @@ -260,7 +239,7 @@ public synchronized void removeEntries(List toBeDeleted) { /** * Removes the given entries. - * The entries are removed based on the id {@link BibEntry#id} + * The entries are removed based on the id {@link BibEntry#getId()} * * @param toBeDeleted Entry to delete * @param eventSource Source the event is sent from @@ -274,7 +253,6 @@ public synchronized void removeEntries(List toBeDeleted, EntriesEventS } boolean anyRemoved = entries.removeIf(entry -> ids.contains(entry.getId())); if (anyRemoved) { - internalIDs.removeAll(ids); eventBus.post(new EntriesRemovedEvent(toBeDeleted, eventSource)); } } @@ -640,7 +618,20 @@ public String generateSharedDatabaseID() { return this.sharedDatabaseID; } - public DuplicationChecker getDuplicationChecker() { - return duplicationChecker; + /** + * Returns the number of occurrences of the given key in this database. + */ + public long getNumberOfKeyOccurrences(String citeKey) { + return entries.stream() + .flatMap(entry -> entry.getCiteKeyOptional().stream()) + .filter(key -> key.equals(citeKey)) + .count(); + } + + /** + * Checks if there is more than one occurrence of the cite key + */ + public boolean isDuplicateCiteKeyExisting(String citeKey) { + return getNumberOfKeyOccurrences(citeKey) > 1; } } diff --git a/src/main/java/org/jabref/model/database/DuplicationChecker.java b/src/main/java/org/jabref/model/database/DuplicationChecker.java deleted file mode 100644 index 4667cdbc1da..00000000000 --- a/src/main/java/org/jabref/model/database/DuplicationChecker.java +++ /dev/null @@ -1,107 +0,0 @@ -package org.jabref.model.database; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -import org.jabref.model.database.event.EntriesAddedEvent; -import org.jabref.model.database.event.EntriesRemovedEvent; -import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.event.FieldChangedEvent; -import org.jabref.model.entry.field.InternalField; - -import com.google.common.eventbus.Subscribe; - -/** - * Determines which bibtex cite keys are duplicates in a single {@link BibDatabase}. - */ -public class DuplicationChecker { - - /** use a map instead of a set since I need to know how many of each key is in there */ - private final Map allKeys = new HashMap<>(); - - /** - * Checks if there is more than one occurrence of this key - */ - private boolean isDuplicateCiteKeyExisting(String citeKey) { - return getNumberOfKeyOccurrences(citeKey) > 1; - } - - /** - * Checks if there is more than one occurrence of the cite key - */ - public boolean isDuplicateCiteKeyExisting(BibEntry entry) { - return isDuplicateCiteKeyExisting(entry.getCiteKeyOptional().orElse(null)); - } - - /** - * Returns the number of occurrences of the given key in this database. - */ - public int getNumberOfKeyOccurrences(String citeKey) { - return allKeys.getOrDefault(citeKey, 0); - } - - /** - * Helper function for counting the number of the key usages. - * Adds the given key to the internal keyset together with the count of it. - * The counter is increased if the key already exists, otherwise set to 1. - *
- * Special case: If a null or empty key is passed, it is not counted and thus not added. - * - * Reasoning: - * Consider this: I add a key xxx, then I add another key xxx. I get a warning. I delete the key xxx. - * Consider JabRef simply removing this key from a set of allKeys. - * Then I add another key xxx. I don't get a warning! - * Thus, I need a way to count the number of keys of each type. - * Solution: hashmap=>int (increment each time at add and decrement each time at remove) - */ - private void addKeyToSet(String key) { - if (key == null || key.isEmpty()) { - return; - } - - allKeys.put(key, getNumberOfKeyOccurrences(key) + 1); - } - - /** - * Helper function for counting the number of the key usages. - * Removes the given key from the internal keyset together with the count of it, if the key is set to 1. - * If it is not set to 1, the counter will be decreased. - *
- * Special case: If a null or empty key is passed, it is not counted and thus not removed. - */ - private void removeKeyFromSet(String key) { - if (key == null || key.isEmpty()) { - return; - } - - int numberOfKeyOccurrences = getNumberOfKeyOccurrences(key); - if (numberOfKeyOccurrences > 1) { - allKeys.put(key, numberOfKeyOccurrences - 1); - } else { - allKeys.remove(key); - } - } - - @Subscribe - public void listen(FieldChangedEvent fieldChangedEvent) { - if (fieldChangedEvent.getField().equals(InternalField.KEY_FIELD)) { - removeKeyFromSet(fieldChangedEvent.getOldValue()); - addKeyToSet(fieldChangedEvent.getNewValue()); - } - } - - @Subscribe - public void listen(EntriesRemovedEvent entriesRemovedEvent) { - List entries = entriesRemovedEvent.getBibEntries(); - entries.stream().map(BibEntry::getCiteKeyOptional).flatMap(Optional::stream).forEach(citeKey -> removeKeyFromSet(citeKey)); - } - - @Subscribe - public void listen(EntriesAddedEvent entriesAddedEvent) { - List entries = entriesAddedEvent.getBibEntries(); - entries.stream().map(BibEntry::getCiteKeyOptional).flatMap(Optional::stream).forEach(citeKey -> addKeyToSet(citeKey)); - } - -} diff --git a/src/test/java/org/jabref/model/database/BibDatabaseTest.java b/src/test/java/org/jabref/model/database/BibDatabaseTest.java index 8f30691b299..5f417a8c486 100644 --- a/src/test/java/org/jabref/model/database/BibDatabaseTest.java +++ b/src/test/java/org/jabref/model/database/BibDatabaseTest.java @@ -26,17 +26,17 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -public class BibDatabaseTest { +class BibDatabaseTest { private BibDatabase database; @BeforeEach - public void setUp() { + void setUp() { database = new BibDatabase(); } @Test - public void insertEntryAddsEntryToEntriesList() { + void insertEntryAddsEntryToEntriesList() { BibEntry entry = new BibEntry(); database.insertEntry(entry); assertEquals(1, database.getEntries().size()); @@ -45,7 +45,7 @@ public void insertEntryAddsEntryToEntriesList() { } @Test - public void containsEntryIdFindsEntry() { + void containsEntryIdFindsEntry() { BibEntry entry = new BibEntry(); assertFalse(database.containsEntryWithId(entry.getId())); database.insertEntry(entry); @@ -53,7 +53,7 @@ public void containsEntryIdFindsEntry() { } @Test - public void insertEntryWithSameIdThrowsException() { + void insertEntryWithSameIdThrowsException() { BibEntry entry0 = new BibEntry(); database.insertEntry(entry0); @@ -63,7 +63,7 @@ public void insertEntryWithSameIdThrowsException() { } @Test - public void removeEntryRemovesEntryFromEntriesList() { + void removeEntryRemovesEntryFromEntriesList() { BibEntry entry = new BibEntry(); database.insertEntry(entry); @@ -73,7 +73,7 @@ public void removeEntryRemovesEntryFromEntriesList() { } @Test - public void removeSomeEntriesRemovesThoseEntriesFromEntriesList() { + void removeSomeEntriesRemovesThoseEntriesFromEntriesList() { BibEntry entry1 = new BibEntry(); BibEntry entry2 = new BibEntry(); BibEntry entry3 = new BibEntry(); @@ -88,7 +88,7 @@ public void removeSomeEntriesRemovesThoseEntriesFromEntriesList() { } @Test - public void removeAllEntriesRemovesAllEntriesFromEntriesList() { + void removeAllEntriesRemovesAllEntriesFromEntriesList() { List allEntries = new ArrayList<>(); BibEntry entry1 = new BibEntry(); BibEntry entry2 = new BibEntry(); @@ -105,23 +105,23 @@ public void removeAllEntriesRemovesAllEntriesFromEntriesList() { } @Test - public void insertNullEntryThrowsException() { + void insertNullEntryThrowsException() { assertThrows(NullPointerException.class, () -> database.insertEntry(null)); } @Test - public void removeNullEntryThrowsException() { + void removeNullEntryThrowsException() { assertThrows(NullPointerException.class, () -> database.removeEntry(null)); } @Test - public void emptyDatabaseHasNoStrings() { + void emptyDatabaseHasNoStrings() { assertEquals(Collections.emptySet(), database.getStringKeySet()); assertTrue(database.hasNoStrings()); } @Test - public void insertStringUpdatesStringList() { + void insertStringUpdatesStringList() { BibtexString string = new BibtexString("DSP", "Digital Signal Processing"); database.addString(string); assertFalse(database.hasNoStrings()); @@ -133,7 +133,7 @@ public void insertStringUpdatesStringList() { } @Test - public void removeStringUpdatesStringList() { + void removeStringUpdatesStringList() { BibtexString string = new BibtexString("DSP", "Digital Signal Processing"); database.addString(string); database.removeString(string.getId()); @@ -146,7 +146,7 @@ public void removeStringUpdatesStringList() { } @Test - public void hasStringLabelFindsString() { + void hasStringLabelFindsString() { BibtexString string = new BibtexString("DSP", "Digital Signal Processing"); database.addString(string); assertTrue(database.hasStringByName("DSP")); @@ -154,7 +154,7 @@ public void hasStringLabelFindsString() { } @Test - public void setSingleStringAsCollection() { + void setSingleStringAsCollection() { BibtexString string = new BibtexString("DSP", "Digital Signal Processing"); List strings = Arrays.asList(string); database.setStrings(strings); @@ -162,7 +162,7 @@ public void setSingleStringAsCollection() { } @Test - public void setStringAsCollectionWithUpdatedContentThrowsKeyCollisionException() { + void setStringAsCollectionWithUpdatedContentThrowsKeyCollisionException() { BibtexString string = new BibtexString("DSP", "Digital Signal Processing"); BibtexString newContent = new BibtexString("DSP", "ABCD"); List strings = Arrays.asList(string, newContent); @@ -170,7 +170,7 @@ public void setStringAsCollectionWithUpdatedContentThrowsKeyCollisionException() } @Test - public void setStringAsCollectionWithNewContent() { + void setStringAsCollectionWithNewContent() { BibtexString string = new BibtexString("DSP", "Digital Signal Processing"); BibtexString vlsi = new BibtexString("VLSI", "Very Large Scale Integration"); List strings = Arrays.asList(string, vlsi); @@ -180,7 +180,7 @@ public void setStringAsCollectionWithNewContent() { } @Test - public void addSameStringLabelTwiceThrowsKeyCollisionException() { + void addSameStringLabelTwiceThrowsKeyCollisionException() { BibtexString string = new BibtexString("DSP", "Digital Signal Processing"); database.addString(string); final BibtexString finalString = new BibtexString("DSP", "Digital Signal Processor"); @@ -189,7 +189,7 @@ public void addSameStringLabelTwiceThrowsKeyCollisionException() { } @Test - public void addSameStringIdTwiceThrowsKeyCollisionException() { + void addSameStringIdTwiceThrowsKeyCollisionException() { BibtexString string = new BibtexString("DSP", "Digital Signal Processing"); string.setId("duplicateid"); database.addString(string); @@ -200,7 +200,7 @@ public void addSameStringIdTwiceThrowsKeyCollisionException() { } @Test - public void insertEntryPostsAddedEntryEvent() { + void insertEntryPostsAddedEntryEvent() { BibEntry expectedEntry = new BibEntry(); TestEventListener tel = new TestEventListener(); database.registerListener(tel); @@ -210,7 +210,7 @@ public void insertEntryPostsAddedEntryEvent() { } @Test - public void insertMultipleEntriesPostsAddedEntryEvent() { + void insertMultipleEntriesPostsAddedEntryEvent() { BibEntry firstEntry = new BibEntry(); BibEntry secondEntry = new BibEntry(); TestEventListener tel = new TestEventListener(); @@ -221,7 +221,7 @@ public void insertMultipleEntriesPostsAddedEntryEvent() { } @Test - public void removeEntriesPostsRemovedEntriesEvent() { + void removeEntriesPostsRemovedEntriesEvent() { BibEntry entry1 = new BibEntry(); BibEntry entry2 = new BibEntry(); List expectedEntries = Arrays.asList(entry1, entry2); @@ -234,7 +234,7 @@ public void removeEntriesPostsRemovedEntriesEvent() { } @Test - public void changingEntryPostsChangeEntryEvent() { + void changingEntryPostsChangeEntryEvent() { BibEntry entry = new BibEntry(); TestEventListener tel = new TestEventListener(); database.insertEntry(entry); @@ -246,26 +246,26 @@ public void changingEntryPostsChangeEntryEvent() { } @Test - public void correctKeyCountOne() { + void correctKeyCountOne() { BibEntry entry = new BibEntry(); entry.setCiteKey("AAA"); database.insertEntry(entry); - assertEquals(1, database.getDuplicationChecker().getNumberOfKeyOccurrences("AAA")); + assertEquals(1, database.getNumberOfKeyOccurrences("AAA")); } @Test - public void correctKeyCountTwo() { + void correctKeyCountTwo() { BibEntry entry = new BibEntry(); entry.setCiteKey("AAA"); database.insertEntry(entry); entry = new BibEntry(); entry.setCiteKey("AAA"); database.insertEntry(entry); - assertEquals(2, database.getDuplicationChecker().getNumberOfKeyOccurrences("AAA")); + assertEquals(2, database.getNumberOfKeyOccurrences("AAA")); } @Test - public void correctKeyCountAfterRemoving() { + void correctKeyCountAfterRemoving() { BibEntry entry = new BibEntry(); entry.setCiteKey("AAA"); database.insertEntry(entry); @@ -273,11 +273,11 @@ public void correctKeyCountAfterRemoving() { entry.setCiteKey("AAA"); database.insertEntry(entry); database.removeEntry(entry); - assertEquals(1, database.getDuplicationChecker().getNumberOfKeyOccurrences("AAA")); + assertEquals(1, database.getNumberOfKeyOccurrences("AAA")); } @Test - public void circularStringResolving() { + void circularStringResolving() { BibtexString string = new BibtexString("AAA", "#BBB#"); database.addString(string); string = new BibtexString("BBB", "#AAA#"); @@ -287,7 +287,7 @@ public void circularStringResolving() { } @Test - public void circularStringResolvingLongerCycle() { + void circularStringResolvingLongerCycle() { BibtexString string = new BibtexString("AAA", "#BBB#"); database.addString(string); string = new BibtexString("BBB", "#CCC#"); @@ -303,26 +303,26 @@ public void circularStringResolvingLongerCycle() { } @Test - public void resolveForStringsMonth() { + void resolveForStringsMonth() { assertEquals("January", database.resolveForStrings("#jan#")); } @Test - public void resolveForStringsSurroundingContent() { + void resolveForStringsSurroundingContent() { BibtexString string = new BibtexString("AAA", "aaa"); database.addString(string); assertEquals("aaaaaAAA", database.resolveForStrings("aa#AAA#AAA")); } @Test - public void resolveForStringsOddHashMarkAtTheEnd() { + void resolveForStringsOddHashMarkAtTheEnd() { BibtexString string = new BibtexString("AAA", "aaa"); database.addString(string); assertEquals("AAAaaaAAA#", database.resolveForStrings("AAA#AAA#AAA#")); } @Test - public void getUsedStrings() { + void getUsedStrings() { BibEntry entry = new BibEntry(); entry.setField(StandardField.AUTHOR, "#AAA#"); BibtexString tripleA = new BibtexString("AAA", "Some other #BBB#"); @@ -342,7 +342,7 @@ public void getUsedStrings() { } @Test - public void getUsedStringsSingleString() { + void getUsedStringsSingleString() { BibEntry entry = new BibEntry(); entry.setField(StandardField.AUTHOR, "#AAA#"); BibtexString tripleA = new BibtexString("AAA", "Some other text"); @@ -359,7 +359,7 @@ public void getUsedStringsSingleString() { } @Test - public void getUsedStringsNoString() { + void getUsedStringsNoString() { BibEntry entry = new BibEntry(); entry.setField(StandardField.AUTHOR, "Oscar Gustafsson"); BibtexString string = new BibtexString("AAA", "Some other text"); @@ -370,7 +370,7 @@ public void getUsedStringsNoString() { } @Test - public void getEntriesSortedWithTwoEntries() { + void getEntriesSortedWithTwoEntries() { BibEntry entryB = new BibEntry(StandardEntryType.Article); entryB.setId("2"); BibEntry entryA = new BibEntry(StandardEntryType.Article); @@ -380,12 +380,12 @@ public void getEntriesSortedWithTwoEntries() { } @Test - public void preambleIsEmptyIfNotSet() { + void preambleIsEmptyIfNotSet() { assertEquals(Optional.empty(), database.getPreamble()); } @Test - public void setPreambleWorks() { + void setPreambleWorks() { database.setPreamble("Oh yeah!"); assertEquals(Optional.of("Oh yeah!"), database.getPreamble()); } diff --git a/src/test/java/org/jabref/model/database/DuplicationCheckerTest.java b/src/test/java/org/jabref/model/database/DuplicationCheckerTest.java index 28782f83642..ebfb036eaaf 100644 --- a/src/test/java/org/jabref/model/database/DuplicationCheckerTest.java +++ b/src/test/java/org/jabref/model/database/DuplicationCheckerTest.java @@ -7,62 +7,62 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -public class DuplicationCheckerTest { +class DuplicationCheckerTest { private BibDatabase database; @BeforeEach - public void setUp() { + void setUp() { database = new BibDatabase(); } @Test - public void addEntry() { + void addEntry() { BibEntry entry = new BibEntry(); entry.setCiteKey("AAA"); database.insertEntry(entry); - assertEquals(1, database.getDuplicationChecker().getNumberOfKeyOccurrences("AAA")); + assertEquals(1, database.getNumberOfKeyOccurrences("AAA")); } @Test - public void addAndRemoveEntry() { + void addAndRemoveEntry() { BibEntry entry = new BibEntry(); entry.setCiteKey("AAA"); database.insertEntry(entry); - assertEquals(1, database.getDuplicationChecker().getNumberOfKeyOccurrences("AAA")); + assertEquals(1, database.getNumberOfKeyOccurrences("AAA")); database.removeEntry(entry); - assertEquals(0, database.getDuplicationChecker().getNumberOfKeyOccurrences("AAA")); + assertEquals(0, database.getNumberOfKeyOccurrences("AAA")); } @Test - public void changeCiteKey() { + void changeCiteKey() { BibEntry entry = new BibEntry(); entry.setCiteKey("AAA"); database.insertEntry(entry); - assertEquals(1, database.getDuplicationChecker().getNumberOfKeyOccurrences("AAA")); + assertEquals(1, database.getNumberOfKeyOccurrences("AAA")); entry.setCiteKey("BBB"); - assertEquals(0, database.getDuplicationChecker().getNumberOfKeyOccurrences("AAA")); - assertEquals(1, database.getDuplicationChecker().getNumberOfKeyOccurrences("BBB")); + assertEquals(0, database.getNumberOfKeyOccurrences("AAA")); + assertEquals(1, database.getNumberOfKeyOccurrences("BBB")); } @Test - public void setCiteKeySameKeyDifferentEntries() { + void setCiteKeySameKeyDifferentEntries() { BibEntry entry0 = new BibEntry(); entry0.setCiteKey("AAA"); database.insertEntry(entry0); BibEntry entry1 = new BibEntry(); entry1.setCiteKey("BBB"); database.insertEntry(entry1); - assertEquals(1, database.getDuplicationChecker().getNumberOfKeyOccurrences("AAA")); - assertEquals(1, database.getDuplicationChecker().getNumberOfKeyOccurrences("BBB")); + assertEquals(1, database.getNumberOfKeyOccurrences("AAA")); + assertEquals(1, database.getNumberOfKeyOccurrences("BBB")); entry1.setCiteKey("AAA"); - assertEquals(2, database.getDuplicationChecker().getNumberOfKeyOccurrences("AAA")); - assertEquals(0, database.getDuplicationChecker().getNumberOfKeyOccurrences("BBB")); + assertEquals(2, database.getNumberOfKeyOccurrences("AAA")); + assertEquals(0, database.getNumberOfKeyOccurrences("BBB")); } @Test - public void removeMultipleCiteKeys() { + void removeMultipleCiteKeys() { BibEntry entry0 = new BibEntry(); entry0.setCiteKey("AAA"); database.insertEntry(entry0); @@ -72,36 +72,36 @@ public void removeMultipleCiteKeys() { BibEntry entry2 = new BibEntry(); entry2.setCiteKey("AAA"); database.insertEntry(entry2); - assertEquals(3, database.getDuplicationChecker().getNumberOfKeyOccurrences("AAA")); + assertEquals(3, database.getNumberOfKeyOccurrences("AAA")); database.removeEntry(entry2); - assertEquals(2, database.getDuplicationChecker().getNumberOfKeyOccurrences("AAA")); + assertEquals(2, database.getNumberOfKeyOccurrences("AAA")); database.removeEntry(entry1); - assertEquals(1, database.getDuplicationChecker().getNumberOfKeyOccurrences("AAA")); + assertEquals(1, database.getNumberOfKeyOccurrences("AAA")); database.removeEntry(entry0); - assertEquals(0, database.getDuplicationChecker().getNumberOfKeyOccurrences("AAA")); + assertEquals(0, database.getNumberOfKeyOccurrences("AAA")); } @Test - public void addEmptyCiteKey() { + void addEmptyCiteKey() { BibEntry entry = new BibEntry(); entry.setCiteKey(""); database.insertEntry(entry); - assertEquals(0, database.getDuplicationChecker().getNumberOfKeyOccurrences("")); + assertEquals(0, database.getNumberOfKeyOccurrences("")); } @Test - public void removeEmptyCiteKey() { + void removeEmptyCiteKey() { BibEntry entry = new BibEntry(); entry.setCiteKey("AAA"); database.insertEntry(entry); - assertEquals(1, database.getDuplicationChecker().getNumberOfKeyOccurrences("AAA")); + assertEquals(1, database.getNumberOfKeyOccurrences("AAA")); entry.setCiteKey(""); database.removeEntry(entry); - assertEquals(0, database.getDuplicationChecker().getNumberOfKeyOccurrences("AAA")); + assertEquals(0, database.getNumberOfKeyOccurrences("AAA")); } } From 07cb5b8921a41dd6436f32e305117377f109e829 Mon Sep 17 00:00:00 2001 From: Carl Christian Snethlage <50491877+calixtus@users.noreply.github.com> Date: Fri, 17 Apr 2020 18:06:29 +0200 Subject: [PATCH 25/25] ActionHelper to test for present file (#6151) * Added ActionHelper to test for present file * Added Validation * Refactored Validation * Refactored unsuccessfully ActionHelper * Fixed issues about opening an online link and applied some suggestions of IntelliJ * Fixed recalculation of selected entry --- src/main/java/org/jabref/gui/JabRefFrame.java | 2 +- .../org/jabref/gui/actions/ActionHelper.java | 22 ++++++++ .../ShowDocumentViewerAction.java | 8 ++- .../jabref/gui/entryeditor/EntryEditor.css | 4 ++ .../gui/fieldeditors/LinkedFileViewModel.java | 54 ++++++++++++------- .../gui/fieldeditors/LinkedFilesEditor.java | 3 +- .../gui/maintable/OpenExternalFileAction.java | 3 +- .../gui/maintable/OpenFolderAction.java | 3 +- .../gui/util/ViewModelListCellFactory.java | 22 ++++++-- .../java/org/jabref/model/entry/BibEntry.java | 2 +- src/main/resources/l10n/JabRef_en.properties | 2 + 11 files changed, 93 insertions(+), 32 deletions(-) diff --git a/src/main/java/org/jabref/gui/JabRefFrame.java b/src/main/java/org/jabref/gui/JabRefFrame.java index 077e8388d95..5a122eb28a4 100644 --- a/src/main/java/org/jabref/gui/JabRefFrame.java +++ b/src/main/java/org/jabref/gui/JabRefFrame.java @@ -831,7 +831,7 @@ private MenuBar createMenu() { new SeparatorMenuItem(), - factory.createMenuItem(StandardActions.SHOW_PDF_VIEWER, new ShowDocumentViewerAction()), + factory.createMenuItem(StandardActions.SHOW_PDF_VIEWER, new ShowDocumentViewerAction(stateManager, prefs)), factory.createMenuItem(StandardActions.EDIT_ENTRY, new OpenEntryEditorAction(this, stateManager)), factory.createMenuItem(StandardActions.OPEN_CONSOLE, new OpenConsoleAction(stateManager)) ); diff --git a/src/main/java/org/jabref/gui/actions/ActionHelper.java b/src/main/java/org/jabref/gui/actions/ActionHelper.java index 01e23d67e22..06f294de5d2 100644 --- a/src/main/java/org/jabref/gui/actions/ActionHelper.java +++ b/src/main/java/org/jabref/gui/actions/ActionHelper.java @@ -1,14 +1,20 @@ package org.jabref.gui.actions; +import java.nio.file.Path; import java.util.Collections; import java.util.List; +import java.util.Optional; import javafx.beans.binding.Bindings; import javafx.beans.binding.BooleanExpression; import org.jabref.gui.StateManager; import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.LinkedFile; import org.jabref.model.entry.field.Field; +import org.jabref.model.entry.field.StandardField; +import org.jabref.model.util.FileHelper; +import org.jabref.preferences.PreferencesService; public class ActionHelper { public static BooleanExpression needsDatabase(StateManager stateManager) { @@ -36,4 +42,20 @@ public static BooleanExpression isAnyFieldSetForSelectedEntry(List fields entry.getFieldsObservable(), stateManager.getSelectedEntries()); } + + public static BooleanExpression isFilePresentForSelectedEntry(StateManager stateManager, PreferencesService preferencesService) { + return Bindings.createBooleanBinding(() -> { + List files = stateManager.getSelectedEntries().get(0).getFiles(); + if ((files.size() > 0) && stateManager.getActiveDatabase().isPresent()) { + Optional filename = FileHelper.expandFilename( + stateManager.getActiveDatabase().get(), + files.get(0).getLink(), + preferencesService.getFilePreferences()); + return filename.isPresent(); + } else { + return false; + } + }, stateManager.getSelectedEntries(), + stateManager.getSelectedEntries().get(0).getFieldBinding(StandardField.FILE)); + } } diff --git a/src/main/java/org/jabref/gui/documentviewer/ShowDocumentViewerAction.java b/src/main/java/org/jabref/gui/documentviewer/ShowDocumentViewerAction.java index 9c91ca7c472..444bf3840e9 100644 --- a/src/main/java/org/jabref/gui/documentviewer/ShowDocumentViewerAction.java +++ b/src/main/java/org/jabref/gui/documentviewer/ShowDocumentViewerAction.java @@ -1,12 +1,18 @@ package org.jabref.gui.documentviewer; +import org.jabref.gui.StateManager; +import org.jabref.gui.actions.ActionHelper; import org.jabref.gui.actions.SimpleCommand; +import org.jabref.preferences.PreferencesService; public class ShowDocumentViewerAction extends SimpleCommand { + public ShowDocumentViewerAction(StateManager stateManager, PreferencesService preferences) { + this.executable.bind(ActionHelper.isFilePresentForSelectedEntry(stateManager, preferences)); + } + @Override public void execute() { new DocumentViewerView().show(); } - } diff --git a/src/main/java/org/jabref/gui/entryeditor/EntryEditor.css b/src/main/java/org/jabref/gui/entryeditor/EntryEditor.css index e53c688a081..61981cde6cb 100644 --- a/src/main/java/org/jabref/gui/entryeditor/EntryEditor.css +++ b/src/main/java/org/jabref/gui/entryeditor/EntryEditor.css @@ -86,6 +86,10 @@ -fx-background-color: -jr-error; } +.list-cell:invalid { + -fx-background-color: -jr-warn; +} + .code-area .context-menu { -fx-font-family: sans-serif; } diff --git a/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java b/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java index 43233afc802..62994a86a20 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java +++ b/src/main/java/org/jabref/gui/fieldeditors/LinkedFileViewModel.java @@ -46,8 +46,13 @@ import org.jabref.model.entry.LinkedFile; import org.jabref.model.metadata.FilePreferences; import org.jabref.model.strings.StringUtil; +import org.jabref.model.util.FileHelper; import org.jabref.model.util.OptionalUtil; +import de.saxsys.mvvmfx.utils.validation.FunctionBasedValidator; +import de.saxsys.mvvmfx.utils.validation.ValidationMessage; +import de.saxsys.mvvmfx.utils.validation.ValidationStatus; +import de.saxsys.mvvmfx.utils.validation.Validator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -69,6 +74,8 @@ public class LinkedFileViewModel extends AbstractViewModel { private final LinkedFileHandler linkedFileHandler; private final ExternalFileTypes externalFileTypes; + private final Validator fileExistsValidator; + public LinkedFileViewModel(LinkedFile linkedFile, BibEntry entry, BibDatabaseContext databaseContext, @@ -88,6 +95,18 @@ public LinkedFileViewModel(LinkedFile linkedFile, this.externalFileTypes = externalFileTypes; this.xmpPreferences = xmpPreferences; + fileExistsValidator = new FunctionBasedValidator<>( + linkedFile.linkProperty(), + link -> { + if (linkedFile.isOnlineLink()) { + return true; + } else { + Optional path = FileHelper.expandFilename(databaseContext, link, filePreferences); + return path.isPresent() && Files.exists(path.get()); + } + }, + ValidationMessage.warning(Localization.lang("Could not find file '%0'.", linkedFile.getLink()))); + downloadOngoing.bind(downloadProgress.greaterThanOrEqualTo(0).and(downloadProgress.lessThan(1))); canWriteXMPMetadata.setValue(!linkedFile.isOnlineLink() && linkedFile.getFileType().equalsIgnoreCase("pdf")); } @@ -172,24 +191,19 @@ public void open() { public void openFolder() { try { - Path path = null; - // absolute path - if (Paths.get(linkedFile.getLink()).isAbsolute()) { - path = Paths.get(linkedFile.getLink()); - } else { - // relative to file folder - for (Path folder : databaseContext.getFileDirectoriesAsPaths(filePreferences)) { - Path file = folder.resolve(linkedFile.getLink()); - if (Files.exists(file)) { - path = file; - break; - } + if (!linkedFile.isOnlineLink()) { + Optional resolvedPath = FileHelper.expandFilename( + databaseContext, + linkedFile.getLink(), + filePreferences); + + if (resolvedPath.isPresent()) { + JabRefDesktop.openFolderAndSelectFile(resolvedPath.get()); + } else { + dialogService.showErrorDialogAndWait(Localization.lang("File not found")); } - } - if (path != null) { - JabRefDesktop.openFolderAndSelectFile(path); } else { - dialogService.showErrorDialogAndWait(Localization.lang("File not found")); + dialogService.showErrorDialogAndWait(Localization.lang("Cannot open folder as the file is an online link.")); } } catch (IOException ex) { LOGGER.debug("Cannot open folder", ex); @@ -251,7 +265,7 @@ public void moveToDefaultDirectory() { // Get target folder Optional fileDir = databaseContext.getFirstExistingFileDir(filePreferences); - if (!fileDir.isPresent()) { + if (fileDir.isEmpty()) { dialogService.showErrorDialogAndWait(Localization.lang("Move file"), Localization.lang("File directory is not set or does not exist!")); return; } @@ -320,7 +334,7 @@ public void moveToDefaultDirectoryAndRename() { public boolean delete() { Optional file = linkedFile.findIn(databaseContext, filePreferences); - if (!file.isPresent()) { + if (file.isEmpty()) { LOGGER.warn("Could not find file " + linkedFile.getLink()); return true; } @@ -365,7 +379,7 @@ public void writeXMPMetadata() { // Localization.lang("Writing XMP metadata...") BackgroundTask writeTask = BackgroundTask.wrap(() -> { Optional file = linkedFile.findIn(databaseContext, filePreferences); - if (!file.isPresent()) { + if (file.isEmpty()) { // TODO: Print error message // Localization.lang("PDF does not exist"); } else { @@ -455,4 +469,6 @@ private Optional inferFileTypeFromURL(String url) { public LinkedFile getFile() { return linkedFile; } + + public ValidationStatus fileExistsValidationStatus() { return fileExistsValidator.getValidationStatus(); } } diff --git a/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditor.java b/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditor.java index 537a17fff08..7dbacc13bc8 100644 --- a/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditor.java +++ b/src/main/java/org/jabref/gui/fieldeditors/LinkedFilesEditor.java @@ -72,7 +72,8 @@ public LinkedFilesEditor(Field field, DialogService dialogService, BibDatabaseCo .withOnMouseClickedEvent(this::handleItemMouseClick) .setOnDragDetected(this::handleOnDragDetected) .setOnDragDropped(this::handleOnDragDropped) - .setOnDragOver(this::handleOnDragOver); + .setOnDragOver(this::handleOnDragOver) + .withValidation(LinkedFileViewModel::fileExistsValidationStatus); listView.setCellFactory(cellFactory); diff --git a/src/main/java/org/jabref/gui/maintable/OpenExternalFileAction.java b/src/main/java/org/jabref/gui/maintable/OpenExternalFileAction.java index 6579eed3102..eb7658f1b28 100644 --- a/src/main/java/org/jabref/gui/maintable/OpenExternalFileAction.java +++ b/src/main/java/org/jabref/gui/maintable/OpenExternalFileAction.java @@ -11,7 +11,6 @@ import org.jabref.gui.fieldeditors.LinkedFileViewModel; import org.jabref.logic.l10n.Localization; import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.field.StandardField; import org.jabref.preferences.PreferencesService; public class OpenExternalFileAction extends SimpleCommand { @@ -25,7 +24,7 @@ public OpenExternalFileAction(DialogService dialogService, StateManager stateMan this.stateManager = stateManager; this.preferencesService = preferencesService; - this.executable.bind(ActionHelper.isFieldSetForSelectedEntry(StandardField.FILE, stateManager) + this.executable.bind(ActionHelper.isFilePresentForSelectedEntry(stateManager, preferencesService) .and(ActionHelper.needsEntriesSelected(1, stateManager))); } diff --git a/src/main/java/org/jabref/gui/maintable/OpenFolderAction.java b/src/main/java/org/jabref/gui/maintable/OpenFolderAction.java index a2c3c211785..d3afc796ad0 100644 --- a/src/main/java/org/jabref/gui/maintable/OpenFolderAction.java +++ b/src/main/java/org/jabref/gui/maintable/OpenFolderAction.java @@ -7,7 +7,6 @@ import org.jabref.gui.actions.SimpleCommand; import org.jabref.gui.externalfiletype.ExternalFileTypes; import org.jabref.gui.fieldeditors.LinkedFileViewModel; -import org.jabref.model.entry.field.StandardField; import org.jabref.preferences.PreferencesService; public class OpenFolderAction extends SimpleCommand { @@ -21,7 +20,7 @@ public OpenFolderAction(DialogService dialogService, StateManager stateManager, this.stateManager = stateManager; this.preferencesService = preferencesService; - this.executable.bind(ActionHelper.isFieldSetForSelectedEntry(StandardField.FILE, stateManager)); + this.executable.bind(ActionHelper.isFilePresentForSelectedEntry(stateManager, preferencesService)); } @Override diff --git a/src/main/java/org/jabref/gui/util/ViewModelListCellFactory.java b/src/main/java/org/jabref/gui/util/ViewModelListCellFactory.java index 72188027e8a..59743c49248 100644 --- a/src/main/java/org/jabref/gui/util/ViewModelListCellFactory.java +++ b/src/main/java/org/jabref/gui/util/ViewModelListCellFactory.java @@ -22,6 +22,7 @@ import org.jabref.gui.icon.JabRefIcon; import org.jabref.model.strings.StringUtil; +import de.saxsys.mvvmfx.utils.validation.ValidationStatus; import org.fxmisc.easybind.Subscription; /** @@ -31,6 +32,8 @@ */ public class ViewModelListCellFactory implements Callback, ListCell> { + private static final PseudoClass INVALID_PSEUDO_CLASS = PseudoClass.getPseudoClass("invalid"); + private Callback toText; private Callback toGraphic; private Callback toTooltip; @@ -43,6 +46,7 @@ public class ViewModelListCellFactory implements Callback, ListCe private BiConsumer toOnDragExited; private BiConsumer toOnDragOver; private Map>> pseudoClasses = new HashMap<>(); + private Callback validationStatusProperty; public ViewModelListCellFactory withText(Callback toText) { this.toText = toText; @@ -66,10 +70,7 @@ public ViewModelListCellFactory withIcon(Callback toIcon) { } public ViewModelListCellFactory withIcon(Callback toIcon, Callback toColor) { - this.toGraphic = viewModel -> { - - return toIcon.call(viewModel).withColor(toColor.call(viewModel)).getGraphicNode(); - }; + this.toGraphic = viewModel -> toIcon.call(viewModel).withColor(toColor.call(viewModel)).getGraphicNode(); return this; } @@ -134,6 +135,11 @@ public ViewModelListCellFactory withPseudoClass(PseudoClass pseudoClass, Call return this; } + public ViewModelListCellFactory withValidation(Callback validationStatusProperty) { + this.validationStatusProperty = validationStatusProperty; + return this; + } + public void install(ComboBox comboBox) { comboBox.setButtonCell(this.call(null)); comboBox.setCellFactory(this); @@ -146,7 +152,7 @@ public void install(ListView listView) { @Override public ListCell call(ListView param) { - return new ListCell() { + return new ListCell<>() { List subscriptions = new ArrayList<>(); @@ -203,6 +209,12 @@ protected void updateItem(T item, boolean empty) { Subscription subscription = BindingsHelper.includePseudoClassWhen(this, pseudoClassWithCondition.getKey(), condition); subscriptions.add(subscription); } + if (validationStatusProperty != null) { + validationStatusProperty.call(viewModel).getHighestMessage().ifPresent(message -> { + setTooltip(new Tooltip(message.getMessage())); + subscriptions.add(BindingsHelper.includePseudoClassWhen(this, INVALID_PSEUDO_CLASS, validationStatusProperty.call(viewModel).validProperty().not())); + }); + } } } }; diff --git a/src/main/java/org/jabref/model/entry/BibEntry.java b/src/main/java/org/jabref/model/entry/BibEntry.java index 2f9ffec5133..0bfe4f7b11b 100644 --- a/src/main/java/org/jabref/model/entry/BibEntry.java +++ b/src/main/java/org/jabref/model/entry/BibEntry.java @@ -918,7 +918,7 @@ public Optional setFiles(List files) { public List getFiles() { // Extract the path Optional oldValue = getField(StandardField.FILE); - if (!oldValue.isPresent()) { + if (oldValue.isEmpty()) { return new ArrayList<>(); // Return new ArrayList because emptyList is immutable } diff --git a/src/main/resources/l10n/JabRef_en.properties b/src/main/resources/l10n/JabRef_en.properties index 28f5f56b5af..777acd7b11c 100644 --- a/src/main/resources/l10n/JabRef_en.properties +++ b/src/main/resources/l10n/JabRef_en.properties @@ -102,6 +102,8 @@ Cannot\ create\ group=Cannot create group Cannot\ create\ group.\ Please\ create\ a\ library\ first.=Cannot create group. Please create a library first. +Cannot\ open\ folder\ as\ the\ file\ is\ an\ online\ link.=Cannot open folder as the file is an online link. + case\ insensitive=case insensitive case\ sensitive=case sensitive