Skip to content

Commit

Permalink
Added preference option to use custom URL for DOI generation (#7480)
Browse files Browse the repository at this point in the history
  • Loading branch information
BJaroszkowski authored Mar 8, 2021
1 parent f7de0a6 commit 2c7715c
Show file tree
Hide file tree
Showing 14 changed files with 199 additions and 12 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Note that this project **does not** adhere to [Semantic Versioning](http://semve

### Added

- We added new "Customization" tab to the preferences which includes option to choose a custom address for DOI access. [#7337](https://github.com/JabRef/jabref/issues/7337)
- We added zbmath to the public databases from which the bibliographic information of an existing entry can be updated. [#7437](https://github.com/JabRef/jabref/issues/7437)
- We added the possibility to add a new entry via its zbMath ID (zbMATH can be chosen as ID type in the "Select entry type" window). [#7202](https://github.com/JabRef/jabref/issues/7202)
- We added the extension support and the external application support (For Texshow, Texmaker and LyX) to the flatpak [#7248](https://github.com/JabRef/jabref/pull/7248)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public IdentifierEditor(Field field,
SuggestionProvider<?> suggestionProvider,
FieldCheckers fieldCheckers,
PreferencesService preferences) {
this.viewModel = new IdentifierEditorViewModel(field, suggestionProvider, taskExecutor, dialogService, fieldCheckers);
this.viewModel = new IdentifierEditorViewModel(field, suggestionProvider, taskExecutor, dialogService, fieldCheckers, preferences);

ViewLoader.view(this)
.root(this)
Expand All @@ -50,6 +50,7 @@ public IdentifierEditor(Field field,
new Tooltip(Localization.lang("Look up %0", field.getDisplayName())));

if (field.equals(StandardField.DOI)) {

textArea.initContextMenu(EditorMenus.getDOIMenu(textArea));
} else {
textArea.initContextMenu(new DefaultMenu(textArea));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@
import org.jabref.logic.l10n.Localization;
import org.jabref.model.entry.BibEntry;
import org.jabref.model.entry.field.Field;
import org.jabref.model.entry.field.StandardField;
import org.jabref.model.entry.identifier.DOI;
import org.jabref.model.entry.identifier.Identifier;
import org.jabref.preferences.PreferencesService;

import com.tobiasdiez.easybind.EasyBind;

Expand All @@ -32,12 +35,16 @@ public class IdentifierEditorViewModel extends AbstractEditorViewModel {
private final ObjectProperty<Optional<? extends Identifier>> identifier = new SimpleObjectProperty<>();
private final TaskExecutor taskExecutor;
private final DialogService dialogService;
private final Field field;
private PreferencesService preferences;

public IdentifierEditorViewModel(Field field, SuggestionProvider<?> suggestionProvider, TaskExecutor taskExecutor, DialogService dialogService, FieldCheckers fieldCheckers) {
public IdentifierEditorViewModel(Field field, SuggestionProvider<?> suggestionProvider, TaskExecutor taskExecutor, DialogService dialogService, FieldCheckers fieldCheckers, PreferencesService preferences) {
super(field, suggestionProvider, fieldCheckers);

this.taskExecutor = taskExecutor;
this.dialogService = dialogService;
this.preferences = preferences;
this.field = field;

identifier.bind(
EasyBind.map(text, input -> IdentifierParser.parse(field, input))
Expand Down Expand Up @@ -67,6 +74,15 @@ public BooleanProperty validIdentifierIsNotPresentProperty() {
}

public void openExternalLink() {
if (field.equals(StandardField.DOI) && preferences.getDOIPreferences().isUseCustom()) {
String baseURI = preferences.getDOIPreferences().getDefaultBaseURI();
openDOIWithCustomBase(baseURI);
} else {
openExternalLinkDefault();
}
}

public void openExternalLinkDefault() {
identifier.get().flatMap(Identifier::getExternalURI).ifPresent(
url -> {
try {
Expand All @@ -78,6 +94,18 @@ public void openExternalLink() {
);
}

public void openDOIWithCustomBase(String baseURI) {
identifier.get().map(identifier -> (DOI) identifier).flatMap(doi -> doi.getExternalURIWithCustomBase(baseURI)).ifPresent(
uri -> {
try {
JabRefDesktop.openBrowser(uri);
} catch (IOException ex) {
dialogService.showErrorDialogAndWait(Localization.lang("Unable to open link."), ex);
}
}
);
}

public boolean getIdentifierLookupInProgress() {
return identifierLookupInProgress.get();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import org.jabref.gui.JabRefFrame;
import org.jabref.gui.preferences.appearance.AppearanceTab;
import org.jabref.gui.preferences.citationkeypattern.CitationKeyPatternTab;
import org.jabref.gui.preferences.customization.CustomizationTab;
import org.jabref.gui.preferences.entryeditor.EntryEditorTab;
import org.jabref.gui.preferences.entryeditortabs.CustomEditorFieldsTab;
import org.jabref.gui.preferences.exporter.ExportCustomizationTab;
Expand Down Expand Up @@ -74,6 +75,7 @@ public PreferencesDialogViewModel(DialogService dialogService, PreferencesServic
new JournalAbbreviationsTab(),
new GroupsTab(),
new EntryEditorTab(),
new CustomizationTab(),
new CustomEditorFieldsTab(),
new CitationKeyPatternTab(),
new LinkedFilesTab(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.layout.HBox?>
<fx:root spacing="10.0" type="VBox"
xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml"
fx:controller="org.jabref.gui.preferences.customization.CustomizationTab">
<Label styleClass="titleHeader" text="%Customization"/>

<Label styleClass="sectionHeader" text="%Custom DOI URI"/>
<HBox alignment="CENTER_LEFT" spacing="10.0">
<CheckBox fx:id="useCustomDOI" text="%Use custom DOI base URI for article access"/>
<TextField fx:id="useCustomDOIName" HBox.hgrow="ALWAYS"/>
</HBox>
</fx:root>
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package org.jabref.gui.preferences.customization;

import javafx.fxml.FXML;
import javafx.scene.control.CheckBox;
import javafx.scene.control.TextField;

import org.jabref.gui.preferences.AbstractPreferenceTabView;
import org.jabref.gui.preferences.PreferencesTab;
import org.jabref.logic.l10n.Localization;

import com.airhacks.afterburner.views.ViewLoader;

public class CustomizationTab extends AbstractPreferenceTabView<CustomizationTabViewModel> implements PreferencesTab {

@FXML private CheckBox useCustomDOI;
@FXML private TextField useCustomDOIName;

public CustomizationTab() {
ViewLoader.view(this)
.root(this)
.load();
}

@Override
public String getTabName() {
return Localization.lang("Customization");
}

public void initialize() {
this.viewModel = new CustomizationTabViewModel(dialogService, preferencesService);

useCustomDOI.selectedProperty().bindBidirectional(viewModel.useCustomDOIProperty());
useCustomDOIName.textProperty().bindBidirectional(viewModel.useCustomDOINameProperty());
useCustomDOIName.disableProperty().bind(useCustomDOI.selectedProperty().not());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package org.jabref.gui.preferences.customization;

import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

import org.jabref.gui.DialogService;
import org.jabref.gui.preferences.PreferenceTabViewModel;
import org.jabref.logic.preferences.DOIPreferences;
import org.jabref.preferences.PreferencesService;

public class CustomizationTabViewModel implements PreferenceTabViewModel {

private final BooleanProperty useCustomDOIProperty = new SimpleBooleanProperty();
private final StringProperty useCustomDOINameProperty = new SimpleStringProperty("");

private final DialogService dialogService;
private final PreferencesService preferencesService;
private final DOIPreferences initialDOIPreferences;

public CustomizationTabViewModel(DialogService dialogService, PreferencesService preferencesService) {
this.dialogService = dialogService;
this.preferencesService = preferencesService;
this.initialDOIPreferences = preferencesService.getDOIPreferences();
}

@Override
public void setValues() {
useCustomDOIProperty.setValue(initialDOIPreferences.isUseCustom());
useCustomDOINameProperty.setValue(initialDOIPreferences.getDefaultBaseURI());
}

@Override
public void storeSettings() {
preferencesService.storeDOIPreferences(new DOIPreferences(
useCustomDOIProperty.getValue(),
useCustomDOINameProperty.getValue().trim()));
}

public BooleanProperty useCustomDOIProperty() {
return this.useCustomDOIProperty;
}

public StringProperty useCustomDOINameProperty() {
return this.useCustomDOINameProperty;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

public class GeneralTab extends AbstractPreferenceTabView<GeneralTabViewModel> implements PreferencesTab {

private final ControlsFxVisualizer validationVisualizer = new ControlsFxVisualizer();
@FXML private ComboBox<Language> language;
@FXML private ComboBox<Charset> defaultEncoding;
@FXML private ComboBox<BibDatabaseMode> biblatexMode;
Expand All @@ -42,8 +43,6 @@ public class GeneralTab extends AbstractPreferenceTabView<GeneralTabViewModel> i
@FXML private CheckBox addCreationDate;
@FXML private CheckBox addModificationDate;

private final ControlsFxVisualizer validationVisualizer = new ControlsFxVisualizer();

public GeneralTab() {
ViewLoader.view(this)
.root(this)
Expand Down
19 changes: 19 additions & 0 deletions src/main/java/org/jabref/logic/preferences/DOIPreferences.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.jabref.logic.preferences;

public class DOIPreferences {
private final boolean useCustom;
private final String defaultBaseURI;

public DOIPreferences(boolean useCustom, String defaultBaseURI) {
this.useCustom = useCustom;
this.defaultBaseURI = defaultBaseURI;
}

public boolean isUseCustom() {
return useCustom;
}

public String getDefaultBaseURI() {
return defaultBaseURI;
}
}
19 changes: 12 additions & 7 deletions src/main/java/org/jabref/model/entry/identifier/DOI.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,15 @@
import org.slf4j.LoggerFactory;

/**
* Class for working with <a href="https://en.wikipedia.org/wiki/Digital_object_identifier">Digital object identifiers
* (DOIs)</a> and <a href="http://shortdoi.org">Short DOIs</a>
* Class for working with <a href="https://en.wikipedia.org/wiki/Digital_object_identifier">Digital object identifiers (DOIs)</a> and <a href="http://shortdoi.org">Short DOIs</a>
*/
public class DOI implements Identifier {

public static final URI AGENCY_RESOLVER = URI.create("https://doi.org/doiRA");

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

// DOI/Short DOI resolver
private static final URI RESOLVER = URI.create("https://doi.org");
private static final URI RESOLVER = URI.create("https://doi.org/");

// Regex
// (see http://www.doi.org/doi_handbook/2_Numbering.html)
Expand Down Expand Up @@ -147,8 +145,7 @@ public DOI(String doi) {
/**
* Creates an Optional&lt;DOI> from various schemes including URL, URN, and plain DOIs.
* <p>
* Useful for suppressing the <c>IllegalArgumentException</c> of the Constructor and checking for
* Optional.isPresent() instead.
* Useful for suppressing the <c>IllegalArgumentException</c> of the Constructor and checking for Optional.isPresent() instead.
*
* @param doi the DOI/Short DOI string
* @return an Optional containing the DOI or an empty Optional
Expand Down Expand Up @@ -233,8 +230,16 @@ public boolean isShortDoi() {
*/
@Override
public Optional<URI> getExternalURI() {
return getExternalURIFromBase(RESOLVER);
}

public Optional<URI> getExternalURIWithCustomBase(String customBase) {
return getExternalURIFromBase(URI.create(customBase));
}

private Optional<URI> getExternalURIFromBase(URI base) {
try {
URI uri = new URI(RESOLVER.getScheme(), RESOLVER.getHost(), "/" + doi, null);
URI uri = new URI(base.getScheme(), base.getHost(), "/" + doi, null);
return Optional.of(uri);
} catch (URISyntaxException e) {
// should never happen
Expand Down
20 changes: 20 additions & 0 deletions src/main/java/org/jabref/preferences/JabRefPreferences.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
import org.jabref.logic.net.ProxyPreferences;
import org.jabref.logic.openoffice.OpenOfficePreferences;
import org.jabref.logic.openoffice.StyleLoader;
import org.jabref.logic.preferences.DOIPreferences;
import org.jabref.logic.preferences.OwnerPreferences;
import org.jabref.logic.preferences.TimestampPreferences;
import org.jabref.logic.preview.PreviewLayout;
Expand Down Expand Up @@ -201,6 +202,9 @@ public class JabRefPreferences implements PreferencesService {
public static final String SHOW_ADVANCED_HINTS = "showAdvancedHints";
public static final String DEFAULT_ENCODING = "defaultEncoding";

public static final String BASE_DOI_URI = "baseDOIURI";
public static final String USE_CUSTOM_DOI_URI = "useCustomDOIURI";

public static final String USE_OWNER = "useOwner";
public static final String DEFAULT_OWNER = "defaultOwner";
public static final String OVERWRITE_OWNER = "overwriteOwner";
Expand Down Expand Up @@ -445,6 +449,9 @@ private JabRefPreferences() {
// Set DOI to be the default ID entry generator
defaults.put(ID_ENTRY_GENERATOR, DoiFetcher.NAME);

defaults.put(USE_CUSTOM_DOI_URI, Boolean.FALSE);
defaults.put(BASE_DOI_URI, "https://doi.org");

if (OS.OS_X) {
defaults.put(FONT_FAMILY, "SansSerif");
defaults.put(PUSH_EMACS_PATH, "emacsclient");
Expand Down Expand Up @@ -1361,6 +1368,19 @@ public void storeTelemetryPreferences(TelemetryPreferences preferences) {
putBoolean(ALREADY_ASKED_TO_COLLECT_TELEMETRY, !preferences.shouldAskToCollectTelemetry()); // mind the !
}

@Override
public DOIPreferences getDOIPreferences() {
return new DOIPreferences(
getBoolean(USE_CUSTOM_DOI_URI),
get(BASE_DOI_URI));
}

@Override
public void storeDOIPreferences(DOIPreferences preferences) {
putBoolean(USE_CUSTOM_DOI_URI, preferences.isUseCustom());
put(BASE_DOI_URI, preferences.getDefaultBaseURI());
}

@Override
public OwnerPreferences getOwnerPreferences() {
return new OwnerPreferences(
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/org/jabref/preferences/PreferencesService.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import org.jabref.logic.layout.format.NameFormatterPreferences;
import org.jabref.logic.net.ProxyPreferences;
import org.jabref.logic.openoffice.OpenOfficePreferences;
import org.jabref.logic.preferences.DOIPreferences;
import org.jabref.logic.preferences.OwnerPreferences;
import org.jabref.logic.preferences.TimestampPreferences;
import org.jabref.logic.protectedterms.ProtectedTermsPreferences;
Expand Down Expand Up @@ -144,6 +145,10 @@ public interface PreferencesService {

void storeTelemetryPreferences(TelemetryPreferences preferences);

DOIPreferences getDOIPreferences();

void storeDOIPreferences(DOIPreferences preferences);

OwnerPreferences getOwnerPreferences();

void storeOwnerPreferences(OwnerPreferences preferences);
Expand Down
4 changes: 4 additions & 0 deletions src/main/resources/l10n/JabRef_en.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2288,3 +2288,7 @@ Separate\ citations=Separate citations
Unprotect\ terms=Unprotect terms
Error\ connecting\ to\ Writer\ document=Error connecting to Writer document
You\ need\ to\ open\ Writer\ with\ a\ document\ before\ connecting=You need to open Writer with a document before connecting
Custom\ DOI\ URI=Custom DOI URI
Customization=Customization
Use\ custom\ DOI\ base\ URI\ for\ article\ access=Use custom DOI base URI for article access
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import org.jabref.gui.util.CurrentThreadTaskExecutor;
import org.jabref.logic.integrity.FieldCheckers;
import org.jabref.model.entry.field.StandardField;
import org.jabref.preferences.PreferencesService;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
Expand All @@ -18,7 +19,7 @@ class IdentifierEditorViewModelTest {

@BeforeEach
void setUp() throws Exception {
viewModel = new IdentifierEditorViewModel(StandardField.DOI, new EmptySuggestionProvider(), new CurrentThreadTaskExecutor(), mock(DialogService.class), mock(FieldCheckers.class));
viewModel = new IdentifierEditorViewModel(StandardField.DOI, new EmptySuggestionProvider(), new CurrentThreadTaskExecutor(), mock(DialogService.class), mock(FieldCheckers.class), mock(PreferencesService.class));
}

@Test
Expand Down

0 comments on commit 2c7715c

Please sign in to comment.