328c3eb62d4f62095df724dbb092c1ffbfa6edaf
[debian/jabref.git] / src / java / net / sf / jabref / external / AutoSetExternalFileForEntries.java
1 package net.sf.jabref.external;
2
3 import net.sf.jabref.*;
4 import net.sf.jabref.gui.AttachFileDialog;
5 import net.sf.jabref.undo.NamedCompound;
6 import net.sf.jabref.undo.UndoableFieldChange;
7
8 import javax.swing.*;
9 import java.io.File;
10 import java.awt.*;
11 import java.awt.event.ActionListener;
12 import java.awt.event.ActionEvent;
13 import java.util.Collection;
14
15 import com.jgoodies.forms.layout.FormLayout;
16 import com.jgoodies.forms.builder.DefaultFormBuilder;
17 import com.jgoodies.forms.builder.ButtonBarBuilder;
18
19 /**
20  * This action goes through all selected entries in the BasePanel, and attempts to autoset the
21  * given external file (pdf, ps, ...) based on the same algorithm used for the "Auto" button in
22  * EntryEditor.
23  */
24 public class AutoSetExternalFileForEntries extends AbstractWorker {
25
26     private String fieldName;
27     private BasePanel panel;
28     private BibtexEntry[] sel = null;
29     private OptionsDialog optDiag = null;
30
31     Object[] brokenLinkOptions =
32             {Globals.lang("Ignore"), Globals.lang("Assign new file"), Globals.lang("Clear field"),
33                     Globals.lang("Quit synchronization")};
34
35     private boolean goOn = true, autoSet = true, overWriteAllowed = true, checkExisting = true;
36
37     private int skipped = 0, entriesChanged = 0, brokenLinks = 0;
38
39
40     public AutoSetExternalFileForEntries(BasePanel panel, String fieldName) {
41         this.fieldName = fieldName;
42         this.panel = panel;
43     }
44
45     public void init() {
46         /*// Get all entries, and make sure there are selected entries:
47         sel = panel.getSelectedEntries();
48         if (sel.length < 1) {
49             // No entries selected. Assume all entries should be treated:
50             */
51         Collection col = panel.database().getEntries();
52         sel = new BibtexEntry[col.size()];
53         sel = (BibtexEntry[]) col.toArray(sel);
54         //goOn = false;
55         //return;
56         //}
57
58         // Ask about rules for the operation:
59         if (optDiag == null)
60             optDiag = new OptionsDialog(panel.frame(), fieldName);
61         Util.placeDialog(optDiag, panel.frame());
62         optDiag.setVisible(true);
63         if (optDiag.canceled()) {
64             goOn = false;
65             return;
66         }
67         autoSet = !optDiag.autoSetNone.isSelected();
68         overWriteAllowed = optDiag.autoSetAll.isSelected();
69         checkExisting = optDiag.checkLinks.isSelected();
70
71         panel.output(Globals.lang("Synchronizing %0 links...", fieldName.toUpperCase()));
72     }
73
74     public void run() {
75         if (!goOn) {
76             panel.output(Globals.lang("No entries selected."));
77             return;
78         }
79         panel.frame().setProgressBarValue(0);
80         panel.frame().setProgressBarVisible(true);
81         int weightAutoSet = 10; // autoSet takes 10 (?) times longer than checkExisting
82         int progressBarMax = (autoSet ? weightAutoSet * sel.length : 0)
83                 + (checkExisting ? sel.length : 0);
84         panel.frame().setProgressBarMaximum(progressBarMax);
85         int progress = 0;
86         skipped = 0;
87         entriesChanged = 0;
88         brokenLinks = 0;
89         NamedCompound ce = new NamedCompound(Globals.lang("Autoset %0 field", fieldName));
90
91         final OpenFileFilter off = Util.getFileFilterForField(fieldName);
92
93         ExternalFilePanel extPan = new ExternalFilePanel(fieldName, panel.metaData(), null, null, off);
94         FieldTextField editor = new FieldTextField(fieldName, "", false);
95
96         // Find the default directory for this field type:
97         String dir = panel.metaData().getFileDirectory(fieldName);
98
99         // First we try to autoset fields
100         if (autoSet) {
101             for (int i = 0; i < sel.length; i++) {
102                 progress += weightAutoSet;
103                 panel.frame().setProgressBarValue(progress);
104
105                 final Object old = sel[i].getField(fieldName);
106                 // Check if a extension is already set, and if so, if we are allowed to overwrite it:
107                 if ((old != null) && !old.equals("") && !overWriteAllowed)
108                     continue;
109                 extPan.setEntry(sel[i], panel.getDatabase());
110                 editor.setText((old != null) ? (String) old : "");
111                 Thread t = extPan.autoSetFile(fieldName, editor);
112                 // Wait for the autoset process to finish:
113                 if (t != null)
114                     try {
115                         t.join();
116                     } catch (InterruptedException e) {
117                         e.printStackTrace();
118                     }
119                 // If something was found, entriesChanged it:
120                 if (!editor.getText().equals("") && !editor.getText().equals(old)) {
121                     // Store an undo edit:
122                     //System.out.println("Setting: "+sel[i].getCiteKey()+" "+editor.getText());
123                     ce.addEdit(new UndoableFieldChange(sel[i], fieldName, old, editor.getText()));
124                     sel[i].setField(fieldName, editor.getText());
125                     entriesChanged++;
126                 }
127             }
128         }
129         //System.out.println("Done setting");
130         // The following loop checks all external links that are already set.
131         if (checkExisting) {
132             mainLoop:
133             for (int i = 0; i < sel.length; i++) {
134                 panel.frame().setProgressBarValue(progress++);
135                 final Object old = sel[i].getField(fieldName);
136                 // Check if a extension is set:
137                 if ((old != null) && !((String) old).equals("")) {
138                     // Get an absolute path representation:
139                     File file = Util.expandFilename((String) old, new String[]{dir, "."});
140
141                     if ((file == null) || !file.exists()) {
142
143                         int answer =
144                                 JOptionPane.showOptionDialog(panel.frame(),
145                                         Globals.lang("<HTML>Could not find file '%0'<BR>linked from entry '%1'</HTML>",
146                                                 new String[]{(String) old, sel[i].getCiteKey()}),
147                                         Globals.lang("Broken link"),
148                                         JOptionPane.YES_NO_CANCEL_OPTION,
149                                         JOptionPane.QUESTION_MESSAGE, null, brokenLinkOptions, brokenLinkOptions[0]);
150                         switch (answer) {
151                             case 1:
152                                 // Assign new file.
153                                 AttachFileDialog afd = new AttachFileDialog(panel.frame(),
154                                         panel.metaData(), sel[i], fieldName);
155                                 Util.placeDialog(afd, panel.frame());
156                                 afd.setVisible(true);
157                                 if (!afd.cancelled()) {
158                                     ce.addEdit(new UndoableFieldChange(sel[i], fieldName, old, afd.getValue()));
159                                     sel[i].setField(fieldName, afd.getValue());
160                                     entriesChanged++;
161                                 }
162                                 break;
163                             case 2:
164                                 // Clear field
165                                 ce.addEdit(new UndoableFieldChange(sel[i], fieldName, old, null));
166                                 sel[i].setField(fieldName, null);
167                                 entriesChanged++;
168                                 break;
169                             case 3:
170                                 // Cancel
171                                 break mainLoop;
172                         }
173                         brokenLinks++;
174                     }
175
176                     continue;
177                 }
178             }
179         }
180
181         if (entriesChanged > 0) {
182             // Add the undo edit:
183             ce.end();
184             panel.undoManager.addEdit(ce);
185         }
186     }
187
188
189     public void update() {
190         if (!goOn)
191             return;
192
193         panel.output(Globals.lang("Finished synchronizing %0 links. Entries changed%c %1.",
194                 new String[]{fieldName.toUpperCase(), String.valueOf(entriesChanged)}));
195         panel.frame().setProgressBarVisible(false);
196         if (entriesChanged > 0) {
197             panel.markBaseChanged();
198         }
199     }
200
201     static class OptionsDialog extends JDialog {
202         JRadioButton autoSetUnset, autoSetAll, autoSetNone;
203         JCheckBox checkLinks;
204         JButton ok = new JButton(Globals.lang("Ok")),
205                 cancel = new JButton(Globals.lang("Cancel"));
206         JLabel description;
207         private boolean canceled = true;
208         private String fieldName;
209
210         public OptionsDialog(JFrame parent, String fieldName) {
211             super(parent, Globals.lang("Synchronize %0 links", fieldName.toUpperCase()), true);
212             final String fn = fieldName.toUpperCase();
213             this.fieldName = fieldName;
214             ok.addActionListener(new ActionListener() {
215                 public void actionPerformed(ActionEvent e) {
216                     canceled = false;
217                     dispose();
218                 }
219             });
220
221             Action closeAction = new AbstractAction() {
222                 public void actionPerformed(ActionEvent e) {
223                     dispose();
224                 }
225             };
226
227
228             cancel.addActionListener(closeAction);
229
230             InputMap im = cancel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
231             ActionMap am = cancel.getActionMap();
232             im.put(Globals.prefs.getKey("Close dialog"), "close");
233             am.put("close", closeAction);
234
235             fieldName = fieldName.toUpperCase();
236             autoSetUnset = new JRadioButton(Globals.lang("Autoset %0 links. Do not overwrite existing links.", fn), true);
237             autoSetAll = new JRadioButton(Globals.lang("Autoset %0 links. Allow overwriting existing links.", fn), false);
238             autoSetNone = new JRadioButton(Globals.lang("Do not autoset"), false);
239             checkLinks = new JCheckBox(Globals.lang("Check existing %0 links", fn), true);
240             ButtonGroup bg = new ButtonGroup();
241             bg.add(autoSetUnset);
242             bg.add(autoSetNone);
243             bg.add(autoSetAll);
244             FormLayout layout = new FormLayout("fill:pref", "");
245             DefaultFormBuilder builder = new DefaultFormBuilder(layout);
246             description = new JLabel("<HTML>" +
247                     Globals.lang(//"This function helps you keep your external %0 links up-to-date." +
248                             "Attempt to autoset %0 links for your entries. Autoset works if "
249                                     + "a %0 file in your %0 directory or a subdirectory<BR>is named identically to an entry's BibTeX key, plus extension.", fn)
250                     + "</HTML>");
251             //            name.setVerticalAlignment(JLabel.TOP);
252             builder.appendSeparator(Globals.lang("Autoset"));
253             builder.append(description);
254             builder.nextLine();
255             builder.append(autoSetUnset);
256             builder.nextLine();
257             builder.append(autoSetAll);
258             builder.nextLine();
259             builder.append(autoSetNone);
260             builder.nextLine();
261             builder.appendSeparator(Globals.lang("Check links"));
262
263             description = new JLabel("<HTML>" +
264                     Globals.lang("This makes JabRef look up each %0 extension and check if the file exists. If not, you will "
265                             + "be given options<BR>to resolve the problem.", fn)
266                     + "</HTML>");
267             builder.append(description);
268             builder.nextLine();
269             builder.append(checkLinks);
270             builder.nextLine();
271             builder.appendSeparator();
272
273
274             JPanel main = builder.getPanel();
275             main.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
276
277             ButtonBarBuilder bb = new ButtonBarBuilder();
278             bb.addGlue();
279             bb.addGridded(ok);
280             bb.addGridded(cancel);
281             bb.addGlue();
282             getContentPane().add(main, BorderLayout.CENTER);
283             getContentPane().add(bb.getPanel(), BorderLayout.SOUTH);
284
285             pack();
286         }
287
288         public void setVisible(boolean visible) {
289             if (visible)
290                 canceled = true;
291
292             String dir = Globals.prefs.get(fieldName + "Directory");
293             if ((dir == null) || (dir.trim().length() == 0)) {
294
295                 autoSetNone.setSelected(true);
296                 autoSetNone.setEnabled(false);
297                 autoSetAll.setEnabled(false);
298                 autoSetUnset.setEnabled(false);
299             } else {
300                 autoSetNone.setEnabled(true);
301                 autoSetAll.setEnabled(true);
302                 autoSetUnset.setEnabled(true);
303             }
304
305             new FocusRequester(ok);
306             super.setVisible(visible);
307
308         }
309
310         public boolean canceled() {
311             return canceled;
312         }
313     }
314 }