ba1678f922a510e057ecd44dbda40d4679568f9f
[debian/jabref.git] / src / java / net / sf / jabref / JabRefFrame.java
1 /*
2  Copyright (C) 2003 Morten O. Alver, Nizar N. Batada
3
4  All programs in this directory and
5  subdirectories are published under the GNU General Public License as
6  described below.
7
8  This program is free software; you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 2 of the License, or (at
11  your option) any later version.
12
13  This program is distributed in the hope that it will be useful, but
14  WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  General Public License for more details.
17
18  You should have received a copy of the GNU General Public License
19  along with this program; if not, write to the Free Software
20  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21  USA
22
23  Further information about the GNU GPL is available at:
24  http://www.gnu.org/copyleft/gpl.ja.html
25
26  */
27
28 // created by : ?
29 //
30 // modified : r.nagel 23.08.2004
31 //               - insert new Menuitem New Database -> New Database from Aux
32 // modified : juan 10.02.2005
33 //               - insert new Menuitem to the Export menu -> Openoffice
34 //                 export filter
35 package net.sf.jabref;
36
37 import net.sf.jabref.gui.*;
38 import net.sf.jabref.label.*;
39 import net.sf.jabref.export.FileActions;
40 import net.sf.jabref.export.ExpandEndnoteFilters;
41 import net.sf.jabref.imports.*;
42 import net.sf.jabref.wizard.auximport.gui.*;
43
44 import javax.swing.*;
45
46 import java.awt.*;
47 import java.awt.event.*;
48 import java.util.*;
49 import java.util.List;
50 import java.io.*;
51 import java.net.URL;
52 import net.sf.jabref.undo.NamedCompound;
53 import net.sf.jabref.undo.UndoableInsertEntry;
54 import net.sf.jabref.undo.UndoableRemoveEntry;
55 import net.sf.jabref.export.ExportCustomizationDialog;
56 import java.lang.reflect.*;
57 import javax.swing.event.*;
58 import net.sf.jabref.wizard.integrity.gui.*;
59 import net.sf.jabref.groups.GroupSelector;
60 import net.sf.jabref.journals.ManageJournalsAction;
61 import net.sf.jabref.external.*;
62 import com.jgoodies.uif_lite.component.UIFSplitPane;
63 import com.jgoodies.looks.Options;
64 import com.jgoodies.looks.HeaderStyle;
65
66
67 /**
68  * The main window of the application.
69  */
70 public class JabRefFrame
71     extends JFrame {
72
73   JabRefFrame ths = this;
74     UIFSplitPane contentPane = new UIFSplitPane();
75
76   JabRefPreferences prefs = Globals.prefs; //new JabRefPreferences();
77     PrefsDialog3 prefsDialog = null;
78   private int lastTabbedPanelSelectionIndex = -1 ;
79
80     // The sidepane manager takes care of populating the sidepane.
81     public SidePaneManager sidePaneManager;
82
83     JTabbedPane tabbedPane = new JTabbedPane();
84   final Insets marg = new Insets(1,0,2,0);
85
86
87     class ToolBar extends JToolBar {
88       void addAction(Action a) {
89         JButton b = new JButton(a);
90         b.setText(null);
91         if (!Globals.ON_MAC)
92             b.setMargin(marg);
93         add(b);
94       }
95     }
96   ToolBar tlb = new ToolBar();
97
98   JMenuBar mb = new JMenuBar();/* {
99     public void paintComponent(Graphics g) {
100       Graphics2D g2 = (Graphics2D)g;
101       g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
102                           RenderingHints.VALUE_ANTIALIAS_ON);
103       g2.setRenderingHint(RenderingHints.KEY_RENDERING,
104                           RenderingHints.VALUE_RENDER_QUALITY);
105       super.paintComponent(g2);
106
107     }
108
109   };*/
110   GridBagLayout gbl = new GridBagLayout();
111   GridBagConstraints con = new GridBagConstraints();
112
113   JLabel statusLine = new JLabel("", SwingConstants.LEFT),
114       statusLabel = new JLabel(Globals.lang("Status") + ":",
115                                SwingConstants.LEFT);
116   //SearchManager searchManager  = new SearchManager(ths, prefs);
117
118   private FileHistory fileHistory = new FileHistory(prefs, this);
119
120   LabelMaker labelMaker;
121
122   // The help window.
123   public HelpDialog helpDiag = new HelpDialog(this);
124
125   // Here we instantiate menu/toolbar actions. Actions regarding
126   // the currently open database are defined as a GeneralAction
127   // with a unique command string. This causes the appropriate
128   // BasePanel's runCommand() method to be called with that command.
129   // Note: GeneralAction's constructor automatically gets translations
130   // for the name and message strings.
131
132   // References to the toggle buttons in the toolbar:
133   public JToggleButton groupToggle, searchToggle, previewToggle, highlightAny,
134       highlightAll;
135
136   OpenDatabaseAction
137       open = new OpenDatabaseAction(this, true);
138   AbstractAction
139       close = new CloseDatabaseAction(),
140       quit = new CloseAction(),
141       selectKeys = new SelectKeysAction(),
142       newDatabaseAction = new NewDatabaseAction(),
143       newSubDatabaseAction = new NewSubDatabaseAction(),
144       integrityCheckAction = new IntegrityCheckAction(),
145       help = new HelpAction("JabRef help", helpDiag,
146                             GUIGlobals.baseFrameHelp, "JabRef help",
147                             prefs.getKey("Help")),
148       contents = new HelpAction("Help contents", helpDiag,
149                                 GUIGlobals.helpContents, "Help contents",
150                                 GUIGlobals.helpContentsIconFile),
151 /* old about*/
152       about = new HelpAction("About JabRef", helpDiag,
153                              GUIGlobals.aboutPage, "About JabRef",
154                              GUIGlobals.aboutIcon),
155 /**/
156   //    about2 = new NewAboutAction(),
157       editEntry = new GeneralAction("edit", "Edit entry",
158                                "Edit entry", GUIGlobals.editIconFile,
159                                prefs.getKey("Edit entry")),
160       save = new GeneralAction("save", "Save database",
161                                "Save database", GUIGlobals.saveIconFile,
162                                prefs.getKey("Save database")),
163       saveAs = new GeneralAction("saveAs", "Save database as ...",
164                                  "Save database as ...",
165                                  GUIGlobals.saveAsIconFile,
166                                  prefs.getKey("Save database as ...")),
167       saveSelectedAs = new GeneralAction("saveSelectedAs",
168                                          "Save selected as ...",
169                                          "Save selected as ...",
170                                          GUIGlobals.saveAsIconFile),
171       nextTab = new ChangeTabAction(true),
172       prevTab = new ChangeTabAction(false),
173       sortTabs = new SortTabsAction(this),
174       undo = new GeneralAction("undo", "Undo", "Undo",
175                                GUIGlobals.undoIconFile,
176                                prefs.getKey("Undo")),
177       redo = new GeneralAction("redo", "Redo", "Redo",
178                                GUIGlobals.redoIconFile,
179                                prefs.getKey("Redo")),
180       /*cut = new GeneralAction("cut", "Cut", "Cut",
181          GUIGlobals.cutIconFile,
182          prefs.getKey("Cut")),*/
183       delete = new GeneralAction("delete", "Delete", "Delete",
184                                  GUIGlobals.removeIconFile,
185                                  prefs.getKey("Delete")),
186       /*copy = new GeneralAction("copy", "Copy", "Copy",
187                                GUIGlobals.copyIconFile,
188                                prefs.getKey("Copy")),*/
189       copy = new EditAction("copy", GUIGlobals.copyIconFile),
190       paste = new EditAction("paste", GUIGlobals.pasteIconFile),
191       cut = new EditAction("cut", GUIGlobals.cutIconFile),
192       mark = new GeneralAction("markEntries", "Mark entries",
193                                "Mark entries",
194                                GUIGlobals.markIcon,
195                                prefs.getKey("Mark entries")),
196        unmark = new GeneralAction("unmarkEntries", "Unmark entries",
197                                   "Unmark entries",
198                                   GUIGlobals.unmarkIcon,
199                                   prefs.getKey("Unmark entries")),
200        unmarkAll = new GeneralAction("unmarkAll", "Unmark all"),
201       manageSelectors = new GeneralAction("manageSelectors", "Manage content selectors"),
202       saveSessionAction = new SaveSessionAction(),
203       loadSessionAction = new LoadSessionAction(),
204       incrementalSearch = new GeneralAction("incSearch", "Incremental search",
205                                             "Start incremental search",
206                                             GUIGlobals.searchIconFile,
207                                             prefs.getKey("Incremental search")),
208       normalSearch = new GeneralAction("search", "Search", "Search",
209                                        GUIGlobals.searchIconFile,
210                                        prefs.getKey("Search")),
211       toggleSearch = new GeneralAction("toggleSearch", "Search", "Toggle search panel",
212                                        GUIGlobals.searchIconFile),
213     //                                       prefs.getKey("Search")),
214       fetchCiteSeer = new FetchCiteSeerAction(),
215       importCiteSeer = new ImportCiteSeerAction(),
216       fetchMedline = new FetchMedlineAction(),
217       citeSeerPanelAction = new CiteSeerPanelAction(),
218       //fetchAuthorMedline = new FetchAuthorMedlineAction(),
219       copyKey = new GeneralAction("copyKey", "Copy BibTeX key"),
220       //"Put a BibTeX reference to the selected entries on the clipboard",
221       copyCiteKey = new GeneralAction("copyCiteKey", "Copy \\cite{BibTeX key}",
222                                       //"Put a BibTeX reference to the selected entries on the clipboard",
223                                       prefs.getKey("Copy \\cite{BibTeX key}")),
224       mergeDatabaseAction = new GeneralAction("mergeDatabase",
225                                               "Append database",
226                                               "Append contents from a BibTeX database into the currently viewed database",
227                                               GUIGlobals.openIconFile),
228       //prefs.getKey("Open")),
229       /*remove = new GeneralAction("remove", "Remove", "Remove selected entries",
230         GUIGlobals.removeIconFile),*/
231       selectAll = new GeneralAction("selectAll", "Select all",
232                                     prefs.getKey("Select all")),
233       replaceAll = new GeneralAction("replaceAll", "Replace string",
234                                      prefs.getKey("Replace string")),
235
236       editPreamble = new GeneralAction("editPreamble", "Edit preamble",
237                                        "Edit preamble",
238                                        GUIGlobals.preambleIconFile,
239                                        prefs.getKey("Edit preamble")),
240       editStrings = new GeneralAction("editStrings", "Edit strings",
241                                       "Edit strings",
242                                       GUIGlobals.stringsIconFile,
243                                       prefs.getKey("Edit strings")),
244       toggleGroups = new GeneralAction("toggleGroups",
245                                        "Toggle groups interface",
246                                        "Toggle groups interface",
247                                        GUIGlobals.groupsIconFile,
248                                        prefs.getKey("Toggle groups interface")),
249       togglePreview = new GeneralAction("togglePreview",
250                                         "Toggle entry preview",
251                                         "Toggle entry preview",
252                                         GUIGlobals.previewIconFile,
253                                         prefs.getKey("Toggle entry preview")),
254       toggleHighlightAny = new GeneralAction("toggleHighlightGroupsMatchingAny",
255                                         "Highlight groups matching any selected entry",
256                                         "Highlight groups matching any selected entry",
257                                         GUIGlobals.groupsHighlightMatchingAnyFile),
258       toggleHighlightAll = new GeneralAction("toggleHighlightGroupsMatchingAll",
259                                         "Highlight groups matching all selected entries",
260                                         "Highlight groups matching all selected entries",
261                                         GUIGlobals.groupsHighlightMatchingAllFile),
262       switchPreview = new GeneralAction("switchPreview",
263                                         "Switch preview layout",
264                                         prefs.getKey("Switch preview layout")),
265        makeKeyAction = new GeneralAction("makeKey", "Autogenerate BibTeX keys",
266                                         "Autogenerate BibTeX keys",
267                                         GUIGlobals.genKeyIconFile,
268                                         prefs.getKey("Autogenerate BibTeX keys")),
269
270       lyxPushAction = new PushToApplicationAction(ths, new PushToLyx()),
271
272       winEdtPushAction = new PushToApplicationAction(ths, new PushToWinEdt()),
273       latexEditorPushAction = new PushToApplicationAction(ths, new PushToLatexEditor()),
274       openFile = new GeneralAction("openFile", "Open PDF or PS",
275                                    "Open PDF or PS",
276                                    GUIGlobals.pdfIcon,
277                                    prefs.getKey("Open PDF or PS")),
278       openUrl = new GeneralAction("openUrl", "Open URL or DOI",
279                                   "Open URL or DOI",
280                                   GUIGlobals.wwwIcon,
281                                   prefs.getKey("Open URL or DOI")),
282       dupliCheck = new GeneralAction("dupliCheck", "Find duplicates"),
283       strictDupliCheck = new GeneralAction("strictDupliCheck", "Find and remove exact duplicates"),
284       plainTextImport = new GeneralAction("plainTextImport",
285                                           "New entry from plain text",
286                                           prefs.getKey("New from plain text")),
287
288
289       customExpAction = new CustomizeExportsAction(),
290       customImpAction = new CustomizeImportsAction(),
291       exportCSV = new ExportCSV(),
292       exportToClipboard = new GeneralAction("exportToClipboard", "Export selected entries to clipboard"),
293       expandEndnoteZip = new ExpandEndnoteFilters(this),
294         autoSetPdf = new GeneralAction("autoSetPdf", Globals.lang("Synchronize %0 links", "PDF"), Globals.prefs.getKey("Synchronize PDF")),
295         autoSetPs = new GeneralAction("autoSetPs", Globals.lang("Synchronize %0 links", "PS"), Globals.prefs.getKey("Synchronize PS")),
296
297     abbreviateMedline = new GeneralAction("abbreviateMedline", "Abbreviate journal names (MEDLINE)",
298                 "Abbreviate journal names of the selected entries (MEDLINE abbreviation)"),
299   abbreviateIso = new GeneralAction("abbreviateIso", "Abbreviate journal names (ISO)",
300                           "Abbreviate journal names of the selected entries (ISO abbreviation)",
301                           Globals.prefs.getKey("Abbreviate")),
302
303
304     unabbreviate = new GeneralAction("unabbreviate", "Unabbreviate journal names",
305                     "Unabbreviate journal names of the selected entries",
306             Globals.prefs.getKey("Unabbreviate")),
307     manageJournals = new ManageJournalsAction(this),
308     databaseProperties = new DatabasePropertiesAction(),
309     emacsPushAction = new PushToApplicationAction(ths, new PushToEmacs()),
310
311       errorConsole = Globals.errorConsole.getAction(this),
312     test = new GeneralAction("test", "Test");
313
314   /*setupSelector = new GeneralAction("setupSelector", "", "",
315           GUIGlobals.pasteIconFile,
316           prefs.getKey(")),*/
317
318
319     MedlineFetcher medlineFetcher;
320     CiteSeerFetcher citeSeerFetcher;
321     CiteSeerFetcherPanel citeSeerFetcherPanel;
322     IEEEXploreFetcher ieeexplorerFetcher;
323     SearchManager2 searchManager;
324     public GroupSelector groupSelector;
325
326   // The menus for importing/appending other formats
327   JMenu importMenu = subMenu("Import into current database"),
328       importNewMenu = subMenu("Import into new database"),
329       exportMenu = subMenu("Export"),
330       customExportMenu = subMenu("Custom export"),
331       newDatabaseMenu = subMenu("New database" );
332
333   // Other submenus
334   JMenu checkAndFix = subMenu("Scan database...");
335
336
337   // The action for adding a new entry of unspecified type.
338   NewEntryAction newEntryAction = new NewEntryAction(prefs.getKey("New entry"));
339   NewEntryAction[] newSpecificEntryAction = new NewEntryAction[]
340   {
341       new NewEntryAction("article", prefs.getKey("New article")),
342       new NewEntryAction("book", prefs.getKey("New book")),
343       new NewEntryAction("phdthesis", prefs.getKey("New phdthesis")),
344       new NewEntryAction("inbook", prefs.getKey("New inbook")),
345       new NewEntryAction("mastersthesis", prefs.getKey("New mastersthesis")),
346       new NewEntryAction("proceedings", prefs.getKey("New proceedings")),
347       new NewEntryAction("inproceedings"),
348       new NewEntryAction("conference"),
349       new NewEntryAction("incollection"),
350       new NewEntryAction("booklet"),
351       new NewEntryAction("manual"),
352       new NewEntryAction("techreport"),
353       new NewEntryAction("unpublished",
354                          prefs.getKey("New unpublished")),
355       new NewEntryAction("misc"),
356       new NewEntryAction("other")
357   };
358
359   public JabRefFrame() {
360     init();
361     setEmptyState();
362   }
363
364   private void init() {
365     /*try {
366         //UIManager.setLookAndFeel("com.jgoodies.plaf.windows.ExtWindowsLookAndFeel");
367         UIManager.setLookAndFeel(new PlasticXPLookAndFeel());
368         } catch (Exception e) { e.printStackTrace();}*/
369
370     //Globals.setLanguage("no", "");
371
372     macOSXRegistration();
373       MyGlassPane glassPane = new MyGlassPane();
374     setGlassPane(glassPane);
375     //  glassPane.setVisible(true);
376
377       setTitle(GUIGlobals.frameTitle);
378     setIconImage(new ImageIcon(GUIGlobals.jabreflogo).getImage());
379     setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
380     addWindowListener(new WindowAdapter() {
381       public void windowClosing(WindowEvent e) {
382         (new CloseAction()).actionPerformed(null);
383       }
384     });
385
386     initLabelMaker();
387
388     sidePaneManager = new SidePaneManager(this);
389
390     Globals.sidePaneManager = this.sidePaneManager;
391     Globals.helpDiag = this.helpDiag;
392
393     medlineFetcher = new MedlineFetcher(sidePaneManager);
394     citeSeerFetcher = new CiteSeerFetcher(sidePaneManager);
395     citeSeerFetcherPanel = new CiteSeerFetcherPanel(sidePaneManager, (CiteSeerFetcher)citeSeerFetcher);
396     ieeexplorerFetcher = new IEEEXploreFetcher();
397     searchManager = new SearchManager2(this, sidePaneManager);
398       // Groups
399       /*if (metaData.getGroups() != null) {
400           panel.groupSelector = new GroupSelector(frame, panel, metaData
401                   .getGroups(), this, prefs);
402           register("groups", panel.groupSelector);
403           if (prefs.getBoolean("groupSelectorVisible"))
404               ensureVisible("groups");
405       } else*/
406       {
407
408           groupSelector = new GroupSelector(this, sidePaneManager);
409           sidePaneManager.register("groups", groupSelector);
410       }
411
412
413     sidePaneManager.register("fetchMedline", medlineFetcher);
414     //medlineAuthorFetcher = new MedlineAuthorFetcher(this, sidePaneManager);
415     //sidePaneManager.register("fetchAuthorMedline", medlineAuthorFetcher);
416
417     sidePaneManager.register("search", searchManager);
418       // Show the search panel if it was visible at last shutdown:
419     if (Globals.prefs.getBoolean("searchPanelVisible"))
420         sidePaneManager.ensureVisible("search");
421     sidePaneManager.register("CiteSeerPanel", citeSeerFetcherPanel);
422     sidePaneManager.register("CiteSeerProgress", citeSeerFetcher);
423     sidePaneManager.populatePanel();
424
425
426
427     setupLayout();
428     setSize(new Dimension(prefs.getInt("sizeX"),
429                           prefs.getInt("sizeY")));
430     setLocation(new Point(prefs.getInt("posX"),
431                           prefs.getInt("posY")));
432     tabbedPane.setBorder(null);
433     tabbedPane.setForeground(GUIGlobals.inActiveTabbed);
434
435     // The following state listener makes sure focus is registered with the correct database
436     // when the user switches tabs. Without this, cut/paste/copy operations would some times
437     // occur in the wrong tab.
438     tabbedPane.addChangeListener(new ChangeListener() {
439       public void stateChanged(ChangeEvent e)
440       {
441         markActiveBasePanel() ;
442
443         BasePanel bp = basePanel();
444         if (bp != null) {
445           groupToggle.setSelected(sidePaneManager.isPanelVisible("groups"));
446           searchToggle.setSelected(sidePaneManager.isPanelVisible("search"));
447           previewToggle.setSelected(Globals.prefs.getBoolean("previewEnabled"));
448           highlightAny.setSelected(Globals.prefs.getBoolean("highlightGroupsMatchingAny"));
449           highlightAll.setSelected(Globals.prefs.getBoolean("highlightGroupsMatchingAll"));
450           Globals.focusListener.setFocused(bp.mainTable);
451           new FocusRequester(bp.mainTable);
452         }
453       }
454     });
455   }
456
457 // -------------------- !!!! NECESSARY ???? OBSOLETE ??? ----------------------
458   AboutAction aboutAction = new AboutAction();
459   class AboutAction
460       extends AbstractAction {
461     public AboutAction() {
462       super(Globals.lang("About JabRef"));
463
464     }
465
466     public void actionPerformed(ActionEvent e) {
467       about();
468     }
469   }
470
471   // -------------------- !!!! NECESSARY ???? OBSOLETE ??? ----------------------
472   // General info dialog.  The OSXAdapter calls this method when "About OSXAdapter"
473   // is selected from the application menu.
474   public void about() {
475     JDialog about = new JDialog(ths, Globals.lang("About JabRef"),
476                                 true);
477     JEditorPane jp = new JEditorPane();
478     JScrollPane sp = new JScrollPane
479         (jp, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
480          JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
481     jp.setEditable(false);
482     try {
483       jp.setPage(GUIGlobals.class.getResource("/help/About.html"));//GUIGlobals.aboutPage);
484       // We need a hyperlink listener to be able to switch to the license
485       // terms and back.
486       jp.addHyperlinkListener(new javax.swing.event.HyperlinkListener() {
487         public void hyperlinkUpdate(javax.swing.event.HyperlinkEvent e) {
488           if (e.getEventType()
489               == javax.swing.event.HyperlinkEvent.EventType.ACTIVATED) {
490             try {
491               ( (JEditorPane) e.getSource()).setPage(e.getURL());
492             }
493             catch (IOException ex) {}
494           }
495         }
496       });
497       about.getContentPane().add(sp);
498       about.setSize(GUIGlobals.aboutSize);
499       Util.placeDialog(about, ths);
500       about.setVisible(true);
501     }
502     catch (IOException ex) {
503       ex.printStackTrace();
504       JOptionPane.showMessageDialog(ths, "Could not load file 'About.html'",
505                                     "Error", JOptionPane.ERROR_MESSAGE);
506     }
507
508   }
509
510   // General preferences dialog.  The OSXAdapter calls this method when "Preferences..."
511   // is selected from the application menu.
512   public void preferences() {
513     //PrefsDialog.showPrefsDialog(ths, prefs);
514       AbstractWorker worker = new AbstractWorker() {
515               public void run() {
516                   output(Globals.lang("Opening preferences..."));
517                   if (prefsDialog == null) {
518                       prefsDialog = new PrefsDialog3(ths, prefs);
519                       Util.placeDialog(prefsDialog, ths);
520                   }
521                   else
522                       prefsDialog.setValues();
523
524               }
525               public void update() {
526                   prefsDialog.setVisible(true);
527                   output("");
528               }
529           };
530       worker.getWorker().run();
531       worker.getCallBack().update();
532   }
533
534 public JabRefPreferences prefs() {
535   return prefs;
536 }
537
538   // General info dialog.  The OSXAdapter calls this method when "Quit OSXAdapter"
539   // is selected from the application menu, Cmd-Q is pressed, or "Quit" is selected from the Dock.
540   public void quit() {
541     // Ask here if the user really wants to close, if the base
542     // has not been saved since last save.
543     boolean close = true;
544     Vector filenames = new Vector();
545     if (tabbedPane.getTabCount() > 0) {
546       loop: for (int i = 0; i < tabbedPane.getTabCount(); i++) {
547         if (baseAt(i).baseChanged) {
548           tabbedPane.setSelectedIndex(i);
549           int answer = JOptionPane.showConfirmDialog
550               (ths, Globals.lang
551                ("Database has changed. Do you "
552                 + "want to save before closing?"),
553                Globals.lang("Save before closing"),
554                JOptionPane.YES_NO_CANCEL_OPTION);
555
556           if ( (answer == JOptionPane.CANCEL_OPTION) ||
557               (answer == JOptionPane.CLOSED_OPTION)) {
558             close = false; // The user has cancelled.
559               return;
560           }
561           if (answer == JOptionPane.YES_OPTION) {
562             // The user wants to save.
563             try {
564               basePanel().runCommand("save");
565             }
566             catch (Throwable ex) {
567               // Something prevented the file
568               // from being saved. Break!!!
569               close = false;
570               break;
571             }
572           }
573         }
574         if (baseAt(i).file != null) {
575           filenames.add(baseAt(i).file.getPath());
576         }
577       }
578     }
579     if (close) {
580       dispose();
581
582       prefs.putInt("posX", ths.getLocation().x);
583       prefs.putInt("posY", ths.getLocation().y);
584       prefs.putInt("sizeX", ths.getSize().width);
585       prefs.putInt("sizeY", ths.getSize().height);
586       prefs.putBoolean("searchPanelVisible", sidePaneManager.isPanelVisible("search"));
587
588       if (prefs.getBoolean("openLastEdited")) {
589         // Here we store the names of allcurrent filea. If
590         // there is no current file, we remove any
591         // previously stored file name.
592         if (filenames.size() == 0) {
593           prefs.remove("lastEdited");
594         }
595         else {
596           String[] names = new String[filenames.size()];
597           for (int i = 0; i < filenames.size(); i++) {
598             names[i] = (String) filenames.elementAt(i);
599
600           }
601           prefs.putStringArray("lastEdited", names);
602         }
603
604       }
605
606       fileHistory.storeHistory();
607       prefs.customExports.store();
608       prefs.customImports.store();
609       BibtexEntryType.saveCustomEntryTypes(prefs);
610
611       // Let the search interface store changes to prefs.
612       // But which one? Let's use the one that is visible.
613       if (basePanel() != null) {
614         ((SearchManager2)searchManager).updatePrefs();
615
616       }
617       System.exit(0); // End program.
618     }
619   }
620
621   private void macOSXRegistration() {
622     if (Globals.osName.equals(Globals.MAC)) {
623       try {
624         Class osxAdapter = Class.forName("osxadapter.OSXAdapter");
625
626         Class[] defArgs = {
627             JabRefFrame.class};
628         Method registerMethod = osxAdapter.getDeclaredMethod(
629             "registerMacOSXApplication", defArgs);
630         if (registerMethod != null) {
631           Object[] args = {
632               this};
633           registerMethod.invoke(osxAdapter, args);
634         }
635         // This is slightly gross.  to reflectively access methods with boolean args,
636         // use "boolean.class", then pass a Boolean object in as the arg, which apparently
637
638         defArgs[0] = boolean.class;
639         Method prefsEnableMethod = osxAdapter.getDeclaredMethod("enablePrefs",
640             defArgs);
641         if (prefsEnableMethod != null) {
642           Object args[] = {
643               Boolean.TRUE};
644           prefsEnableMethod.invoke(osxAdapter, args);
645         }
646       }
647       catch (NoClassDefFoundError e) {
648         // This will be thrown first if the OSXAdapter is loaded on a system without the EAWT
649         // because OSXAdapter extends ApplicationAdapter in its def
650         System.err.println("This version of Mac OS X does not support the Apple EAWT.  Application Menu handling has been disabled (" +
651                            e + ")");
652       }
653       catch (ClassNotFoundException e) {
654         // This shouldn't be reached; if there's a problem with the OSXAdapter we should get the
655         // above NoClassDefFoundError first.
656         System.err.println("This version of Mac OS X does not support the Apple EAWT.  Application Menu handling has been disabled (" +
657                            e + ")");
658       }
659       catch (Exception e) {
660         System.err.println("Exception while loading the OSXAdapter:");
661         e.printStackTrace();
662       }
663     }
664   }
665
666   private void setupLayout() {
667     fillMenu();
668     createToolBar();
669     getContentPane().setLayout(gbl);
670       contentPane.setDividerSize(2);
671       contentPane.setBorder(null);
672     //getContentPane().setBackground(GUIGlobals.lightGray);
673     con.fill = GridBagConstraints.HORIZONTAL;
674     con.anchor = GridBagConstraints.WEST;
675     con.weightx = 1;
676     con.weighty = 0;
677     con.gridwidth = GridBagConstraints.REMAINDER;
678     mb.setMinimumSize(mb.getPreferredSize());
679     //gbl.setConstraints(mb, con);
680     //getContentPane().add(mb);
681     setJMenuBar(mb);
682     con.anchor = GridBagConstraints.NORTH;
683     //con.gridwidth = 1;//GridBagConstraints.REMAINDER;;
684     gbl.setConstraints(tlb, con);
685     getContentPane().add(tlb);
686
687     Component lim = Box.createGlue();
688     gbl.setConstraints(lim, con);
689     //getContentPane().add(lim);
690     /*
691       JPanel empt = new JPanel();
692       empt.setBackground(GUIGlobals.lightGray);
693       gbl.setConstraints(empt, con);
694            getContentPane().add(empt);
695
696       con.insets = new Insets(1,0,1,1);
697       con.anchor = GridBagConstraints.EAST;
698       con.weightx = 0;
699       gbl.setConstraints(searchManager, con);
700       getContentPane().add(searchManager);*/
701     con.gridwidth = GridBagConstraints.REMAINDER;
702     con.weightx = 1;
703     con.weighty = 0;
704     con.fill = GridBagConstraints.BOTH;
705     con.anchor = GridBagConstraints.WEST;
706     con.insets = new Insets(0, 0, 0, 0);
707     lim = Box.createGlue();
708     gbl.setConstraints(lim, con);
709     getContentPane().add(lim);
710     //tabbedPane.setVisible(false);
711     //tabbedPane.setForeground(GUIGlobals.lightGray);
712     con.weighty = 1;
713     gbl.setConstraints(contentPane, con);
714     getContentPane().add(contentPane);
715     contentPane.setRightComponent(tabbedPane);
716     contentPane.setLeftComponent(sidePaneManager.getPanel());
717     sidePaneManager.updateView();
718
719     JPanel status = new JPanel();
720     status.setLayout(gbl);
721     con.weighty = 0;
722     con.weightx = 0;
723     con.gridwidth = 1;
724     con.insets = new Insets(0, 2, 0, 0);
725     gbl.setConstraints(statusLabel, con);
726     status.add(statusLabel);
727     con.weightx = 1;
728     con.insets = new Insets(0, 4, 0, 0);
729     con.gridwidth = GridBagConstraints.REMAINDER;
730     gbl.setConstraints(statusLine, con);
731     status.add(statusLine);
732     con.gridwidth = GridBagConstraints.REMAINDER;
733     statusLabel.setForeground(GUIGlobals.validFieldColor.darker());
734     con.insets = new Insets(0, 0, 0, 0);
735     gbl.setConstraints(status, con);
736     getContentPane().add(status);
737
738
739
740   }
741
742   private void initLabelMaker() {
743     // initialize the labelMaker
744     labelMaker = new LabelMaker();
745     labelMaker.addRule(new ArticleLabelRule(),
746                        BibtexEntryType.ARTICLE);
747     labelMaker.addRule(new BookLabelRule(),
748                        BibtexEntryType.BOOK);
749     labelMaker.addRule(new IncollectionLabelRule(),
750                        BibtexEntryType.INCOLLECTION);
751     labelMaker.addRule(new InproceedingsLabelRule(),
752                        BibtexEntryType.INPROCEEDINGS);
753   }
754
755   /**
756    * Returns the indexed BasePanel.
757    * @param i Index of base
758    */
759   BasePanel baseAt(int i) {
760     return (BasePanel) tabbedPane.getComponentAt(i);
761   }
762
763   public void showBaseAt(int i) {
764       tabbedPane.setSelectedIndex(i);
765   }
766
767   /**
768    * Returns the currently viewed BasePanel.
769    */
770   public BasePanel basePanel() {
771     return (BasePanel) tabbedPane.getSelectedComponent();
772   }
773
774   /**
775    * handle the color of active and inactive JTabbedPane tabs
776    */
777   private void markActiveBasePanel()
778   {
779     int now = tabbedPane.getSelectedIndex() ;
780     int len = tabbedPane.getTabCount() ;
781     if ((lastTabbedPanelSelectionIndex > -1) && (lastTabbedPanelSelectionIndex < len))
782       tabbedPane.setForegroundAt(lastTabbedPanelSelectionIndex, GUIGlobals.inActiveTabbed);
783     if ( (now > -1) &&  (now < len))
784       tabbedPane.setForegroundAt(now, GUIGlobals.activeTabbed);
785     lastTabbedPanelSelectionIndex = now ;
786   }
787
788   private int getTabIndex(JComponent comp) {
789     for (int i = 0; i < tabbedPane.getTabCount(); i++) {
790       if (tabbedPane.getComponentAt(i) == comp) {
791         return i;
792       }
793     }
794     return -1;
795   }
796
797   public JTabbedPane getTabbedPane() { return tabbedPane; }
798
799   public String getTabTitle(JComponent comp) {
800     return tabbedPane.getTitleAt(getTabIndex(comp));
801   }
802
803   public void setTabTitle(JComponent comp, String s) {
804     tabbedPane.setTitleAt(getTabIndex(comp), s);
805   }
806
807   class GeneralAction
808       extends MnemonicAwareAction {
809     private String command;
810     public GeneralAction(String command, String text,
811                          String description, URL icon) {
812       super(new ImageIcon(icon));
813       this.command = command;
814       putValue(NAME, text);
815       putValue(SHORT_DESCRIPTION, Globals.lang(description));
816     }
817
818     public GeneralAction(String command, String text,
819                          String description, URL icon,
820                          KeyStroke key) {
821       super(new ImageIcon(icon));
822       this.command = command;
823       putValue(NAME, text);
824       putValue(ACCELERATOR_KEY, key);
825       putValue(SHORT_DESCRIPTION, Globals.lang(description));
826     }
827
828     public GeneralAction(String command, String text) {
829       putValue(NAME, text);
830       this.command = command;
831     }
832
833     public GeneralAction(String command, String text, KeyStroke key) {
834       this.command = command;
835       putValue(NAME, text);
836       putValue(ACCELERATOR_KEY, key);
837     }
838
839     public GeneralAction(String command, String text, String description) {
840       this.command = command;
841       putValue(NAME, text);
842       putValue(SHORT_DESCRIPTION, Globals.lang(description));
843     }
844     public GeneralAction(String command, String text, String description, KeyStroke key) {
845       this.command = command;
846       putValue(NAME, text);
847       putValue(SHORT_DESCRIPTION, Globals.lang(description));
848         putValue(ACCELERATOR_KEY, key);
849     }
850
851     public void actionPerformed(ActionEvent e) {
852       if (tabbedPane.getTabCount() > 0) {
853         try {
854           ( (BasePanel) (tabbedPane.getSelectedComponent()))
855               .runCommand(command);
856         }
857         catch (Throwable ex) {
858           ex.printStackTrace();
859         }
860       }
861       else {
862         Util.pr("Action '" + command + "' must be disabled when no "
863                 + "database is open.");
864       }
865     }
866   }
867
868   /** This got removed when we introduced SearchManager2.
869        class IncrementalSearchAction extends AbstractAction {
870     public IncrementalSearchAction() {
871    super("Incremental search", new ImageIcon(GUIGlobals.searchIconFile));
872    putValue(SHORT_DESCRIPTION, Globals.lang("Start incremental search"));
873    putValue(ACCELERATOR_KEY, prefs.getKey("Incremental search"));
874     }
875     public void actionPerformed(ActionEvent e) {
876    if (tabbedPane.getTabCount() > 0)
877      searchManager.startIncrementalSearch();
878     }
879        }
880
881        class SearchAction extends AbstractAction {
882     public SearchAction() {
883    super("Search", new ImageIcon(GUIGlobals.searchIconFile));
884    putValue(SHORT_DESCRIPTION, Globals.lang("Start search"));
885    putValue(ACCELERATOR_KEY, prefs.getKey("Search"));
886     }
887     public void actionPerformed(ActionEvent e) {
888    if (tabbedPane.getTabCount() > 0)
889      searchManager.startSearch();
890     }
891        }
892    */
893
894   class NewEntryAction
895       extends MnemonicAwareAction {
896
897     String type = null; // The type of item to create.
898     KeyStroke keyStroke = null; // Used for the specific instances.
899
900     public NewEntryAction(KeyStroke key) {
901       // This action leads to a dialog asking for entry type.
902       super(new ImageIcon(GUIGlobals.addIconFile));
903       putValue(NAME, "New entry");
904       putValue(ACCELERATOR_KEY, key);
905       putValue(SHORT_DESCRIPTION, Globals.lang("New BibTeX entry"));
906     }
907
908     public NewEntryAction(String type_) {
909       // This action leads to the creation of a specific entry.
910       putValue(NAME, Util.nCase(type_));
911       type = type_;
912     }
913
914     public NewEntryAction(String type_, KeyStroke key) {
915         // This action leads to the creation of a specific entry.
916         putValue(NAME, Util.nCase(type_));
917         putValue(ACCELERATOR_KEY, key);
918         type = type_;
919     }
920
921     public void actionPerformed(ActionEvent e) {
922       String thisType = type;
923       if (thisType == null) {
924         EntryTypeDialog etd = new EntryTypeDialog(ths);
925         Util.placeDialog(etd, ths);
926         etd.setVisible(true);
927         BibtexEntryType tp = etd.getChoice();
928         if (tp == null) {
929           return;
930         }
931         thisType = tp.getName();
932       }
933
934       if (tabbedPane.getTabCount() > 0) {
935         ( (BasePanel) (tabbedPane.getSelectedComponent()))
936             .newEntry(BibtexEntryType.getType(thisType));
937       }
938       else {
939         Util.pr("Action 'New entry' must be disabled when no "
940                 + "database is open.");
941       }
942     }
943   }
944
945   /*
946        private void setupDatabaseLayout() {
947     // This method is called whenever this frame has been provided
948     // with a database, and completes the layout.
949
950
951     if (file != null)
952    setTitle(GUIGlobals.baseTitle+file.getName());
953     else
954     setTitle(GUIGlobals.untitledTitle);
955
956     //DragNDropManager dndm = new DragNDropManager(this);
957
958     //setNonEmptyState();
959     Util.pr("JabRefFrame: Must set non-empty state.");
960     }*/
961
962   /**
963    * Refresh import menus.
964    */
965   public void setUpImportMenus() {
966     setUpImportMenu(importMenu, false);
967     setUpImportMenu(importNewMenu, true);
968   }
969
970   private void fillMenu() {
971     //mb.putClientProperty(Options.HEADER_STYLE_KEY, HeaderStyle.BOTH);
972       mb.setBorder(null);
973     JMenu file = subMenu("File"),
974         edit = subMenu("Edit"),
975         bibtex = subMenu("BibTeX"),
976         view = subMenu("View"),
977         tools = subMenu("Tools"),
978         web = subMenu("Web search"),
979         options = subMenu("Options"),
980         newSpec = subMenu("New entry..."),
981         helpMenu = subMenu("Help");
982
983     setUpImportMenus();
984     setUpExportMenu(exportMenu);
985     setUpCustomExportMenu();
986
987     newDatabaseMenu.add(newDatabaseAction) ;
988     newDatabaseMenu.add(newSubDatabaseAction) ;
989
990     file.add(newDatabaseAction);
991     file.add(open); //opendatabaseaction
992     file.add(mergeDatabaseAction);
993     file.add(importMenu);
994     //file.add(importMenu);
995     file.add(importNewMenu);
996     file.add(save);
997     file.add(saveAs);
998     file.add(saveSelectedAs);
999     file.add(exportMenu);
1000     file.add(customExportMenu);
1001     file.addSeparator();
1002     file.add(databaseProperties);
1003       file.addSeparator();
1004
1005       file.add(fileHistory);
1006     //file.addSeparator();
1007     file.add(loadSessionAction);
1008     file.add(saveSessionAction);
1009     file.addSeparator();
1010     file.add(close);
1011     //==============================
1012     // NB: I added this because my frame borders are so tiny that I cannot click
1013     // on the "x" close button. Anyways, I think it is good to have and "exit" button
1014     // I was too lazy to make a new ExitAction
1015     //JMenuItem exit_mItem = new JMenuItem(Globals.lang("Exit"));
1016     //exit_mItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, KeyEvent.CTRL_MASK)); //Ctrl-Q to exit
1017     // above keybinding should be from user define
1018     //exit_mItem.addActionListener(new CloseAction() );
1019     //file.add( exit_mItem);
1020     //=====================================
1021     file.add(quit);
1022     mb.add(file);
1023     //edit.add(test);
1024     edit.add(undo);
1025     edit.add(redo);
1026     edit.addSeparator();
1027
1028     edit.add(cut);
1029     edit.add(copy);
1030     edit.add(paste);
1031     //edit.add(remove);
1032     edit.add(delete);
1033     edit.add(copyKey);
1034     edit.add(copyCiteKey);
1035     //edit.add(exportToClipboard);
1036     edit.addSeparator();
1037     edit.add(mark);
1038     edit.add(unmark);
1039     edit.add(unmarkAll);
1040     edit.addSeparator();
1041     edit.add(selectAll);
1042     mb.add(edit);
1043     view.add(nextTab);
1044     view.add(prevTab);
1045       view.add(sortTabs);
1046     view.addSeparator();
1047     view.add(toggleGroups);
1048     view.add(togglePreview);
1049     view.add(switchPreview);
1050     view.addSeparator();
1051     view.add(toggleHighlightAny);
1052     view.add(toggleHighlightAll);
1053     mb.add(view);
1054
1055     bibtex.add(newEntryAction);
1056     for (int i = 0; i < newSpecificEntryAction.length; i++) {
1057       newSpec.add(newSpecificEntryAction[i]);
1058     }
1059     bibtex.add(newSpec);
1060     bibtex.add(plainTextImport);
1061     bibtex.addSeparator();
1062     bibtex.add(editEntry);
1063     bibtex.add(importCiteSeer);
1064     bibtex.add(editPreamble);
1065     bibtex.add(editStrings);
1066     mb.add(bibtex);
1067
1068     tools.add(normalSearch);
1069     tools.add(incrementalSearch);
1070     tools.add(replaceAll);
1071
1072     tools.add( makeKeyAction);
1073
1074      // [kiar] I think we should group these festures
1075      tools.add(checkAndFix) ;
1076      checkAndFix.add(dupliCheck);
1077      checkAndFix.add(strictDupliCheck);
1078      checkAndFix.add(autoSetPdf);
1079      checkAndFix.add(autoSetPs);
1080      checkAndFix.add(integrityCheckAction) ;
1081
1082
1083
1084     tools.addSeparator();
1085     tools.add(manageSelectors);
1086     tools.add(emacsPushAction);
1087     tools.add(lyxPushAction);
1088     tools.add(winEdtPushAction);
1089     //tools.add(latexEditorPushAction);
1090     //tools.add(fetchAuthorMedline);
1091     tools.addSeparator();
1092     tools.add(openFile);
1093     tools.add(openUrl);
1094     tools.addSeparator();
1095     tools.add(newSubDatabaseAction);
1096
1097       tools.addSeparator();
1098       tools.add(abbreviateIso);
1099       tools.add(abbreviateMedline);
1100       tools.add(unabbreviate);
1101
1102     mb.add(tools);
1103
1104     web.add(fetchMedline);
1105     web.add(citeSeerPanelAction);
1106     web.add(fetchCiteSeer);
1107     GeneralFetcher ieex = new GeneralFetcher(sidePaneManager, this, ieeexplorerFetcher);
1108     web.add(ieex.getAction());
1109
1110       mb.add(web);
1111
1112     options.add(showPrefs);
1113     AbstractAction customizeAction = new CustomizeEntryTypeAction();
1114     AbstractAction genFieldsCustomization = new GenFieldsCustomizationAction();
1115     options.add(customizeAction);
1116     options.add(genFieldsCustomization);
1117     options.add(customExpAction);
1118     options.add(customImpAction);
1119     options.add(manageJournals);
1120
1121     /*options.add(new AbstractAction("Font") {
1122     public void actionPerformed(ActionEvent e) {
1123         // JDialog dl = new EntryCustomizationDialog(ths);
1124         Font f=new FontSelectorDialog
1125       (ths, GUIGlobals.CURRENTFONT).getSelectedFont();
1126      if(f==null)
1127       return;
1128      else
1129       GUIGlobals.CURRENTFONT=f;
1130      // updatefont
1131      prefs.put("fontFamily", GUIGlobals.CURRENTFONT.getFamily());
1132      prefs.putInt("fontStyle", GUIGlobals.CURRENTFONT.getStyle());
1133      prefs.putInt("fontSize", GUIGlobals.CURRENTFONT.getSize());
1134      if (tabbedPane.getTabCount() > 0) {
1135       for (int i=0; i<tabbedPane.getTabCount(); i++) {
1136        baseAt(i).entryTable.updateFont();
1137        baseAt(i).refreshTable();
1138       }
1139      }
1140     }
1141     });*/
1142
1143     //options.add(selectKeys);
1144     mb.add(options);
1145
1146     helpMenu.add(help);
1147     helpMenu.add(contents);
1148     helpMenu.addSeparator();
1149 //old about    helpMenu.add(about);
1150     helpMenu.add(about);
1151     mb.add(helpMenu);
1152       helpMenu.addSeparator();
1153       helpMenu.add(errorConsole);
1154   }
1155
1156     private JMenu subMenu(String name) {
1157         name = Globals.menuTitle(name);
1158         int i = name.indexOf('&');
1159         JMenu res;
1160         if (i >= 0) {
1161             res = new JMenu(name.substring(0, i)+name.substring(i+1));
1162             char mnemonic = Character.toUpperCase(name.charAt(i+1));
1163             res.setMnemonic((int)mnemonic);
1164         }
1165         else res = new JMenu(name);
1166
1167         return res;
1168     }
1169
1170   private void createToolBar() {
1171     tlb.putClientProperty(Options.HEADER_STYLE_KEY, HeaderStyle.BOTH);
1172     tlb.setBorder(null);
1173     tlb.setRollover(true);
1174
1175     //tlb.setBorderPainted(true);
1176     //tlb.setBackground(GUIGlobals.lightGray);
1177     //tlb.setForeground(GUIGlobals.lightGray);
1178     tlb.setFloatable(false);
1179     tlb.addAction(newDatabaseAction);
1180     tlb.addAction(open);
1181     tlb.addAction(save);
1182
1183     tlb.addSeparator();
1184     tlb.addAction(cut);
1185     tlb.addAction(copy);
1186     tlb.addAction(paste);
1187     tlb.addAction(undo);
1188     tlb.addAction(redo);
1189
1190     tlb.addSeparator();
1191     tlb.addAction(newEntryAction);
1192     tlb.addAction(editEntry);
1193     tlb.addAction(editPreamble);
1194     tlb.addAction(editStrings);
1195     tlb.addAction(makeKeyAction);
1196
1197
1198     tlb.addSeparator();
1199     tlb.addAction(mark);
1200     tlb.addAction(unmark);
1201
1202     tlb.addSeparator();
1203     searchToggle = new JToggleButton(toggleSearch);
1204     searchToggle.setText(null);
1205     if (!Globals.ON_MAC)
1206         searchToggle.setMargin(marg);
1207     tlb.add(searchToggle);
1208
1209     previewToggle = new JToggleButton(togglePreview);
1210     previewToggle.setText(null);
1211     if (!Globals.ON_MAC)
1212         previewToggle.setMargin(marg);
1213     tlb.add(previewToggle);
1214     tlb.addSeparator();
1215
1216     groupToggle = new JToggleButton(toggleGroups);
1217     groupToggle.setText(null);
1218     if (!Globals.ON_MAC)
1219         groupToggle.setMargin(marg);
1220     tlb.add(groupToggle);
1221
1222
1223     highlightAny = new JToggleButton(toggleHighlightAny);
1224     highlightAny.setText(null);
1225     if (!Globals.ON_MAC)
1226         highlightAny.setMargin(marg);
1227     tlb.add(highlightAny);
1228     highlightAll = new JToggleButton(toggleHighlightAll);
1229     highlightAll.setText(null);
1230     if (!Globals.ON_MAC)
1231         highlightAll.setMargin(marg);
1232     tlb.add(highlightAll);
1233
1234     tlb.addSeparator();
1235     tlb.addAction(emacsPushAction);
1236     tlb.addAction(lyxPushAction);
1237     tlb.addAction(winEdtPushAction);
1238     tlb.addAction(openFile);
1239     tlb.addAction(openUrl);
1240
1241     //tlb.addSeparator();
1242     //tlb.addAction(showPrefs);
1243     tlb.add(Box.createHorizontalGlue());
1244     //tlb.add(new JabRefLabel(GUIGlobals.frameTitle+" "+GUIGlobals.version));
1245
1246     tlb.addAction(closeDatabaseAction);
1247     //Insets margin = new Insets(0, 0, 0, 0);
1248     //for (int i=0; i<tlb.getComponentCount(); i++)
1249     //  ((JButton)tlb.getComponentAtIndex(i)).setMargin(margin);
1250
1251   }
1252
1253   private class JabRefLabel
1254       extends JPanel {
1255     private String label;
1256     public JabRefLabel(String name) {
1257       label = name;
1258     }
1259
1260     public void paint(Graphics g) {
1261       Graphics2D g2 = (Graphics2D) g;
1262       g2.setColor(GUIGlobals.nullFieldColor);
1263       g2.setFont(GUIGlobals.jabRefFont);
1264       FontMetrics fm = g2.getFontMetrics();
1265       int width = fm.stringWidth(label);
1266       g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
1267                           RenderingHints.VALUE_ANTIALIAS_ON);
1268       g2.drawString(label, getWidth() - width - 7, getHeight() - 10);
1269
1270
1271     }
1272   }
1273
1274   private JMenuItem mItem(AbstractAction a, KeyStroke ks) {
1275     // Set up a menu item with action and accelerator key.
1276     JMenuItem mi = new JMenuItem();
1277     mi.setAction(a);
1278     if (ks != null) {
1279       mi.setAccelerator(ks);
1280     }
1281     return mi;
1282   }
1283
1284   //private void setupMainPanel() {
1285
1286
1287   /*public Completer getAutoCompleter(String field) {
1288     return (Completer)autoCompleters.get(field);
1289     }
1290
1291
1292        public void assignAutoCompleters() {
1293     // Set up which fields should have autocompletion. This should
1294     // probably be made customizable. Existing Completer objects are
1295     // forgotten. The completers must be updated towards the database.
1296     byte[] fields = prefs.getByteArray("autoCompFields");
1297     autoCompleters = new Hashtable();
1298     for (int i=0; i<fields.length; i++) {
1299    autoCompleters.put(GUIGlobals.ALL_FIELDS[fields[i]], new Completer());
1300     }
1301
1302        }
1303
1304        public void updateAutoCompleters() {
1305     if (database != null)
1306    database.setCompleters(autoCompleters);
1307    }*/
1308
1309  public void output(final String s) {
1310
1311       SwingUtilities.invokeLater(new Runnable() {
1312           public void run() {
1313               statusLine.setText(s);
1314               statusLine.repaint();
1315           }
1316       });
1317   }
1318
1319   public void stopShowingSearchResults() {
1320     for (int i = 0; i < tabbedPane.getTabCount(); i++) {
1321       baseAt(i).stopShowingSearchResults();
1322     }
1323   }
1324
1325     /**
1326      * Disable actions that demand an open database.
1327      */
1328     private void setEmptyState() {
1329         manageSelectors.setEnabled(false);
1330         mergeDatabaseAction.setEnabled(false);
1331         newSubDatabaseAction.setEnabled(false);
1332         close.setEnabled(false);
1333         save.setEnabled(false);
1334         saveAs.setEnabled(false);
1335         saveSelectedAs.setEnabled(false);
1336         nextTab.setEnabled(false);
1337         prevTab.setEnabled(false);
1338         sortTabs.setEnabled(false);
1339         undo.setEnabled(false);
1340         redo.setEnabled(false);
1341         cut.setEnabled(false);
1342         delete.setEnabled(false);
1343         copy.setEnabled(false);
1344         paste.setEnabled(false);
1345         mark.setEnabled(false);
1346         unmark.setEnabled(false);
1347         unmarkAll.setEnabled(false);
1348         editEntry.setEnabled(false);
1349         importCiteSeer.setEnabled(false);
1350         selectAll.setEnabled(false);
1351         copyKey.setEnabled(false);
1352         copyCiteKey.setEnabled(false);
1353         editPreamble.setEnabled(false);
1354         editStrings.setEnabled(false);
1355         toggleGroups.setEnabled(false);
1356         toggleSearch.setEnabled(false);
1357         makeKeyAction.setEnabled(false);
1358         emacsPushAction.setEnabled(false);
1359         lyxPushAction.setEnabled(false);
1360         winEdtPushAction.setEnabled(false);
1361         normalSearch.setEnabled(false);
1362         incrementalSearch.setEnabled(false);
1363         replaceAll.setEnabled(false);
1364         importMenu.setEnabled(false);
1365         exportMenu.setEnabled(false);
1366         fetchMedline.setEnabled(false);
1367         fetchCiteSeer.setEnabled(false);
1368         openFile.setEnabled(false);
1369         openUrl.setEnabled(false);
1370         togglePreview.setEnabled(false);
1371         dupliCheck.setEnabled(false);
1372         strictDupliCheck.setEnabled(false);
1373         highlightAll.setEnabled(false);
1374         highlightAny.setEnabled(false);
1375         citeSeerPanelAction.setEnabled(false);
1376         for (int i = 0; i < newSpecificEntryAction.length; i++) {
1377             newSpecificEntryAction[i].setEnabled(false);
1378         }
1379         newEntryAction.setEnabled(false);
1380         plainTextImport.setEnabled(false);
1381         closeDatabaseAction.setEnabled(false);
1382         switchPreview.setEnabled(false);
1383         integrityCheckAction.setEnabled(false);
1384         autoSetPdf.setEnabled(false);
1385         autoSetPs.setEnabled(false);
1386         toggleHighlightAny.setEnabled(false);
1387         toggleHighlightAll.setEnabled(false);
1388         databaseProperties.setEnabled(false);
1389         abbreviateIso.setEnabled(false);
1390         abbreviateMedline.setEnabled(false);
1391         unabbreviate.setEnabled(false);
1392     }
1393
1394     /**
1395      * Enable actions that demand an open database.
1396      */
1397     private void setNonEmptyState() {
1398         manageSelectors.setEnabled(true);
1399         mergeDatabaseAction.setEnabled(true);
1400         newSubDatabaseAction.setEnabled(true);
1401         close.setEnabled(true);
1402         save.setEnabled(true);
1403         saveAs.setEnabled(true);
1404         saveSelectedAs.setEnabled(true);
1405         undo.setEnabled(true);
1406         redo.setEnabled(true);
1407         cut.setEnabled(true);
1408         delete.setEnabled(true);
1409         copy.setEnabled(true);
1410         paste.setEnabled(true);
1411         mark.setEnabled(true);
1412         unmark.setEnabled(true);
1413         unmarkAll.setEnabled(true);
1414         editEntry.setEnabled(true);
1415         importCiteSeer.setEnabled(true);
1416         selectAll.setEnabled(true);
1417         copyKey.setEnabled(true);
1418         copyCiteKey.setEnabled(true);
1419         editPreamble.setEnabled(true);
1420         editStrings.setEnabled(true);
1421         toggleGroups.setEnabled(true);
1422         toggleSearch.setEnabled(true);
1423         makeKeyAction.setEnabled(true);
1424         emacsPushAction.setEnabled(true);
1425         lyxPushAction.setEnabled(true);
1426         winEdtPushAction.setEnabled(true);
1427         normalSearch.setEnabled(true);
1428         incrementalSearch.setEnabled(true);
1429         replaceAll.setEnabled(true);
1430         importMenu.setEnabled(true);
1431         exportMenu.setEnabled(true);
1432         fetchMedline.setEnabled(true);
1433         fetchCiteSeer.setEnabled(true);
1434         openFile.setEnabled(true);
1435         openUrl.setEnabled(true);
1436         togglePreview.setEnabled(true);
1437         dupliCheck.setEnabled(true);
1438         strictDupliCheck.setEnabled(true);
1439         highlightAll.setEnabled(true);
1440         highlightAny.setEnabled(true);
1441         citeSeerPanelAction.setEnabled(true);
1442         for (int i = 0; i < newSpecificEntryAction.length; i++) {
1443             newSpecificEntryAction[i].setEnabled(true);
1444         }
1445         newEntryAction.setEnabled(true);
1446         plainTextImport.setEnabled(true);
1447         closeDatabaseAction.setEnabled(true);
1448         switchPreview.setEnabled(true);
1449         integrityCheckAction.setEnabled(true);
1450         autoSetPdf.setEnabled(true);
1451         autoSetPs.setEnabled(true);
1452         toggleHighlightAny.setEnabled(true);
1453         toggleHighlightAll.setEnabled(true);
1454         databaseProperties.setEnabled(true);
1455         abbreviateIso.setEnabled(true);
1456         abbreviateMedline.setEnabled(true);
1457         unabbreviate.setEnabled(true);
1458     }
1459
1460     /**
1461      * Disable actions that need more than one database open.
1462      */
1463     private void setOnlyOne() {
1464         nextTab.setEnabled(false);
1465         prevTab.setEnabled(false);
1466         sortTabs.setEnabled(false);
1467     }
1468
1469     /**
1470      * Disable actions that need more than one database open.
1471      */
1472     private void setMultiple() {
1473         nextTab.setEnabled(true);
1474         prevTab.setEnabled(true);
1475         sortTabs.setEnabled(true);
1476     }
1477
1478   /**
1479    * This method causes all open BasePanels to set up their tables
1480    * anew. When called from PrefsDialog2, this updates to the new
1481    * settings.
1482    */
1483   public void setupAllTables() {
1484     // This action can be invoked without an open database, so
1485     // we have to check if we have one before trying to invoke
1486     // methods to execute changes in the preferences.
1487
1488     // We want to notify all tabs about the changes to
1489     // avoid problems when changing the column set.
1490     for (int i = 0; i < tabbedPane.getTabCount(); i++) {
1491       BasePanel bf = baseAt(i);
1492
1493       // Update tables:
1494       if (bf.database != null) {
1495         bf.setupMainPanel();
1496
1497       }
1498
1499     }
1500   }
1501
1502   public BasePanel addTab(BibtexDatabase db, File file, HashMap meta, String encoding, boolean raisePanel) {
1503       BasePanel bp = new BasePanel(ths, db, file, meta, encoding);
1504       addTab(bp, file, raisePanel);
1505       return bp;
1506   }
1507
1508     public void addTab(BasePanel bp, File file, boolean raisePanel) {
1509         tabbedPane.add((file != null ? file.getName(): Globals.lang(GUIGlobals.untitledTitle)),
1510                        bp);
1511         if (raisePanel) {
1512             tabbedPane.setSelectedComponent(bp);
1513         }
1514         if (tabbedPane.getTabCount() == 1) {
1515             setNonEmptyState();
1516         } else if (tabbedPane.getTabCount() == 2) {
1517             setMultiple();
1518         }
1519     }
1520
1521   class SelectKeysAction
1522       extends AbstractAction {
1523     public SelectKeysAction() {
1524       super(Globals.lang("Customize key bindings"));
1525     }
1526
1527     public void actionPerformed(ActionEvent e) {
1528       KeyBindingsDialog d = new KeyBindingsDialog
1529           ( (HashMap) prefs.getKeyBindings().clone(),
1530            prefs.getDefaultKeys());
1531       d.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
1532       d.pack(); //setSize(300,500);
1533       Util.placeDialog(d, ths);
1534       d.setVisible(true);
1535       if (d.getAction()) {
1536         prefs.setNewKeyBindings(d.getNewKeyBindings());
1537         JOptionPane.showMessageDialog
1538             (ths,
1539              Globals.lang("Your new key bindings have been stored.") + "\n"
1540              + Globals.lang("You must restart JabRef for the new key "
1541                             + "bindings to work properly."),
1542              Globals.lang("Key bindings changed"),
1543              JOptionPane.INFORMATION_MESSAGE);
1544       }
1545     }
1546   }
1547
1548   /**
1549    * The action concerned with closing the window.
1550    */
1551   class CloseAction
1552       extends MnemonicAwareAction {
1553     public CloseAction() {
1554       putValue(NAME, "Quit");
1555       putValue(SHORT_DESCRIPTION, Globals.lang("Quit JabRef"));
1556       putValue(ACCELERATOR_KEY, prefs.getKey("Quit JabRef"));
1557       //putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_Q,
1558       //    Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
1559
1560     }
1561
1562     public void actionPerformed(ActionEvent e) {
1563       quit();
1564     }
1565   }
1566
1567   // The action for closing the current database and leaving the window open.
1568   CloseDatabaseAction closeDatabaseAction = new CloseDatabaseAction();
1569   class CloseDatabaseAction
1570       extends MnemonicAwareAction {
1571     public CloseDatabaseAction() {
1572         super(new ImageIcon(GUIGlobals.closeIconFile));
1573         putValue(NAME, "Close database");
1574         putValue(SHORT_DESCRIPTION,
1575                  Globals.lang("Close the current database"));
1576         putValue(ACCELERATOR_KEY, prefs.getKey("Close database"));
1577     }
1578
1579     public void actionPerformed(ActionEvent e) {
1580       // Ask here if the user really wants to close, if the base
1581       // has not been saved since last save.
1582       boolean close = true;
1583       if (basePanel() == null) { // when it is initially empty
1584         return; //nbatada nov 7
1585       }
1586
1587       if (basePanel().baseChanged) {
1588         int answer = JOptionPane.showConfirmDialog
1589             (ths, Globals.lang("Database has changed. Do you want to save " +
1590                                "before closing?"),
1591              Globals.lang("Save before closing"),
1592              JOptionPane.YES_NO_CANCEL_OPTION);
1593         if ( (answer == JOptionPane.CANCEL_OPTION) ||
1594             (answer == JOptionPane.CLOSED_OPTION)) {
1595           close = false; // The user has cancelled.
1596         }
1597         if (answer == JOptionPane.YES_OPTION) {
1598           // The user wants to save.
1599           try {
1600             basePanel().runCommand("save");
1601           }
1602           catch (Throwable ex) {
1603             // Something prevented the file
1604             // from being saved. Break!!!
1605             close = false;
1606           }
1607
1608         }
1609       }
1610
1611       if (close) {
1612         basePanel().cleanUp();
1613         tabbedPane.remove(basePanel());
1614         if (tabbedPane.getTabCount() == 0) {
1615           setEmptyState();
1616         } else
1617         {
1618             sidePaneManager.stateChanged(new ChangeEvent(tabbedPane));
1619           markActiveBasePanel() ;
1620           if (tabbedPane.getTabCount() == 1) { setOnlyOne() ; }
1621         }
1622         output(Globals.lang("Closed database") + ".");
1623           System.gc(); // Test
1624       }
1625     }
1626   }
1627
1628
1629   // The action concerned with opening a new database.
1630   class NewDatabaseAction
1631       extends MnemonicAwareAction {
1632     public NewDatabaseAction() {
1633         super(new ImageIcon(GUIGlobals.newIconFile));
1634         putValue(NAME, "New database");
1635         putValue(SHORT_DESCRIPTION, Globals.lang("New BibTeX database"));
1636         //putValue(MNEMONIC_KEY, GUIGlobals.newKeyCode);
1637     }
1638
1639     public void actionPerformed(ActionEvent e) {
1640         // Create a new, empty, database.
1641         BibtexDatabase database = new BibtexDatabase();
1642         addTab(database, null, null, Globals.prefs.get("defaultEncoding"), true);
1643         output(Globals.lang("New database created."));
1644     }
1645   }
1646
1647 class ImportCiteSeerAction
1648         extends MnemonicAwareAction {
1649
1650     public ImportCiteSeerAction() {
1651         super(new ImageIcon(GUIGlobals.wwwCiteSeerIcon));
1652         putValue(NAME, "Import Fields from CiteSeer");
1653         putValue(SHORT_DESCRIPTION, Globals.lang("Import Fields from CiteSeer Database"));
1654         putValue(ACCELERATOR_KEY, prefs.getKey("Import Fields from CiteSeer")); // Key defined in MenuTitles!
1655         }
1656
1657         public void actionPerformed(ActionEvent e) {
1658
1659                 if(citeSeerFetcher.activateImportFetcher()) {
1660
1661
1662                         (new Thread() {
1663
1664                                 BasePanel currentBp;
1665                                 BibtexEntry toShow;
1666                                 //String id;
1667                                 int[] clickedOn = null;
1668
1669                                 class UpdateComponent implements Runnable {
1670                                         boolean changesMade;
1671
1672                                         UpdateComponent(boolean changesMade) {
1673                                                 this.changesMade = changesMade;
1674                                         }
1675
1676                                         public void run() {
1677                                             citeSeerFetcher.endImportCiteSeerProgress();
1678                                             if (changesMade)
1679                                                     currentBp.markBaseChanged();
1680                                                 //for(int i=0; i < clickedOn.length; i++)
1681                                                 //        currentBp.entryTable.addRowSelectionInterval(i,i);
1682                                                 //currentBp.showEntry(toShow);
1683                                                 output(Globals.lang("Completed Import Fields from CiteSeer."));
1684                                         }
1685                                 }
1686
1687                             public void run() {
1688                                 currentBp = (BasePanel) tabbedPane.getSelectedComponent();
1689                                         // We demand that at least one row is selected.
1690
1691                                         int rowCount = currentBp.mainTable.getSelectedRowCount();
1692                                         if (rowCount >= 1) {
1693                                                 clickedOn = currentBp.mainTable.getSelectedRows();
1694                                         } else {
1695                                                 JOptionPane.showMessageDialog(currentBp.frame(),
1696                                                 Globals.lang("You must select at least one row to perform this operation."),
1697                                                 Globals.lang("CiteSeer Import Error"),
1698                                                 JOptionPane.WARNING_MESSAGE);
1699                                         }
1700                                         toShow = (BibtexEntry)currentBp.mainTable.getSelected().get(0);
1701                                         if (clickedOn != null) {
1702                                                 citeSeerFetcher.beginImportCiteSeerProgress();
1703                                                 NamedCompound citeseerNamedCompound =
1704                                                         new NamedCompound(Globals.lang("CiteSeer Import Fields"));
1705                                                 boolean newValues = citeSeerFetcher.importCiteSeerEntries(clickedOn, citeseerNamedCompound);
1706                                                 if (newValues) {
1707                                                         citeseerNamedCompound.end();
1708                                                         currentBp.undoManager.addEdit(citeseerNamedCompound);
1709                                                 }
1710                                                 UpdateComponent updateComponent = new UpdateComponent(newValues);
1711                                                 SwingUtilities.invokeLater(updateComponent);
1712                                         }
1713                                         citeSeerFetcher.deactivateImportFetcher();
1714                             }
1715                         }).start();
1716                 } else {
1717                         JOptionPane.showMessageDialog(tabbedPane.getSelectedComponent(),
1718                                         Globals.lang("A CiteSeer import operation is currently in progress.") + "  " +
1719                                         Globals.lang("Please wait until it has finished."),
1720                                         Globals.lang("CiteSeer Import Error"),
1721                                         JOptionPane.WARNING_MESSAGE);
1722                 }
1723         }
1724 }
1725
1726 class FetchCiteSeerAction
1727         extends MnemonicAwareAction {
1728
1729                 public FetchCiteSeerAction() {
1730                     super(new ImageIcon(GUIGlobals.wwwCiteSeerIcon));
1731                     putValue(NAME, "Fetch citations from CiteSeer");
1732
1733                     putValue(SHORT_DESCRIPTION, Globals.lang("Fetch Articles Citing your Database"));
1734                     putValue(ACCELERATOR_KEY, prefs.getKey("Fetch citations from CiteSeer"));
1735                 }
1736
1737                 public void actionPerformed(ActionEvent e) {
1738
1739                         if(citeSeerFetcher.activateCitationFetcher()) {
1740                                 sidePaneManager.ensureVisible("CiteSeerProgress");
1741                                 (new Thread() {
1742                                         BasePanel newBp;
1743                                         BasePanel targetBp;
1744                                         BibtexDatabase newDatabase;
1745                                         BibtexDatabase targetDatabase;
1746
1747                                         Runnable updateComponent = new Runnable() {
1748
1749                                                 /* TODO: This should probably be selectable on/off
1750                                                  * in the preferences window, but for now all
1751                                                  * Citation fetcher operations will sort by citation count.
1752                                                  */
1753                                                 private void setSortingByCitationCount() {
1754                                                         newBp.sortingByCiteSeerResults = true;
1755                                                 }
1756
1757                                                 public void run() {
1758                                                         setSortingByCitationCount();
1759                                                         tabbedPane.add(Globals.lang(GUIGlobals.untitledTitle), newBp);
1760                                                         tabbedPane.setSelectedComponent(newBp);
1761                                                         output(Globals.lang("Fetched all citations from target database."));
1762                                                         citeSeerFetcher.deactivateCitationFetcher();
1763                                                 }
1764                                         };
1765
1766                                   public void run() {
1767                                         try {
1768                                                 newBp = new BasePanel(ths);
1769                                                 int errorCode;
1770                                                 targetBp = (BasePanel) tabbedPane.getSelectedComponent();
1771                                                 newDatabase = newBp.getDatabase();
1772                                                 targetDatabase = targetBp.getDatabase();
1773                                                 errorCode = citeSeerFetcher.populate(newDatabase, targetDatabase);
1774                                                 if (newDatabase.getEntryCount() > 0) {
1775                                                         SwingUtilities.invokeLater(updateComponent);
1776                                                 } else if(errorCode == 0) {
1777                                                         SwingUtilities.invokeLater(citeSeerFetcher.getEmptyFetchSetDialog());
1778                                             } else {
1779                                                     citeSeerFetcher.deactivateCitationFetcher();
1780                                             }
1781                                         }
1782                                         catch (Exception ex) {
1783                                           ex.printStackTrace();
1784                                         }
1785                                   }
1786                                 }).start();
1787                         } else {
1788                             JOptionPane.showMessageDialog(tabbedPane.getSelectedComponent(),
1789                                                 Globals.lang("A CiteSeer fetch operation is currently in progress.") + "  " +
1790                                                 Globals.lang("Please wait until it has finished."),
1791                                                 Globals.lang("CiteSeer Fetch Error"),
1792                                                 JOptionPane.WARNING_MESSAGE);
1793                         }
1794                 }
1795         }
1796
1797
1798
1799     // The action concerned with generate a new (sub-)database from latex aux file.
1800     class NewSubDatabaseAction extends MnemonicAwareAction
1801     {
1802       public NewSubDatabaseAction()
1803       {
1804         super(new ImageIcon( GUIGlobals.newBibFile));
1805         putValue(NAME, "New subdatabase based on AUX file" );
1806         putValue( SHORT_DESCRIPTION, Globals.lang( "New BibTeX subdatabase" ) ) ;
1807             //putValue(MNEMONIC_KEY, GUIGlobals.newKeyCode);
1808       }
1809
1810       public void actionPerformed( ActionEvent e )
1811       {
1812         // Create a new, empty, database.
1813
1814         FromAuxDialog dialog = new FromAuxDialog(ths, "", true, ths.tabbedPane) ;
1815
1816         Util.placeDialog(dialog, ths);
1817         dialog.setVisible(true) ;
1818
1819         if (dialog.okPressed())
1820         {
1821           BasePanel bp = new BasePanel( ths,
1822                                         dialog.getGenerateDB(),   // database
1823                                         null,                     // file
1824                                         null, Globals.prefs.get("defaultEncoding"));                     // meta data
1825           tabbedPane.add( Globals.lang( GUIGlobals.untitledTitle ), bp ) ;
1826           tabbedPane.setSelectedComponent( bp ) ;
1827           if ( tabbedPane.getTabCount() == 1 )
1828           {
1829             setNonEmptyState() ;
1830           }
1831           output( Globals.lang( "New database created." ) ) ;
1832         }
1833       }
1834     }
1835
1836
1837     // The action should test the database and report errors/warnings
1838     class IntegrityCheckAction extends AbstractAction
1839     {
1840       public IntegrityCheckAction()
1841       {
1842         super(Globals.menuTitle("Integrity check"),
1843                new ImageIcon( GUIGlobals.integrityCheck ) ) ;
1844                //putValue( SHORT_DESCRIPTION, "integrity" ) ;  //Globals.lang( "integrity" ) ) ;
1845             //putValue(MNEMONIC_KEY, GUIGlobals.newKeyCode);
1846       }
1847
1848       public void actionPerformed( ActionEvent e )
1849       {
1850        Object selComp = tabbedPane.getSelectedComponent() ;
1851        if (selComp != null)
1852        {
1853          BasePanel bp = ( BasePanel ) selComp ;
1854          BibtexDatabase refBase = bp.getDatabase() ;
1855          if (refBase != null)
1856          {
1857              IntegrityWizard wizard = new IntegrityWizard(ths, basePanel()) ;
1858              Util.placeDialog(wizard, ths);
1859              wizard.setVisible(true) ;
1860
1861          }
1862        }
1863       }
1864     }
1865
1866   class FetchMedlineAction
1867       extends MnemonicAwareAction {
1868     public FetchMedlineAction() {
1869       super(new ImageIcon(GUIGlobals.fetchMedlineIcon));
1870       putValue(NAME, "Fetch Medline");
1871       putValue(ACCELERATOR_KEY, prefs.getKey("Fetch Medline"));
1872       putValue(SHORT_DESCRIPTION, Globals.lang("Fetch Medline by ID"));
1873     }
1874
1875     public void actionPerformed(ActionEvent e) {
1876       if (tabbedPane.getTabCount() > 0) {
1877         //for (int i = 0; i < tabbedPane.getTabCount(); i++) {
1878         //  ( (BasePanel) tabbedPane.getComponentAt(i)).sidePaneManager.
1879         sidePaneManager.togglePanel("fetchMedline");// ensureVisible("fetchMedline");
1880         if (sidePaneManager.isPanelVisible("fetchMedline"))
1881           new FocusRequester(medlineFetcher.getTextField());
1882         //}
1883       }
1884     }
1885
1886   }
1887
1888   class CiteSeerPanelAction
1889       extends MnemonicAwareAction {
1890     public CiteSeerPanelAction() {
1891       super(new ImageIcon(GUIGlobals.fetchMedlineIcon));
1892       putValue(NAME, "Fetch CiteSeer");
1893       //System.out.println(Globals.menuTitle("Fetch CiteSeer"));
1894       putValue(ACCELERATOR_KEY, prefs.getKey("Fetch CiteSeer"));
1895     }
1896
1897     public void actionPerformed(ActionEvent e) {
1898       if (tabbedPane.getTabCount() > 0) {
1899           sidePaneManager.togglePanel("CiteSeerPanel");// ensureVisible("fetchMedline");
1900           if (sidePaneManager.isPanelVisible("CiteSeerPanel"))
1901           new FocusRequester(citeSeerFetcherPanel.getTextField());
1902         //}
1903       }
1904     }
1905
1906   }
1907
1908     /*class FetchAuthorMedlineAction
1909       extends AbstractAction {
1910     public FetchAuthorMedlineAction() {
1911       super(Globals.lang("Fetch Medline by author"),
1912             new ImageIcon(GUIGlobals.fetchMedlineIcon));
1913       putValue(SHORT_DESCRIPTION, Globals.lang("Fetch Medline by author"));
1914     }
1915
1916     public void actionPerformed(ActionEvent e) {
1917       if (tabbedPane.getTabCount() > 0) {
1918         for (int i = 0; i < tabbedPane.getTabCount(); i++) {
1919           ( (BasePanel) tabbedPane.getComponentAt(i)).sidePaneManager.
1920               ensureVisible("fetchAuthorMedline");
1921           new FocusRequester(basePanel().medlineFetcher);
1922         }
1923       }
1924     }
1925
1926     }*/
1927
1928   // The action for opening the preferences dialog.
1929
1930   AbstractAction showPrefs = new ShowPrefsAction();
1931
1932   class ShowPrefsAction
1933       extends MnemonicAwareAction {
1934     public ShowPrefsAction() {
1935       super(new ImageIcon(GUIGlobals.prefsIconFile));
1936       putValue(NAME, "Preferences");
1937       putValue(SHORT_DESCRIPTION, Globals.lang("Preferences"));
1938     }
1939
1940     public void actionPerformed(ActionEvent e) {
1941       preferences();
1942     }
1943   }
1944
1945   /**
1946    * This method does the job of adding imported entries into the active database, or into a new one.
1947    * It shows the ImportInspectionDialog if preferences indicate it should be used. Otherwise it imports
1948    * directly.
1949    * @param panel The BasePanel to add to.
1950    * @param entries The entries to add.
1951    * @param filename Name of the file where the import came from.
1952    * @param openInNew Should the entries be imported into a new database?
1953    * @param callBack The callback for the ImportInspectionDialog to use.
1954    */
1955   public void addImportedEntries(final BasePanel panel, final List entries, String filename, boolean openInNew,
1956                                  ImportInspectionDialog.CallBack callBack) {
1957       // Use the import inspection dialog if it is enabled in preferences, and (there are more than
1958       // one entry or the inspection dialog is also enabled for single entries):
1959       if (Globals.prefs.getBoolean("useImportInspectionDialog") &&
1960               (Globals.prefs.getBoolean("useImportInspectionDialogForSingle") || (entries.size() > 1))) {
1961                 ImportInspectionDialog diag = new ImportInspectionDialog(ths, panel,
1962                         BibtexFields.DEFAULT_INSPECTION_FIELDS,
1963                         Globals.lang("Import"), openInNew);
1964                 diag.addEntries(entries);
1965                 diag.addCallBack(callBack);
1966                 diag.entryListComplete();
1967                 Util.placeDialog(diag, ths);
1968                 diag.setVisible(true);
1969         diag.toFront();
1970         } else {
1971             ths.addBibEntries(entries, filename, openInNew);
1972           if ((panel != null) && (entries.size() == 1)) {
1973               SwingUtilities.invokeLater(new Runnable() {
1974                   public void run() {
1975                       panel.highlightEntry((BibtexEntry)entries.get(0));
1976                   }
1977               });
1978
1979
1980           }
1981        }
1982   }
1983
1984     /**
1985      * Adds the entries to the database, possibly checking for duplicates first.
1986      * @param filename If non-null, a message is printed to the status line describing
1987      * how many entries were imported, and from which file. If null, the message will not
1988      * be printed.
1989      * @param intoNew Determines if the entries will be put in a new database or in the current
1990      * one.
1991      */
1992   public int addBibEntries(java.util.List bibentries, String filename,
1993                            boolean intoNew) {
1994           if (bibentries == null || bibentries.size() == 0) {
1995
1996       // No entries found. We need a message for this.
1997       JOptionPane.showMessageDialog(ths, Globals.lang("No entries found. Please make sure you are "
1998                                                       +"using the correct import filter."), Globals.lang("Import failed"),
1999                                     JOptionPane.ERROR_MESSAGE);
2000       return 0;
2001     }
2002
2003       int addedEntries = 0;
2004
2005     // Set owner and timestamp fields:
2006     Util.setAutomaticFields(bibentries);
2007
2008     if (intoNew || (tabbedPane.getTabCount() == 0)) {
2009       // Import into new database.
2010       BibtexDatabase database = new BibtexDatabase();
2011       Iterator it = bibentries.iterator();
2012       while (it.hasNext()) {
2013         BibtexEntry entry = (BibtexEntry) it.next();
2014
2015         try {
2016           entry.setId(Util.createNeutralId());
2017           database.insertEntry(entry);
2018         }
2019         catch (KeyCollisionException ex) {
2020           //ignore
2021           System.err.println("KeyCollisionException [ addBibEntries(...) ]");
2022         }
2023       }
2024       HashMap meta = new HashMap();
2025       // Metadata are only put in bibtex files, so we will not find it
2026       // in imported files. Instead we pass an empty HashMap.
2027       BasePanel bp = new BasePanel(ths, database, null, meta, Globals.prefs.get("defaultEncoding"));
2028       /*
2029             if (prefs.getBoolean("autoComplete")) {
2030             db.setCompleters(autoCompleters);
2031             }
2032        */
2033       addedEntries = database.getEntryCount();
2034       tabbedPane.add(Globals.lang("untitled"), bp);
2035       bp.markBaseChanged();
2036       tabbedPane.setSelectedComponent(bp);
2037       if (tabbedPane.getTabCount() == 1) {
2038         setNonEmptyState();
2039       }
2040       if (filename != null)
2041           output(Globals.lang("Imported database") + " '" + filename + "' " +
2042                  Globals.lang("with") + " " +
2043                  database.getEntryCount() + " " +
2044                  Globals.lang("entries into new database") + ".");
2045     }
2046     else {
2047       // Import into current database.
2048       boolean checkForDuplicates = true;
2049       BasePanel basePanel = basePanel();
2050       BibtexDatabase database = basePanel.database;
2051       int oldCount = database.getEntryCount();
2052       NamedCompound ce = new NamedCompound(Globals.lang("Import entries"));
2053       Iterator it = bibentries.iterator();
2054
2055       mainLoop: while (it.hasNext()) {
2056         BibtexEntry entry = (BibtexEntry) it.next();
2057         boolean dupli = false;
2058         // Check for duplicates among the current entries:
2059         if (checkForDuplicates) {
2060             loop: for (Iterator i2=database.getKeySet().iterator();
2061                        i2.hasNext();) {
2062                 BibtexEntry existingEntry = database.getEntryById((String)i2.next());
2063                 if (Util.isDuplicate(entry, existingEntry,
2064                                      Globals.duplicateThreshold)) {
2065                     DuplicateResolverDialog drd = new DuplicateResolverDialog
2066                         (ths, existingEntry, entry, DuplicateResolverDialog.IMPORT_CHECK);
2067                     drd.setVisible(true);
2068                     int res = drd.getSelected();
2069                     if (res == DuplicateResolverDialog.KEEP_LOWER)   {
2070                         dupli = true;
2071                     }
2072                     else if (res == DuplicateResolverDialog.KEEP_UPPER) {
2073                         database.removeEntry(existingEntry.getId());
2074                         ce.addEdit(new UndoableRemoveEntry
2075                                    (database, existingEntry, basePanel));
2076                     } else if (res == DuplicateResolverDialog.BREAK) {
2077                         break mainLoop;
2078                     }
2079                     break loop;
2080                 }
2081             }
2082         }
2083
2084         if (!dupli) {
2085             try {
2086                 entry.setId(Util.createNeutralId());
2087                 database.insertEntry(entry);
2088                 ce.addEdit(new UndoableInsertEntry
2089                            (database, entry, basePanel));
2090                 addedEntries++;
2091             }
2092             catch (KeyCollisionException ex) {
2093                 //ignore
2094                 System.err.println("KeyCollisionException [ addBibEntries(...) ]");
2095             }
2096         }
2097       }
2098         if (addedEntries > 0) {
2099             ce.end();
2100             basePanel.undoManager.addEdit(ce);
2101             basePanel.markBaseChanged();
2102             if (filename != null)
2103                 output(Globals.lang("Imported database") + " '" + filename + "' " +
2104                      Globals.lang("with") + " " +
2105                      (database.getEntryCount() - oldCount) + " " +
2106                      Globals.lang("entries into new database") + ".");
2107         }
2108
2109     }
2110
2111     return addedEntries;
2112   }
2113
2114   private void setUpImportMenu(JMenu importMenu, boolean intoNew_) {
2115       final boolean intoNew = intoNew_;
2116       importMenu.removeAll();
2117
2118       // Add a menu item for autodetecting import format:
2119       importMenu.add(new ImportMenuItem(ths, intoNew));
2120
2121       // Add custom importers
2122       importMenu.addSeparator();
2123
2124       SortedSet customImporters = Globals.importFormatReader.getCustomImportFormats();
2125       JMenu submenu = new JMenu(Globals.lang("Custom importers"));
2126       submenu.setMnemonic(KeyEvent.VK_S);
2127       if (customImporters.size() == 0) {
2128         submenu.setEnabled(false);
2129         submenu.setToolTipText(Globals.lang("No custom imports registered yet."));
2130       } else {
2131         // Put in all formatters registered in ImportFormatReader:
2132         for (Iterator i=customImporters.iterator(); i.hasNext();) {
2133             ImportFormat imFo = (ImportFormat)i.next();
2134             submenu.add(new ImportMenuItem(ths, intoNew, imFo));
2135         }
2136       }
2137
2138       importMenu.add(submenu);
2139       importMenu.addSeparator();
2140
2141       // Put in all formatters registered in ImportFormatReader:
2142       for (Iterator i=Globals.importFormatReader.getBuiltInInputFormats().iterator(); i.hasNext();) {
2143           ImportFormat imFo = (ImportFormat)i.next();
2144           importMenu.add(new ImportMenuItem(ths, intoNew, imFo));
2145       }
2146   }
2147
2148
2149     public FileHistory getFileHistory() {
2150         return fileHistory;
2151     }
2152
2153   JMenuItem
2154       htmlItem = new JMenuItem(Globals.lang("HTML")),
2155       simpleHtmlItem = new JMenuItem(Globals.lang("Simple HTML")),
2156       //plainTextItem = new JMenuItem(Globals.lang("Plain text")),
2157       docbookItem = new JMenuItem(Globals.lang("Docbook")),
2158       bibtexmlItem = new JMenuItem(Globals.lang("BibTeXML")),
2159       modsItem = new JMenuItem(Globals.lang("MODS")),
2160       rtfItem = new JMenuItem(Globals.lang("Harvard RTF")),
2161       endnoteItem = new JMenuItem(Globals.lang("Endnote")),
2162       openofficeItem = new JMenuItem("OpenOffice Calc"),
2163       odsItem = new JMenuItem("OpenDocument Spreadsheet");
2164
2165
2166
2167
2168   private void setUpExportMenu(JMenu menu) {
2169       ActionListener listener = new ActionListener() {
2170           public void actionPerformed(ActionEvent e) {
2171               JMenuItem source = (JMenuItem) e.getSource();
2172               String lfFileName = null, extension = null;
2173               if (source == htmlItem) {
2174                   lfFileName = "html";
2175                   extension = ".html";
2176               }
2177               else if (source == simpleHtmlItem) {
2178                   lfFileName = "simplehtml";
2179                   extension = ".html";
2180               } else if (source == docbookItem) {
2181                   lfFileName = "docbook";
2182                   extension = ".xml";
2183               } else if (source == bibtexmlItem) {
2184                   lfFileName = "bibtexml";
2185                   extension = ".xml";
2186               } else if (source == modsItem) {
2187                   lfFileName = "mods";
2188                   extension = ".xml";
2189               } else if (source == rtfItem) {
2190                   lfFileName = "harvard";
2191                   extension = ".rtf";
2192               } else if (source == endnoteItem) {
2193                   lfFileName = "endnote";
2194                   extension = ".txt";
2195               } else if (source == openofficeItem) {
2196                   lfFileName = "oocalc";
2197                   extension = ".sxc";
2198               } else if (source == odsItem) {
2199                   lfFileName = "ods";
2200                   extension = ".ods";
2201               }
2202               // We need to find out:
2203               // 1. The layout definition string to use. Or, rather, we
2204               //    must provide a Reader for the layout definition.
2205               // 2. The preferred extension for the layout format.
2206               // 3. The name of the file to use.
2207               final String chosenFile = Globals.getNewFile(ths, new File(prefs.get("workingDirectory")),
2208                       extension, JFileChooser.SAVE_DIALOG, false);
2209               final String exportName = lfFileName;
2210               if (chosenFile == null)
2211                   return;
2212
2213               (new Thread() {
2214                   public void run() {
2215                       try {
2216                           FileActions.performExport(basePanel().database(), exportName,
2217                                   chosenFile, basePanel().getEncoding());
2218                           output(Globals.lang("Exported database to file") + " '" +
2219                                   chosenFile + "'.");
2220                       }
2221                       catch (Exception ex) {
2222                           ex.printStackTrace();
2223                       }
2224                   }
2225               }).start();
2226
2227           }
2228       };
2229
2230       htmlItem.addActionListener(listener);
2231       menu.add(htmlItem);
2232       simpleHtmlItem.addActionListener(listener);
2233       menu.add(simpleHtmlItem);
2234       //plainTextItem.addActionListener(listener);
2235       //menu.add(plainTextItem);
2236       bibtexmlItem.addActionListener(listener);
2237       menu.add(bibtexmlItem);
2238       docbookItem.addActionListener(listener);
2239       menu.add(docbookItem);
2240       modsItem.addActionListener(listener);
2241       menu.add(modsItem);
2242       rtfItem.addActionListener(listener);
2243       menu.add(rtfItem);
2244       endnoteItem.addActionListener(listener);
2245       menu.add(endnoteItem);
2246       openofficeItem.addActionListener(listener);
2247       odsItem.addActionListener(listener);
2248       menu.add(openofficeItem);
2249       menu.add(odsItem);
2250       menu.add(exportCSV);
2251
2252       menu.addSeparator();
2253       menu.add(expandEndnoteZip);
2254
2255   }
2256
2257   /**
2258    * Interrogates the list of custom export formats defined, and adds them to the custom
2259    * export menu.
2260    */
2261   public void setUpCustomExportMenu() {
2262     customExportMenu.removeAll();
2263     for (int i=0; i<prefs.customExports.size(); i++) {
2264       String[] s = prefs.customExports.getElementAt(i);
2265       customExportMenu.add(new CustomExportAction(s[0], s[2], s[1]));
2266     }
2267
2268   }
2269
2270     /**
2271      * Set the preview active state for all BasePanel instances.
2272      * @param enabled
2273      */
2274     public void setPreviewActive(boolean enabled) {
2275         for (int i=0; i<tabbedPane.getTabCount(); i++) {
2276             baseAt(i).setPreviewActive(enabled);
2277         }
2278     }
2279
2280
2281    public void removeCachedEntryEditors() {
2282        for (int j=0; j<tabbedPane.getTabCount(); j++) {
2283             BasePanel bp = (BasePanel)tabbedPane.getComponentAt(j);
2284             bp.entryEditors.clear();
2285        }
2286    }
2287
2288     /**
2289      * This method shows a wait cursor and blocks all input to the JFrame's contents.
2290      */
2291     public void block() {
2292         getGlassPane().setVisible(true);
2293         //getGlassPane().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
2294     }
2295
2296     /**
2297      * This method reverts the cursor to normal, and stops blocking input to the JFrame's contents.
2298      */
2299     public void unblock() {
2300         getGlassPane().setVisible(false);
2301         //      getGlassPane().setCursor(Cursor.WAIT_CURSOR);
2302     }
2303
2304
2305
2306 class SaveSessionAction
2307       extends MnemonicAwareAction {
2308     public SaveSessionAction() {
2309       super(new ImageIcon(GUIGlobals.saveIconFile));
2310       putValue(NAME, "Save session");
2311       putValue(ACCELERATOR_KEY, prefs.getKey("Save session"));
2312     }
2313
2314     public void actionPerformed(ActionEvent e) {
2315       // Here we store the names of allcurrent filea. If
2316       // there is no current file, we remove any
2317       // previously stored file name.
2318       Vector filenames = new Vector();
2319       if (tabbedPane.getTabCount() > 0) {
2320         for (int i = 0; i < tabbedPane.getTabCount(); i++) {
2321           if (tabbedPane.getTitleAt(i).equals(GUIGlobals.untitledTitle)) {
2322             tabbedPane.setSelectedIndex(i);
2323             int answer = JOptionPane.showConfirmDialog
2324                 (ths, Globals.lang
2325                  ("This untitled database must be saved first to be "
2326                   + "included in the saved session. Save now?"),
2327                  Globals.lang("Save database"),
2328                  JOptionPane.YES_NO_OPTION);
2329             if (answer == JOptionPane.YES_OPTION) {
2330               // The user wants to save.
2331               try {
2332                 basePanel().runCommand("save");
2333               }
2334               catch (Throwable ex) {}
2335             }
2336           }
2337           if (baseAt(i).file != null) {
2338             filenames.add(baseAt(i).file.getPath());
2339           }
2340         }
2341       }
2342
2343       if (filenames.size() == 0) {
2344         output(Globals.lang("Not saved (empty session)") + ".");
2345         return;
2346       }
2347       else {
2348         String[] names = new String[filenames.size()];
2349         for (int i = 0; i < filenames.size(); i++) {
2350           names[i] = (String) filenames.elementAt(i);
2351         }
2352         prefs.putStringArray("savedSession", names);
2353         output(Globals.lang("Saved session") + ".");
2354       }
2355
2356     }
2357   }
2358
2359   class CustomExportAction extends AbstractAction {
2360
2361     String extension, lfFileName, directory;
2362
2363     public CustomExportAction(String name, String ext, String lf) {
2364       super(name);
2365       File lfFile = new File(lf);
2366       extension = ext;
2367       String filename = lfFile.getName();
2368
2369       lfFileName = filename.substring(0, filename.length()-7);
2370       directory = lfFile.getParent()+File.separator;
2371     }
2372
2373     public void actionPerformed(ActionEvent e) {
2374       // We need to find out:
2375       // 1. The layout definition string to use. Or, rather, we
2376       //    must provide a Reader for the layout definition.
2377       // 2. The preferred extension for the layout format.
2378       // 3. The name of the file to use.
2379       File outFile;
2380       String chosenFile = Globals.getNewFile(ths,
2381               new File(prefs.get("workingDirectory")),
2382                                              extension,
2383                                              JFileChooser.SAVE_DIALOG, false);
2384
2385       if (chosenFile != null)
2386         outFile = new File(chosenFile);
2387
2388       else {
2389         return;
2390       }
2391
2392       final String lfName = lfFileName;
2393       final File oFile = outFile;
2394
2395       (new Thread() {
2396         public void run() {
2397           try {
2398             FileActions.exportDatabase
2399                 (basePanel().database, directory,
2400                  lfName, oFile, basePanel().getEncoding());
2401             output(Globals.lang("Exported database to file") + " '" +
2402                    oFile.getPath() + "'.");
2403           }
2404           catch (Exception ex) {
2405             //ex.printStackTrace();
2406             JOptionPane.showMessageDialog(ths, ex.getMessage(), Globals.lang("Error"),
2407                                           JOptionPane.ERROR_MESSAGE);
2408           }
2409         }
2410       }).start();
2411     }
2412   }
2413
2414   class LoadSessionAction
2415       extends MnemonicAwareAction {
2416       boolean running = false;
2417     public LoadSessionAction() {
2418       super(new ImageIcon(GUIGlobals.openIconFile));
2419       putValue(NAME, "Load session");
2420       putValue(ACCELERATOR_KEY, prefs.getKey("Load session"));
2421     }
2422
2423     public void actionPerformed(ActionEvent e) {
2424       if (prefs.get("savedSession") == null) {
2425         output(Globals.lang("No saved session found."));
2426         return;
2427       }
2428       if (running)
2429           return;
2430       else running = true;
2431       output(Globals.lang("Loading session..."));
2432       (new Thread() {
2433         public void run() {
2434           HashSet currentFiles = new HashSet();
2435           if (tabbedPane.getTabCount() > 0) {
2436             for (int i = 0; i < tabbedPane.getTabCount(); i++) {
2437                 if (baseAt(i).file != null)
2438                     currentFiles.add(baseAt(i).file.getPath());
2439             }
2440           }
2441           int i0 = tabbedPane.getTabCount();
2442           String[] names = prefs.getStringArray("savedSession");
2443           for (int i = 0; i < names.length; i++) {
2444             if (!currentFiles.contains(names[i])) {
2445               File file = new File(names[i]);
2446               if (file.exists()) {
2447                 //Util.pr("Opening last edited file:"
2448                 //+fileToOpen.getName());
2449                 open.openIt(file, i == 0);
2450               }
2451             }
2452           }
2453           output(Globals.lang("Files opened") + ": " +
2454                  (tabbedPane.getTabCount() - i0));
2455           running = false;
2456         }
2457       }).start();
2458
2459     }
2460   }
2461
2462   class ChangeTabAction
2463       extends MnemonicAwareAction {
2464     private boolean next;
2465     public ChangeTabAction(boolean next) {
2466       putValue(NAME, next ? "Next tab" : "Previous tab");
2467       this.next = next;
2468       //Util.pr(""+prefs.getKey("Next tab"));
2469       putValue(ACCELERATOR_KEY,
2470                (next ? prefs.getKey("Next tab") : prefs.getKey("Previous tab")));
2471     }
2472
2473     public void actionPerformed(ActionEvent e) {
2474       int i = tabbedPane.getSelectedIndex();
2475       int newI = (next ? i + 1 : i - 1);
2476       if (newI < 0) {
2477         newI = tabbedPane.getTabCount() - 1;
2478       }
2479       if (newI == tabbedPane.getTabCount()) {
2480         newI = 0;
2481       }
2482       tabbedPane.setSelectedIndex(newI);
2483     }
2484   }
2485
2486   /**
2487    * Class for handling general actions; cut, copy and paste. The focused component is
2488    * kept track of by Globals.focusListener, and we call the action stored under the
2489    * relevant name in its action map.
2490    */
2491   class EditAction
2492       extends MnemonicAwareAction {
2493     private String command;
2494     public EditAction(String command, URL icon) {
2495       super(new ImageIcon(icon));
2496       this.command = command;
2497       String nName = Util.nCase(command);
2498       putValue(NAME, nName);
2499       putValue(ACCELERATOR_KEY, prefs.getKey(nName));
2500       putValue(SHORT_DESCRIPTION, Globals.lang(nName));
2501       //putValue(ACCELERATOR_KEY,
2502       //         (next?prefs.getKey("Next tab"):prefs.getKey("Previous tab")));
2503     }
2504
2505     public void actionPerformed(ActionEvent e) {
2506
2507       //Util.pr(Globals.focusListener.getFocused().toString());
2508       JComponent source = Globals.focusListener.getFocused();
2509       try {
2510         source.getActionMap().get(command).actionPerformed
2511             (new ActionEvent(source, 0, command));
2512       } catch (NullPointerException ex) {
2513         // No component is focused, so we do nothing.
2514       }
2515     }
2516   }
2517
2518   class CustomizeExportsAction extends MnemonicAwareAction {
2519     public CustomizeExportsAction() {
2520       putValue(NAME, "Manage custom exports");
2521     }
2522
2523     public void actionPerformed(ActionEvent e) {
2524       ExportCustomizationDialog ecd = new ExportCustomizationDialog(ths);
2525       ecd.setVisible(true);
2526     }
2527   }
2528
2529   class CustomizeImportsAction extends MnemonicAwareAction {
2530     public CustomizeImportsAction() {
2531       putValue(NAME, "Manage custom imports");
2532     }
2533
2534     public void actionPerformed(ActionEvent e) {
2535       ImportCustomizationDialog ecd = new ImportCustomizationDialog(ths);
2536       ecd.setVisible(true);
2537     }
2538   }
2539
2540     class ExportCSV extends MnemonicAwareAction {
2541         public ExportCSV() {
2542             putValue(NAME, "Tab-separated file");
2543         }
2544         public void actionPerformed(ActionEvent e) {
2545             String chosenFile = Globals.getNewFile(ths, new File(prefs.get("workingDirectory")), ".csv",
2546                                                    JFileChooser.SAVE_DIALOG, true);
2547             if (chosenFile == null)
2548                 return;
2549             try {
2550                 FileActions.exportToCSV(basePanel().database(), new File(chosenFile),
2551                                         prefs);
2552             } catch (Exception ex) {
2553                 ex.printStackTrace();
2554             }
2555
2556         }
2557     }
2558
2559     class CustomizeEntryTypeAction extends MnemonicAwareAction {
2560         public CustomizeEntryTypeAction() {
2561             putValue(NAME, "Customize entry types");
2562         }
2563         public void actionPerformed(ActionEvent e) {
2564             JDialog dl = new EntryCustomizationDialog2(ths);
2565             Util.placeDialog(dl, ths);
2566             dl.setVisible(true);
2567         }
2568     }
2569
2570     class GenFieldsCustomizationAction extends MnemonicAwareAction {
2571         public GenFieldsCustomizationAction() {
2572             putValue(NAME, "Set up general fields");
2573         }
2574         public void actionPerformed(ActionEvent e) {
2575             GenFieldsCustomizer gf = new GenFieldsCustomizer(ths);
2576             Util.placeDialog(gf, ths);
2577             gf.setVisible(true);
2578
2579         }
2580     }
2581
2582     class DatabasePropertiesAction extends MnemonicAwareAction {
2583         DatabasePropertiesDialog propertiesDialog = null;
2584         public DatabasePropertiesAction() {
2585             putValue(NAME, "Database properties");
2586         }
2587
2588         public void actionPerformed(ActionEvent e) {
2589             if (propertiesDialog == null)
2590                 propertiesDialog = new DatabasePropertiesDialog(JabRefFrame.this);
2591             propertiesDialog.setPanel(basePanel());
2592             Util.placeDialog(propertiesDialog, JabRefFrame.this);
2593             propertiesDialog.setVisible(true);
2594         }
2595     }
2596
2597     /*private class ForegroundLabel extends JLabel {
2598          public ForegroundLabel(String s) {
2599              super(s);
2600              setFont(new Font("plain", Font.BOLD, 70));
2601              setHorizontalAlignment(JLabel.CENTER);
2602          }
2603
2604         public void paint(Graphics g) {
2605             Graphics2D g2 = (Graphics2D)g;
2606             g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
2607             super.paint(g2);    //To change body of overridden methods use File | Settings | File Templates.
2608         }
2609     }       */
2610
2611   private class MyGlassPane extends JPanel {
2612     //ForegroundLabel infoLabel = new ForegroundLabel("Showing search");
2613     public MyGlassPane() {
2614       addKeyListener(new KeyAdapter() { });
2615       addMouseListener(new MouseAdapter() { });
2616       /*  infoLabel.setForeground(new Color(255, 100, 100, 124));
2617
2618         setLayout(new BorderLayout());
2619         add(infoLabel, BorderLayout.CENTER);*/
2620       super.setCursor(
2621         Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
2622     }
2623       // Override isOpaque() to prevent the glasspane from hiding the window contents:
2624       public boolean isOpaque() { return false; }
2625   }
2626 }