Skip to content

Commit

Permalink
Rework AutoSetFileLinks (#3368)
Browse files Browse the repository at this point in the history
* Rework AutoSetFileLinks

* Only add first found file

* Improve magic AutoFileLinking in entry editor by using same logic as manually triggering it

* Don't use paths.get

* add changelog entry

* refactor
TODO: remove duplicate findings

* Use HashMap with BibEntry and LinkedFiles
Only call setFiles when pressing F7
Fix javafx thread error

* improve optional code
use streams in externalfiletype

* logging
remove javadoc params

* pass preferences to method

* Return list of Linkedfiles and let caller handle bib entries
Add test

* Replace mocking of Jabrefs prefs with autolink prefs
  • Loading branch information
Siedlerchr authored Oct 31, 2017
1 parent 0235f63 commit 551cb91
Show file tree
Hide file tree
Showing 7 changed files with 204 additions and 164 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package org.jabref.gui.externalfiles;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import org.jabref.gui.externalfiletype.ExternalFileType;
import org.jabref.gui.externalfiletype.ExternalFileTypes;
import org.jabref.gui.externalfiletype.UnknownExternalFileType;
import org.jabref.logic.util.io.AutoLinkPreferences;
import org.jabref.logic.util.io.FileFinder;
import org.jabref.logic.util.io.FileFinders;
import org.jabref.model.database.BibDatabaseContext;
import org.jabref.model.entry.BibEntry;
import org.jabref.model.entry.LinkedFile;
import org.jabref.model.metadata.FileDirectoryPreferences;
import org.jabref.model.util.FileHelper;

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

public class AutoSetFileLinksUtil {

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

public List<LinkedFile> findassociatedNotLinkedFiles(BibEntry entry, BibDatabaseContext databaseContext, FileDirectoryPreferences fileDirPrefs, AutoLinkPreferences autoLinkPrefs, ExternalFileTypes externalFileTypes) {
List<LinkedFile> linkedFiles = new ArrayList<>();

List<Path> dirs = databaseContext.getFileDirectoriesAsPaths(fileDirPrefs);
List<String> extensions = externalFileTypes.getExternalFileTypeSelection().stream().map(ExternalFileType::getExtension).collect(Collectors.toList());

// Run the search operation:
FileFinder fileFinder = FileFinders.constructFromConfiguration(autoLinkPrefs);
List<Path> result = fileFinder.findAssociatedFiles(entry, dirs, extensions);

// Iterate over the entries:

for (Path foundFile : result) {
boolean existingSameFile = entry.getFiles().stream()
.map(file -> file.findIn(dirs))
.anyMatch(file -> {
try {
return file.isPresent() && Files.isSameFile(file.get(), foundFile);
} catch (IOException e) {
LOGGER.error("Problem with isSameFile", e);
}
return false;
});
if (!existingSameFile) {

Optional<ExternalFileType> type = FileHelper.getFileExtension(foundFile)
.map(externalFileTypes::getExternalFileTypeByExt)
.orElse(Optional.of(new UnknownExternalFileType("")));

String strType = type.isPresent() ? type.get().getName() : "";

LinkedFile linkedFile = new LinkedFile("", foundFile.toString(), strType);
linkedFiles.add(linkedFile);
}
}

return linkedFiles;
}
}
153 changes: 49 additions & 104 deletions src/main/java/org/jabref/gui/externalfiles/AutoSetLinks.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,10 @@
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import javax.swing.BorderFactory;
import javax.swing.JDialog;
Expand All @@ -24,19 +18,15 @@
import org.jabref.Globals;
import org.jabref.gui.externalfiletype.ExternalFileType;
import org.jabref.gui.externalfiletype.ExternalFileTypes;
import org.jabref.gui.externalfiletype.UnknownExternalFileType;
import org.jabref.gui.filelist.FileListEntry;
import org.jabref.gui.filelist.FileListTableModel;
import org.jabref.gui.undo.NamedCompound;
import org.jabref.gui.undo.UndoableFieldChange;
import org.jabref.gui.util.DefaultTaskExecutor;
import org.jabref.logic.l10n.Localization;
import org.jabref.logic.util.io.FileFinder;
import org.jabref.logic.util.io.FileFinders;
import org.jabref.logic.util.io.FileUtil;
import org.jabref.model.database.BibDatabaseContext;
import org.jabref.model.entry.BibEntry;
import org.jabref.model.entry.FieldName;
import org.jabref.model.util.FileHelper;
import org.jabref.model.entry.FileFieldWriter;
import org.jabref.model.entry.LinkedFile;

public class AutoSetLinks {

Expand All @@ -50,7 +40,7 @@ private AutoSetLinks() {
* @param databaseContext the database for which links are set
*/
public static void autoSetLinks(List<BibEntry> entries, BibDatabaseContext databaseContext) {
autoSetLinks(entries, null, null, null, databaseContext, null, null);
autoSetLinks(entries, null, null, databaseContext, null, null);
}

/**
Expand All @@ -64,12 +54,7 @@ public static void autoSetLinks(List<BibEntry> entries, BibDatabaseContext datab
* @param entries A collection of BibEntry objects to find links for.
* @param ce A NamedCompound to add UndoEdit elements to.
* @param changedEntries MODIFIED, optional. A Set of BibEntry objects to which all modified entries is added.
* This is used for status output and debugging
* @param singleTableModel UGLY HACK. The table model to insert links into. Already existing links are not
* duplicated or removed. This parameter has to be null if entries.count() != 1. The hack has been
* introduced as a bibtexentry does not (yet) support the function getListTableModel() and the
* FileListEntryEditor editor holds an instance of that table model and does not reconstruct it after the
* search has succeeded.
* @param databaseContext The database providing the relevant file directory, if any.
* @param callback An ActionListener that is notified (on the event dispatch thread) when the search is finished.
* The ActionEvent has id=0 if no new links were added, and id=1 if one or more links were added. This
Expand All @@ -79,7 +64,7 @@ public static void autoSetLinks(List<BibEntry> entries, BibDatabaseContext datab
* @return the thread performing the automatically setting
*/
public static Runnable autoSetLinks(final List<BibEntry> entries, final NamedCompound ce,
final Set<BibEntry> changedEntries, final FileListTableModel singleTableModel,
final Set<BibEntry> changedEntries,
final BibDatabaseContext databaseContext, final ActionListener callback, final JDialog diag) {
final Collection<ExternalFileType> types = ExternalFileTypes.getInstance().getExternalFileTypeSelection();
if (diag != null) {
Expand All @@ -95,97 +80,58 @@ public static Runnable autoSetLinks(final List<BibEntry> entries, final NamedCom
diag.setLocationRelativeTo(diag.getParent());
}

Runnable r = new Runnable() {

@Override
public void run() {
// determine directories to search in
final List<Path> dirs = databaseContext.getFileDirectoriesAsPaths(Globals.prefs.getFileDirectoryPreferences());

// determine extensions
final List<String> extensions = types.stream().map(ExternalFileType::getExtension).collect(Collectors.toList());

// Run the search operation:
FileFinder fileFinder = FileFinders.constructFromConfiguration(Globals.prefs.getAutoLinkPreferences());
Map<BibEntry, List<Path>> result = fileFinder.findAssociatedFiles(entries, dirs, extensions);

boolean foundAny = false;
// Iterate over the entries:
for (Entry<BibEntry, List<Path>> entryFilePair : result.entrySet()) {
FileListTableModel tableModel;
Optional<String> oldVal = entryFilePair.getKey().getField(FieldName.FILE);
if (singleTableModel == null) {
tableModel = new FileListTableModel();
oldVal.ifPresent(tableModel::setContent);
} else {
assert entries.size() == 1;
tableModel = singleTableModel;
Runnable r = () -> {
boolean foundAny = false;
AutoSetFileLinksUtil util = new AutoSetFileLinksUtil();

for (BibEntry entry : entries) {

List<LinkedFile> linkedFiles = util.findassociatedNotLinkedFiles(entry, databaseContext, Globals.prefs.getFileDirectoryPreferences(), Globals.prefs.getAutoLinkPreferences(), ExternalFileTypes.getInstance());

if (ce != null) {
for (LinkedFile linkedFile : linkedFiles) {
// store undo information
String newVal = FileFieldWriter.getStringRepresentation(linkedFile);

String oldVal = entry.getField(FieldName.FILE).orElse(null);

UndoableFieldChange fieldChange = new UndoableFieldChange(entry, FieldName.FILE, oldVal, newVal);
ce.addEdit(fieldChange);

DefaultTaskExecutor.runInJavaFXThread(() -> {
entry.addFile(linkedFile);
});
foundAny = true;
}
List<Path> files = entryFilePair.getValue();
for (Path file : files) {
file = FileUtil.shortenFileName(file, dirs);
boolean alreadyHas = false;

for (int j = 0; j < tableModel.getRowCount(); j++) {
FileListEntry existingEntry = tableModel.getEntry(j);
if (Paths.get(existingEntry.getLink()).equals(file)) {
alreadyHas = true;
foundAny = true;
break;
}
}
if (!alreadyHas) {
foundAny = true;
Optional<ExternalFileType> type = FileHelper.getFileExtension(file)
.map(extension -> ExternalFileTypes.getInstance().getExternalFileTypeByExt(extension))
.orElse(Optional.of(new UnknownExternalFileType("")));
FileListEntry flEntry = new FileListEntry("", file.toString(), type);
tableModel.addEntry(tableModel.getRowCount(), flEntry);

String newVal = tableModel.getStringRepresentation();
if (newVal.isEmpty()) {
newVal = null;
}
if (ce != null) {
// store undo information
UndoableFieldChange change = new UndoableFieldChange(entryFilePair.getKey(),
FieldName.FILE, oldVal.orElse(null), newVal);
ce.addEdit(change);
}
// hack: if table model is given, do NOT modify entry
if (singleTableModel == null) {
entryFilePair.getKey().setField(FieldName.FILE, newVal);
}
if (changedEntries != null) {
changedEntries.add(entryFilePair.getKey());
}
}

if (changedEntries != null) {
changedEntries.add(entry);
}
}

// handle callbacks and dialog
// FIXME: The ID signals if action was successful :/
final int id = foundAny ? 1 : 0;
SwingUtilities.invokeLater(new Runnable() {

@Override
public void run() {
if (diag != null) {
diag.dispose();
}
if (callback != null) {
callback.actionPerformed(new ActionEvent(this, id, ""));
}
}
});
}

final int id = foundAny ? 1 : 0;
SwingUtilities.invokeLater(() -> {

if (diag != null) {
diag.dispose();
}
if (callback != null) {
callback.actionPerformed(new ActionEvent(AutoSetLinks.class, id, ""));
}

});

};

SwingUtilities.invokeLater(() -> {
// show dialog which will be hidden when the task is done
if (diag != null) {
diag.setVisible(true);
}
});

return r;
}

Expand All @@ -194,8 +140,7 @@ public void run() {
* of external file types. The entry itself is not modified. The entry's bibtex key must have been set.
*
* @param entry The BibEntry to find links for.
* @param singleTableModel The table model to insert links into. Already existing links are not duplicated or
* removed.
* @param databaseContext The database providing the relevant file directory, if any.
* @param callback An ActionListener that is notified (on the event dispatch thread) when the search is finished.
* The ActionEvent has id=0 if no new links were added, and id=1 if one or more links were added. This
Expand All @@ -206,9 +151,9 @@ public void run() {
* parameter can be null, which means that no progress update will be shown.
* @return the runnable able to perform the automatically setting
*/
public static Runnable autoSetLinks(final BibEntry entry, final FileListTableModel singleTableModel,
public static Runnable autoSetLinks(final BibEntry entry,
final BibDatabaseContext databaseContext, final ActionListener callback, final JDialog diag) {
return autoSetLinks(Collections.singletonList(entry), null, null, singleTableModel, databaseContext, callback,
return autoSetLinks(Collections.singletonList(entry), null, null, databaseContext, callback,
diag);
}

Expand Down
25 changes: 15 additions & 10 deletions src/main/java/org/jabref/gui/externalfiles/FindFullTextAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.io.IOException;
import java.net.URL;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
Expand All @@ -14,6 +15,7 @@
import org.jabref.Globals;
import org.jabref.gui.BasePanel;
import org.jabref.gui.undo.UndoableFieldChange;
import org.jabref.gui.util.DefaultTaskExecutor;
import org.jabref.gui.worker.AbstractWorker;
import org.jabref.logic.importer.FulltextFetchers;
import org.jabref.logic.l10n.Localization;
Expand Down Expand Up @@ -81,9 +83,9 @@ public void update() {
BibEntry entry = download.getValue();
Optional<URL> result = download.getKey();
if (result.isPresent()) {
List<String> dirs = basePanel.getBibDatabaseContext()
.getFileDirectories(Globals.prefs.getFileDirectoryPreferences());
if (dirs.isEmpty()) {
Optional<Path> dir = basePanel.getBibDatabaseContext().getFirstExistingFileDir(Globals.prefs.getFileDirectoryPreferences());

if (!dir.isPresent()) {
JOptionPane.showMessageDialog(basePanel.frame(),
Localization.lang("Main file directory not set!") + " " + Localization.lang("Preferences")
+ " -> " + Localization.lang("File"),
Expand All @@ -94,13 +96,16 @@ public void update() {
basePanel.getBibDatabaseContext(), entry);
try {
def.download(result.get(), file -> {
Optional<FieldChange> fieldChange = entry.addFile(file);
if (fieldChange.isPresent()) {
UndoableFieldChange edit = new UndoableFieldChange(entry, FieldName.FILE,
entry.getField(FieldName.FILE).orElse(null), fieldChange.get().getNewValue());
basePanel.getUndoManager().addEdit(edit);
basePanel.markBaseChanged();
}
DefaultTaskExecutor.runInJavaFXThread(() -> {
Optional<FieldChange> fieldChange = entry.addFile(file);
if (fieldChange.isPresent()) {
UndoableFieldChange edit = new UndoableFieldChange(entry, FieldName.FILE,
entry.getField(FieldName.FILE).orElse(null), fieldChange.get().getNewValue());
basePanel.getUndoManager().addEdit(edit);
basePanel.markBaseChanged();
}
});

});
} catch (IOException e) {
LOGGER.warn("Problem downloading file", e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ public void run() {
List<BibEntry> entries = new ArrayList<>(sel);

// Start the automatically setting process:
Runnable r = AutoSetLinks.autoSetLinks(entries, ce, changedEntries, null, panel.getBibDatabaseContext(), null, null);
Runnable r = AutoSetLinks.autoSetLinks(entries, ce, changedEntries, panel.getBibDatabaseContext(), null, null);
JabRefExecutorService.INSTANCE.executeAndWait(r);
}
progress += sel.size() * weightAutoSet;
Expand Down
Loading

0 comments on commit 551cb91

Please sign in to comment.