1 package net.sf.jabref.external;
3 import net.sf.jabref.*;
4 import net.sf.jabref.gui.FileListEditor;
5 import net.sf.jabref.gui.FileListEntryEditor;
6 import net.sf.jabref.gui.FileListEntry;
7 import net.sf.jabref.net.URLDownload;
11 import java.io.IOException;
13 import java.net.MalformedURLException;
16 * This class handles the download of an external file. Typically called when the user clicks
17 * the "Download" button in a FileListEditor shown in an EntryEditor.
19 * The FileListEditor constructs the DownloadExternalFile instance, then calls the download()
20 * method passing a reference to itself as a callback. The download() method asks for the URL,
21 * then starts the download. When the download is completed, it calls the downloadCompleted()
22 * method on the callback FileListEditor, which then needs to take care of linking to the file.
23 * The local filename is passed as an argument to the downloadCompleted() method.
25 * If the download is cancelled, or failed, the user is informed. The callback is never called.
27 public class DownloadExternalFile {
28 private JabRefFrame frame;
29 private JDialog dialog;
30 private MetaData metaData;
31 private String bibtexKey;
32 private FileListEntryEditor editor;
33 private boolean downloadFinished = false;
35 public DownloadExternalFile(JabRefFrame frame, MetaData metaData, String bibtexKey) {
38 this.metaData = metaData;
39 this.bibtexKey = bibtexKey;
45 * @param callback The object to which the filename should be reported when download
48 public void download(final DownloadCallback callback) throws IOException {
50 final String res = JOptionPane.showInputDialog(frame,
51 Globals.lang("Enter URL to download"));
53 if (res == null || res.trim().length() == 0)
56 // First of all, start the download itself in the background to a temporary file:
57 final File tmp = File.createTempFile("jabref_download", "tmp");
64 URL url = new URL(res);
65 URLDownload udl = new URLDownload(frame, url, tmp);
68 } catch (IOException e2) {
69 JOptionPane.showMessageDialog(frame, Globals.lang("Invalid URL: "
70 + e2.getMessage()), Globals.lang("Download file"),
71 JOptionPane.ERROR_MESSAGE);
72 Globals.logger("Error while downloading " + url.toString());
76 // Download finished: call the method that stops the progress bar etc.:
77 SwingUtilities.invokeLater(new Runnable() {
84 } catch (MalformedURLException e1) {
85 JOptionPane.showMessageDialog(frame, Globals.lang("Invalid URL"), Globals
86 .lang("Download file"), JOptionPane.ERROR_MESSAGE);
91 // Then, while the download is proceeding, let the user choose the details of the file:
92 String suffix = getSuffix(res);
93 String suggestedName = bibtexKey != null ? getSuggestedFileName(res, suffix) : "";
94 final String directory = getFileDirectory(res);
95 File file = new File(new File(directory), suggestedName);
96 FileListEntry entry = new FileListEntry("", bibtexKey != null ? file.getPath() : "",
97 Globals.prefs.getExternalFileTypeByExt(suffix));
98 editor = new FileListEntryEditor(frame, entry, true, metaData);
99 editor.getProgressBar().setIndeterminate(true);
100 editor.setOkEnabled(false);
101 editor.setExternalConfirm(new ConfirmCloseFileListEntryEditor() {
102 public boolean confirmClose(FileListEntry entry) {
103 File f = expandFilename(directory, entry.getLink());
104 if (f.isDirectory()) {
105 JOptionPane.showMessageDialog(frame,
106 Globals.lang("Target file cannot be a directory."), Globals.lang("Download file"),
107 JOptionPane.ERROR_MESSAGE);
111 return JOptionPane.showConfirmDialog
112 (frame, "'"+f.getName()+"' "+Globals.lang("exists. Overwrite file?"),
113 Globals.lang("Download file"), JOptionPane.OK_CANCEL_OPTION)
114 == JOptionPane.OK_OPTION;
119 editor.setVisible(true);
120 // Editor closed. Go on:
121 if (editor.okPressed()) {
122 String dirPrefix = directory+System.getProperty("file.separator");
123 File toFile = expandFilename(directory, entry.getLink());
125 boolean success = Util.copyFile(tmp, toFile, true);
127 // OOps, the file exists!
128 System.out.println("File already exists! DownloadExternalFile.download()");
131 // If the local file is in or below the main file directory, change the
133 if (entry.getLink().startsWith(directory) &&
134 (entry.getLink().length() > dirPrefix.length())) {
135 entry.setLink(entry.getLink().substring(dirPrefix.length()));
138 callback.downloadComplete(entry);
139 } catch (IOException ex) {
140 ex.printStackTrace();
146 // Cancelled. Just delete the temp file:
147 if (downloadFinished)
154 * Construct a File object pointing to the file linked, whether the link is
155 * absolute or relative to the main directory.
156 * @param directory The main directory.
157 * @param link The absolute or relative link.
158 * @return The expanded File.
160 private File expandFilename(String directory, String link) {
161 File toFile = new File(link);
162 // If this is a relative link, we should perhaps append the directory:
163 String dirPrefix = directory+System.getProperty("file.separator");
164 if (!toFile.isAbsolute()) {
165 toFile = new File(dirPrefix+link);
171 * This is called by the download thread when download is completed.
173 public void downloadFinished() {
174 downloadFinished = true;
175 editor.getProgressBar().setVisible(false);
176 editor.getProgressBarLabel().setVisible(false);
177 editor.setOkEnabled(true);
178 editor.getProgressBar().setValue(editor.getProgressBar().getMaximum());
181 public String getSuggestedFileName(String res, String suffix) {
182 if (suffix == null) {
183 System.out.println("Link has no obvious extension (DownloadExternalFile.download()");
186 String plannedName = bibtexKey + "." + suffix;
189 * [ 1548875 ] download pdf produces unsupported filename
191 * http://sourceforge.net/tracker/index.php?func=detail&aid=1548875&group_id=92314&atid=600306
194 if (Globals.ON_WIN) {
195 plannedName = plannedName.replaceAll(
196 "\\?|\\*|\\<|\\>|\\||\\\"|\\:|\\.$|\\[|\\]", "");
197 } else if (Globals.ON_MAC) {
198 plannedName = plannedName.replaceAll(":", "");
205 * Look for the last '.' in the link, and returnthe following characters.
206 * This gives the extension for most reasonably named links.
208 * @param link The link
209 * @return The suffix, excluding the dot (e.g. ".pdf")
211 public String getSuffix(String link) {
212 int index = link.lastIndexOf('.');
213 if ((index <= 0) || (index == link.length() - 1)) // No occurence, or at the end
215 return link.substring(index + 1);
218 public String getFileDirectory(String link) {
219 // TODO: getFileDirectory()
220 return metaData.getFileDirectory(GUIGlobals.FILE_FIELD);
224 * Callback interface that users of this class must implement in order to receive
225 * notification when download is complete.
227 public interface DownloadCallback {
228 public void downloadComplete(FileListEntry file);