98af0ec5b074711ace0f76d58f2cf3e9d8f1a69c
[debian/jabref.git] / src / java / net / sf / jabref / EntryCustomizationDialog.java
1 /*
2 Copyright (C) 2002-2003 Nizar N. Batada nbatada@stanford.edu
3 All programs in this directory and
4 subdirectories are published under the GNU General Public License as
5 described below.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or (at
10 your option) any later version.
11
12 This program is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 USA
21
22 Further information about the GNU GPL is available at:
23 http://www.gnu.org/copyleft/gpl.ja.html
24
25 */
26 package net.sf.jabref;
27
28 import java.util.*;
29 import java.io.*;
30 import javax.swing.*;
31 import java.awt.event.*;
32 import java.awt.*;
33
34 class EntryCustomizationDialog extends JDialog implements ItemListener
35 {
36     BibtexEntryType type;
37
38     JScrollPane reqSP, optSP;
39     JButton ok, cancel, helpButton, delete, importTypes, exportTypes;
40     JPanel panel=new JPanel(),
41         fieldPanel = new JPanel(),
42         typePanel = new JPanel();
43     int width=10;
44     JLabel messageLabel=new JLabel("", SwingConstants.CENTER);
45
46     JTextField name = new JTextField("", width);
47     JTextArea req_ta=new JTextArea("",5,width),//10 row, 20 columns
48         opt_ta=new JTextArea("",5,width);//10 row, 20 columns
49     // need to get FIeld name from somewhere
50
51     JComboBox types_cb = new JComboBox();
52
53     HelpAction help;
54
55     GridBagLayout gbl = new GridBagLayout();
56     GridBagConstraints con = new GridBagConstraints();
57     JPanel buttonPanel = new JPanel();
58
59     JabRefFrame parent;
60     EntryCustomizationDialog ths = this;
61
62     public EntryCustomizationDialog(JabRefFrame parent)
63     {
64         //Type=Article, Book etc
65         // templateName will be used to put on the dialog frame
66         // create 10 default entries
67         // return an array
68         super(parent,Globals.lang("Customize entry types"), false);
69         this.parent = parent;
70         help = new HelpAction(parent.helpDiag, GUIGlobals.customEntriesHelp,
71                               "Help", GUIGlobals.helpSmallIconFile);
72         setTypeSelection();
73         //setSize(440,400);
74         initialize();
75         makeButtons();
76
77         reqSP = new JScrollPane(req_ta,
78                                 JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
79                                 JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
80         optSP = new JScrollPane(opt_ta,
81                                 JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
82                                 JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
83         //helpButton = new JButton(help);
84         //helpButton.setText(null);
85         JToolBar tlb = new JToolBar();
86         tlb.setFloatable(false);
87         tlb.add(help);
88         //panel.setBackground(GUIGlobals.lightGray);
89         //buttonPanel.setBackground(GUIGlobals.lightGray);
90         panel.setLayout(gbl);
91         typePanel.setLayout(gbl);
92         fieldPanel.setLayout(gbl);
93         //panel.setBorder(BorderFactory.createEtchedBorder());
94         fieldPanel.setBorder(BorderFactory.createEtchedBorder());
95         typePanel.setBorder(BorderFactory.createEtchedBorder());
96
97         JLabel lab = new JLabel(Globals.lang("Type")+": "),
98             lab2 = new JLabel(Globals.lang("Name")+": ");
99         con.insets = new Insets(5, 5, 5, 5);
100         gbl.setConstraints(lab, con);
101         gbl.setConstraints(lab2, con);
102         gbl.setConstraints(types_cb, con);
103
104         con.weightx = 1;
105         con.fill = GridBagConstraints.HORIZONTAL;
106         gbl.setConstraints(name, con);
107         con.fill = GridBagConstraints.NONE;
108         con.gridwidth = GridBagConstraints.REMAINDER;
109         con.weightx = 0;
110         //gbl.setConstraints(helpButton, con);
111         gbl.setConstraints(tlb, con);
112         con.gridwidth = 1;
113         typePanel.add(lab);
114         typePanel.add(types_cb);
115         typePanel.add(lab2);
116         typePanel.add(name);
117         //typePanel.add(helpButton);
118         typePanel.add(tlb);
119         lab = new JLabel(Globals.lang("Required fields"));
120         con.fill = GridBagConstraints.BOTH;
121         con.weightx = 1;
122         gbl.setConstraints(lab, con);
123         con.weighty = 1;
124         gbl.setConstraints(reqSP, con);
125         fieldPanel.add(lab);
126         con.gridwidth = GridBagConstraints.REMAINDER;
127         lab = new JLabel(Globals.lang("Optional fields"));
128         con.weighty = 0;
129         gbl.setConstraints(lab, con);
130         fieldPanel.add(lab);
131         con.weighty = 1;
132         gbl.setConstraints(optSP, con);
133
134         fieldPanel.add(reqSP);
135         fieldPanel.add(optSP);
136
137         con.gridwidth = GridBagConstraints.REMAINDER;
138         con.weighty = 0;
139         gbl.setConstraints(typePanel, con);
140         con.weighty = 1;
141         gbl.setConstraints(fieldPanel, con);
142         con.weighty = 0;
143         gbl.setConstraints(messageLabel, con);
144         panel.add(typePanel);
145         panel.add(fieldPanel);
146         panel.add(messageLabel);
147
148         // Key bindings:
149         ActionMap am = panel.getActionMap();
150         InputMap im = panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
151         im.put(Globals.prefs.getKey("Close dialog"), "close");
152         am.put("close", new AbstractAction() {
153           public void actionPerformed(ActionEvent e) {
154             dispose();
155           }
156         });
157         pack();
158         name.requestFocus();
159     }
160
161     public EntryCustomizationDialog(JabRefFrame parent,
162                                     BibtexEntryType type_) {
163         this(parent);
164         type = type_;
165
166     }
167
168     void initialize(){
169
170         getContentPane().setLayout(new BorderLayout());
171         getContentPane().add( buttonPanel, BorderLayout.SOUTH);
172         getContentPane().add( panel, BorderLayout.CENTER);
173
174         messageLabel.setForeground(Color.black);
175         messageLabel.setText(Globals.lang("Delimit fields with semicolon, ex.")
176                              +": author;title;journal");
177
178         types_cb.addItemListener(this);
179     }
180
181     void save()
182     {
183       String typeName = name.getText().trim();
184       if (typeName.indexOf(" ") >= 0) {
185         JOptionPane.showMessageDialog(ths, Globals.lang("The type name can not contain spaces."),
186                                       Globals.lang("Illegal type name"), JOptionPane.ERROR_MESSAGE);
187         return;
188       }
189
190
191         String
192             reqStr = req_ta.getText().replaceAll("\\s+","")
193             .replaceAll("\\n+","").trim(),
194             optStr = opt_ta.getText().replaceAll("\\s+","")
195             .replaceAll("\\n+","").trim();
196
197
198         if(! typeName.equals("")) {
199             CustomEntryType typ = new CustomEntryType
200                 (Util.nCase(typeName), reqStr, optStr);
201             BibtexEntryType.ALL_TYPES.put(typeName.toLowerCase(), typ);
202             updateTypesForEntries(typ.getName());
203             setTypeSelection();
204             messageLabel.setText(Globals.lang("Stored definition for type")+
205                                  " '"+Util.nCase(typ.getName())
206                                  +"'.");
207         }
208         else{
209             messageLabel.setText(Globals.lang("You must fill in a name for the entry type."));
210         }
211
212     }
213
214     private void setTypeSelection() {
215         types_cb.removeAllItems();
216         types_cb.addItem("<new>");
217         Iterator i = BibtexEntryType.ALL_TYPES.keySet().iterator();
218         BibtexEntryType type;
219         String toSet;
220         while (i.hasNext()) {
221             type = BibtexEntryType.getType((String)i.next());
222             toSet = Util.nCase(type.getName());
223             if (type instanceof CustomEntryType)
224                 toSet = toSet + " *";
225             types_cb.addItem(toSet);
226
227         }
228     }
229
230     void makeButtons(){
231         ok = new JButton(Globals.lang("Store"));
232         cancel=new JButton(Globals.lang("Close"));
233         delete = new JButton(Globals.lang("Delete custom"));
234         //genFields = new JButton(Globals.lang("Set general fields"));
235         importTypes = new JButton(Globals.lang("Import"));
236         exportTypes = new JButton(Globals.lang("Export"));
237         buttonPanel.add( ok );
238         buttonPanel.add(delete);
239         buttonPanel.add(Box.createHorizontalStrut(5));
240         //buttonPanel.add(genFields);
241         buttonPanel.add(importTypes);
242         buttonPanel.add(exportTypes);
243         buttonPanel.add(Box.createHorizontalStrut(5));
244         buttonPanel.add( cancel);
245         ok.addActionListener(new ActionListener() {
246                 public void actionPerformed(ActionEvent e) {
247                     save();
248                 }
249             });
250         cancel.addActionListener(new ActionListener() {
251                 public void actionPerformed(ActionEvent e) {
252                     dispose();
253                 }
254             });
255         /*genFields.addActionListener(new ActionListener() {
256           public void actionPerformed(ActionEvent e) {
257             GenFieldsCustomizer gf = new GenFieldsCustomizer(parent, ths);
258             Util.placeDialog(gf, parent);
259             gf.show();
260           }
261         });*/
262         delete.addActionListener(new ActionListener() {
263                 public void actionPerformed(ActionEvent e) {
264                     BibtexEntryType type = BibtexEntryType
265                         .getType(name.getText());
266                     if (type == null)
267                         messageLabel.setText(Globals.lang("There is no entry type")+
268                                              " '"+Util.nCase(name.getText())+
269                                              "' "+Globals.lang("defined."));
270                     else if (!(type instanceof CustomEntryType))
271                         messageLabel.setText("'"+type.getName()+"' "+
272                                              Globals.lang("is a standard type."));
273                     else {
274                         String nm = name.getText();
275                         if (BibtexEntryType.getStandardType(nm) == null) {
276                             int reply = JOptionPane.showConfirmDialog
277                                 (parent, Globals.lang("All entries of this "
278                                                       +"type will be declared "
279                                                       +"typeless. Continue?"),
280                                  Globals.lang("Delete custom format")+
281                                  " '"+Util.nCase(nm)+"'", JOptionPane.YES_NO_OPTION,
282                                  JOptionPane.WARNING_MESSAGE);
283                             if (reply != JOptionPane.YES_OPTION)
284                                 return;
285                         }
286                         BibtexEntryType.removeType(nm);
287                         setTypeSelection();
288                         updateTypesForEntries(Util.nCase(nm));
289                         messageLabel.setText
290                             (Globals.lang("Removed entry type."));
291                     }
292                 }
293             });
294
295         exportTypes.addActionListener(new ActionListener() {
296                 public void actionPerformed(ActionEvent e) {
297                     String filename = Globals.getNewFile
298                         (parent, Globals.prefs, new File(System.getProperty("user.home")), 
299                          ".txt", JFileChooser.SAVE_DIALOG, false);
300                     if (filename == null) 
301                         return;
302                     File file = new File(filename);
303                     if (!file.exists() ||  
304                         (JOptionPane.showConfirmDialog
305                          (ths, "'"+file.getName()+"' "+Globals.lang("exists. Overwrite file?"),
306                           Globals.lang("Export entry types"), JOptionPane.OK_CANCEL_OPTION)
307                          == JOptionPane.OK_OPTION)) {
308
309                         try {
310                             FileWriter out = new FileWriter(file);
311                             Iterator i=BibtexEntryType.ALL_TYPES.keySet().iterator();
312                             while (i.hasNext()) {
313                                 Object o=BibtexEntryType.ALL_TYPES.get(i.next());
314                                 if (o instanceof CustomEntryType) {
315                                     // Store this entry type.
316                                     ((CustomEntryType)o).save(out);
317                                 }
318                             }
319                             out.close();
320                         } catch (IOException ex) {
321                             JOptionPane.showMessageDialog
322                                 (ths, Globals.lang("Could not export entry types")+": "+ex.getMessage(), Globals.lang("Export preferences"), JOptionPane.ERROR_MESSAGE);
323                             //ex.printStackTrace();
324                         }
325                     }
326
327                 }
328             });
329
330         importTypes.addActionListener(new ActionListener() {
331                 public void actionPerformed(ActionEvent e) {
332                     String filename = Globals.getNewFile
333                         (parent, Globals.prefs, new File(System.getProperty("user.home")), 
334                          ".txt", JFileChooser.OPEN_DIALOG, false);
335                     if (filename == null) 
336                         return;
337
338                     try {
339                         BufferedReader in = new BufferedReader(new FileReader(new File(filename)));
340                         String line;
341                         int count = 0;
342                         while ((line = in.readLine()) != null) {
343                             line = line.trim();
344                             if ((line.length() > 9+GUIGlobals.ENTRYTYPE_FLAG.length())
345                                 && line.substring(0, 9+GUIGlobals.ENTRYTYPE_FLAG.length()).equals("@comment{"+GUIGlobals.ENTRYTYPE_FLAG)
346                                 && line.substring(line.length()-1).equals("}")) {
347                                 // Matches a @comment{jabref-entrytype: ...} section.
348                                 CustomEntryType type = CustomEntryType.parseEntryType(line.substring(9, line.length()-1));
349                                 if (type != null) {
350                                     // Parsing succeeded.
351                                     BibtexEntryType.ALL_TYPES.put(type.getName().toLowerCase(), type);
352                                     count++;
353                                 }
354                             }
355
356                             if (count > 0) {
357                                 setTypeSelection();
358                                 req_ta.setText("");
359                                 opt_ta.setText("");
360                                 name.setText("");
361                                 messageLabel.setText(Globals.lang("Imported entry types")+": "+count);
362                             }
363                         }
364                     } catch (IOException ex) {
365                         JOptionPane.showMessageDialog
366                             (ths, Globals.lang("Could not import entry types")+": "+ex.getMessage(), Globals.lang("Import entry types"), JOptionPane.ERROR_MESSAGE);
367                         //ex.printStackTrace();
368                     }
369                 }
370
371                 
372             });
373     }
374
375     /**
376      * Cycle through all databases, and make sure everything is updated with
377      * the new type customization. This includes making sure all entries have
378      * a valid type, that no obsolete entry editors are around, and that
379      * the right-click menus' change type menu is up-to-date.
380      */
381     private void updateTypesForEntries(String typeName) {
382         if (parent.tabbedPane.getTabCount() == 0)
383             return;
384         messageLabel.setText(Globals.lang("Updating entries..."));
385         BibtexDatabase base;
386         Iterator iter;
387         for (int i=0; i<parent.tabbedPane.getTabCount(); i++) {
388             BasePanel bp = (BasePanel)parent.tabbedPane.getComponentAt(i);
389             boolean anyChanges = false;
390             bp.entryEditors.remove(typeName);
391             //bp.rcm.populateTypeMenu(); // Update type menu for change type.
392             base = bp.database;
393             iter = base.getKeySet().iterator();
394             while (iter.hasNext()) {
395                 anyChanges = anyChanges |
396                     !(base.getEntryById((String)iter.next())).updateType();
397             }
398             if (anyChanges) {
399                 bp.markBaseChanged();
400             }
401         }
402     }
403
404     public void itemStateChanged(ItemEvent e) {
405         if (types_cb.getSelectedIndex() > 0) {
406             // User has selected one of the existing types.
407             String name = (String)types_cb.getSelectedItem();
408             updateToType((name.split(" "))[0]);
409         } else {
410             name.setText("");
411             req_ta.setText("");
412             opt_ta.setText("");
413             name.requestFocus();
414         }
415     }
416
417     public void updateToType(String o) {
418
419         BibtexEntryType type = BibtexEntryType.getType(o);
420         name.setText(type.getName());
421         req_ta.setText(Util.stringArrayToDelimited
422                        (type.getRequiredFields(), ";\n"));
423         opt_ta.setText(Util.stringArrayToDelimited
424                        (type.getOptionalFields(), ";\n"));
425
426         req_ta.requestFocus();
427     }
428 }