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