package net.sf.jabref.imports; import java.io.File; import java.io.FileFilter; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import net.sf.jabref.BibtexDatabase; import net.sf.jabref.BibtexEntry; import net.sf.jabref.FindUnlinkedFilesDialog.CheckableTreeNode; import net.sf.jabref.FindUnlinkedFilesDialog.FileNodeWrapper; /** * Util class for searching files on the filessystem which are not linked to a * provided {@link BibtexDatabase}. * * @author Nosh&Dan * @version 09.11.2008 | 19:55:20 * */ public class UnlinkedFilesCrawler { /** * File filter, that accepts directorys only. */ public final FileFilter directoryFilter = new FileFilter() { public boolean accept(File pathname) { if (pathname == null) return false; return pathname.isDirectory(); } }; private final BibtexDatabase database; /** * CONSTRUCTOR * * @param database */ public UnlinkedFilesCrawler(BibtexDatabase database) { this.database = database; } public CheckableTreeNode searchDirectory(File directory, FileFilter aFileFilter) { UnlinkedPDFFileFilter ff = new UnlinkedPDFFileFilter(aFileFilter, database); return searchDirectory(directory, ff, new int[] {1}, null); } /** * Searches recursively all files in the specified directory. <br> * <br> * All {@link File}s, which match the {@link FileFilter} that comes with the * {@link EntryFromFileCreatorManager}, are taken into the resulting tree. <br> * <br> * The result will be a tree structure of nodes of the type * {@link CheckableTreeNode}. <br> * <br> * The user objects that are attached to the nodes is the * {@link FileNodeWrapper}, which wrapps the {@link File}-Object. <br> * <br> * For ensuring the capability to cancel the work of this recursive method, * the first position in the integer array 'state' must be set to 1, to keep * the recursion running. When the states value changes, the methode will * resolve its recursion and return what it has saved so far. */ public CheckableTreeNode searchDirectory(File directory, UnlinkedPDFFileFilter ff, int[] state, ChangeListener changeListener) { /* Cancellation of the search from outside! */ if (state == null || state.length < 1 || state[0] != 1) { return null; } /* Return null if the directory is not valid. */ if (directory == null || !directory.exists() || !directory.isDirectory()) { return null; } File[] files = directory.listFiles(ff); CheckableTreeNode root = new CheckableTreeNode(null); int filesCount = 0; File[] subDirectories = directory.listFiles(directoryFilter); for (int i = 0; i < subDirectories.length; i++) { CheckableTreeNode subRoot = searchDirectory(subDirectories[i], ff, state, changeListener); if (subRoot != null && subRoot.getChildCount() > 0) { filesCount += ((FileNodeWrapper) subRoot.getUserObject()).fileCount; root.add(subRoot); } } root.setUserObject(new FileNodeWrapper(directory, files.length + filesCount)); for (int i = 0; i < files.length; i++) { root.add(new CheckableTreeNode(new FileNodeWrapper(files[i]))); if (changeListener != null) changeListener.stateChanged(new ChangeEvent(this)); } return root; } }