package net.sf.jabref.external; import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.util.Collection; import javax.swing.*; import net.sf.jabref.*; import net.sf.jabref.gui.AttachFileDialog; import net.sf.jabref.undo.NamedCompound; import net.sf.jabref.undo.UndoableFieldChange; import com.jgoodies.forms.builder.ButtonBarBuilder; import com.jgoodies.forms.builder.DefaultFormBuilder; import com.jgoodies.forms.layout.FormLayout; /** * This action goes through all selected entries in the BasePanel, and attempts to autoset the * given external file (pdf, ps, ...) based on the same algorithm used for the "Auto" button in * EntryEditor. */ public class AutoSetExternalFileForEntries extends AbstractWorker { private String fieldName; private BasePanel panel; private BibtexEntry[] sel = null; private OptionsDialog optDiag = null; Object[] brokenLinkOptions = {Globals.lang("Ignore"), Globals.lang("Assign new file"), Globals.lang("Clear field"), Globals.lang("Quit synchronization")}; private boolean goOn = true, autoSet = true, overWriteAllowed = true, checkExisting = true; private int entriesChanged = 0, brokenLinks = 0; public AutoSetExternalFileForEntries(BasePanel panel, String fieldName) { this.fieldName = fieldName; this.panel = panel; } public void init() { Collection<BibtexEntry> col = panel.database().getEntries(); sel = col.toArray(new BibtexEntry[col.size()]); // Ask about rules for the operation: if (optDiag == null) optDiag = new OptionsDialog(panel.frame().getFrame(), fieldName); Util.placeDialog(optDiag, panel.frame()); optDiag.setVisible(true); if (optDiag.canceled()) { goOn = false; return; } autoSet = !optDiag.autoSetNone.isSelected(); overWriteAllowed = optDiag.autoSetAll.isSelected(); checkExisting = optDiag.checkLinks.isSelected(); panel.output(Globals.lang("Synchronizing %0 links...", fieldName.toUpperCase())); } public void run() { if (!goOn) { panel.output(Globals.lang("No entries selected.")); return; } panel.frame().setProgressBarValue(0); panel.frame().setProgressBarVisible(true); int weightAutoSet = 10; // autoSet takes 10 (?) times longer than checkExisting int progressBarMax = (autoSet ? weightAutoSet * sel.length : 0) + (checkExisting ? sel.length : 0); panel.frame().setProgressBarMaximum(progressBarMax); int progress = 0; entriesChanged = 0; brokenLinks = 0; NamedCompound ce = new NamedCompound(Globals.lang("Autoset %0 field", fieldName)); final OpenFileFilter off = Util.getFileFilterForField(fieldName); ExternalFilePanel extPan = new ExternalFilePanel(fieldName, panel.metaData(), null, null, off); FieldTextField editor = new FieldTextField(fieldName, "", false); // Find the default directory for this field type: String dir = panel.metaData().getFileDirectory(fieldName); // First we try to autoset fields if (autoSet) { for (int i = 0; i < sel.length; i++) { progress += weightAutoSet; panel.frame().setProgressBarValue(progress); final String old = sel[i].getField(fieldName); // Check if a extension is already set, and if so, if we are allowed to overwrite it: if ((old != null) && !old.equals("") && !overWriteAllowed) continue; extPan.setEntry(sel[i], panel.getDatabase()); editor.setText((old != null) ? (String) old : ""); Thread t = extPan.autoSetFile(fieldName, editor); // Wait for the autoset process to finish: if (t != null) try { t.join(); } catch (InterruptedException e) { e.printStackTrace(); } // If something was found, entriesChanged it: if (!editor.getText().equals("") && !editor.getText().equals(old)) { // Store an undo edit: //System.out.println("Setting: "+sel[i].getCiteKey()+" "+editor.getText()); ce.addEdit(new UndoableFieldChange(sel[i], fieldName, old, editor.getText())); sel[i].setField(fieldName, editor.getText()); entriesChanged++; } } } //System.out.println("Done setting"); // The following loop checks all external links that are already set. if (checkExisting) { mainLoop: for (int i = 0; i < sel.length; i++) { panel.frame().setProgressBarValue(progress++); final String old = sel[i].getField(fieldName); // Check if a extension is set: if ((old != null) && !old.equals("")) { // Get an absolute path representation: File file = Util.expandFilename(old, new String[]{dir, "."}); if ((file == null) || !file.exists()) { int answer = JOptionPane.showOptionDialog(panel.frame(), Globals.lang("<HTML>Could not find file '%0'<BR>linked from entry '%1'</HTML>", new String[]{old, sel[i].getCiteKey()}), Globals.lang("Broken link"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, brokenLinkOptions, brokenLinkOptions[0]); switch (answer) { case 1: // Assign new file. AttachFileDialog afd = new AttachFileDialog(panel.frame().getFrame(), panel.metaData(), sel[i], fieldName); Util.placeDialog(afd, panel.frame()); afd.setVisible(true); if (!afd.cancelled()) { ce.addEdit(new UndoableFieldChange(sel[i], fieldName, old, afd.getValue())); sel[i].setField(fieldName, afd.getValue()); entriesChanged++; } break; case 2: // Clear field ce.addEdit(new UndoableFieldChange(sel[i], fieldName, old, null)); sel[i].setField(fieldName, null); entriesChanged++; break; case 3: // Cancel break mainLoop; } brokenLinks++; } continue; } } } if (entriesChanged > 0) { // Add the undo edit: ce.end(); panel.undoManager.addEdit(ce); } } public void update() { if (!goOn) return; panel.output(Globals.lang("Finished synchronizing %0 links. Entries changed%c %1.", new String[]{fieldName.toUpperCase(), String.valueOf(entriesChanged)})); panel.frame().setProgressBarVisible(false); if (entriesChanged > 0) { panel.markBaseChanged(); } } class OptionsDialog extends JDialog { JRadioButton autoSetUnset, autoSetAll, autoSetNone; JCheckBox checkLinks; JButton ok = new JButton(Globals.lang("Ok")), cancel = new JButton(Globals.lang("Cancel")); JLabel description; private boolean canceled = true; private String fieldName; public OptionsDialog(JFrame parent, String fieldName) { super(parent, Globals.lang("Synchronize %0 links", fieldName.toUpperCase()), true); final String fn = fieldName.toUpperCase(); this.fieldName = fieldName; ok.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { canceled = false; dispose(); } }); Action closeAction = new AbstractAction() { public void actionPerformed(ActionEvent e) { dispose(); } }; cancel.addActionListener(closeAction); InputMap im = cancel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); ActionMap am = cancel.getActionMap(); im.put(Globals.prefs.getKey("Close dialog"), "close"); am.put("close", closeAction); fieldName = fieldName.toUpperCase(); autoSetUnset = new JRadioButton(Globals.lang("Autoset %0 links. Do not overwrite existing links.", fn), true); autoSetAll = new JRadioButton(Globals.lang("Autoset %0 links. Allow overwriting existing links.", fn), false); autoSetNone = new JRadioButton(Globals.lang("Do not autoset"), false); checkLinks = new JCheckBox(Globals.lang("Check existing %0 links", fn), true); ButtonGroup bg = new ButtonGroup(); bg.add(autoSetUnset); bg.add(autoSetNone); bg.add(autoSetAll); FormLayout layout = new FormLayout("fill:pref", ""); DefaultFormBuilder builder = new DefaultFormBuilder(layout); description = new JLabel("<HTML>" + Globals.lang(//"This function helps you keep your external %0 links up-to-date." + "Attempt to autoset %0 links for your entries. Autoset works if " + "a %0 file in your %0 directory or a subdirectory<BR>is named identically to an entry's BibTeX key, plus extension.", fn) + "</HTML>"); // name.setVerticalAlignment(JLabel.TOP); builder.appendSeparator(Globals.lang("Autoset")); builder.append(description); builder.nextLine(); builder.append(autoSetUnset); builder.nextLine(); builder.append(autoSetAll); builder.nextLine(); builder.append(autoSetNone); builder.nextLine(); builder.appendSeparator(Globals.lang("Check links")); description = new JLabel("<HTML>" + Globals.lang("This makes JabRef look up each %0 link and check if the file exists. If not, you will " + "be given options<BR>to resolve the problem.", fn) + "</HTML>"); builder.append(description); builder.nextLine(); builder.append(checkLinks); builder.nextLine(); builder.appendSeparator(); JPanel main = builder.getPanel(); main.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); ButtonBarBuilder bb = new ButtonBarBuilder(); bb.addGlue(); bb.addGridded(ok); bb.addGridded(cancel); bb.addGlue(); getContentPane().add(main, BorderLayout.CENTER); getContentPane().add(bb.getPanel(), BorderLayout.SOUTH); pack(); } public void setVisible(boolean visible) { if (visible) canceled = true; String dir = panel.metaData().getFileDirectory(fieldName); if ((dir == null) || (dir.trim().length() == 0)) { autoSetNone.setSelected(true); autoSetNone.setEnabled(false); autoSetAll.setEnabled(false); autoSetUnset.setEnabled(false); } else { autoSetNone.setEnabled(true); autoSetAll.setEnabled(true); autoSetUnset.setEnabled(true); } new FocusRequester(ok); super.setVisible(visible); } public boolean canceled() { return canceled; } } }