454813a858393e825fb357dd27135d067fad91cb
[debian/jabref.git] / src / java / net / sf / jabref / gui / EntryCustomizationDialog2.java
1 /*
2  * EntryCustomizationDialog2.java
3  *
4  * Created on February 10, 2005, 9:57 PM
5  */
6
7 package net.sf.jabref.gui;
8
9 import net.sf.jabref.*;
10 import javax.swing.*;
11 import javax.swing.event.ListSelectionEvent;
12 import javax.swing.event.ListSelectionListener;
13 import java.awt.*;
14 import java.awt.event.ActionEvent;
15 import java.awt.event.ActionListener;
16 import java.util.HashMap;
17 import java.util.Map;
18 import java.util.ArrayList;
19 import java.util.HashSet;
20 import java.util.List;
21 import java.util.Iterator;
22 import java.util.Set;
23 import javax.swing.event.ListDataListener;
24
25 /**
26  * NOTAT:
27  *    * S?rg for at ting oppdateres riktig ved tillegg av ny type. (velge, unng? at det blir feil innhold i listene).
28  *    *
29  *
30  *
31  * @author alver
32  */
33 public class EntryCustomizationDialog2 extends JDialog implements ListSelectionListener, ActionListener {
34
35     protected JabRefFrame frame;
36     protected GridBagLayout gbl = new GridBagLayout();
37     protected GridBagConstraints con = new GridBagConstraints();
38     protected FieldSetComponent reqComp, optComp;
39     protected EntryTypeList typeComp;
40     protected JButton ok, cancel, apply, helpButton, delete, importTypes, exportTypes;
41     protected final List preset = java.util.Arrays.asList(BibtexFields.getAllFieldNames());
42     protected String lastSelected = null;
43     protected Map reqLists = new HashMap(),
44             optLists = new HashMap();
45     protected Set defaulted = new HashSet(), changed = new HashSet();
46
47     /** Creates a new instance of EntryCustomizationDialog2 */
48     public EntryCustomizationDialog2(JabRefFrame frame) {
49         super(frame, Globals.lang("Customize entry types"), false);
50
51         this.frame = frame;
52         initGui();
53     }
54
55     protected final void initGui() {
56         Container pane = getContentPane();
57         pane.setLayout(new BorderLayout());
58
59         JPanel main = new JPanel(), buttons = new JPanel(),
60                 right = new JPanel();
61         main.setLayout(new BorderLayout());
62         right.setLayout(new GridLayout(1, 2));
63
64         java.util.List entryTypes = new ArrayList();
65         for (Iterator i=BibtexEntryType.ALL_TYPES.keySet().iterator(); i.hasNext();) {
66             entryTypes.add(i.next());
67         }
68
69         typeComp = new EntryTypeList(entryTypes);
70         typeComp.addListSelectionListener(this);
71         typeComp.addAdditionActionListener(this);
72         typeComp.addDefaultActionListener(new DefaultListener());
73         typeComp.setListSelectionMode(ListSelectionModel.SINGLE_SELECTION);
74
75         //typeComp.setEnabled(false);
76         reqComp = new FieldSetComponent(Globals.lang("Required fields"), new ArrayList(), preset, true, true);
77         reqComp.setEnabled(false);
78         reqComp.setBorder(BorderFactory.createEmptyBorder(2,2,2,2));
79         ListDataListener dataListener = new DataListener();
80         reqComp.addListDataListener(dataListener);
81         optComp = new FieldSetComponent(Globals.lang("Optional fields"), new ArrayList(), preset, true, true);
82         optComp.setEnabled(false);
83         optComp.setBorder(BorderFactory.createEmptyBorder(2,2,2,2));
84         optComp.addListDataListener(dataListener);
85         right.add(reqComp);
86         right.add(optComp);
87         //right.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), Globals.lang("Fields")));
88         right.setBorder(BorderFactory.createEtchedBorder());
89         ok = new JButton("OK");
90         cancel = new JButton("Cancel");
91         apply = new JButton("Apply");
92         ok.addActionListener(this);
93         apply.addActionListener(this);
94         cancel.addActionListener(this);
95         buttons.add(ok);
96         buttons.add(apply);
97         buttons.add(cancel);
98
99
100         //con.fill = GridBagConstraints.BOTH;
101         //con.weightx = 0.3;
102         //con.weighty = 1;
103         //gbl.setConstraints(typeComp, con);
104         main.add(typeComp, BorderLayout.WEST);
105         main.add(right, BorderLayout.CENTER);
106         main.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
107         pane.add(main, BorderLayout.CENTER);
108         pane.add(buttons, BorderLayout.SOUTH);
109         pack();
110     }
111
112     public void valueChanged(ListSelectionEvent e) {
113         if (e.getValueIsAdjusting()) {
114             return;
115         }
116
117
118         if (lastSelected != null) {
119             // The entry type lastSelected is now unselected, so we store the current settings
120             // for that type in our two maps.
121             reqLists.put(lastSelected, reqComp.getFields());
122             optLists.put(lastSelected, optComp.getFields());
123         }
124
125         String s = typeComp.getFirstSelected();
126         if (s == null)
127             return;
128         Object rl = reqLists.get(s);
129         if (rl == null) {
130             BibtexEntryType type = BibtexEntryType.getType(s);
131             if (type != null) {
132                 String[] rf = type.getRequiredFields(),
133                         of = type.getOptionalFields();
134                 List req, opt;
135                 if (rf != null)
136                     req = java.util.Arrays.asList(rf);
137                 else
138                     req = new ArrayList();
139                 if (of != null)
140                     opt = java.util.Arrays.asList(of);
141                 else
142                     opt = new ArrayList();
143
144                 reqComp.setFields(req);
145                 reqComp.setEnabled(true);
146                 optComp.setFields(opt);
147                 optComp.setEnabled(true);
148             } else {
149                 // New entry, veintle
150                 reqComp.setFields(new ArrayList());
151                 reqComp.setEnabled(true);
152                 optComp.setFields(new ArrayList());
153                 optComp.setEnabled(true);
154                 new FocusRequester(reqComp);
155             }
156         } else {
157             reqComp.setFields((List)rl);
158             optComp.setFields((List)optLists.get(s));
159         }
160
161         lastSelected = s;
162         typeComp.enable(s, changed.contains(lastSelected) && !defaulted.contains(lastSelected));
163     }
164
165     protected void applyChanges() {
166         valueChanged(new ListSelectionEvent(new JList(), 0, 0, false));
167         // Iterate over our map of required fields, and list those types if necessary:
168
169         List types = typeComp.getFields();
170         boolean globalChangesMade = false;
171         for (Iterator i=reqLists.keySet().iterator(); i.hasNext();) {
172             String typeName = (String)i.next();
173             if (!types.contains(typeName))
174                 continue;
175
176             List reqFields = (List)reqLists.get(typeName);
177             List optFields = (List)optLists.get(typeName);
178             String[] reqStr = new String[reqFields.size()];
179             reqFields.toArray(reqStr);
180             String[] optStr = new String[optFields.size()];
181             optFields.toArray(optStr);
182
183             // If this type is already existing, check if any changes have
184             // been made
185             boolean changesMade = true;
186
187             if (defaulted.contains(typeName)) {
188                 // This type should be reverted to its default setup.
189                 //System.out.println("Defaulting: "+typeName);
190                 String nm = Util.nCase(typeName);
191                 BibtexEntryType.removeType(nm);
192
193                 updateTypesForEntries(nm);
194                 globalChangesMade = true;
195                 continue;
196             }
197
198             BibtexEntryType oldType = BibtexEntryType.getType(typeName);
199             if (oldType != null) {
200                 String[] oldReq = oldType.getRequiredFields(),
201                         oldOpt = oldType.getOptionalFields();
202                 if (equalArrays(oldReq, reqStr) && equalArrays(oldOpt, optStr))
203                     changesMade = false;
204             }
205
206             if (changesMade) {
207                 //System.out.println("Updating: "+typeName);
208                 CustomEntryType typ = new CustomEntryType(Util.nCase(typeName), reqStr, optStr);
209                 BibtexEntryType.ALL_TYPES.put(typeName.toLowerCase(), typ);
210                 updateTypesForEntries(typ.getName());
211                 globalChangesMade = true;
212             }
213         }
214
215
216         Set toRemove = new HashSet();
217         for (Iterator i=BibtexEntryType.ALL_TYPES.keySet().iterator(); i.hasNext();) {
218             Object o = i.next();
219             if (!types.contains(o)) {
220                 //System.out.println("Deleted entry type (TODO): "+o);
221                 toRemove.add(o);
222             }
223         }
224
225         // Remove those that should be removed:
226         if (toRemove.size() > 0) {
227             for (Iterator i=toRemove.iterator(); i.hasNext();)
228                 typeDeletion((String)i.next());
229         }
230
231         updateTables();
232     }
233
234     protected void typeDeletion(String name) {
235         BibtexEntryType type = BibtexEntryType.getType(name);
236
237         if (type instanceof CustomEntryType) {
238             if (BibtexEntryType.getStandardType(name) == null) {
239                 int reply = JOptionPane.showConfirmDialog
240                         (frame, Globals.lang("All entries of this "
241                         +"type will be declared "
242                         +"typeless. Continue?"),
243                         Globals.lang("Delete custom format")+
244                         " '"+Util.nCase(name)+"'", JOptionPane.YES_NO_OPTION,
245                         JOptionPane.WARNING_MESSAGE);
246                 if (reply != JOptionPane.YES_OPTION)
247                     return;
248             }
249             BibtexEntryType.removeType(name);
250             updateTypesForEntries(Util.nCase(name));
251             changed.remove(name);
252             reqLists.remove(name);
253             optLists.remove(name);
254         }
255         //messageLabel.setText("'"+type.getName()+"' "+
256         //        Globals.lang("is a standard type."));
257
258     }
259
260
261 protected boolean equalArrays(String[] one, String[] two) {
262     if ((one == null) && (two == null))
263         return true; // Both null.
264     if ((one == null) || (two == null))
265         return false; // One of them null, the other not.
266     if (one.length != two.length)
267         return false; // Different length.
268     // If we get here, we know that both are non-null, and that they have the same length.
269     for (int i=0; i<one.length; i++) {
270         if (!one[i].equals(two[i]))
271             return false;
272     }
273     // If we get here, all entries have matched.
274     return true;
275 }
276
277 public void actionPerformed(ActionEvent e) {
278     if (e.getSource() == ok) {
279         applyChanges();
280         setVisible(false);
281     } else if (e.getSource() == cancel) {
282         setVisible(false);
283     } else if (e.getSource() == apply) {
284         applyChanges();
285     } else if (e.getSource() == typeComp) {
286         //System.out.println("add: "+e.getActionCommand());
287         typeComp.selectField(e.getActionCommand());
288     }
289 }
290
291 /**
292  * Cycle through all databases, and make sure everything is updated with
293  * the new type customization. This includes making sure all entries have
294  * a valid type, that no obsolete entry editors are around, and that
295  * the right-click menus' change type menu is up-to-date.
296  */
297 private void updateTypesForEntries(String typeName) {
298     if (frame.getTabbedPane().getTabCount() == 0)
299         return;
300     //messageLabel.setText(Globals.lang("Updating entries..."));
301     BibtexDatabase base;
302     Iterator iter;
303     for (int i=0; i<frame.getTabbedPane().getTabCount(); i++) {
304         BasePanel bp = (BasePanel)frame.getTabbedPane().getComponentAt(i);
305         boolean anyChanges = false;
306
307         bp.entryEditors.remove(typeName);
308
309         //bp.rcm.populateTypeMenu(); // Update type menu for change type.
310         base = bp.database();
311         iter = base.getKeySet().iterator();
312         while (iter.hasNext()) {
313             anyChanges = anyChanges |
314                     !(base.getEntryById((String)iter.next())).updateType();
315         }
316             /*if (anyChanges) {
317                 bp.refreshTable();
318                 bp.markBaseChanged();
319             }*/
320     }
321
322 }
323
324 private void updateTables() {
325     if (frame.getTabbedPane().getTabCount() == 0)
326         return;
327     //messageLabel.setText(Globals.lang("Updating entries..."));
328     BibtexDatabase base;
329     Iterator iter;
330     for (int i=0; i<frame.getTabbedPane().getTabCount(); i++) {
331         BasePanel bp = (BasePanel)frame.getTabbedPane().getComponentAt(i);
332         //bp.markBaseChanged();
333     }
334
335 }
336
337 // DEFAULT button pressed. Remember that this entry should be reset to default,
338 // unless changes are made later.
339 class DefaultListener implements ActionListener {
340     public void actionPerformed(ActionEvent e) {
341         if (lastSelected == null)
342             return;
343         defaulted.add(lastSelected);
344
345         BibtexEntryType type = BibtexEntryType.getStandardType(lastSelected);
346         if (type != null) {
347             String[] rf = type.getRequiredFields(),
348                     of = type.getOptionalFields();
349             List req, opt;
350             if (rf != null)
351                 req = java.util.Arrays.asList(rf);
352             else
353                 req = new ArrayList();
354             if (of != null)
355                 opt = java.util.Arrays.asList(of);
356             else
357                 opt = new ArrayList();
358
359             reqComp.setFields(req);
360             reqComp.setEnabled(true);
361             optComp.setFields(opt);
362         }
363     }
364 }
365
366 class DataListener implements ListDataListener {
367
368
369     public void intervalAdded(javax.swing.event.ListDataEvent e) {
370         record();
371     }
372
373     public void intervalRemoved(javax.swing.event.ListDataEvent e) {
374         record();
375     }
376
377     public void contentsChanged(javax.swing.event.ListDataEvent e) {
378         record();
379     }
380
381     private void record() {
382         if (lastSelected == null)
383             return;
384         defaulted.remove(lastSelected);
385         changed.add(lastSelected);
386         typeComp.enable(lastSelected, true);
387     }
388
389 }
390 }