package org.jabref.gui.importer; import java.io.File; import java.io.FileFilter; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedList; import java.util.List; import java.util.Optional; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.undo.CompoundEdit; import org.jabref.gui.BasePanel; import org.jabref.gui.externalfiletype.ExternalFileType; import org.jabref.gui.externalfiletype.ExternalFileTypes; import org.jabref.gui.undo.UndoableInsertEntry; import org.jabref.logic.l10n.Localization; import org.jabref.model.database.BibDatabase; import org.jabref.model.entry.BibEntry; import org.jabref.model.entry.EntryType; import org.jabref.model.entry.IdGenerator; /** * The class EntryFromFileCreatorManager manages entry creators. * The manager knows all existing implementations of the interface EntryFromFileCreator. * Given a file, the manager can then provide a creator, which is able to create a Bibtex entry for his file. * Knowing all implementations of the interface, the manager also knows the set of all files, of which Bibtex entries can be created. * The GUI uses this capability for offering the user only such files, of which entries could actually be created. * @author Dan&Nosh * */ public final class EntryFromFileCreatorManager { private final List<EntryFromFileCreator> entryCreators; public EntryFromFileCreatorManager() { entryCreators = new ArrayList<>(10); entryCreators.add(new EntryFromPDFCreator()); // add a creator for each ExternalFileType if there is no specialized // creator existing. Collection<ExternalFileType> fileTypes = ExternalFileTypes.getInstance().getExternalFileTypeSelection(); for (ExternalFileType exFileType : fileTypes) { if (!hasSpecialisedCreatorForExternalFileType(exFileType)) { entryCreators.add(new EntryFromExternalFileCreator(exFileType)); } } } private boolean hasSpecialisedCreatorForExternalFileType( ExternalFileType externalFileType) { for (EntryFromFileCreator entryCreator : entryCreators) { if ((entryCreator.getExternalFileType() == null) || (entryCreator.getExternalFileType().getExtension().isEmpty())) { continue; } if (entryCreator.getExternalFileType().getExtension().equals( externalFileType.getExtension())) { return true; } } return false; } /** * Returns a EntryFromFileCreator object that is capable of creating a * BibEntry for the given File. * * @param file the pdf file * @return null if there is no EntryFromFileCreator for this File. */ public EntryFromFileCreator getEntryCreator(File file) { if ((file == null) || !file.exists()) { return null; } for (EntryFromFileCreator creator : entryCreators) { if (creator.accept(file)) { return creator; } } return null; } /** * Tries to add a entry for each file in the List. * * @param files * @param database * @param entryType * @return List of unexpected import event messages including failures. */ public List<String> addEntrysFromFiles(List<File> files, BibDatabase database, EntryType entryType, boolean generateKeywordsFromPathToFile) { List<String> importGUIMessages = new LinkedList<>(); addEntriesFromFiles(files, database, null, entryType, generateKeywordsFromPathToFile, null, importGUIMessages); return importGUIMessages; } /** * Tries to add a entry for each file in the List. * * @param files * @param database * @param panel * @param entryType * @param generateKeywordsFromPathToFile * @param changeListener * @param importGUIMessages list of unexpected import event - Messages including * failures * @return Returns The number of entries added */ public int addEntriesFromFiles(List<File> files, BibDatabase database, BasePanel panel, EntryType entryType, boolean generateKeywordsFromPathToFile, ChangeListener changeListener, List<String> importGUIMessages) { int count = 0; CompoundEdit ce = new CompoundEdit(); for (File f : files) { EntryFromFileCreator creator = getEntryCreator(f); if (creator == null) { importGUIMessages.add("Problem importing " + f.getPath() + ": Unknown filetype."); } else { Optional<BibEntry> entry = creator.createEntry(f, generateKeywordsFromPathToFile); if (!entry.isPresent()) { importGUIMessages.add("Problem importing " + f.getPath() + ": Entry could not be created."); continue; } if (entryType != null) { entry.get().setType(entryType); } if (entry.get().getId() == null) { entry.get().setId(IdGenerator.next()); } /* * TODO: database.insertEntry(BibEntry) is not sensible. Why * does 'true' mean "There were duplicates", while 'false' means * "Everything alright"? */ if (!database.containsEntryWithId(entry.get().getId())) { // Work around SIDE EFFECT of creator.createEntry. The EntryFromPDFCreator also creates the entry in the table // Therefore, we only insert the entry if it is not already present if (database.insertEntry(entry.get())) { importGUIMessages.add("Problem importing " + f.getPath() + ": Insert into BibDatabase failed."); } else { count++; if (panel != null) { ce.addEdit(new UndoableInsertEntry(database, entry.get(), panel)); } } } } if (changeListener != null) { changeListener.stateChanged(new ChangeEvent(this)); } } if ((count > 0) && (panel != null)) { ce.end(); panel.getUndoManager().addEdit(ce); } return count; } /** * Returns a {@link FileFilter} instance which will accept all files, for * which a {@link EntryFromFileCreator} exists, that accepts the files. <br> * <br> * This {@link FileFilter} will be displayed in the GUI as * "All supported files". * * @return A {@link FileFilter} that accepts all files for which creators * exist. */ private FileFilter getFileFilter() { return new FileFilter() { /** * Accepts all files, which are accepted by any known creator. */ @Override public boolean accept(File file) { for (EntryFromFileCreator creator : entryCreators) { if (creator.accept(file)) { return true; } } return false; } @Override public String toString() { return Localization.lang("All external files"); } }; } /** * Returns a list of all {@link FileFilter} instances (i.e. * {@link EntryFromFileCreator}, plus the file filter that comes with the * {@link #getFileFilter()} method. * * @return A List of all known possible file filters. */ public List<FileFilter> getFileFilterList() { List<FileFilter> filters = new ArrayList<>(); filters.add(getFileFilter()); for (FileFilter creator : entryCreators) { filters.add(creator); } return filters; } }