Skip to content

Commit

Permalink
Merge pull request #2442 from JabRef/lookupdoi
Browse files Browse the repository at this point in the history
Add "Look up DOIs" to Quality menu
  • Loading branch information
koppor authored Mar 18, 2017
2 parents b3381ed + e29be92 commit 63620ff
Show file tree
Hide file tree
Showing 50 changed files with 289 additions and 64 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `#
- The `Move linked files to default file directory`-Cleanup operation respects the `File directory pattern` setting
- We separated the `Move file` and `Rename Pdfs` logic and context menu entries in the `General`-Tab for the Field `file` to improve the semantics
- A scrollbar was added to the cleanup panel, as a result of issue [#2501](https://github.com/JabRef/jabref/issues/2501)
- Using "Look up document identifier" in the quality menu, it is possible to look up DOIs and other identifiers for multiple entries.
- F4 opens selected file in current JTable context not just from selected entry inside the main table [#2355](https://github.com/JabRef/jabref/issues/2355)
- We added an option to copy the title of BibTeX entries to the clipboard through `Edit -> Copy title` (implements [#210](https://github.com/koppor/jabref/issues/210))
- Several scrollbars were added to the preference dialog which show up when content is too large [#2559](https://github.com/JabRef/jabref/issues/2559)
Expand Down
38 changes: 21 additions & 17 deletions src/main/java/org/jabref/gui/BasePanel.java
Original file line number Diff line number Diff line change
Expand Up @@ -988,23 +988,7 @@ public void runCommand(final String _command) {
if (o instanceof BaseAction) {
((BaseAction) o).action();
} else {
// This part uses Spin's features:
Runnable wrk = ((AbstractWorker) o).getWorker();
// The Worker returned by getWorker() has been wrapped
// by Spin.off(), which makes its methods be run in
// a different thread from the EDT.
CallBack clb = ((AbstractWorker) o).getCallBack();

((AbstractWorker) o).init(); // This method runs in this same thread, the EDT.
// Useful for initial GUI actions, like printing a message.

// The CallBack returned by getCallBack() has been wrapped
// by Spin.over(), which makes its methods be run on
// the EDT.
wrk.run(); // Runs the potentially time-consuming action
// without freezing the GUI. The magic is that THIS line
// of execution will not continue until run() is finished.
clb.update(); // Runs the update() method on the EDT.
runWorker((AbstractWorker) o);
}
} catch (Throwable ex) {
// If the action has blocked the JabRefFrame before crashing, we need to unblock it.
Expand All @@ -1015,6 +999,26 @@ public void runCommand(final String _command) {
}
}

public static void runWorker(AbstractWorker worker) throws Exception {
// This part uses Spin's features:
Runnable wrk = worker.getWorker();
// The Worker returned by getWorker() has been wrapped
// by Spin.off(), which makes its methods be run in
// a different thread from the EDT.
CallBack clb = worker.getCallBack();

worker.init(); // This method runs in this same thread, the EDT.
// Useful for initial GUI actions, like printing a message.

// The CallBack returned by getCallBack() has been wrapped
// by Spin.over(), which makes its methods be run on
// the EDT.
wrk.run(); // Runs the potentially time-consuming action
// without freezing the GUI. The magic is that THIS line
// of execution will not continue until run() is finished.
clb.update(); // Runs the update() method on the EDT.
}

private boolean saveDatabase(File file, boolean selectedOnly, Charset enc,
SavePreferences.DatabaseSaveType saveType) throws SaveException {
SaveSession session;
Expand Down
13 changes: 11 additions & 2 deletions src/main/java/org/jabref/gui/JabRefFrame.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
import org.jabref.gui.actions.ConnectToSharedDatabaseAction;
import org.jabref.gui.actions.ErrorConsoleAction;
import org.jabref.gui.actions.IntegrityCheckAction;
import org.jabref.gui.actions.LookupIdentifierAction;
import org.jabref.gui.actions.ManageKeywordsAction;
import org.jabref.gui.actions.MassSetFieldAction;
import org.jabref.gui.actions.MnemonicAwareAction;
Expand Down Expand Up @@ -110,8 +111,10 @@
import org.jabref.logic.autosaveandbackup.AutosaveManager;
import org.jabref.logic.autosaveandbackup.BackupManager;
import org.jabref.logic.help.HelpFile;
import org.jabref.logic.importer.IdFetcher;
import org.jabref.logic.importer.OutputPrinter;
import org.jabref.logic.importer.ParserResult;
import org.jabref.logic.importer.WebFetchers;
import org.jabref.logic.l10n.Localization;
import org.jabref.logic.search.SearchQuery;
import org.jabref.logic.undo.AddUndoableActionEvent;
Expand Down Expand Up @@ -405,6 +408,7 @@ public void actionPerformed(ActionEvent e) {
Localization.lang("Send as email"), IconTheme.JabRefIcon.EMAIL.getIcon());
private final MassSetFieldAction massSetField = new MassSetFieldAction(this);
private final ManageKeywordsAction manageKeywords = new ManageKeywordsAction(this);
private final JMenu lookupIdentifiers = JabRefFrame.subMenu(Localization.menuTitle("Look up document identifier..."));
private final GeneralAction findUnlinkedFiles = new GeneralAction(
FindUnlinkedFilesDialog.ACTION_COMMAND,
FindUnlinkedFilesDialog.ACTION_MENU_TITLE, FindUnlinkedFilesDialog.ACTION_SHORT_DESCRIPTION,
Expand Down Expand Up @@ -1173,6 +1177,11 @@ private void fillMenu() {
quality.add(autoSetFile);
quality.add(findUnlinkedFiles);
quality.add(autoLinkFile);

for (IdFetcher fetcher : WebFetchers.getIdFetchers()) {
lookupIdentifiers.add(new LookupIdentifierAction(this, fetcher));
}
quality.add(lookupIdentifiers);
quality.add(downloadFullText);
mb.add(quality);

Expand Down Expand Up @@ -1356,7 +1365,7 @@ private void initActions() {
saveAs, saveSelectedAs, saveSelectedAsPlain, editModeAction, undo, redo, cut, deleteEntry, copy, paste, mark, markSpecific, unmark,
unmarkAll, rankSubMenu, editEntry, selectAll, copyKey, copyCiteKey, copyKeyAndTitle, copyKeyAndLink, editPreamble, editStrings,
groupSelector.getToggleAction(), makeKeyAction, normalSearch, generalFetcher.getToggleAction(), mergeEntries, cleanupEntries, exportToClipboard, replaceAll,
sendAsEmail, downloadFullText, writeXmpAction, openOfficePanel.getToggleAction(), findUnlinkedFiles, addToGroup, removeFromGroup,
sendAsEmail, downloadFullText, lookupIdentifiers, writeXmpAction, openOfficePanel.getToggleAction(), findUnlinkedFiles, addToGroup, removeFromGroup,
moveToGroup, autoLinkFile, resolveDuplicateKeys, openUrl, openFolder, openFile, togglePreview,
dupliCheck, autoSetFile, newEntryAction, newSpec, customizeAction, plainTextImport, getMassSetField(), getManageKeywords(),
pushExternalButton.getMenuAction(), closeDatabaseAction, getNextPreviewStyleAction(), getPreviousPreviewStyleAction(), checkIntegrity,
Expand Down Expand Up @@ -1389,7 +1398,7 @@ dupliCheck, autoSetFile, newEntryAction, newSpec, customizeAction, plainTextImpo
twoEntriesOnlyActions.addAll(Arrays.asList(mergeEntries));

atLeastOneEntryActions.clear();
atLeastOneEntryActions.addAll(Arrays.asList(downloadFullText));
atLeastOneEntryActions.addAll(Arrays.asList(downloadFullText, lookupIdentifiers));

tabbedPane.addChangeListener(event -> updateEnabledState());

Expand Down
38 changes: 38 additions & 0 deletions src/main/java/org/jabref/gui/actions/LookupIdentifierAction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package org.jabref.gui.actions;

import java.awt.event.ActionEvent;

import javax.swing.Action;

import org.jabref.gui.BasePanel;
import org.jabref.gui.JabRefFrame;
import org.jabref.gui.worker.LookupIdentifiersWorker;
import org.jabref.logic.importer.IdFetcher;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class LookupIdentifierAction extends MnemonicAwareAction {

private static final Log LOGGER = LogFactory.getLog(LookupIdentifierAction.class);

private final JabRefFrame frame;
private final IdFetcher fetcher;

@Override
public void actionPerformed(ActionEvent actionEvent) {
try {
BasePanel.runWorker(new LookupIdentifiersWorker(frame, fetcher));
} catch (Exception e) {
LOGGER.error(e);
}
}

public LookupIdentifierAction(JabRefFrame frame, IdFetcher fetcher) {
super();
this.frame = frame;
this.fetcher = fetcher;

putValue(Action.NAME, fetcher.getIdentifierName());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ public static Optional<JComponent> getDoiExtraComponent(BasePanel panel, EntryEd
}
});
// lookup doi
JButton doiButton = new JButton(Localization.lang("Lookup DOI"));
JButton doiButton = new JButton(Localization.lang("Look up DOI"));
doiButton.addActionListener(actionEvent -> {
try {
Optional<DOI> doi = WebFetchers.getIdFetcherForIdentifier(DOI.class).findIdentifier(entryEditor.getEntry());
Expand Down
19 changes: 1 addition & 18 deletions src/main/java/org/jabref/gui/exporter/SaveDatabaseAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import org.jabref.gui.JabRefFrame;
import org.jabref.gui.autosaveandbackup.AutosaveUIManager;
import org.jabref.gui.worker.AbstractWorker;
import org.jabref.gui.worker.CallBack;
import org.jabref.logic.autosaveandbackup.AutosaveManager;
import org.jabref.logic.autosaveandbackup.BackupManager;
import org.jabref.logic.exporter.BibtexDatabaseWriter;
Expand Down Expand Up @@ -280,23 +279,7 @@ private boolean saveDatabase(File file, boolean selectedOnly, Charset encoding)
* still runs synchronously using Spin (the method returns only after completing the operation).
*/
public void runCommand() throws Exception {
// This part uses Spin's features:
Runnable worker = getWorker();
// The Worker returned by getWorker() has been wrapped
// by Spin.off(), which makes its methods be run in
// a different thread from the EDT.
CallBack callback = getCallBack();

init(); // This method runs in this same thread, the EDT.
// Useful for initial GUI actions, like printing a message.

// The CallBack returned by getCallBack() has been wrapped
// by Spin.over(), which makes its methods be run on
// the EDT.
worker.run(); // Runs the potentially time-consuming action
// without freezing the GUI. The magic is that THIS line
// of execution will not continue until run() is finished.
callback.update(); // Runs the update() method on the EDT.
BasePanel.runWorker(this);
}

public void save() throws Exception {
Expand Down
76 changes: 76 additions & 0 deletions src/main/java/org/jabref/gui/worker/LookupIdentifiersWorker.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package org.jabref.gui.worker;

import java.util.List;
import java.util.Objects;
import java.util.Optional;

import org.jabref.gui.BasePanel;
import org.jabref.gui.JabRefFrame;
import org.jabref.gui.undo.NamedCompound;
import org.jabref.gui.undo.UndoableFieldChange;
import org.jabref.logic.importer.FetcherException;
import org.jabref.logic.importer.IdFetcher;
import org.jabref.logic.l10n.Localization;
import org.jabref.model.FieldChange;
import org.jabref.model.entry.BibEntry;
import org.jabref.model.entry.identifier.Identifier;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class LookupIdentifiersWorker<T extends Identifier> extends AbstractWorker {

private final JabRefFrame frame;
private final IdFetcher<T> fetcher;
private String message;

private static final Log LOGGER = LogFactory.getLog(LookupIdentifiersWorker.class);

public LookupIdentifiersWorker(JabRefFrame frame, IdFetcher<T> fetcher) {
this.frame = Objects.requireNonNull(frame);
this.fetcher = Objects.requireNonNull(fetcher);
}

@Override
public void run() {
BasePanel basePanel = Objects.requireNonNull(frame.getCurrentBasePanel());
List<BibEntry> bibEntries = basePanel.getSelectedEntries();
if (!bibEntries.isEmpty()) {
String totalCount = Integer.toString(bibEntries.size());
NamedCompound namedCompound = new NamedCompound(Localization.lang("Look up %0", fetcher.getIdentifierName()));
int count = 0;
int foundCount = 0;
for (BibEntry bibEntry : bibEntries) {
count++;
frame.output(Localization.lang("Looking up %0... - entry %1 out of %2 - found %3",
fetcher.getIdentifierName(), Integer.toString(count), totalCount, Integer.toString(foundCount)));
Optional<T> identifier = Optional.empty();
try {
identifier = fetcher.findIdentifier(bibEntry);
} catch (FetcherException e) {
LOGGER.error("Could not fetch " + fetcher.getIdentifierName(), e);
}
if (identifier.isPresent() && !bibEntry.hasField(identifier.get().getDefaultField())) {
Optional<FieldChange> fieldChange = bibEntry.setField(identifier.get().getDefaultField(), identifier.get().getNormalized());
if (fieldChange.isPresent()) {
namedCompound.addEdit(new UndoableFieldChange(fieldChange.get()));
foundCount++;
frame.output(Localization.lang("Looking up %0... - entry %1 out of %2 - found %3",
Integer.toString(count), totalCount, Integer.toString(foundCount)));
}
}
}
namedCompound.end();
if (foundCount > 0) {
basePanel.getUndoManager().addEdit(namedCompound);
basePanel.markBaseChanged();
}
message = Localization.lang("Determined %0 for %1 entries", fetcher.getIdentifierName(), Integer.toString(foundCount));
}
}

@Override
public void update() {
frame.output(message);
}
}
3 changes: 0 additions & 3 deletions src/main/java/org/jabref/gui/worker/MarkEntriesAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
*
*/
public class MarkEntriesAction extends AbstractWorker implements ActionListener {

private final JabRefFrame frame;
Expand Down
8 changes: 7 additions & 1 deletion src/main/java/org/jabref/logic/importer/IdFetcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
import java.util.Optional;

import org.jabref.model.entry.BibEntry;
import org.jabref.model.entry.identifier.Identifier;

/**
* Looks for article identifier based on already present bibliographic information.
*/
public interface IdFetcher<T> extends WebFetcher {
public interface IdFetcher<T extends Identifier> extends WebFetcher {

/**
* Looks for an identifier based on the information stored in the given {@link BibEntry}.
Expand All @@ -16,4 +17,9 @@ public interface IdFetcher<T> extends WebFetcher {
* @return the identifier (if an ID was found, otherwise an empty {@link Optional})
*/
Optional<T> findIdentifier(BibEntry entry) throws FetcherException;

/**
* Returns the name of the identifier that is returned by this fetcher.
*/
String getIdentifierName();
}
3 changes: 2 additions & 1 deletion src/main/java/org/jabref/logic/importer/IdParserFetcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

import org.jabref.model.cleanup.Formatter;
import org.jabref.model.entry.BibEntry;
import org.jabref.model.entry.identifier.Identifier;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
Expand All @@ -23,7 +24,7 @@
* 2. Parse the response to get a list of {@link BibEntry}
* 3. Extract identifier
*/
public interface IdParserFetcher<T> extends IdFetcher<T> {
public interface IdParserFetcher<T extends Identifier> extends IdFetcher<T> {

Log LOGGER = LogFactory.getLog(IdParserFetcher.class);

Expand Down
10 changes: 9 additions & 1 deletion src/main/java/org/jabref/logic/importer/WebFetchers.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.jabref.logic.importer.fetcher.zbMATH;
import org.jabref.model.entry.FieldName;
import org.jabref.model.entry.identifier.DOI;
import org.jabref.model.entry.identifier.Identifier;

public class WebFetchers {

Expand All @@ -42,7 +43,7 @@ public static Optional<IdBasedFetcher> getIdBasedFetcherForField(String field, I
}

@SuppressWarnings("unchecked")
public static <T> IdFetcher<T> getIdFetcherForIdentifier(Class<T> clazz) {
public static <T extends Identifier> IdFetcher<T> getIdFetcherForIdentifier(Class<T> clazz) {
if (clazz == DOI.class) {
return (IdFetcher<T>) new CrossRef();
} else {
Expand Down Expand Up @@ -89,4 +90,11 @@ public static List<EntryBasedFetcher> getEntryBasedFetchers(ImportFormatPreferen
list.sort(Comparator.comparing(WebFetcher::getName));
return list;
}

public static List<IdFetcher> getIdFetchers() {
ArrayList<IdFetcher> list = new ArrayList<>();
list.add(new CrossRef());
list.sort(Comparator.comparing(WebFetcher::getName));
return list;
}
}
5 changes: 5 additions & 0 deletions src/main/java/org/jabref/logic/importer/fetcher/CrossRef.java
Original file line number Diff line number Diff line change
Expand Up @@ -181,4 +181,9 @@ public Optional<DOI> extractIdentifier(BibEntry inputEntry, List<BibEntry> fetch

return Optional.empty();
}

@Override
public String getIdentifierName() {
return "DOI";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public Optional<URL> findFullText(BibEntry entry) throws IOException {

Optional<DOI> doi = entry.getField(FieldName.DOI).flatMap(DOI::build);

if(doi.isPresent()) {
if (doi.isPresent()) {
String sciLink = doi.get().getURIAsASCIIString();

// follow all redirects and scan for a single pdf link
Expand Down
Loading

0 comments on commit 63620ff

Please sign in to comment.