20b8f84d950a944077ec6fc8c77d77044025f8fd
[debian/jabref.git] / src / main / java / net / sf / jabref / JabRef.java
1 /*  Copyright (C) 2003-2014 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 com.jgoodies.looks.plastic.Plastic3DLookAndFeel;
19 import com.jgoodies.looks.plastic.theme.SkyBluer;
20
21 import java.awt.Font;
22 import java.awt.Frame;
23 import java.io.File;
24 import java.io.FileNotFoundException;
25 import java.io.IOException;
26 import java.util.ArrayList;
27 import java.util.Collection;
28 import java.util.Enumeration;
29 import java.util.Iterator;
30 import java.util.List;
31 import java.util.Vector;
32 import java.util.prefs.BackingStoreException;
33
34 import javax.swing.*;
35 import javax.swing.plaf.FontUIResource;
36
37 import net.sf.jabref.export.AutoSaveManager;
38 import net.sf.jabref.export.ExportFormats;
39 import net.sf.jabref.export.FileActions;
40 import net.sf.jabref.export.IExportFormat;
41 import net.sf.jabref.export.SaveException;
42 import net.sf.jabref.export.SaveSession;
43 import net.sf.jabref.imports.*;
44 import net.sf.jabref.plugin.PluginCore;
45 import net.sf.jabref.plugin.PluginInstaller;
46 import net.sf.jabref.plugin.SidePanePlugin;
47 import net.sf.jabref.plugin.core.JabRefPlugin;
48 import net.sf.jabref.plugin.core.generated._JabRefPlugin;
49 import net.sf.jabref.plugin.core.generated._JabRefPlugin.EntryFetcherExtension;
50 import net.sf.jabref.remote.RemoteListener;
51 import net.sf.jabref.wizard.auximport.AuxCommandLine;
52
53 import com.sun.jna.Native;
54 import com.sun.jna.NativeLong;
55 import com.sun.jna.Pointer;
56 import com.sun.jna.WString;
57 import com.sun.jna.ptr.PointerByReference;
58
59 /**
60  * JabRef Main Class - The application gets started here.
61  *
62  */
63 public class JabRef {
64
65         public static JabRef singleton;
66     public static RemoteListener remoteListener = null;
67     public static JabRefFrame jrf;
68     public static Frame splashScreen = null;
69
70     boolean graphicFailure = false;
71
72
73     public static final int MAX_DIALOG_WARNINGS = 10;
74     private JabRefCLI cli;
75
76     public static void main(String[] args) {
77         new JabRef(args);
78     }
79
80     protected JabRef(String[] args) {
81
82                 singleton = this;
83
84
85                 JabRefPreferences prefs = JabRefPreferences.getInstance();
86
87         // See if there are plugins scheduled for deletion:
88         if (prefs.hasKey("deletePlugins") && (prefs.get("deletePlugins").length() > 0)) {
89             String[] toDelete = prefs.getStringArray("deletePlugins");
90             PluginInstaller.deletePluginsOnStartup(toDelete);
91             prefs.put("deletePlugins", "");
92         }
93
94         if (prefs.getBoolean("useProxy")) {
95                 // NetworkTab.java ensures that proxyHostname and proxyPort are not null
96                         System.getProperties().put("http.proxyHost", prefs.get("proxyHostname"));
97                         System.getProperties().put("http.proxyPort", prefs.get("proxyPort"));
98
99                         // currently, the following cannot be configured
100                         if (prefs.get("proxyUsername") != null) {
101                                 System.getProperties().put("http.proxyUser", prefs.get("proxyUsername"));
102                                 System.getProperties().put("http.proxyPassword", prefs.get("proxyPassword"));
103                         }
104                 } else {
105                         // The following two lines signal that the system proxy settings
106                         // should be used:
107                         System.setProperty("java.net.useSystemProxies", "true");
108                         System.getProperties().put("proxySet", "true");
109                 }
110
111         Globals.startBackgroundTasks();
112         Globals.setupLogging();
113                 Globals.prefs = prefs;
114         String langStr = prefs.get("language");
115         String[] parts = langStr.split("_");
116         String language, country;
117         if (parts.length == 1) {
118             language = langStr;
119             country = "";
120         }
121         else {
122             language = parts[0];
123             country = parts[1];
124         }
125
126                 Globals.setLanguage(language, country);
127         Globals.prefs.setLanguageDependentDefaultValues();
128                 /*
129                  * The Plug-in System is started automatically on the first call to
130                  * PluginCore.getManager().
131                  * 
132                  * Plug-ins are activated on the first call to their getInstance method.
133                  */
134
135         // Update which fields should be treated as numeric, based on preferences:
136         BibtexFields.setNumericFieldsFromPrefs();
137                 
138                 /* Build list of Import and Export formats */
139                 Globals.importFormatReader.resetImportFormats();
140                 BibtexEntryType.loadCustomEntryTypes(prefs);
141                 ExportFormats.initAllExports();
142                 
143                 // Read list(s) of journal names and abbreviations:
144         Globals.initializeJournalNames();
145
146                 // Check for running JabRef
147                 if (Globals.prefs.getBoolean("useRemoteServer")) {
148                         remoteListener = RemoteListener.openRemoteListener(this);
149
150                         if (remoteListener == null) {
151                                 // Unless we are alone, try to contact already running JabRef:
152                                 if (RemoteListener.sendToActiveJabRefInstance(args)) {
153
154                                         /*
155                                          * We have successfully sent our command line options
156                                          * through the socket to another JabRef instance. So we
157                                          * assume it's all taken care of, and quit.
158                                          */
159                                         System.out.println(
160                             Globals.lang("Arguments passed on to running JabRef instance. Shutting down."));
161                                         System.exit(0);
162                                 }
163                         } else {
164                                 // No listener found, thus we are the first instance to be
165                                 // started.
166                                 remoteListener.start();
167                         }
168                 }
169
170                 /*
171                  * See if the user has a personal journal list set up. If so, add these
172                  * journal names and abbreviations to the list:
173                  */
174                 String personalJournalList = prefs.get("personalJournalList");
175                 if (personalJournalList != null && !personalJournalList.isEmpty()) {
176                         try {
177                                 Globals.journalAbbrev.readJournalList(new File(
178                                                 personalJournalList));
179                         } catch (FileNotFoundException e) {
180                                 JOptionPane.showMessageDialog(null, Globals.lang("Journal file not found") + ": " + e.getMessage(), Globals.lang("Error opening file"), JOptionPane.ERROR_MESSAGE);
181                                 Globals.prefs.put("personalJournalList", "");
182                         }
183                 }
184                 
185                 // override used newline character with the one stored in the preferences
186                 // The preferences return the system newline character sequence as default
187                 Globals.NEWLINE = Globals.prefs.get(JabRefPreferences.NEWLINE);
188                 Globals.NEWLINE_LENGTH = Globals.NEWLINE.length();
189                 
190                 
191                 // Set application user model id so that pinning JabRef to the Win7/8 taskbar works
192                 // Based on http://stackoverflow.com/a/1928830
193                 setCurrentProcessExplicitAppUserModelID("JabRef."+Globals.VERSION);
194             //System.out.println(getCurrentProcessExplicitAppUserModelID());
195                 
196                 openWindow(processArguments(args, true));
197         }
198     
199     // Do not use this code in release version, it contains some memory leaks
200     public static String getCurrentProcessExplicitAppUserModelID()
201     {
202       final PointerByReference r = new PointerByReference();
203
204       if (GetCurrentProcessExplicitAppUserModelID(r).longValue() == 0)
205       {
206         final Pointer p = r.getValue();
207
208
209         return p.getString(0, true); // here we leak native memory by lazyness
210       }      
211       return "N/A";
212     }
213
214     public static void setCurrentProcessExplicitAppUserModelID(final String appID)
215     {
216       if (SetCurrentProcessExplicitAppUserModelID(new WString(appID)).longValue() != 0)
217         throw new RuntimeException("unable to set current process explicit AppUserModelID to: " + appID);
218     }
219
220     private static native NativeLong GetCurrentProcessExplicitAppUserModelID(PointerByReference appID);
221     private static native NativeLong SetCurrentProcessExplicitAppUserModelID(WString appID);
222
223
224     static
225     {
226       Native.register("shell32");
227     }
228
229
230     public Vector<ParserResult> processArguments(String[] args, boolean initialStartup) {
231
232         cli = new JabRefCLI(args);
233
234         if (initialStartup && cli.isShowVersion()) {
235             cli.options.displayVersion();
236             cli.disableGui.setInvoked(true);
237         }
238
239         if (initialStartup && cli.isHelp()) {
240             System.out.println("jabref [options] [bibtex-file]\n");
241             System.out.println(cli.getHelp());
242
243             String importFormats = Globals.importFormatReader.getImportFormatList();
244             System.out.println(Globals.lang("Available import formats") + ":\n"
245                 + importFormats);
246
247             String outFormats = ExportFormats.getConsoleExportList(70, 20, "\t");
248             System.out.println(Globals.lang("Available export formats") + ": " + outFormats
249                 + ".");
250             System.exit(0);
251         }
252         
253         boolean commandmode = cli.isDisableGui() || cli.fetcherEngine.isInvoked();
254         
255         // First we quickly scan the command line parameters for any that signal
256         // that the GUI
257         // should not be opened. This is used to decide whether we should show the
258         // splash screen or not.
259         if (initialStartup && !commandmode && !cli.isDisableSplash()) {
260             try {
261                 splashScreen = SplashScreen.splash();
262             } catch (Throwable ex) {
263                 graphicFailure = true;
264                 System.err.println(Globals.lang("Unable to create graphical interface")
265                     + ".");
266             }
267         }
268
269         // Check if we should reset all preferences to default values:
270         if (cli.defPrefs.isInvoked()) {
271             String value = cli.defPrefs.getStringValue();
272             if (value.trim().equals("all")) {
273                 try {
274                     System.out.println(Globals.lang("Setting all preferences to default values."));
275                     Globals.prefs.clear();
276                 } catch (BackingStoreException e) {
277                     System.err.println(Globals.lang("Unable to clear preferences."));
278                     e.printStackTrace();
279                 }
280             } else {
281                 String[] keys = value.split(",");
282                 for (String key : keys) {
283                     if (Globals.prefs.hasKey(key.trim())) {
284                         System.out.println(Globals.lang("Resetting preference key '%0'", key.trim()));
285                         Globals.prefs.clear(key.trim());
286                     } else {
287                         System.out.println(Globals.lang("Unknown preference key '%0'", key.trim()));
288                     }
289                 }
290             }
291
292         }
293
294         // Check if we should import preferences from a file:
295         if (cli.importPrefs.isInvoked()) {
296             try {
297                 Globals.prefs.importPreferences(cli.importPrefs.getStringValue());
298                 BibtexEntryType.loadCustomEntryTypes(Globals.prefs);
299                 ExportFormats.initAllExports();
300             }
301             catch (IOException ex) {
302             Util.pr(ex.getMessage());
303             }
304         }
305
306         // Vector to put imported/loaded database(s) in.
307         Vector<ParserResult> loaded = new Vector<ParserResult>();
308         Vector<String> toImport = new Vector<String>();
309         if (!cli.isBlank() && (cli.getLeftOver().length > 0))  {
310             for (String aLeftOver : cli.getLeftOver()) {
311                 // Leftover arguments that have a "bib" extension are interpreted as
312                 // bib files to open. Other files, and files that could not be opened
313                 // as bib, we try to import instead.
314                 boolean bibExtension = aLeftOver.toLowerCase().endsWith("bib");
315                 ParserResult pr = null;
316                 if (bibExtension)
317                     pr = openBibFile(aLeftOver, false);
318
319                 if ((pr == null) || (pr == ParserResult.INVALID_FORMAT)) {
320                     // We will try to import this file. Normally we
321                     // will import it into a new tab, but if this import has
322                     // been initiated by another instance through the remote
323                     // listener, we will instead import it into the current database.
324                     // This will enable easy integration with web browers that can
325                     // open a reference file in JabRef.
326                     if (initialStartup) {
327                         toImport.add(aLeftOver);
328                     } else {
329                         ParserResult res = importToOpenBase(aLeftOver);
330                         if (res != null)
331                             loaded.add(res);
332                         else
333                             loaded.add(ParserResult.INVALID_FORMAT);
334                     }
335                 } else if (pr != ParserResult.FILE_LOCKED)
336                     loaded.add(pr);
337
338             }
339         }
340
341         if (!cli.isBlank() && cli.importFile.isInvoked()) {
342             toImport.add(cli.importFile.getStringValue());
343         }
344
345         for (String filenameString : toImport) {
346                         ParserResult pr = importFile(filenameString);
347                         if (pr != null)
348                                 loaded.add(pr);
349                 }
350
351         if (!cli.isBlank() && cli.importToOpenBase.isInvoked()) {
352             ParserResult res = importToOpenBase(cli.importToOpenBase.getStringValue());
353             if (res != null)
354                 loaded.add(res);
355         }
356
357         if (!cli.isBlank() && cli.fetcherEngine.isInvoked()) {
358             ParserResult res = fetch(cli.fetcherEngine.getStringValue());
359             if (res != null)
360                 loaded.add(res);
361         }
362
363
364         if(cli.exportMatches.isInvoked()) {
365             if (loaded.size() > 0) {
366                 String[] data = cli.exportMatches.getStringValue().split(",");
367                 String searchTerm = data[0].replace("\\$"," "); //enables blanks within the search term:
368                                                                 //? stands for a blank
369                 ParserResult pr =
370                         loaded.elementAt(loaded.size() - 1);
371                 BibtexDatabase dataBase = pr.getDatabase();
372                 SearchManagerNoGUI smng = new SearchManagerNoGUI(searchTerm, dataBase);
373                 BibtexDatabase newBase = smng.getDBfromMatches(); //newBase contains only match entries
374                 
375                 
376                 //export database
377                 if (newBase != null && newBase.getEntryCount() > 0) {
378                         String formatName = null;
379                         IExportFormat format = null;
380
381                         //read in the export format, take default format if no format entered
382                         switch (data.length){
383                                 case(3):{
384                                         formatName = data[2];
385                                         break;
386                                 }
387                                 case (2):{
388                                         //default ExportFormat: HTML table (with Abstract & BibTeX)
389                                         formatName = "tablerefsabsbib";
390                                         break;
391                                 }
392                                 default:{
393                                         System.err.println(Globals.lang("Output file missing").concat(". \n \t ").concat("Usage").concat(": ") + JabRefCLI.exportMatchesSyntax);
394                                         System.exit(0);
395                                 }
396                         } //end switch
397                         
398                         //export new database
399                         format = ExportFormats.getExportFormat(formatName);
400                         if (format != null) {
401                             // We have an ExportFormat instance:
402                             try {
403                                 System.out.println(Globals.lang("Exporting") + ": " + data[1]);
404                                 format.performExport(newBase, pr.getMetaData(), data[1], pr.getEncoding(), null);
405                             } catch (Exception ex) {
406                                 System.err.println(Globals.lang("Could not export file")
407                                     + " '" + data[1] + "': " + ex.getMessage());
408                             }
409                         } else
410                             System.err.println(Globals.lang("Unknown export format")
411                                     + ": " + formatName);
412                 } /*end if newBase != null*/ else {
413                         System.err.println(Globals.lang("No search matches."));
414                 }
415             } else {
416                 System.err.println(Globals.lang("The output option depends on a valid input option."));
417             }  //end if(loaded.size > 0)
418         } //end exportMatches invoked 
419
420
421         if (cli.exportFile.isInvoked()) {
422             if (loaded.size() > 0) {
423                 String[] data = cli.exportFile.getStringValue().split(",");
424
425                 if (data.length == 1) {
426                     // This signals that the latest import should be stored in BibTeX
427                     // format to the given file.
428                     if (loaded.size() > 0) {
429                         ParserResult pr =
430                             loaded.elementAt(loaded.size() - 1);
431                         if (!pr.isInvalid()) {
432                             try {
433                                 System.out.println(Globals.lang("Saving") + ": " + data[0]);
434                                 SaveSession session = FileActions.saveDatabase(pr.getDatabase(),
435                                     pr.getMetaData(), new File(data[0]), Globals.prefs,
436                                     false, false, Globals.prefs.get("defaultEncoding"), false);
437                                 // Show just a warning message if encoding didn't work for all characters:
438                                 if (!session.getWriter().couldEncodeAll())
439                                     System.err.println(Globals.lang("Warning")+": "+
440                                         Globals.lang("The chosen encoding '%0' could not encode the following characters: ",
441                                         session.getEncoding())+session.getWriter().getProblemCharacters());
442                                 session.commit();
443                             } catch (SaveException ex) {
444                                 System.err.println(Globals.lang("Could not save file") + " '"
445                                     + data[0] + "': " + ex.getMessage());
446                             }
447                         }
448                     } else
449                         System.err.println(Globals.lang(
450                                 "The output option depends on a valid import option."));
451                 } else if (data.length == 2) {
452                     // This signals that the latest import should be stored in the given
453                     // format to the given file.
454                     ParserResult pr = loaded.elementAt(loaded.size() - 1);
455
456                     // Set the global variable for this database's file directory before exporting,
457                     // so formatters can resolve linked files correctly.
458                     // (This is an ugly hack!)
459                     File theFile = pr.getFile();
460                     if (!theFile.isAbsolute())
461                         theFile = theFile.getAbsoluteFile();
462                     MetaData metaData = pr.getMetaData();
463                     metaData.setFile(theFile);
464                     Globals.prefs.fileDirForDatabase = metaData.getFileDirectory(GUIGlobals.FILE_FIELD);
465                     Globals.prefs.databaseFile = metaData.getFile();
466                     System.out.println(Globals.lang("Exporting") + ": " + data[0]);
467                     IExportFormat format = ExportFormats.getExportFormat(data[1]);
468                     if (format != null) {
469                         // We have an ExportFormat instance:
470                         try {
471                             format.performExport(pr.getDatabase(), 
472                                     pr.getMetaData(), data[0], pr.getEncoding(), null);
473                         } catch (Exception ex) {
474                             System.err.println(Globals.lang("Could not export file")
475                                 + " '" + data[0] + "': " + ex.getMessage());
476                         }
477                     }
478                     else
479                         System.err.println(Globals.lang("Unknown export format")
480                                 + ": " + data[1]);
481
482                 }
483             } else
484                 System.err.println(Globals.lang(
485                         "The output option depends on a valid import option."));
486         }
487
488         //Util.pr(": Finished export");
489
490         if (cli.exportPrefs.isInvoked()) {
491             try {
492                 Globals.prefs.exportPreferences(cli.exportPrefs.getStringValue());
493             } catch (IOException ex) {
494                 Util.pr(ex.getMessage());
495             }
496         }
497
498
499         if (!cli.isBlank() && cli.auxImExport.isInvoked()) {
500             boolean usageMsg = false;
501
502             if (loaded.size() > 0) // bibtex file loaded
503              {
504                 String[] data = cli.auxImExport.getStringValue().split(",");
505
506                 if (data.length == 2) {
507                     ParserResult pr = loaded.firstElement();
508                     AuxCommandLine acl = new AuxCommandLine(data[0], pr.getDatabase());
509                     BibtexDatabase newBase = acl.perform();
510
511                     boolean notSavedMsg = false;
512
513                     // write an output, if something could be resolved
514                     if (newBase != null) {
515                         if (newBase.getEntryCount() > 0) {
516                             String subName = Util.getCorrectFileName(data[1], "bib");
517
518                             try {
519                                 System.out.println(Globals.lang("Saving") + ": "
520                                     + subName);
521                                 SaveSession session = FileActions.saveDatabase(newBase, new MetaData(), // no Metadata
522                                     new File(subName), Globals.prefs, false, false,
523                                     Globals.prefs.get("defaultEncoding"), false);
524                                 // Show just a warning message if encoding didn't work for all characters:
525                                 if (!session.getWriter().couldEncodeAll())
526                                     System.err.println(Globals.lang("Warning")+": "+
527                                         Globals.lang("The chosen encoding '%0' could not encode the following characters: ",
528                                         session.getEncoding())+session.getWriter().getProblemCharacters());
529                                 session.commit();
530                             } catch (SaveException ex) {
531                                 System.err.println(Globals.lang("Could not save file")
532                                     + " '" + subName + "': " + ex.getMessage());
533                             }
534
535                             notSavedMsg = true;
536                         }
537                     }
538
539                     if (!notSavedMsg)
540                         System.out.println(Globals.lang("no database generated"));
541                 } else
542                     usageMsg = true;
543             } else
544                 usageMsg = true;
545
546             if (usageMsg) {
547                 System.out.println(Globals.lang("no base-bibtex-file specified"));
548                 System.out.println(Globals.lang("usage") + " :");
549                 System.out.println(
550                     "jabref --aux infile[.aux],outfile[.bib] base-bibtex-file");
551             }
552         }
553
554         return loaded;
555     }
556
557     /**
558      * Run an entry fetcher from the command line.
559      * 
560      * Note that this only works headlessly if the EntryFetcher does not show
561      * any GUI.
562      * 
563      * @param fetchCommand
564      *            A string containing both the fetcher to use (id of
565      *            EntryFetcherExtension minus Fetcher) and the search query,
566      *            separated by a :
567      * @return A parser result containing the entries fetched or null if an
568      *         error occurred.
569      */
570     protected ParserResult fetch(String fetchCommand) {
571
572         if (fetchCommand == null || !fetchCommand.contains(":") ||
573             fetchCommand.split(":").length != 2) {
574             System.out.println(Globals.lang("Expected syntax for --fetch='<name of fetcher>:<query>'"));
575             System.out.println(Globals.lang("The following fetchers are available:"));
576             return null;
577         }
578
579         String engine = fetchCommand.split(":")[0];
580         String query = fetchCommand.split(":")[1];
581
582         EntryFetcher fetcher = null;
583         for (EntryFetcherExtension e : JabRefPlugin.getInstance(PluginCore.getManager())
584             .getEntryFetcherExtensions()) {
585             if (engine.toLowerCase().equals(e.getId().replaceAll("Fetcher", "").toLowerCase()))
586                 fetcher = e.getEntryFetcher();
587         }
588
589         if (fetcher == null) {
590             System.out.println(Globals.lang("Could not find fetcher '%0'", engine));
591             System.out.println(Globals.lang("The following fetchers are available:"));
592             for (EntryFetcherExtension e : JabRefPlugin.getInstance(PluginCore.getManager())
593                 .getEntryFetcherExtensions()) {
594                 System.out.println("  " + e.getId().replaceAll("Fetcher", "").toLowerCase());
595             }
596             return null;
597         }
598
599         System.out.println(Globals.lang("Running Query '%0' with fetcher '%1'.", query, engine) +
600             " " + Globals.lang("Please wait..."));
601         Collection<BibtexEntry> result = new ImportInspectionCommandLine().query(query, fetcher);
602
603         if (result == null || result.size() == 0) {
604             System.out.println(Globals.lang(
605                 "Query '%0' with fetcher '%1' did not return any results.", query, engine));
606             return null;
607         }
608
609         return new ParserResult(result);
610     }
611     
612     private void setLookAndFeel() {
613         try {
614             String systemLnF;
615             // * Look first into the Preferences
616             // * Fallback to the System Look & Fell
617             if (Globals.prefs.getBoolean("useDefaultLookAndFeel")) {
618                 systemLnF = UIManager.getSystemLookAndFeelClassName();
619             } else {
620                 systemLnF = Globals.prefs.get("lookAndFeel");
621             }
622
623             // At all cost, avoid ending up with the Metal look and feel:
624             if (systemLnF.equals("javax.swing.plaf.metal.MetalLookAndFeel")) {
625                 Plastic3DLookAndFeel lnf = new Plastic3DLookAndFeel();
626                 Plastic3DLookAndFeel.setCurrentTheme(new SkyBluer());
627                 com.jgoodies.looks.Options.setPopupDropShadowEnabled(true);
628                 UIManager.setLookAndFeel(lnf);
629             }
630             else {
631                 UIManager.setLookAndFeel(systemLnF);
632             }
633         } catch (Exception e) {
634             e.printStackTrace();
635         }
636
637         // In JabRef v2.8, we did it only on NON-Mac. Now, we try on all platforms
638         boolean overrideDefaultFonts = Globals.prefs.getBoolean("overrideDefaultFonts");
639         if (overrideDefaultFonts) {
640             int fontSize = Globals.prefs.getInt("menuFontSize");
641             UIDefaults defaults = UIManager.getDefaults();
642             Enumeration<Object> keys = defaults.keys();
643             Double zoomLevel = null;
644             while (keys.hasMoreElements()) {
645                 Object key = keys.nextElement();
646                 if ((key instanceof String) && (((String) key).endsWith(".font"))) {
647                     FontUIResource font = (FontUIResource) UIManager.get(key);
648                     if (zoomLevel == null) {
649                         // zoomLevel not yet set, calculate it based on the first found font
650                         zoomLevel = (double) fontSize / (double) font.getSize();
651                     }
652                     font = new FontUIResource(font.getName(), font.getStyle(), fontSize);
653                     defaults.put(key, font);
654                 }
655             }
656             if (zoomLevel != null) {
657                 GUIGlobals.zoomLevel = zoomLevel;
658             }
659         }
660     }
661
662         public void openWindow(Vector<ParserResult> loaded) {
663         if (!graphicFailure && !cli.isDisableGui()) {
664             // Call the method performCompatibilityUpdate(), which does any
665             // necessary changes for users with a preference set from an older
666             // Jabref version.
667             Util.performCompatibilityUpdate();
668
669
670             // Set up custom or default icon theme:
671             GUIGlobals.setUpIconTheme();
672
673             // TODO: remove temporary registering of external file types?
674             Globals.prefs.updateExternalFileTypes();
675
676            // This property is set to make the Mac OSX Java VM move the menu bar to
677             // the top
678             // of the screen, where Mac users expect it to be.
679             System.setProperty("apple.laf.useScreenMenuBar", "true");
680
681             // Set antialiasing on everywhere. This only works in JRE >= 1.5.
682             // Or... it doesn't work, period.
683             //System.setProperty("swing.aatext", "true");
684             // TODO test and maybe remove this! I found this commented out with no additional info ( payload@lavabit.com )
685
686             // Set the Look & Feel for Swing.
687             try {
688                 setLookAndFeel();
689             } catch (Throwable e) {
690                 e.printStackTrace();
691             }
692
693
694             // If the option is enabled, open the last edited databases, if any.
695             if (!cli.isBlank() && Globals.prefs.getBoolean("openLastEdited") && (Globals.prefs.get("lastEdited") != null)) {
696                 // How to handle errors in the databases to open?
697                 String[] names = Globals.prefs.getStringArray("lastEdited");
698                 lastEdLoop:
699                 for (String name : names) {
700                     File fileToOpen = new File(name);
701
702                     for (int j = 0; j < loaded.size(); j++) {
703                         ParserResult pr = loaded.elementAt(j);
704
705                         if ((pr.getFile() != null) && pr.getFile().equals(fileToOpen))
706                             continue lastEdLoop;
707                     }
708
709                     if (fileToOpen.exists()) {
710                         ParserResult pr = openBibFile(name, false);
711
712                         if (pr != null) {
713
714                             if (pr == ParserResult.INVALID_FORMAT) {
715                                 System.out.println(Globals.lang("Error opening file") + " '" + fileToOpen.getPath() + "'");
716                             } else if (pr != ParserResult.FILE_LOCKED)
717                                 loaded.add(pr);
718
719                         }
720                     }
721                 }
722             }
723
724             GUIGlobals.init();
725             GUIGlobals.CURRENTFONT =
726                 new Font(Globals.prefs.get("fontFamily"), Globals.prefs.getInt("fontStyle"),
727                     Globals.prefs.getInt("fontSize"));
728
729             //Util.pr(": Initializing frame");
730             jrf = new JabRefFrame();
731
732             // Add all loaded databases to the frame:
733             
734                 boolean first = true;
735             List<File> postponed = new ArrayList<File>();
736             List<ParserResult> failed = new ArrayList<ParserResult>();
737             List<ParserResult> toOpenTab = new ArrayList<ParserResult>();
738             if (loaded.size() > 0) {
739                 for (Iterator<ParserResult> i = loaded.iterator(); i.hasNext();){
740                     ParserResult pr = i.next();
741                     if (pr.isInvalid()) {
742                         failed.add(pr);
743                         i.remove();
744                     }
745                     else if (!pr.isPostponedAutosaveFound()) {
746                         if (pr.toOpenTab()) {
747                             // things to be appended to an opened tab should be done after opening all tabs
748                             // add them to the list
749                             toOpenTab.add(pr);
750                         } else {
751                             jrf.addParserResult(pr, first);
752                             first = false;
753                         }
754                     }
755                     else {
756                         i.remove();
757                         postponed.add(pr.getFile());
758                     }
759                 }
760             }
761
762             // finally add things to the currently opened tab
763             for (ParserResult pr: toOpenTab) {
764                 jrf.addParserResult(pr, first);
765                 first = false;
766             }
767
768             if (cli.isLoadSession())
769                 jrf.loadSessionAction.actionPerformed(new java.awt.event.ActionEvent(
770                         jrf, 0, ""));
771
772             if (splashScreen != null) {// do this only if splashscreen was actually created
773                 splashScreen.dispose();
774                 splashScreen = null;
775             }
776
777             /*JOptionPane.showMessageDialog(null, Globals.lang("Please note that this "
778                 +"is an early beta version. Do not use it without backing up your files!"),
779                     Globals.lang("Beta version"), JOptionPane.WARNING_MESSAGE);*/
780
781
782             // Start auto save timer:
783             if (Globals.prefs.getBoolean("autoSave"))
784                 Globals.startAutoSaveManager(jrf);
785
786             // If we are set to remember the window location, we also remember the maximised
787             // state. This needs to be set after the window has been made visible, so we
788             // do it here:
789             if (Globals.prefs.getBoolean("windowMaximised")) {
790                 jrf.setExtendedState(JFrame.MAXIMIZED_BOTH);
791             }
792
793             jrf.setVisible(true);
794
795             if (Globals.prefs.getBoolean("windowMaximised")) {
796                 jrf.setExtendedState(JFrame.MAXIMIZED_BOTH);
797             }
798
799             // TEST TEST TEST TEST TEST TEST
800             startSidePanePlugins(jrf);
801
802             for (ParserResult pr : failed) {
803                 String message = "<html>"+Globals.lang("Error opening file '%0'.", pr.getFile().getName())
804                     +"<p>"+pr.getErrorMessage()+"</html>";
805
806                 JOptionPane.showMessageDialog(jrf, message, Globals.lang("Error opening file"),
807                     JOptionPane.ERROR_MESSAGE);
808             }
809
810             for (int i = 0; i < loaded.size(); i++) {
811                 ParserResult pr = loaded.elementAt(i);
812                 if (Globals.prefs.getBoolean("displayKeyWarningDialogAtStartup") && pr.hasWarnings()) {
813                     String[] wrns = pr.warnings();
814                     StringBuilder wrn = new StringBuilder();
815                     for (int j = 0; j<Math.min(MAX_DIALOG_WARNINGS, wrns.length); j++)
816                         wrn.append(j + 1).append(". ").append(wrns[j]).append("\n");
817                     if (wrns.length > MAX_DIALOG_WARNINGS) {
818                         wrn.append("... ");
819                         wrn.append(Globals.lang("%0 warnings", String.valueOf(wrns.length)));
820                     }
821                     else if (wrn.length() > 0)
822                         wrn.deleteCharAt(wrn.length() - 1);
823                     jrf.showBaseAt(i);
824                     JOptionPane.showMessageDialog(jrf, wrn.toString(),
825                         Globals.lang("Warnings")+" ("+pr.getFile().getName()+")",
826                         JOptionPane.WARNING_MESSAGE);
827                 }
828             }
829
830             // After adding the databases, go through each and see if
831             // any post open actions need to be done. For instance, checking
832             // if we found new entry types that can be imported, or checking
833             // if the database contents should be modified due to new features
834             // in this version of JabRef.
835             // Note that we have to check whether i does not go over baseCount().
836             // This is because importToOpen might have been used, which adds to
837             // loaded, but not to baseCount()
838             for (int i = 0; (i < loaded.size()) && (i < jrf.baseCount()); i++) {
839                 ParserResult pr = loaded.elementAt(i);
840                 BasePanel panel = jrf.baseAt(i);
841                 OpenDatabaseAction.performPostOpenActions(panel, pr, true);
842             }
843
844             //Util.pr(": Finished adding panels");
845
846             // If any database loading was postponed due to an autosave, schedule them
847             // for handing now:
848             if (postponed.size() > 0) {
849                 AutosaveStartupPrompter asp = new AutosaveStartupPrompter(jrf, postponed);
850                 SwingUtilities.invokeLater(asp);
851             }
852
853             if (loaded.size() > 0) {
854                 jrf.tabbedPane.setSelectedIndex(0);
855                 new FocusRequester(((BasePanel) jrf.tabbedPane.getComponentAt(0)).mainTable);
856             }
857         } else
858             System.exit(0);
859     }
860
861     /**
862      * Go through all registered instances of SidePanePlugin, and register them
863      * in the SidePaneManager.
864      *
865      * @param jrf The JabRefFrame.
866      */
867     private void startSidePanePlugins(JabRefFrame jrf) {
868
869         JabRefPlugin jabrefPlugin = JabRefPlugin.getInstance(PluginCore.getManager());
870         List<_JabRefPlugin.SidePanePluginExtension> plugins = jabrefPlugin.getSidePanePluginExtensions();
871         for (_JabRefPlugin.SidePanePluginExtension extension : plugins) {
872             SidePanePlugin plugin = extension.getSidePanePlugin();
873             plugin.init(jrf, jrf.sidePaneManager);
874             SidePaneComponent comp = plugin.getSidePaneComponent();
875             jrf.sidePaneManager.register(comp.getName(), comp);
876             jrf.addPluginMenuItem(plugin.getMenuItem());
877         }
878     }
879
880     public static ParserResult openBibFile(String name, boolean ignoreAutosave) {
881         Globals.logger(Globals.lang("Opening") + ": " + name);
882         File file = new File(name);
883         if (!file.exists()) {
884             ParserResult pr = new ParserResult(null, null, null);
885             pr.setFile(file);
886             pr.setInvalid(true);
887             System.err.println(Globals.lang("Error")+": "+Globals.lang("File not found"));
888             return pr;
889
890         }
891         try {
892
893             if (!ignoreAutosave) {
894                 boolean autoSaveFound = AutoSaveManager.newerAutoSaveExists(file);
895                 if (autoSaveFound) {
896                     // We have found a newer autosave. Make a note of this, so it can be
897                     // handled after startup:
898                     ParserResult postp = new ParserResult(null, null, null);
899                     postp.setPostponedAutosaveFound(true);
900                     postp.setFile(file);
901                     return postp;
902                 }
903             }
904
905             if (!Util.waitForFileLock(file, 10)) {
906                 System.out.println(Globals.lang("Error opening file")+" '"+name+"'. "+
907                     "File is locked by another JabRef instance.");
908                 return ParserResult.FILE_LOCKED;
909             }
910
911             String encoding = Globals.prefs.get("defaultEncoding");
912             ParserResult pr = OpenDatabaseAction.loadDatabase(file, encoding);
913             if (pr == null) {
914                 pr = new ParserResult(null, null, null);
915                 pr.setFile(file);
916                 pr.setInvalid(true);
917                 return pr;
918
919             }
920             pr.setFile(file);
921             if (pr.hasWarnings()) {
922                 String[] warn = pr.warnings();
923                 for (String aWarn : warn) System.out.println(Globals.lang("Warning") + ": " + aWarn);
924
925             }
926             return pr;
927         } catch (Throwable ex) {
928             ParserResult pr = new ParserResult(null, null, null);
929             pr.setFile(file);
930             pr.setInvalid(true);
931             pr.setErrorMessage(ex.getMessage());
932             return pr;
933         }
934
935     }
936
937     public static ParserResult importFile(String argument){
938         String[] data = argument.split(",");
939         try {
940             if ((data.length > 1) && !"*".equals(data[1])) {
941                 System.out.println(Globals.lang("Importing") + ": " + data[0]);
942                 try {
943                     List<BibtexEntry> entries;
944                     if (Globals.ON_WIN) {
945                       entries = Globals.importFormatReader.importFromFile(data[1], data[0], jrf);
946                     }
947                     else {
948                       entries = Globals.importFormatReader.importFromFile( data[1],
949                                 data[0].replaceAll("~", System.getProperty("user.home")), jrf );
950                     }
951                     return new ParserResult(entries);
952                 } catch (IllegalArgumentException ex) {
953                     System.err.println(Globals.lang("Unknown import format")+": "+data[1]);
954                     return null;
955                 }
956             } else {
957                 // * means "guess the format":
958                 System.out.println(Globals.lang("Importing in unknown format")
959                         + ": " + data[0]);
960
961                 ImportFormatReader.UnknownFormatImport  importResult;
962                 if (Globals.ON_WIN) {
963                   importResult = Globals.importFormatReader.importUnknownFormat(data[0]);
964                 }
965                 else {
966                   importResult = Globals.importFormatReader.importUnknownFormat(
967                                  data[0].replaceAll("~", System.getProperty("user.home")));
968                 }
969                 
970                 if (importResult != null){
971                         System.out.println(Globals.lang("Format used") + ": "
972                         + importResult.format);
973                         
974                         return importResult.parserResult;
975                 } else {
976                         System.out.println(Globals.lang(
977                                 "Could not find a suitable import format."));
978                 }
979             }
980         } catch (IOException ex) {
981             System.err.println(Globals.lang("Error opening file") + " '"
982                     + data[0] + "': " + ex.getLocalizedMessage());
983         }
984         return null;
985     }
986
987     /**
988      * Will open a file (like importFile), but will also request JabRef to focus on this database 
989      * @param argument See importFile.
990      * @return ParserResult with setToOpenTab(true)
991      */
992     public static ParserResult importToOpenBase(String argument) {
993         ParserResult result = importFile(argument);
994         
995         if (result != null)
996                 result.setToOpenTab(true);
997         
998         return result;
999     }
1000 }