bbd94dc3e44aba938978b5d1c3ff250d065274f6
[debian/jabref.git] / src / java / net / sf / jabref / gui / FileListEntryEditor.java
1 package net.sf.jabref.gui;
2
3 import com.jgoodies.forms.builder.DefaultFormBuilder;
4 import com.jgoodies.forms.builder.ButtonBarBuilder;
5 import com.jgoodies.forms.layout.FormLayout;
6
7 import javax.swing.*;
8 import javax.swing.event.DocumentListener;
9 import javax.swing.event.DocumentEvent;
10
11 import net.sf.jabref.*;
12 import net.sf.jabref.external.ExternalFileType;
13 import net.sf.jabref.external.ConfirmCloseFileListEntryEditor;
14 import net.sf.jabref.external.ExternalFileMenuItem;
15
16 import java.awt.*;
17 import java.awt.event.*;
18 import java.io.File;
19 import java.io.FileFilter;
20 import java.io.IOException;
21 import java.util.ArrayList;
22
23 /**
24  * This class produces a dialog box for editing a single file link from a Bibtex entry.
25  *
26  * The information to be edited includes the file description, the link itself and the
27  * file type. The dialog also includes convenience buttons for quick linking.
28  *
29  * For use when downloading files, this class also offers a progress bar and a "Downloading..."
30  * label that can be hidden when the download is complete.
31  */
32 public class FileListEntryEditor {
33
34     JDialog diag;
35     JTextField link = new JTextField(), description = new JTextField();
36     JButton ok = new JButton(Globals.lang("Ok")),
37             cancel = new JButton(Globals.lang("Cancel")),
38             open = new JButton(Globals.lang("Open"));
39     JComboBox types;
40     JProgressBar prog = new JProgressBar(JProgressBar.HORIZONTAL);
41     JLabel downloadLabel = new JLabel(Globals.lang("Downloading..."));
42     ConfirmCloseFileListEntryEditor externalConfirm = null;
43
44     private AbstractAction okAction;
45     private JabRefFrame frame;
46     private FileListEntry entry;
47     private MetaData metaData;
48     private boolean okPressed = false;
49
50     public FileListEntryEditor(JabRefFrame frame, FileListEntry entry, boolean showProgressBar,
51                                MetaData metaData) {
52         this.frame = frame;
53         this.entry = entry;
54         this.metaData = metaData;
55
56         okAction = new AbstractAction() {
57                 public void actionPerformed(ActionEvent e) {
58                     // If OK button is disabled, ignore this event:
59                     if (!ok.isEnabled())
60                         return;
61                     // If necessary, ask the external confirm object whether we are ready to close.
62                     if (externalConfirm != null) {
63                         // Construct an updated FileListEntry:
64                         FileListEntry testEntry = new FileListEntry("", "", null);
65                         storeSettings(testEntry);
66                         if (!externalConfirm.confirmClose(testEntry))
67                             return;
68                     }
69                     diag.dispose();
70                     storeSettings(FileListEntryEditor.this.entry);
71                     okPressed = true;
72                 }
73             };
74         types = new JComboBox();
75         types.addItemListener(new ItemListener() {
76             public void itemStateChanged(ItemEvent itemEvent) {
77                 ok.setEnabled(types.getSelectedItem() != null);
78             }
79         });
80         
81         DefaultFormBuilder builder = new DefaultFormBuilder(new FormLayout
82                 ("left:pref, 4dlu, fill:150dlu, 4dlu, fill:pref", ""));
83         builder.append(Globals.lang("Link"));
84         builder.append(link);
85         BrowseListener browse = new BrowseListener(frame, link);
86         JButton browseBut = new JButton(Globals.lang("Browse"));
87         browseBut.addActionListener(browse);
88         builder.append(browseBut);
89         builder.nextLine();
90         builder.append(Globals.lang("Description"));
91         builder.append(description);
92         builder.getPanel().setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
93         builder.nextLine();
94         builder.append(Globals.lang("File type"));
95         builder.append(types);
96         if (showProgressBar) {
97             builder.nextLine();
98             builder.append(downloadLabel);
99             builder.append(prog);
100         }
101         
102         ButtonBarBuilder bb = new ButtonBarBuilder();
103         bb.addGlue();
104         bb.addGridded(open);
105         bb.addRelatedGap();
106         bb.addGridded(ok);
107         bb.addGridded(cancel);
108         bb.addGlue();
109
110
111         ok.addActionListener(okAction);
112         // Add OK action to the two text fields to simplify entering:
113         link.addActionListener(okAction);
114         description.addActionListener(okAction);
115
116         open.addActionListener(new ActionListener() {
117             public void actionPerformed(ActionEvent actionEvent) {
118                 openFile();
119             }
120         });
121
122         AbstractAction cancelAction = new AbstractAction() {
123                 public void actionPerformed(ActionEvent e) {
124                     diag.dispose();
125                 }
126             };
127         cancel.addActionListener(cancelAction);
128
129         // Key bindings:
130         ActionMap am = builder.getPanel().getActionMap();
131         InputMap im = builder.getPanel().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
132         im.put(Globals.prefs.getKey("Close dialog"), "close");
133         am.put("close", cancelAction);
134
135         link.getDocument().addDocumentListener(new DocumentListener() {
136             public void insertUpdate(DocumentEvent documentEvent) {
137                 checkExtension();
138             }
139             public void removeUpdate(DocumentEvent documentEvent) {
140             }
141             public void changedUpdate(DocumentEvent documentEvent) {
142                 checkExtension();
143             }
144
145         });
146
147
148         diag = new JDialog(frame, Globals.lang("Edit file link"), true);
149         diag.getContentPane().add(builder.getPanel(), BorderLayout.CENTER);
150         diag.getContentPane().add(bb.getPanel(), BorderLayout.SOUTH);
151         diag.pack();
152         Util.placeDialog(diag, frame);
153
154         setValues(entry);
155     }
156
157     private void checkExtension() {
158         if ((types.getSelectedIndex() == -1) &&
159                 (link.getText().trim().length() > 0)) {
160             // Try to guess the file type:
161             String theLink = link.getText().trim();
162             int index = theLink.lastIndexOf('.');
163             if ((index >= 0) && (index < theLink.length()-1)) {
164
165                 ExternalFileType type = Globals.prefs.getExternalFileTypeByExt
166                         (theLink.substring(index+1));
167                 if (type != null)
168                     types.setSelectedItem(type);
169             }
170         }
171     }
172
173     public void openFile() {
174         ExternalFileType type = (ExternalFileType)types.getSelectedItem();
175         if (type != null)
176             try {
177                 Util.openExternalFileAnyFormat(metaData, link.getText(), entry.getType());
178             } catch (IOException e) {
179                 e.printStackTrace();
180             }
181     }
182
183     public void setExternalConfirm(ConfirmCloseFileListEntryEditor eC) {
184         this.externalConfirm = eC;
185     }
186
187     public void setOkEnabled(boolean enabled) {
188         ok.setEnabled(enabled);
189     }
190
191     public JProgressBar getProgressBar() {
192         return prog;
193     }
194
195     public JLabel getProgressBarLabel() {
196         return downloadLabel;
197     }
198
199     public void setEntry(FileListEntry entry) {
200         this.entry = entry;
201         setValues(entry);
202     }
203
204     public void setVisible(boolean visible) {
205         if (visible)
206             okPressed = false;
207         diag.setVisible(visible);
208     }
209
210     public void setValues(FileListEntry entry) {
211         description.setText(entry.getDescription());
212         link.setText(entry.getLink());
213         if (link.getText().length() > 0)
214             checkExtension();
215         types.setModel(new DefaultComboBoxModel(Globals.prefs.getExternalFileTypeSelection()));
216         types.setSelectedIndex(-1);
217         // See what is a reasonable selection for the type combobox:
218         if (entry.getType() != null)
219             types.setSelectedItem(entry.getType());
220         // If the entry has a link but not a file type, try to deduce the file type:
221         else if ((entry.getLink() != null) && (entry.getLink().length() > 0)) {
222             checkExtension();    
223         }
224
225     }
226
227     public void storeSettings(FileListEntry entry) {
228         entry.setDescription(description.getText().trim());
229         // See if we should trim the file link to be relative to the file directory:
230         try {
231         String fileDir = metaData.getFileDirectory(GUIGlobals.FILE_FIELD);
232         if ((fileDir == null) ||(fileDir.equals(""))) {
233             entry.setLink(link.getText().trim());
234         } else {
235             String canPath = (new File(fileDir)).getCanonicalPath();
236             File fl = new File(link.getText().trim());
237             String flPath = fl.getCanonicalPath();
238             if ((flPath.length() > canPath.length()) && (flPath.startsWith(canPath))) {
239                 String relFileName = fl.getCanonicalPath().substring(canPath.length()+1);
240                 entry.setLink(relFileName);
241             } else
242                 entry.setLink(link.getText().trim());
243         }
244     } catch (java.io.IOException ex)
245         { 
246                 ex.printStackTrace();
247                 // Don't think this should happen, but set the file link directly as a fallback:
248                 entry.setLink(link.getText().trim());
249         }
250         
251         entry.setType((ExternalFileType)types.getSelectedItem());
252     }
253
254     public boolean okPressed() {
255         return okPressed;
256     }
257
258     class BrowseListener implements ActionListener {
259         private JFrame parent;
260         private JTextField comp;
261
262         public BrowseListener(JFrame parent, JTextField comp) {
263             this.parent = parent;
264             this.comp = comp;
265         }
266
267         public void actionPerformed(ActionEvent e) {
268             File initial = new File(comp.getText().trim());
269             if (comp.getText().trim().length() == 0) {
270                 // Nothing in the field. Go to the last file dir used:
271                 initial = new File(Globals.prefs.get("fileWorkingDirectory"));
272             }
273             String chosen = Globals.getNewFile(parent, initial, Globals.NONE,
274                 JFileChooser.OPEN_DIALOG, false);
275             if (chosen != null) {
276                 File newFile = new File(chosen);
277                 // Store the directory for next time:
278                 Globals.prefs.put("fileWorkingDirectory", newFile.getParent());
279
280                 // If the file is below the file directory, make the path relative:
281                 ArrayList<File> dirs = new ArrayList<File>();
282                 String fileDir = metaData.getFileDirectory(GUIGlobals.FILE_FIELD);
283                 if (fileDir != null)
284                     dirs.add(new File(fileDir));
285                 if (dirs.size() > 0) {
286                     newFile = FileListEditor.relativizePath(newFile, dirs);
287                 }
288
289                 comp.setText(newFile.getPath());
290                 comp.requestFocus();
291             }
292         }
293     }
294 }