7b3689fad07595110d90c200fca696e8e9589a64
[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 and append"),
328       importNewMenu = subMenu("Import"),
329       exportMenu = subMenu("Export"),
330       customExportMenu = subMenu("Custom export"),
331       newDatabaseMenu = subMenu("New database" );
332
333   // Other submenus
334   JMenu checkAndFix = subMenu("Find And Fix") ;
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     // [kiar] I think we should group these festures
1073     tools.add(checkAndFix) ;
1074      checkAndFix.add( dupliCheck);
1075      checkAndFix.add( strictDupliCheck);
1076      checkAndFix.add( makeKeyAction);
1077      checkAndFix.add( integrityCheckAction) ;
1078
1079     tools.addSeparator();
1080     tools.add(manageSelectors);
1081     tools.add(emacsPushAction);
1082     tools.add(lyxPushAction);
1083     tools.add(winEdtPushAction);
1084     tools.add(latexEditorPushAction);
1085     //tools.add(fetchAuthorMedline);
1086     tools.addSeparator();
1087     tools.add(openFile);
1088     tools.add(openUrl);
1089     tools.addSeparator();
1090     tools.add(newSubDatabaseAction);
1091
1092       tools.addSeparator();
1093       tools.add(autoSetPdf);
1094       tools.add(autoSetPs);
1095       tools.add(abbreviateIso);
1096       tools.add(abbreviateMedline);
1097       tools.add(unabbreviate);
1098
1099     mb.add(tools);
1100
1101     web.add(fetchMedline);
1102     web.add(citeSeerPanelAction);
1103     web.add(fetchCiteSeer);
1104     GeneralFetcher ieex = new GeneralFetcher(sidePaneManager, this, ieeexplorerFetcher);
1105     web.add(ieex.getAction());
1106
1107       mb.add(web);
1108
1109     options.add(showPrefs);
1110     AbstractAction customizeAction = new CustomizeEntryTypeAction();
1111     AbstractAction genFieldsCustomization = new GenFieldsCustomizationAction();
1112     options.add(customizeAction);
1113     options.add(genFieldsCustomization);
1114     options.add(customExpAction);
1115     options.add(customImpAction);
1116     options.add(manageJournals);
1117
1118     /*options.add(new AbstractAction("Font") {
1119     public void actionPerformed(ActionEvent e) {
1120         // JDialog dl = new EntryCustomizationDialog(ths);
1121         Font f=new FontSelectorDialog
1122       (ths, GUIGlobals.CURRENTFONT).getSelectedFont();
1123      if(f==null)
1124       return;
1125      else
1126       GUIGlobals.CURRENTFONT=f;
1127      // updatefont
1128      prefs.put("fontFamily", GUIGlobals.CURRENTFONT.getFamily());
1129      prefs.putInt("fontStyle", GUIGlobals.CURRENTFONT.getStyle());
1130      prefs.putInt("fontSize", GUIGlobals.CURRENTFONT.getSize());
1131      if (tabbedPane.getTabCount() > 0) {
1132       for (int i=0; i<tabbedPane.getTabCount(); i++) {
1133        baseAt(i).entryTable.updateFont();
1134        baseAt(i).refreshTable();
1135       }
1136      }
1137     }
1138     });*/
1139
1140     //options.add(selectKeys);
1141     mb.add(options);
1142
1143     helpMenu.add(help);
1144     helpMenu.add(contents);
1145     helpMenu.addSeparator();
1146 //old about    helpMenu.add(about);
1147     helpMenu.add(about);
1148     mb.add(helpMenu);
1149       helpMenu.addSeparator();
1150       helpMenu.add(errorConsole);
1151   }
1152
1153     private JMenu subMenu(String name) {
1154         name = Globals.menuTitle(name);
1155         int i = name.indexOf('&');
1156         JMenu res;
1157         if (i >= 0) {
1158             res = new JMenu(name.substring(0, i)+name.substring(i+1));
1159             char mnemonic = Character.toUpperCase(name.charAt(i+1));
1160             res.setMnemonic((int)mnemonic);
1161         }
1162         else res = new JMenu(name);
1163
1164         return res;
1165     }
1166
1167   private void createToolBar() {
1168     tlb.putClientProperty(Options.HEADER_STYLE_KEY, HeaderStyle.BOTH);
1169     tlb.setBorder(null);
1170     tlb.setRollover(true);
1171
1172     //tlb.setBorderPainted(true);
1173     //tlb.setBackground(GUIGlobals.lightGray);
1174     //tlb.setForeground(GUIGlobals.lightGray);
1175     tlb.setFloatable(false);
1176     tlb.addAction(newDatabaseAction);
1177     tlb.addAction(open);
1178     tlb.addAction(save);
1179
1180     tlb.addSeparator();
1181     tlb.addAction(cut);
1182     tlb.addAction(copy);
1183     tlb.addAction(paste);
1184     tlb.addAction(undo);
1185     tlb.addAction(redo);
1186
1187     tlb.addSeparator();
1188     tlb.addAction(newEntryAction);
1189     tlb.addAction(editEntry);
1190     tlb.addAction(editPreamble);
1191     tlb.addAction(editStrings);
1192     tlb.addAction(makeKeyAction);
1193
1194
1195     tlb.addSeparator();
1196     tlb.addAction(mark);
1197     tlb.addAction(unmark);
1198
1199     tlb.addSeparator();
1200     searchToggle = new JToggleButton(toggleSearch);
1201     searchToggle.setText(null);
1202     if (!Globals.ON_MAC)
1203         searchToggle.setMargin(marg);
1204     tlb.add(searchToggle);
1205
1206     previewToggle = new JToggleButton(togglePreview);
1207     previewToggle.setText(null);
1208     if (!Globals.ON_MAC)
1209         previewToggle.setMargin(marg);
1210     tlb.add(previewToggle);
1211     tlb.addSeparator();
1212
1213     groupToggle = new JToggleButton(toggleGroups);
1214     groupToggle.setText(null);
1215     if (!Globals.ON_MAC)
1216         groupToggle.setMargin(marg);
1217     tlb.add(groupToggle);
1218
1219
1220     highlightAny = new JToggleButton(toggleHighlightAny);
1221     highlightAny.setText(null);
1222     if (!Globals.ON_MAC)
1223         highlightAny.setMargin(marg);
1224     tlb.add(highlightAny);
1225     highlightAll = new JToggleButton(toggleHighlightAll);
1226     highlightAll.setText(null);
1227     if (!Globals.ON_MAC)
1228         highlightAll.setMargin(marg);
1229     tlb.add(highlightAll);
1230
1231     tlb.addSeparator();
1232     tlb.addAction(emacsPushAction);
1233     tlb.addAction(lyxPushAction);
1234     tlb.addAction(winEdtPushAction);
1235     tlb.addAction(openFile);
1236     tlb.addAction(openUrl);
1237
1238     //tlb.addSeparator();
1239     //tlb.addAction(showPrefs);
1240     tlb.add(Box.createHorizontalGlue());
1241     //tlb.add(new JabRefLabel(GUIGlobals.frameTitle+" "+GUIGlobals.version));
1242
1243     tlb.addAction(closeDatabaseAction);
1244     //Insets margin = new Insets(0, 0, 0, 0);
1245     //for (int i=0; i<tlb.getComponentCount(); i++)
1246     //  ((JButton)tlb.getComponentAtIndex(i)).setMargin(margin);
1247
1248   }
1249
1250   private class JabRefLabel
1251       extends JPanel {
1252     private String label;
1253     public JabRefLabel(String name) {
1254       label = name;
1255     }
1256
1257     public void paint(Graphics g) {
1258       Graphics2D g2 = (Graphics2D) g;
1259       g2.setColor(GUIGlobals.nullFieldColor);
1260       g2.setFont(GUIGlobals.jabRefFont);
1261       FontMetrics fm = g2.getFontMetrics();
1262       int width = fm.stringWidth(label);
1263       g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
1264                           RenderingHints.VALUE_ANTIALIAS_ON);
1265       g2.drawString(label, getWidth() - width - 7, getHeight() - 10);
1266
1267
1268     }
1269   }
1270
1271   private JMenuItem mItem(AbstractAction a, KeyStroke ks) {
1272     // Set up a menu item with action and accelerator key.
1273     JMenuItem mi = new JMenuItem();
1274     mi.setAction(a);
1275     if (ks != null) {
1276       mi.setAccelerator(ks);
1277     }
1278     return mi;
1279   }
1280
1281   //private void setupMainPanel() {
1282
1283
1284   /*public Completer getAutoCompleter(String field) {
1285     return (Completer)autoCompleters.get(field);
1286     }
1287
1288
1289        public void assignAutoCompleters() {
1290     // Set up which fields should have autocompletion. This should
1291     // probably be made customizable. Existing Completer objects are
1292     // forgotten. The completers must be updated towards the database.
1293     byte[] fields = prefs.getByteArray("autoCompFields");
1294     autoCompleters = new Hashtable();
1295     for (int i=0; i<fields.length; i++) {
1296    autoCompleters.put(GUIGlobals.ALL_FIELDS[fields[i]], new Completer());
1297     }
1298
1299        }
1300
1301        public void updateAutoCompleters() {
1302     if (database != null)
1303    database.setCompleters(autoCompleters);
1304    }*/
1305
1306  public void output(final String s) {
1307
1308       SwingUtilities.invokeLater(new Runnable() {
1309           public void run() {
1310               statusLine.setText(s);
1311               statusLine.repaint();
1312           }
1313       });
1314   }
1315
1316   public void stopShowingSearchResults() {
1317     for (int i = 0; i < tabbedPane.getTabCount(); i++) {
1318       baseAt(i).stopShowingSearchResults();
1319     }
1320   }
1321
1322     /**
1323      * Disable actions that demand an open database.
1324      */
1325     private void setEmptyState() {
1326         manageSelectors.setEnabled(false);
1327         mergeDatabaseAction.setEnabled(false);
1328         newSubDatabaseAction.setEnabled(false);
1329         close.setEnabled(false);
1330         save.setEnabled(false);
1331         saveAs.setEnabled(false);
1332         saveSelectedAs.setEnabled(false);
1333         nextTab.setEnabled(false);
1334         prevTab.setEnabled(false);
1335         sortTabs.setEnabled(false);
1336         undo.setEnabled(false);
1337         redo.setEnabled(false);
1338         cut.setEnabled(false);
1339         delete.setEnabled(false);
1340         copy.setEnabled(false);
1341         paste.setEnabled(false);
1342         mark.setEnabled(false);
1343         unmark.setEnabled(false);
1344         unmarkAll.setEnabled(false);
1345         editEntry.setEnabled(false);
1346         importCiteSeer.setEnabled(false);
1347         selectAll.setEnabled(false);
1348         copyKey.setEnabled(false);
1349         copyCiteKey.setEnabled(false);
1350         editPreamble.setEnabled(false);
1351         editStrings.setEnabled(false);
1352         toggleGroups.setEnabled(false);
1353         toggleSearch.setEnabled(false);
1354         makeKeyAction.setEnabled(false);
1355         emacsPushAction.setEnabled(false);
1356         lyxPushAction.setEnabled(false);
1357         winEdtPushAction.setEnabled(false);
1358         normalSearch.setEnabled(false);
1359         incrementalSearch.setEnabled(false);
1360         replaceAll.setEnabled(false);
1361         importMenu.setEnabled(false);
1362         exportMenu.setEnabled(false);
1363         fetchMedline.setEnabled(false);
1364         fetchCiteSeer.setEnabled(false);
1365         openFile.setEnabled(false);
1366         openUrl.setEnabled(false);
1367         togglePreview.setEnabled(false);
1368         dupliCheck.setEnabled(false);
1369         strictDupliCheck.setEnabled(false);
1370         highlightAll.setEnabled(false);
1371         highlightAny.setEnabled(false);
1372         citeSeerPanelAction.setEnabled(false);
1373         for (int i = 0; i < newSpecificEntryAction.length; i++) {
1374             newSpecificEntryAction[i].setEnabled(false);
1375         }
1376         newEntryAction.setEnabled(false);
1377         plainTextImport.setEnabled(false);
1378         closeDatabaseAction.setEnabled(false);
1379         switchPreview.setEnabled(false);
1380         integrityCheckAction.setEnabled(false);
1381         autoSetPdf.setEnabled(false);
1382         autoSetPs.setEnabled(false);
1383         toggleHighlightAny.setEnabled(false);
1384         toggleHighlightAll.setEnabled(false);
1385         databaseProperties.setEnabled(false);
1386         abbreviateIso.setEnabled(false);
1387         abbreviateMedline.setEnabled(false);
1388         unabbreviate.setEnabled(false);
1389     }
1390
1391     /**
1392      * Enable actions that demand an open database.
1393      */
1394     private void setNonEmptyState() {
1395         manageSelectors.setEnabled(true);
1396         mergeDatabaseAction.setEnabled(true);
1397         newSubDatabaseAction.setEnabled(true);
1398         close.setEnabled(true);
1399         save.setEnabled(true);
1400         saveAs.setEnabled(true);
1401         saveSelectedAs.setEnabled(true);
1402         undo.setEnabled(true);
1403         redo.setEnabled(true);
1404         cut.setEnabled(true);
1405         delete.setEnabled(true);
1406         copy.setEnabled(true);
1407         paste.setEnabled(true);
1408         mark.setEnabled(true);
1409         unmark.setEnabled(true);
1410         unmarkAll.setEnabled(true);
1411         editEntry.setEnabled(true);
1412         importCiteSeer.setEnabled(true);
1413         selectAll.setEnabled(true);
1414         copyKey.setEnabled(true);
1415         copyCiteKey.setEnabled(true);
1416         editPreamble.setEnabled(true);
1417         editStrings.setEnabled(true);
1418         toggleGroups.setEnabled(true);
1419         toggleSearch.setEnabled(true);
1420         makeKeyAction.setEnabled(true);
1421         emacsPushAction.setEnabled(true);
1422         lyxPushAction.setEnabled(true);
1423         winEdtPushAction.setEnabled(true);
1424         normalSearch.setEnabled(true);
1425         incrementalSearch.setEnabled(true);
1426         replaceAll.setEnabled(true);
1427         importMenu.setEnabled(true);
1428         exportMenu.setEnabled(true);
1429         fetchMedline.setEnabled(true);
1430         fetchCiteSeer.setEnabled(true);
1431         openFile.setEnabled(true);
1432         openUrl.setEnabled(true);
1433         togglePreview.setEnabled(true);
1434         dupliCheck.setEnabled(true);
1435         strictDupliCheck.setEnabled(true);
1436         highlightAll.setEnabled(true);
1437         highlightAny.setEnabled(true);
1438         citeSeerPanelAction.setEnabled(true);
1439         for (int i = 0; i < newSpecificEntryAction.length; i++) {
1440             newSpecificEntryAction[i].setEnabled(true);
1441         }
1442         newEntryAction.setEnabled(true);
1443         plainTextImport.setEnabled(true);
1444         closeDatabaseAction.setEnabled(true);
1445         switchPreview.setEnabled(true);
1446         integrityCheckAction.setEnabled(true);
1447         autoSetPdf.setEnabled(true);
1448         autoSetPs.setEnabled(true);
1449         toggleHighlightAny.setEnabled(true);
1450         toggleHighlightAll.setEnabled(true);
1451         databaseProperties.setEnabled(true);
1452         abbreviateIso.setEnabled(true);
1453         abbreviateMedline.setEnabled(true);
1454         unabbreviate.setEnabled(true);
1455     }
1456
1457     /**
1458      * Disable actions that need more than one database open.
1459      */
1460     private void setOnlyOne() {
1461         nextTab.setEnabled(false);
1462         prevTab.setEnabled(false);
1463         sortTabs.setEnabled(false);
1464     }
1465
1466     /**
1467      * Disable actions that need more than one database open.
1468      */
1469     private void setMultiple() {
1470         nextTab.setEnabled(true);
1471         prevTab.setEnabled(true);
1472         sortTabs.setEnabled(true);
1473     }
1474
1475   /**
1476    * This method causes all open BasePanels to set up their tables
1477    * anew. When called from PrefsDialog2, this updates to the new
1478    * settings.
1479    */
1480   public void setupAllTables() {
1481     // This action can be invoked without an open database, so
1482     // we have to check if we have one before trying to invoke
1483     // methods to execute changes in the preferences.
1484
1485     // We want to notify all tabs about the changes to
1486     // avoid problems when changing the column set.
1487     for (int i = 0; i < tabbedPane.getTabCount(); i++) {
1488       BasePanel bf = baseAt(i);
1489
1490       // Update tables:
1491       if (bf.database != null) {
1492         bf.setupMainPanel();
1493
1494       }
1495
1496     }
1497   }
1498
1499   public BasePanel addTab(BibtexDatabase db, File file, HashMap meta, String encoding, boolean raisePanel) {
1500       BasePanel bp = new BasePanel(ths, db, file, meta, encoding);
1501       addTab(bp, file, raisePanel);
1502       return bp;
1503   }
1504
1505     public void addTab(BasePanel bp, File file, boolean raisePanel) {
1506         tabbedPane.add((file != null ? file.getName(): Globals.lang(GUIGlobals.untitledTitle)),
1507                        bp);
1508         if (raisePanel) {
1509             tabbedPane.setSelectedComponent(bp);
1510         }
1511         if (tabbedPane.getTabCount() == 1) {
1512             setNonEmptyState();
1513         } else if (tabbedPane.getTabCount() == 2) {
1514             setMultiple();
1515         }
1516     }
1517
1518   class SelectKeysAction
1519       extends AbstractAction {
1520     public SelectKeysAction() {
1521       super(Globals.lang("Customize key bindings"));
1522     }
1523
1524     public void actionPerformed(ActionEvent e) {
1525       KeyBindingsDialog d = new KeyBindingsDialog
1526           ( (HashMap) prefs.getKeyBindings().clone(),
1527            prefs.getDefaultKeys());
1528       d.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
1529       d.pack(); //setSize(300,500);
1530       Util.placeDialog(d, ths);
1531       d.setVisible(true);
1532       if (d.getAction()) {
1533         prefs.setNewKeyBindings(d.getNewKeyBindings());
1534         JOptionPane.showMessageDialog
1535             (ths,
1536              Globals.lang("Your new key bindings have been stored.") + "\n"
1537              + Globals.lang("You must restart JabRef for the new key "
1538                             + "bindings to work properly."),
1539              Globals.lang("Key bindings changed"),
1540              JOptionPane.INFORMATION_MESSAGE);
1541       }
1542     }
1543   }
1544
1545   /**
1546    * The action concerned with closing the window.
1547    */
1548   class CloseAction
1549       extends MnemonicAwareAction {
1550     public CloseAction() {
1551       putValue(NAME, "Quit");
1552       putValue(SHORT_DESCRIPTION, Globals.lang("Quit JabRef"));
1553       putValue(ACCELERATOR_KEY, prefs.getKey("Quit JabRef"));
1554       //putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_Q,
1555       //    Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
1556
1557     }
1558
1559     public void actionPerformed(ActionEvent e) {
1560       quit();
1561     }
1562   }
1563
1564   // The action for closing the current database and leaving the window open.
1565   CloseDatabaseAction closeDatabaseAction = new CloseDatabaseAction();
1566   class CloseDatabaseAction
1567       extends MnemonicAwareAction {
1568     public CloseDatabaseAction() {
1569         super(new ImageIcon(GUIGlobals.closeIconFile));
1570         putValue(NAME, "Close database");
1571         putValue(SHORT_DESCRIPTION,
1572                  Globals.lang("Close the current database"));
1573         putValue(ACCELERATOR_KEY, prefs.getKey("Close database"));
1574     }
1575
1576     public void actionPerformed(ActionEvent e) {
1577       // Ask here if the user really wants to close, if the base
1578       // has not been saved since last save.
1579       boolean close = true;
1580       if (basePanel() == null) { // when it is initially empty
1581         return; //nbatada nov 7
1582       }
1583
1584       if (basePanel().baseChanged) {
1585         int answer = JOptionPane.showConfirmDialog
1586             (ths, Globals.lang("Database has changed. Do you want to save " +
1587                                "before closing?"),
1588              Globals.lang("Save before closing"),
1589              JOptionPane.YES_NO_CANCEL_OPTION);
1590         if ( (answer == JOptionPane.CANCEL_OPTION) ||
1591             (answer == JOptionPane.CLOSED_OPTION)) {
1592           close = false; // The user has cancelled.
1593         }
1594         if (answer == JOptionPane.YES_OPTION) {
1595           // The user wants to save.
1596           try {
1597             basePanel().runCommand("save");
1598           }
1599           catch (Throwable ex) {
1600             // Something prevented the file
1601             // from being saved. Break!!!
1602             close = false;
1603           }
1604
1605         }
1606       }
1607
1608       if (close) {
1609         basePanel().cleanUp();
1610         tabbedPane.remove(basePanel());
1611         if (tabbedPane.getTabCount() == 0) {
1612           setEmptyState();
1613         } else
1614         {
1615             sidePaneManager.stateChanged(new ChangeEvent(tabbedPane));
1616           markActiveBasePanel() ;
1617           if (tabbedPane.getTabCount() == 1) { setOnlyOne() ; }
1618         }
1619         output(Globals.lang("Closed database") + ".");
1620           System.gc(); // Test
1621       }
1622     }
1623   }
1624
1625
1626   // The action concerned with opening a new database.
1627   class NewDatabaseAction
1628       extends MnemonicAwareAction {
1629     public NewDatabaseAction() {
1630         super(new ImageIcon(GUIGlobals.newIconFile));
1631         putValue(NAME, "New database");
1632         putValue(SHORT_DESCRIPTION, Globals.lang("New BibTeX database"));
1633         //putValue(MNEMONIC_KEY, GUIGlobals.newKeyCode);
1634     }
1635
1636     public void actionPerformed(ActionEvent e) {
1637         // Create a new, empty, database.
1638         BibtexDatabase database = new BibtexDatabase();
1639         addTab(database, null, null, Globals.prefs.get("defaultEncoding"), true);
1640         output(Globals.lang("New database created."));
1641     }
1642   }
1643
1644 class ImportCiteSeerAction
1645         extends MnemonicAwareAction {
1646
1647     public ImportCiteSeerAction() {
1648         super(new ImageIcon(GUIGlobals.wwwCiteSeerIcon));
1649         putValue(NAME, "Import Fields from CiteSeer");
1650         putValue(SHORT_DESCRIPTION, Globals.lang("Import Fields from CiteSeer Database"));
1651         putValue(ACCELERATOR_KEY, prefs.getKey("Import Fields from CiteSeer")); // Key defined in MenuTitles!
1652         }
1653
1654         public void actionPerformed(ActionEvent e) {
1655
1656                 if(citeSeerFetcher.activateImportFetcher()) {
1657
1658
1659                         (new Thread() {
1660
1661                                 BasePanel currentBp;
1662                                 BibtexEntry toShow;
1663                                 //String id;
1664                                 int[] clickedOn = null;
1665
1666                                 class UpdateComponent implements Runnable {
1667                                         boolean changesMade;
1668
1669                                         UpdateComponent(boolean changesMade) {
1670                                                 this.changesMade = changesMade;
1671                                         }
1672
1673                                         public void run() {
1674                                             citeSeerFetcher.endImportCiteSeerProgress();
1675                                             if (changesMade)
1676                                                     currentBp.markBaseChanged();
1677                                                 //for(int i=0; i < clickedOn.length; i++)
1678                                                 //        currentBp.entryTable.addRowSelectionInterval(i,i);
1679                                                 //currentBp.showEntry(toShow);
1680                                                 output(Globals.lang("Completed Import Fields from CiteSeer."));
1681                                         }
1682                                 }
1683
1684                             public void run() {
1685                                 currentBp = (BasePanel) tabbedPane.getSelectedComponent();
1686                                         // We demand that at least one row is selected.
1687
1688                                         int rowCount = currentBp.mainTable.getSelectedRowCount();
1689                                         if (rowCount >= 1) {
1690                                                 clickedOn = currentBp.mainTable.getSelectedRows();
1691                                         } else {
1692                                                 JOptionPane.showMessageDialog(currentBp.frame(),
1693                                                 Globals.lang("You must select at least one row to perform this operation."),
1694                                                 Globals.lang("CiteSeer Import Error"),
1695                                                 JOptionPane.WARNING_MESSAGE);
1696                                         }
1697                                         toShow = (BibtexEntry)currentBp.mainTable.getSelected().get(0);
1698                                         if (clickedOn != null) {
1699                                                 citeSeerFetcher.beginImportCiteSeerProgress();
1700                                                 NamedCompound citeseerNamedCompound =
1701                                                         new NamedCompound(Globals.lang("CiteSeer Import Fields"));
1702                                                 boolean newValues = citeSeerFetcher.importCiteSeerEntries(clickedOn, citeseerNamedCompound);
1703                                                 if (newValues) {
1704                                                         citeseerNamedCompound.end();
1705                                                         currentBp.undoManager.addEdit(citeseerNamedCompound);
1706                                                 }
1707                                                 UpdateComponent updateComponent = new UpdateComponent(newValues);
1708                                                 SwingUtilities.invokeLater(updateComponent);
1709                                         }
1710                                         citeSeerFetcher.deactivateImportFetcher();
1711                             }
1712                         }).start();
1713                 } else {
1714                         JOptionPane.showMessageDialog(tabbedPane.getSelectedComponent(),
1715                                         Globals.lang("A CiteSeer import operation is currently in progress.") + "  " +
1716                                         Globals.lang("Please wait until it has finished."),
1717                                         Globals.lang("CiteSeer Import Error"),
1718                                         JOptionPane.WARNING_MESSAGE);
1719                 }
1720         }
1721 }
1722
1723 class FetchCiteSeerAction
1724         extends MnemonicAwareAction {
1725
1726                 public FetchCiteSeerAction() {
1727                     super(new ImageIcon(GUIGlobals.wwwCiteSeerIcon));
1728                     putValue(NAME, "Fetch citations from CiteSeer");
1729
1730                     putValue(SHORT_DESCRIPTION, Globals.lang("Fetch Articles Citing your Database"));
1731                     putValue(ACCELERATOR_KEY, prefs.getKey("Fetch citations from CiteSeer"));
1732                 }
1733
1734                 public void actionPerformed(ActionEvent e) {
1735
1736                         if(citeSeerFetcher.activateCitationFetcher()) {
1737                                 sidePaneManager.ensureVisible("CiteSeerProgress");
1738                                 (new Thread() {
1739                                         BasePanel newBp;
1740                                         BasePanel targetBp;
1741                                         BibtexDatabase newDatabase;
1742                                         BibtexDatabase targetDatabase;
1743
1744                                         Runnable updateComponent = new Runnable() {
1745
1746                                                 /* TODO: This should probably be selectable on/off
1747                                                  * in the preferences window, but for now all
1748                                                  * Citation fetcher operations will sort by citation count.
1749                                                  */
1750                                                 private void setSortingByCitationCount() {
1751                                                         newBp.sortingByCiteSeerResults = true;
1752                                                 }
1753
1754                                                 public void run() {
1755                                                         setSortingByCitationCount();
1756                                                         tabbedPane.add(Globals.lang(GUIGlobals.untitledTitle), newBp);
1757                                                         tabbedPane.setSelectedComponent(newBp);
1758                                                         output(Globals.lang("Fetched all citations from target database."));
1759                                                         citeSeerFetcher.deactivateCitationFetcher();
1760                                                 }
1761                                         };
1762
1763                                   public void run() {
1764                                         try {
1765                                                 newBp = new BasePanel(ths);
1766                                                 int errorCode;
1767                                                 targetBp = (BasePanel) tabbedPane.getSelectedComponent();
1768                                                 newDatabase = newBp.getDatabase();
1769                                                 targetDatabase = targetBp.getDatabase();
1770                                                 errorCode = citeSeerFetcher.populate(newDatabase, targetDatabase);
1771                                                 if (newDatabase.getEntryCount() > 0) {
1772                                                         SwingUtilities.invokeLater(updateComponent);
1773                                                 } else if(errorCode == 0) {
1774                                                         SwingUtilities.invokeLater(citeSeerFetcher.getEmptyFetchSetDialog());
1775                                             } else {
1776                                                     citeSeerFetcher.deactivateCitationFetcher();
1777                                             }
1778                                         }
1779                                         catch (Exception ex) {
1780                                           ex.printStackTrace();
1781                                         }
1782                                   }
1783                                 }).start();
1784                         } else {
1785                             JOptionPane.showMessageDialog(tabbedPane.getSelectedComponent(),
1786                                                 Globals.lang("A CiteSeer fetch operation is currently in progress.") + "  " +
1787                                                 Globals.lang("Please wait until it has finished."),
1788                                                 Globals.lang("CiteSeer Fetch Error"),
1789                                                 JOptionPane.WARNING_MESSAGE);
1790                         }
1791                 }
1792         }
1793
1794
1795
1796     // The action concerned with generate a new (sub-)database from latex aux file.
1797     class NewSubDatabaseAction extends MnemonicAwareAction
1798     {
1799       public NewSubDatabaseAction()
1800       {
1801         super(new ImageIcon( GUIGlobals.newBibFile));
1802         putValue(NAME, "New subdatabase based on AUX file" );
1803         putValue( SHORT_DESCRIPTION, Globals.lang( "New BibTeX subdatabase" ) ) ;
1804             //putValue(MNEMONIC_KEY, GUIGlobals.newKeyCode);
1805       }
1806
1807       public void actionPerformed( ActionEvent e )
1808       {
1809         // Create a new, empty, database.
1810
1811         FromAuxDialog dialog = new FromAuxDialog(ths, "", true, ths.tabbedPane) ;
1812
1813         Util.placeDialog(dialog, ths);
1814         dialog.setVisible(true) ;
1815
1816         if (dialog.okPressed())
1817         {
1818           BasePanel bp = new BasePanel( ths,
1819                                         dialog.getGenerateDB(),   // database
1820                                         null,                     // file
1821                                         null, Globals.prefs.get("defaultEncoding"));                     // meta data
1822           tabbedPane.add( Globals.lang( GUIGlobals.untitledTitle ), bp ) ;
1823           tabbedPane.setSelectedComponent( bp ) ;
1824           if ( tabbedPane.getTabCount() == 1 )
1825           {
1826             setNonEmptyState() ;
1827           }
1828           output( Globals.lang( "New database created." ) ) ;
1829         }
1830       }
1831     }
1832
1833
1834     // The action should test the database and report errors/warnings
1835     class IntegrityCheckAction extends AbstractAction
1836     {
1837       public IntegrityCheckAction()
1838       {
1839         super(Globals.menuTitle("Integrity check"),
1840                new ImageIcon( GUIGlobals.integrityCheck ) ) ;
1841                //putValue( SHORT_DESCRIPTION, "integrity" ) ;  //Globals.lang( "integrity" ) ) ;
1842             //putValue(MNEMONIC_KEY, GUIGlobals.newKeyCode);
1843       }
1844
1845       public void actionPerformed( ActionEvent e )
1846       {
1847        Object selComp = tabbedPane.getSelectedComponent() ;
1848        if (selComp != null)
1849        {
1850          BasePanel bp = ( BasePanel ) selComp ;
1851          BibtexDatabase refBase = bp.getDatabase() ;
1852          if (refBase != null)
1853          {
1854              IntegrityWizard wizard = new IntegrityWizard(ths, basePanel()) ;
1855              Util.placeDialog(wizard, ths);
1856              wizard.setVisible(true) ;
1857
1858          }
1859        }
1860       }
1861     }
1862
1863   class FetchMedlineAction
1864       extends MnemonicAwareAction {
1865     public FetchMedlineAction() {
1866       super(new ImageIcon(GUIGlobals.fetchMedlineIcon));
1867       putValue(NAME, "Fetch Medline");
1868       putValue(ACCELERATOR_KEY, prefs.getKey("Fetch Medline"));
1869       putValue(SHORT_DESCRIPTION, Globals.lang("Fetch Medline by ID"));
1870     }
1871
1872     public void actionPerformed(ActionEvent e) {
1873       if (tabbedPane.getTabCount() > 0) {
1874         //for (int i = 0; i < tabbedPane.getTabCount(); i++) {
1875         //  ( (BasePanel) tabbedPane.getComponentAt(i)).sidePaneManager.
1876         sidePaneManager.togglePanel("fetchMedline");// ensureVisible("fetchMedline");
1877         if (sidePaneManager.isPanelVisible("fetchMedline"))
1878           new FocusRequester(medlineFetcher.getTextField());
1879         //}
1880       }
1881     }
1882
1883   }
1884
1885   class CiteSeerPanelAction
1886       extends MnemonicAwareAction {
1887     public CiteSeerPanelAction() {
1888       super(new ImageIcon(GUIGlobals.fetchMedlineIcon));
1889       putValue(NAME, "Fetch CiteSeer");
1890       //System.out.println(Globals.menuTitle("Fetch CiteSeer"));
1891       putValue(ACCELERATOR_KEY, prefs.getKey("Fetch CiteSeer"));
1892     }
1893
1894     public void actionPerformed(ActionEvent e) {
1895       if (tabbedPane.getTabCount() > 0) {
1896           sidePaneManager.togglePanel("CiteSeerPanel");// ensureVisible("fetchMedline");
1897           if (sidePaneManager.isPanelVisible("CiteSeerPanel"))
1898           new FocusRequester(citeSeerFetcherPanel.getTextField());
1899         //}
1900       }
1901     }
1902
1903   }
1904
1905     /*class FetchAuthorMedlineAction
1906       extends AbstractAction {
1907     public FetchAuthorMedlineAction() {
1908       super(Globals.lang("Fetch Medline by author"),
1909             new ImageIcon(GUIGlobals.fetchMedlineIcon));
1910       putValue(SHORT_DESCRIPTION, Globals.lang("Fetch Medline by author"));
1911     }
1912
1913     public void actionPerformed(ActionEvent e) {
1914       if (tabbedPane.getTabCount() > 0) {
1915         for (int i = 0; i < tabbedPane.getTabCount(); i++) {
1916           ( (BasePanel) tabbedPane.getComponentAt(i)).sidePaneManager.
1917               ensureVisible("fetchAuthorMedline");
1918           new FocusRequester(basePanel().medlineFetcher);
1919         }
1920       }
1921     }
1922
1923     }*/
1924
1925   // The action for opening the preferences dialog.
1926
1927   AbstractAction showPrefs = new ShowPrefsAction();
1928
1929   class ShowPrefsAction
1930       extends MnemonicAwareAction {
1931     public ShowPrefsAction() {
1932       super(new ImageIcon(GUIGlobals.prefsIconFile));
1933       putValue(NAME, "Preferences");
1934       putValue(SHORT_DESCRIPTION, Globals.lang("Preferences"));
1935     }
1936
1937     public void actionPerformed(ActionEvent e) {
1938       preferences();
1939     }
1940   }
1941
1942   /**
1943    * This method does the job of adding imported entries into the active database, or into a new one.
1944    * It shows the ImportInspectionDialog if preferences indicate it should be used. Otherwise it imports
1945    * directly.
1946    * @param panel The BasePanel to add to.
1947    * @param entries The entries to add.
1948    * @param filename Name of the file where the import came from.
1949    * @param openInNew Should the entries be imported into a new database?
1950    * @param callBack The callback for the ImportInspectionDialog to use.
1951    */
1952   public void addImportedEntries(final BasePanel panel, final List entries, String filename, boolean openInNew,
1953                                  ImportInspectionDialog.CallBack callBack) {
1954       // Use the import inspection dialog if it is enabled in preferences, and (there are more than
1955       // one entry or the inspection dialog is also enabled for single entries):
1956       if (Globals.prefs.getBoolean("useImportInspectionDialog") &&
1957               (Globals.prefs.getBoolean("useImportInspectionDialogForSingle") || (entries.size() > 1))) {
1958                 ImportInspectionDialog diag = new ImportInspectionDialog(ths, panel,
1959                         BibtexFields.DEFAULT_INSPECTION_FIELDS,
1960                         Globals.lang("Import"), openInNew);
1961                 diag.addEntries(entries);
1962                 diag.addCallBack(callBack);
1963                 diag.entryListComplete();
1964                 Util.placeDialog(diag, ths);
1965                 diag.setVisible(true);
1966         diag.toFront();
1967         } else {
1968             ths.addBibEntries(entries, filename, openInNew);
1969           if ((panel != null) && (entries.size() == 1)) {
1970               SwingUtilities.invokeLater(new Runnable() {
1971                   public void run() {
1972                       panel.highlightEntry((BibtexEntry)entries.get(0));
1973                   }
1974               });
1975
1976
1977           }
1978        }
1979   }
1980
1981     /**
1982      * Adds the entries to the database, possibly checking for duplicates first.
1983      * @param filename If non-null, a message is printed to the status line describing
1984      * how many entries were imported, and from which file. If null, the message will not
1985      * be printed.
1986      * @param intoNew Determines if the entries will be put in a new database or in the current
1987      * one.
1988      */
1989   public int addBibEntries(java.util.List bibentries, String filename,
1990                            boolean intoNew) {
1991           if (bibentries == null || bibentries.size() == 0) {
1992
1993       // No entries found. We need a message for this.
1994       JOptionPane.showMessageDialog(ths, Globals.lang("No entries found. Please make sure you are "
1995                                                       +"using the correct import filter."), Globals.lang("Import failed"),
1996                                     JOptionPane.ERROR_MESSAGE);
1997       return 0;
1998     }
1999
2000       int addedEntries = 0;
2001
2002     // Set owner and timestamp fields:
2003     Util.setAutomaticFields(bibentries);
2004
2005     if (intoNew || (tabbedPane.getTabCount() == 0)) {
2006       // Import into new database.
2007       BibtexDatabase database = new BibtexDatabase();
2008       Iterator it = bibentries.iterator();
2009       while (it.hasNext()) {
2010         BibtexEntry entry = (BibtexEntry) it.next();
2011
2012         try {
2013           entry.setId(Util.createNeutralId());
2014           database.insertEntry(entry);
2015         }
2016         catch (KeyCollisionException ex) {
2017           //ignore
2018           System.err.println("KeyCollisionException [ addBibEntries(...) ]");
2019         }
2020       }
2021       HashMap meta = new HashMap();
2022       // Metadata are only put in bibtex files, so we will not find it
2023       // in imported files. Instead we pass an empty HashMap.
2024       BasePanel bp = new BasePanel(ths, database, null, meta, Globals.prefs.get("defaultEncoding"));
2025       /*
2026             if (prefs.getBoolean("autoComplete")) {
2027             db.setCompleters(autoCompleters);
2028             }
2029        */
2030       addedEntries = database.getEntryCount();
2031       tabbedPane.add(Globals.lang("untitled"), bp);
2032       bp.markBaseChanged();
2033       tabbedPane.setSelectedComponent(bp);
2034       if (tabbedPane.getTabCount() == 1) {
2035         setNonEmptyState();
2036       }
2037       if (filename != null)
2038           output(Globals.lang("Imported database") + " '" + filename + "' " +
2039                  Globals.lang("with") + " " +
2040                  database.getEntryCount() + " " +
2041                  Globals.lang("entries into new database") + ".");
2042     }
2043     else {
2044       // Import into current database.
2045       boolean checkForDuplicates = true;
2046       BasePanel basePanel = basePanel();
2047       BibtexDatabase database = basePanel.database;
2048       int oldCount = database.getEntryCount();
2049       NamedCompound ce = new NamedCompound(Globals.lang("Import entries"));
2050       Iterator it = bibentries.iterator();
2051
2052       mainLoop: while (it.hasNext()) {
2053         BibtexEntry entry = (BibtexEntry) it.next();
2054         boolean dupli = false;
2055         // Check for duplicates among the current entries:
2056         if (checkForDuplicates) {
2057             loop: for (Iterator i2=database.getKeySet().iterator();
2058                        i2.hasNext();) {
2059                 BibtexEntry existingEntry = database.getEntryById((String)i2.next());
2060                 if (Util.isDuplicate(entry, existingEntry,
2061                                      Globals.duplicateThreshold)) {
2062                     DuplicateResolverDialog drd = new DuplicateResolverDialog
2063                         (ths, existingEntry, entry, DuplicateResolverDialog.IMPORT_CHECK);
2064                     drd.setVisible(true);
2065                     int res = drd.getSelected();
2066                     if (res == DuplicateResolverDialog.KEEP_LOWER)   {
2067                         dupli = true;
2068                     }
2069                     else if (res == DuplicateResolverDialog.KEEP_UPPER) {
2070                         database.removeEntry(existingEntry.getId());
2071                         ce.addEdit(new UndoableRemoveEntry
2072                                    (database, existingEntry, basePanel));
2073                     } else if (res == DuplicateResolverDialog.BREAK) {
2074                         break mainLoop;
2075                     }
2076                     break loop;
2077                 }
2078             }
2079         }
2080
2081         if (!dupli) {
2082             try {
2083                 entry.setId(Util.createNeutralId());
2084                 database.insertEntry(entry);
2085                 ce.addEdit(new UndoableInsertEntry
2086                            (database, entry, basePanel));
2087                 addedEntries++;
2088             }
2089             catch (KeyCollisionException ex) {
2090                 //ignore
2091                 System.err.println("KeyCollisionException [ addBibEntries(...) ]");
2092             }
2093         }
2094       }
2095         if (addedEntries > 0) {
2096             ce.end();
2097             basePanel.undoManager.addEdit(ce);
2098             basePanel.markBaseChanged();
2099             if (filename != null)
2100                 output(Globals.lang("Imported database") + " '" + filename + "' " +
2101                      Globals.lang("with") + " " +
2102                      (database.getEntryCount() - oldCount) + " " +
2103                      Globals.lang("entries into new database") + ".");
2104         }
2105
2106     }
2107
2108     return addedEntries;
2109   }
2110
2111   private void setUpImportMenu(JMenu importMenu, boolean intoNew_) {
2112       final boolean intoNew = intoNew_;
2113       importMenu.removeAll();
2114
2115       // Add a menu item for autodetecting import format:
2116       importMenu.add(new ImportUnknownMenuItem(ths, intoNew));
2117
2118       // Add custom importers
2119       importMenu.addSeparator();
2120
2121       SortedSet customImporters = Globals.importFormatReader.getCustomImportFormats();
2122       JMenu submenu = new JMenu(Globals.lang("Custom importers"));
2123       submenu.setMnemonic(KeyEvent.VK_S);
2124       if (customImporters.size() == 0) {
2125         submenu.setEnabled(false);
2126         submenu.setToolTipText(Globals.lang("No custom imports registered yet."));
2127       } else {
2128         // Put in all formatters registered in ImportFormatReader:
2129         for (Iterator i=customImporters.iterator(); i.hasNext();) {
2130             ImportFormat imFo = (ImportFormat)i.next();
2131             submenu.add(new ImportMenuItem(ths, imFo, intoNew));
2132         }
2133       }
2134
2135       importMenu.add(submenu);
2136       importMenu.addSeparator();
2137
2138       // Put in all formatters registered in ImportFormatReader:
2139       for (Iterator i=Globals.importFormatReader.getBuiltInInputFormats().iterator(); i.hasNext();) {
2140           ImportFormat imFo = (ImportFormat)i.next();
2141           importMenu.add(new ImportMenuItem(ths, imFo, intoNew));
2142       }
2143   }
2144
2145
2146   //
2147   // simply opens up a jfilechooser dialog and gets a filename
2148   // returns null if user selects cancel
2149   // it should also do a check perhaps to see if
2150   // file exists and is readable?
2151   //
2152
2153   public String getNewFile() {
2154
2155     return Globals.getNewFile(ths, prefs, new File(prefs.get("workingDirectory")),
2156                               null, JFileChooser.OPEN_DIALOG, false);
2157
2158     /*JFileChooser fc;
2159     if (prefs.get("workingDirectory") == null) {
2160       fc = new JabRefFileChooser(new File(System.getProperty("user.home"))); //cwd));
2161     }
2162     else {
2163       fc = new JabRefFileChooser(new File(prefs.get("workingDirectory"))); //cwd));
2164     }
2165
2166     fc.addChoosableFileFilter(new OpenFileFilter());
2167     fc.setDialogType(JFileChooser.OPEN_DIALOG);
2168     fc.showOpenDialog(null);
2169     File selectedFile = fc.getSelectedFile();
2170     if (selectedFile == null) { // cancel
2171       return null;
2172     }
2173     prefs.put("workingDirectory", selectedFile.getPath());
2174     return selectedFile.getAbsolutePath();*/
2175   }
2176
2177     public FileHistory getFileHistory() {
2178         return fileHistory;
2179     }
2180
2181   JMenuItem
2182       htmlItem = new JMenuItem(Globals.lang("HTML")),
2183       simpleHtmlItem = new JMenuItem(Globals.lang("Simple HTML")),
2184       //plainTextItem = new JMenuItem(Globals.lang("Plain text")),
2185       docbookItem = new JMenuItem(Globals.lang("Docbook")),
2186       bibtexmlItem = new JMenuItem(Globals.lang("BibTeXML")),
2187       modsItem = new JMenuItem(Globals.lang("MODS")),
2188       rtfItem = new JMenuItem(Globals.lang("Harvard RTF")),
2189       endnoteItem = new JMenuItem(Globals.lang("Endnote")),
2190       openofficeItem = new JMenuItem("OpenOffice Calc"),
2191       odsItem = new JMenuItem("OpenDocument Spreadsheet");
2192
2193
2194
2195
2196   private void setUpExportMenu(JMenu menu) {
2197       ActionListener listener = new ActionListener() {
2198           public void actionPerformed(ActionEvent e) {
2199               JMenuItem source = (JMenuItem) e.getSource();
2200               String lfFileName = null, extension = null;
2201               if (source == htmlItem) {
2202                   lfFileName = "html";
2203                   extension = ".html";
2204               }
2205               else if (source == simpleHtmlItem) {
2206                   lfFileName = "simplehtml";
2207                   extension = ".html";
2208               } else if (source == docbookItem) {
2209                   lfFileName = "docbook";
2210                   extension = ".xml";
2211               } else if (source == bibtexmlItem) {
2212                   lfFileName = "bibtexml";
2213                   extension = ".xml";
2214               } else if (source == modsItem) {
2215                   lfFileName = "mods";
2216                   extension = ".xml";
2217               } else if (source == rtfItem) {
2218                   lfFileName = "harvard";
2219                   extension = ".rtf";
2220               } else if (source == endnoteItem) {
2221                   lfFileName = "endnote";
2222                   extension = ".txt";
2223               } else if (source == openofficeItem) {
2224                   lfFileName = "oocalc";
2225                   extension = ".sxc";
2226               } else if (source == odsItem) {
2227                   lfFileName = "ods";
2228                   extension = ".ods";
2229               }
2230               // We need to find out:
2231               // 1. The layout definition string to use. Or, rather, we
2232               //    must provide a Reader for the layout definition.
2233               // 2. The preferred extension for the layout format.
2234               // 3. The name of the file to use.
2235               final String chosenFile = Globals.getNewFile(ths, prefs, new File(prefs.get("workingDirectory")),
2236                       extension, JFileChooser.SAVE_DIALOG, false);
2237               final String exportName = lfFileName;
2238               if (chosenFile == null)
2239                   return;
2240
2241               (new Thread() {
2242                   public void run() {
2243                       try {
2244                           FileActions.performExport(basePanel().database(), exportName,
2245                                   chosenFile, basePanel().getEncoding());
2246                           output(Globals.lang("Exported database to file") + " '" +
2247                                   chosenFile + "'.");
2248                       }
2249                       catch (Exception ex) {
2250                           ex.printStackTrace();
2251                       }
2252                   }
2253               }).start();
2254
2255           }
2256       };
2257
2258       htmlItem.addActionListener(listener);
2259       menu.add(htmlItem);
2260       simpleHtmlItem.addActionListener(listener);
2261       menu.add(simpleHtmlItem);
2262       //plainTextItem.addActionListener(listener);
2263       //menu.add(plainTextItem);
2264       bibtexmlItem.addActionListener(listener);
2265       menu.add(bibtexmlItem);
2266       docbookItem.addActionListener(listener);
2267       menu.add(docbookItem);
2268       modsItem.addActionListener(listener);
2269       menu.add(modsItem);
2270       rtfItem.addActionListener(listener);
2271       menu.add(rtfItem);
2272       endnoteItem.addActionListener(listener);
2273       menu.add(endnoteItem);
2274       openofficeItem.addActionListener(listener);
2275       odsItem.addActionListener(listener);
2276       menu.add(openofficeItem);
2277       menu.add(odsItem);
2278       menu.add(exportCSV);
2279
2280       menu.addSeparator();
2281       menu.add(expandEndnoteZip);
2282
2283   }
2284
2285   /**
2286    * Interrogates the list of custom export formats defined, and adds them to the custom
2287    * export menu.
2288    */
2289   public void setUpCustomExportMenu() {
2290     customExportMenu.removeAll();
2291     for (int i=0; i<prefs.customExports.size(); i++) {
2292       String[] s = prefs.customExports.getElementAt(i);
2293       customExportMenu.add(new CustomExportAction(s[0], s[2], s[1]));
2294     }
2295
2296   }
2297
2298     /**
2299      * Set the preview active state for all BasePanel instances.
2300      * @param enabled
2301      */
2302     public void setPreviewActive(boolean enabled) {
2303         for (int i=0; i<tabbedPane.getTabCount(); i++) {
2304             baseAt(i).setPreviewActive(enabled);
2305         }
2306     }
2307
2308
2309    public void removeCachedEntryEditors() {
2310        for (int j=0; j<tabbedPane.getTabCount(); j++) {
2311             BasePanel bp = (BasePanel)tabbedPane.getComponentAt(j);
2312             bp.entryEditors.clear();
2313        }
2314    }
2315
2316     /**
2317      * This method shows a wait cursor and blocks all input to the JFrame's contents.
2318      */
2319     public void block() {
2320         getGlassPane().setVisible(true);
2321         //getGlassPane().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
2322     }
2323
2324     /**
2325      * This method reverts the cursor to normal, and stops blocking input to the JFrame's contents.
2326      */
2327     public void unblock() {
2328         getGlassPane().setVisible(false);
2329         //      getGlassPane().setCursor(Cursor.WAIT_CURSOR);
2330     }
2331
2332
2333
2334 class SaveSessionAction
2335       extends MnemonicAwareAction {
2336     public SaveSessionAction() {
2337       super(new ImageIcon(GUIGlobals.saveIconFile));
2338       putValue(NAME, "Save session");
2339       putValue(ACCELERATOR_KEY, prefs.getKey("Save session"));
2340     }
2341
2342     public void actionPerformed(ActionEvent e) {
2343       // Here we store the names of allcurrent filea. If
2344       // there is no current file, we remove any
2345       // previously stored file name.
2346       Vector filenames = new Vector();
2347       if (tabbedPane.getTabCount() > 0) {
2348         for (int i = 0; i < tabbedPane.getTabCount(); i++) {
2349           if (tabbedPane.getTitleAt(i).equals(GUIGlobals.untitledTitle)) {
2350             tabbedPane.setSelectedIndex(i);
2351             int answer = JOptionPane.showConfirmDialog
2352                 (ths, Globals.lang
2353                  ("This untitled database must be saved first to be "
2354                   + "included in the saved session. Save now?"),
2355                  Globals.lang("Save database"),
2356                  JOptionPane.YES_NO_OPTION);
2357             if (answer == JOptionPane.YES_OPTION) {
2358               // The user wants to save.
2359               try {
2360                 basePanel().runCommand("save");
2361               }
2362               catch (Throwable ex) {}
2363             }
2364           }
2365           if (baseAt(i).file != null) {
2366             filenames.add(baseAt(i).file.getPath());
2367           }
2368         }
2369       }
2370
2371       if (filenames.size() == 0) {
2372         output(Globals.lang("Not saved (empty session)") + ".");
2373         return;
2374       }
2375       else {
2376         String[] names = new String[filenames.size()];
2377         for (int i = 0; i < filenames.size(); i++) {
2378           names[i] = (String) filenames.elementAt(i);
2379         }
2380         prefs.putStringArray("savedSession", names);
2381         output(Globals.lang("Saved session") + ".");
2382       }
2383
2384     }
2385   }
2386
2387   class CustomExportAction extends AbstractAction {
2388
2389     String extension, lfFileName, directory;
2390
2391     public CustomExportAction(String name, String ext, String lf) {
2392       super(name);
2393       File lfFile = new File(lf);
2394       extension = ext;
2395       String filename = lfFile.getName();
2396
2397       lfFileName = filename.substring(0, filename.length()-7);
2398       directory = lfFile.getParent()+File.separator;
2399     }
2400
2401     public void actionPerformed(ActionEvent e) {
2402       // We need to find out:
2403       // 1. The layout definition string to use. Or, rather, we
2404       //    must provide a Reader for the layout definition.
2405       // 2. The preferred extension for the layout format.
2406       // 3. The name of the file to use.
2407       File outFile;
2408       String chosenFile = Globals.getNewFile(ths, prefs,
2409                                              new File(prefs.get("workingDirectory")),
2410                                              extension,
2411                                              JFileChooser.SAVE_DIALOG, false);
2412
2413       if (chosenFile != null)
2414         outFile = new File(chosenFile);
2415
2416       else {
2417         return;
2418       }
2419
2420       final String lfName = lfFileName;
2421       final File oFile = outFile;
2422
2423       (new Thread() {
2424         public void run() {
2425           try {
2426             FileActions.exportDatabase
2427                 (basePanel().database, directory,
2428                  lfName, oFile, basePanel().getEncoding());
2429             output(Globals.lang("Exported database to file") + " '" +
2430                    oFile.getPath() + "'.");
2431           }
2432           catch (Exception ex) {
2433             //ex.printStackTrace();
2434             JOptionPane.showMessageDialog(ths, ex.getMessage(), Globals.lang("Error"),
2435                                           JOptionPane.ERROR_MESSAGE);
2436           }
2437         }
2438       }).start();
2439     }
2440   }
2441
2442   class LoadSessionAction
2443       extends MnemonicAwareAction {
2444       boolean running = false;
2445     public LoadSessionAction() {
2446       super(new ImageIcon(GUIGlobals.openIconFile));
2447       putValue(NAME, "Load session");
2448       putValue(ACCELERATOR_KEY, prefs.getKey("Load session"));
2449     }
2450
2451     public void actionPerformed(ActionEvent e) {
2452       if (prefs.get("savedSession") == null) {
2453         output(Globals.lang("No saved session found."));
2454         return;
2455       }
2456       if (running)
2457           return;
2458       else running = true;
2459       output(Globals.lang("Loading session..."));
2460       (new Thread() {
2461         public void run() {
2462           HashSet currentFiles = new HashSet();
2463           if (tabbedPane.getTabCount() > 0) {
2464             for (int i = 0; i < tabbedPane.getTabCount(); i++) {
2465                 if (baseAt(i).file != null)
2466                     currentFiles.add(baseAt(i).file.getPath());
2467             }
2468           }
2469           int i0 = tabbedPane.getTabCount();
2470           String[] names = prefs.getStringArray("savedSession");
2471           for (int i = 0; i < names.length; i++) {
2472             if (!currentFiles.contains(names[i])) {
2473               File file = new File(names[i]);
2474               if (file.exists()) {
2475                 //Util.pr("Opening last edited file:"
2476                 //+fileToOpen.getName());
2477                 open.openIt(file, i == 0);
2478               }
2479             }
2480           }
2481           output(Globals.lang("Files opened") + ": " +
2482                  (tabbedPane.getTabCount() - i0));
2483           running = false;
2484         }
2485       }).start();
2486
2487     }
2488   }
2489
2490   class ChangeTabAction
2491       extends MnemonicAwareAction {
2492     private boolean next;
2493     public ChangeTabAction(boolean next) {
2494       putValue(NAME, next ? "Next tab" : "Previous tab");
2495       this.next = next;
2496       //Util.pr(""+prefs.getKey("Next tab"));
2497       putValue(ACCELERATOR_KEY,
2498                (next ? prefs.getKey("Next tab") : prefs.getKey("Previous tab")));
2499     }
2500
2501     public void actionPerformed(ActionEvent e) {
2502       int i = tabbedPane.getSelectedIndex();
2503       int newI = (next ? i + 1 : i - 1);
2504       if (newI < 0) {
2505         newI = tabbedPane.getTabCount() - 1;
2506       }
2507       if (newI == tabbedPane.getTabCount()) {
2508         newI = 0;
2509       }
2510       tabbedPane.setSelectedIndex(newI);
2511     }
2512   }
2513
2514   /**
2515    * Class for handling general actions; cut, copy and paste. The focused component is
2516    * kept track of by Globals.focusListener, and we call the action stored under the
2517    * relevant name in its action map.
2518    */
2519   class EditAction
2520       extends MnemonicAwareAction {
2521     private String command;
2522     public EditAction(String command, URL icon) {
2523       super(new ImageIcon(icon));
2524       this.command = command;
2525       String nName = Util.nCase(command);
2526       putValue(NAME, nName);
2527       putValue(ACCELERATOR_KEY, prefs.getKey(nName));
2528       putValue(SHORT_DESCRIPTION, Globals.lang(nName));
2529       //putValue(ACCELERATOR_KEY,
2530       //         (next?prefs.getKey("Next tab"):prefs.getKey("Previous tab")));
2531     }
2532
2533     public void actionPerformed(ActionEvent e) {
2534
2535       //Util.pr(Globals.focusListener.getFocused().toString());
2536       JComponent source = Globals.focusListener.getFocused();
2537       try {
2538         source.getActionMap().get(command).actionPerformed
2539             (new ActionEvent(source, 0, command));
2540       } catch (NullPointerException ex) {
2541         // No component is focused, so we do nothing.
2542       }
2543     }
2544   }
2545
2546   class CustomizeExportsAction extends MnemonicAwareAction {
2547     public CustomizeExportsAction() {
2548       putValue(NAME, "Manage custom exports");
2549     }
2550
2551     public void actionPerformed(ActionEvent e) {
2552       ExportCustomizationDialog ecd = new ExportCustomizationDialog(ths);
2553       ecd.setVisible(true);
2554     }
2555   }
2556
2557   class CustomizeImportsAction extends MnemonicAwareAction {
2558     public CustomizeImportsAction() {
2559       putValue(NAME, "Manage custom imports");
2560     }
2561
2562     public void actionPerformed(ActionEvent e) {
2563       ImportCustomizationDialog ecd = new ImportCustomizationDialog(ths);
2564       ecd.setVisible(true);
2565     }
2566   }
2567
2568     class ExportCSV extends MnemonicAwareAction {
2569         public ExportCSV() {
2570             putValue(NAME, "Tab-separated file");
2571         }
2572         public void actionPerformed(ActionEvent e) {
2573             String chosenFile = Globals.getNewFile(ths, prefs, new File(prefs.get("workingDirectory")), ".csv",
2574                                                    JFileChooser.SAVE_DIALOG, true);
2575             if (chosenFile == null)
2576                 return;
2577             try {
2578                 FileActions.exportToCSV(basePanel().database(), new File(chosenFile),
2579                                         prefs);
2580             } catch (Exception ex) {
2581                 ex.printStackTrace();
2582             }
2583
2584         }
2585     }
2586
2587     class CustomizeEntryTypeAction extends MnemonicAwareAction {
2588         public CustomizeEntryTypeAction() {
2589             putValue(NAME, "Customize entry types");
2590         }
2591         public void actionPerformed(ActionEvent e) {
2592             JDialog dl = new EntryCustomizationDialog2(ths);
2593             Util.placeDialog(dl, ths);
2594             dl.setVisible(true);
2595         }
2596     }
2597
2598     class GenFieldsCustomizationAction extends MnemonicAwareAction {
2599         public GenFieldsCustomizationAction() {
2600             putValue(NAME, "Set up general fields");
2601         }
2602         public void actionPerformed(ActionEvent e) {
2603             GenFieldsCustomizer gf = new GenFieldsCustomizer(ths);
2604             Util.placeDialog(gf, ths);
2605             gf.setVisible(true);
2606
2607         }
2608     }
2609
2610     class DatabasePropertiesAction extends MnemonicAwareAction {
2611         DatabasePropertiesDialog propertiesDialog = null;
2612         public DatabasePropertiesAction() {
2613             putValue(NAME, "Database properties");
2614         }
2615
2616         public void actionPerformed(ActionEvent e) {
2617             if (propertiesDialog == null)
2618                 propertiesDialog = new DatabasePropertiesDialog(JabRefFrame.this);
2619             propertiesDialog.setPanel(basePanel());
2620             Util.placeDialog(propertiesDialog, JabRefFrame.this);
2621             propertiesDialog.setVisible(true);
2622         }
2623     }
2624
2625     /*private class ForegroundLabel extends JLabel {
2626          public ForegroundLabel(String s) {
2627              super(s);
2628              setFont(new Font("plain", Font.BOLD, 70));
2629              setHorizontalAlignment(JLabel.CENTER);
2630          }
2631
2632         public void paint(Graphics g) {
2633             Graphics2D g2 = (Graphics2D)g;
2634             g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
2635             super.paint(g2);    //To change body of overridden methods use File | Settings | File Templates.
2636         }
2637     }       */
2638
2639   private class MyGlassPane extends JPanel {
2640     //ForegroundLabel infoLabel = new ForegroundLabel("Showing search");
2641     public MyGlassPane() {
2642       addKeyListener(new KeyAdapter() { });
2643       addMouseListener(new MouseAdapter() { });
2644       /*  infoLabel.setForeground(new Color(255, 100, 100, 124));
2645
2646         setLayout(new BorderLayout());
2647         add(infoLabel, BorderLayout.CENTER);*/
2648       super.setCursor(
2649         Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
2650     }
2651       // Override isOpaque() to prevent the glasspane from hiding the window contents:
2652       public boolean isOpaque() { return false; }
2653   }
2654 }