Imported Upstream version 2.11~beta3+ds upstream upstream/2.11_beta3+ds
authorgregor herrmann <gregoa@debian.org>
Thu, 9 Jul 2015 16:53:48 +0000 (18:53 +0200)
committergregor herrmann <gregoa@debian.org>
Thu, 9 Jul 2015 16:53:48 +0000 (18:53 +0200)
148 files changed:
.travis.yml
CHANGELOG
CONTRIBUTING.md
README.md
build.gradle
build.xml
src/main/java/net/sf/jabref/AdvancedTab.java
src/main/java/net/sf/jabref/BasePanel.java
src/main/java/net/sf/jabref/BibtexDatabase.java
src/main/java/net/sf/jabref/BibtexEntry.java
src/main/java/net/sf/jabref/BibtexEntryWriter.java [new file with mode: 0644]
src/main/java/net/sf/jabref/ContentSelectorDialog2.java
src/main/java/net/sf/jabref/EntryEditor.java
src/main/java/net/sf/jabref/FieldComparator.java
src/main/java/net/sf/jabref/FieldContentSelector.java
src/main/java/net/sf/jabref/FileSortTab.java
src/main/java/net/sf/jabref/FileTab.java
src/main/java/net/sf/jabref/FindUnlinkedFilesDialog.java
src/main/java/net/sf/jabref/FontSelectorDialog.java
src/main/java/net/sf/jabref/GeneralTab.java
src/main/java/net/sf/jabref/Globals.java
src/main/java/net/sf/jabref/JabRef.java
src/main/java/net/sf/jabref/JabRefCLI.java
src/main/java/net/sf/jabref/JabRefFrame.java
src/main/java/net/sf/jabref/JabRefPreferences.java
src/main/java/net/sf/jabref/KeyBindingsDialog.java
src/main/java/net/sf/jabref/MarkEntriesAction.java
src/main/java/net/sf/jabref/MonthUtil.java [new file with mode: 0644]
src/main/java/net/sf/jabref/PrefsDialog3.java
src/main/java/net/sf/jabref/RightClickMenu.java
src/main/java/net/sf/jabref/SendAsEMailAction.java
src/main/java/net/sf/jabref/SidePaneManager.java
src/main/java/net/sf/jabref/TableColumnsTab.java
src/main/java/net/sf/jabref/TablePrefsTab.java
src/main/java/net/sf/jabref/TransferableBibtexEntry.java
src/main/java/net/sf/jabref/UrlDragDrop.java
src/main/java/net/sf/jabref/Util.java
src/main/java/net/sf/jabref/UtilFindFiles.java [new file with mode: 0644]
src/main/java/net/sf/jabref/export/ExportToClipboardAction.java
src/main/java/net/sf/jabref/export/FileActions.java
src/main/java/net/sf/jabref/export/LatexFieldFormatter.java
src/main/java/net/sf/jabref/export/layout/format/RisMonth.java
src/main/java/net/sf/jabref/external/DownloadExternalFile.java
src/main/java/net/sf/jabref/external/ExternalFilePanel.java
src/main/java/net/sf/jabref/external/FindFullText.java
src/main/java/net/sf/jabref/external/IconSelection.java
src/main/java/net/sf/jabref/groups/EntryTableTransferHandler.java
src/main/java/net/sf/jabref/groups/KeywordGroup.java
src/main/java/net/sf/jabref/gui/CleanUpAction.java
src/main/java/net/sf/jabref/gui/DatabasePropertiesDialog.java
src/main/java/net/sf/jabref/gui/EntryTypeList.java
src/main/java/net/sf/jabref/gui/FieldSetComponent.java
src/main/java/net/sf/jabref/gui/FileListEntryEditor.java
src/main/java/net/sf/jabref/gui/MainTable.java
src/main/java/net/sf/jabref/gui/MainTableFormat.java
src/main/java/net/sf/jabref/gui/menus/help/ForkMeOnGitHubAction.java [new file with mode: 0644]
src/main/java/net/sf/jabref/imports/BibsonomyScraper.java
src/main/java/net/sf/jabref/imports/BibtexParser.java
src/main/java/net/sf/jabref/imports/CiteSeerXFetcher.java
src/main/java/net/sf/jabref/imports/GeneralFetcher.java
src/main/java/net/sf/jabref/imports/GoogleScholarFetcher.java
src/main/java/net/sf/jabref/imports/IsiImporter.java
src/main/java/net/sf/jabref/imports/JSTORFetcher2.java
src/main/java/net/sf/jabref/imports/OAI2Fetcher.java
src/main/java/net/sf/jabref/imports/RisImporter.java
src/main/java/net/sf/jabref/imports/ScienceDirectFetcher.java
src/main/java/net/sf/jabref/imports/fetcher/ISBNtoBibTeXFetcher.java
src/main/java/net/sf/jabref/journals/JournalAbbreviations.java
src/main/java/net/sf/jabref/journals/ManageJournalsPanel.java
src/main/java/net/sf/jabref/net/URLDownload.java
src/main/java/net/sf/jabref/oo/OOUtil.java
src/main/java/net/sf/jabref/plugin/ManagePluginsDialog.java
src/main/java/net/sf/jabref/plugin/PluginInstaller.java
src/main/java/net/sf/jabref/specialfields/Priority.java
src/main/java/net/sf/jabref/specialfields/Rank.java
src/main/java/net/sf/jabref/specialfields/RankCompact.java
src/main/java/net/sf/jabref/specialfields/RankExtended.java
src/main/java/net/sf/jabref/specialfields/ReadStatus.java
src/main/java/net/sf/jabref/sql/DBConnectDialog.java
src/main/java/net/sf/jabref/util/ManageKeywordsAction.java
src/main/java/net/sf/jabref/util/ResourceExtractor.java
src/main/java/net/sf/jabref/util/XMPUtil.java
src/main/java/net/sf/jabref/wizard/auximport/gui/FromAuxDialog.java
src/main/java/net/sf/jabref/wizard/integrity/gui/IntegrityMessagePanel.java
src/main/java/net/sf/jabref/wizard/text/gui/HintListModel.java
src/main/java/net/sf/jabref/wizard/text/gui/TextInputDialog.java
src/main/java/org/xnap/commons/gui/shortcut/EmacsKeyBindings.java
src/main/resources/help/About.html
src/main/resources/help/da/About.html
src/main/resources/help/de/About.html
src/main/resources/help/fr/About.html
src/main/resources/help/in/About.html
src/main/resources/help/ja/About.html
src/main/resources/images/splash-beta2.svg [new file with mode: 0644]
src/main/resources/images/splash-beta3.svg [new file with mode: 0644]
src/main/resources/images/splash.png
src/main/resources/osx/macadapter/MacAdapter.java [new file with mode: 0644]
src/main/resources/osx/osxadapter/OSXAdapter.java [deleted file]
src/main/resources/plugins/net.sf.jabref.core/plugin.xml
src/main/resources/resource/JabRef_da.properties
src/main/resources/resource/JabRef_de.properties
src/main/resources/resource/JabRef_en.properties
src/main/resources/resource/JabRef_es.properties
src/main/resources/resource/JabRef_fr.properties
src/main/resources/resource/JabRef_in.properties
src/main/resources/resource/JabRef_it.properties
src/main/resources/resource/JabRef_ja.properties
src/main/resources/resource/JabRef_nl.properties
src/main/resources/resource/JabRef_no.properties
src/main/resources/resource/JabRef_pt_BR.properties
src/main/resources/resource/JabRef_ru.properties
src/main/resources/resource/JabRef_tr.properties
src/main/resources/resource/JabRef_vi.properties
src/main/resources/resource/JabRef_zh.properties
src/main/resources/resource/Menu_da.properties
src/main/resources/resource/Menu_de.properties
src/main/resources/resource/Menu_en.properties
src/main/resources/resource/Menu_es.properties
src/main/resources/resource/Menu_fr.properties
src/main/resources/resource/Menu_in.properties
src/main/resources/resource/Menu_it.properties
src/main/resources/resource/Menu_ja.properties
src/main/resources/resource/Menu_nl.properties
src/main/resources/resource/Menu_no.properties
src/main/resources/resource/Menu_pt_BR.properties
src/main/resources/resource/Menu_ru.properties
src/main/resources/resource/Menu_tr.properties
src/main/resources/resource/Menu_vi.properties
src/main/resources/resource/Menu_zh.properties
src/main/resources/resource/journalList.txt
src/main/tex/manuals/JabRef-UserManual.lyx [deleted file]
src/main/tex/manuals/de/JabRef-UserManual_de.bib [deleted file]
src/main/tex/manuals/de/JabRef-UserManual_de.tex [deleted file]
src/test/java/net/sf/jabref/AssertUtil.java [new file with mode: 0644]
src/test/java/net/sf/jabref/BibtexDatabaseTest.java
src/test/java/net/sf/jabref/Bug1283.java [new file with mode: 0644]
src/test/java/net/sf/jabref/FileBasedTestCase.java
src/test/java/net/sf/jabref/JabRefCLITest.java
src/test/java/net/sf/jabref/MonthUtilTest.java [new file with mode: 0644]
src/test/java/net/sf/jabref/UtilFindFileTest.java
src/test/java/net/sf/jabref/UtilTest.java
src/test/java/net/sf/jabref/gui/AutoCompleterTest.java
src/test/java/net/sf/jabref/imports/CopacImporterTest.java
src/test/java/net/sf/jabref/imports/GeneralFetcherTest.java
src/test/java/net/sf/jabref/imports/IsiImporterTest.java
src/test/java/net/sf/jabref/net/URLDownloadTest.java [new file with mode: 0644]
src/test/java/net/sf/jabref/testutils/TestUtils.java
used-libaries.txt [new file with mode: 0644]

index b4177ef..11f7997 100644 (file)
@@ -1,5 +1,6 @@
 language: java
 jdk:
+  - openjdk6
   - openjdk7
   - oraclejdk7
   - oraclejdk8
@@ -8,4 +9,7 @@ before_install:
   - chmod +x gradlew
 
 script:
-  - TERM=dumb ./gradlew assemble
\ No newline at end of file
+  - ./gradlew check --info
+
+after_success:
+  - ./gradlew jacocoTestReport coveralls
index d863ed3..389bc56 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,23 @@
+2.11 beta 3
+    - New MacOSX integration
+    - Two releases for MacOSX: OSX-Java6 for Apple Java 1.6 and OSX for Oracle Java 1.7+
+    - Fix for bug #1278 Crash after changing LookAndFeel (showing a proper error message if L&F is not available)
+    - Adds some predefined look and feels in preference window (lists only available L&Fs)
+    - Fixes #1131: MacOSX: JabRef minimizes when clicking on x
+    - Dropped jayatana version 1.2.4 as version 2.x superseeds it
+    - Feature: Trim journal names before looking up the abbreviation
+    - Minor fixes regarding the status output of marking/unmarking entries
+    - Internal default key bindings are honored again
+    - Default key bindings for "Find unlinked files" (shift F7), "Open folder" (ctrl shift O), and "Hide/show toolbar" (ctrl alt t)
+    - Opening a file using the CLI works again. Just use the filename as parameter, without any command.
+    - Emacs keybindings: CTRL+f is not rebound as CTRL+f is more often used for "search"
+    - Performance Improvement: Saving of large databases is dramatically faster
+    - When a syntax error in the BibTeX source panel is made, the error cause is now always output
+    - Jars that are available in maven are now downloaded and used in both ant and gradle
+    - Replaced option parsing library ritopt with apache commons-cli which is in maven repository
+    - BREAKING passing an option file to the cli command no longer works due to change of internal cli library!
+    - Fix for bug #1283: Month fields like {8,} no longer cause exceptions
+    - Disabled ISBNtoBibTeX fetcher (see bug #1241)
 2.11 beta 2
     - Feature: Option to clean URLs generated by Google (patch #204)
     - Fix for bug #1272: JabRef now launches on Mac OS X
index 3a72c17..d1efbec 100644 (file)
@@ -1,23 +1,38 @@
 ## Understanding the basics
-Not sure what a pull request is, or how to submit one?  Take a look at GitHub's excellent [help documentation] first.
+We welcome contributions to JabRef and encourage to create a fork, make a patch, and create a pull request.
+Be sure to create a separate branch for each improvement you implement.
+Take a look at GitHub's excellent [help documentation] for a detailed explanation.
 
 We also have [guidelines for setting up a local workspace](https://github.com/JabRef/jabref/wiki/Guidelines-for-setting-up-a-local-workspace).
 
+For newcomers, [FLOSS Coach](http://www.flosscoach.com/) might be helpful.
+It contains steps to get start with JabRef development.
 
-## Add your change to the CHANGELOG
+Please keep in mind that JabRef relies on Java 6 due to the availability of Java 6 on older Mac OS X operating system.
+
+In case you have any questions, you can use our [GITTER channel](https://gitter.im/JabRef/jabref) or use our [developers mailinglist](https://lists.sourceforge.net/lists/listinfo/jabref-devel).
+
+
+## Formal requirements for a pull request
+
+The main goal of the formal requirements is to provide credit to you and to be able to understand the patch.
+
+### Add your change to the CHANGELOG
 You should edit the [CHANGELOG](CHANGELOG) located in the root directory of the JabRef source.
 Add a line with your changes and your name.
-Nicknames are OK
+Nicknames are OK.
 
 
-## Add yourself to src/main/resources/help/About.html
+### Add yourself to src/main/resources/help/About.html
 We try to keep an updated list of contributors in `About.html`.
 Open `About.html` and add yourself below `Contributions from:`.
 
 
-## Adapt the year in the header
+### Add yourself to the header
 
-The years stated in the header of each .java file should match the years where the file has been modified.
+The headers of each `.java` file state the authors.
+These entries should match the modifications done.
+If you do not want to add your real name, add yourself as `JabRef contriubtors`.
 
 For instance,
 
@@ -28,13 +43,14 @@ For instance,
 gets
 
 ```plain
-/*  Copyright (C) 2003-2014 JabRef contributors.
+/*  Copyright (C) 2003-2011 JabRef contributors.
+ *  Copyright (C) 2015 Stefan Jauch
 ```
 
 
-## Write a good commit message.
+### Write a good commit message
 See [good commit message] or [commit guidelines section of Pro Git].
 
 [commit guidelines section of Pro Git]: http://git-scm.com/book/en/Distributed-Git-Contributing-to-a-Project#Commit-Guidelines
 [good commit message]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
-[help documentation]: http://help.github.com/send-pull-requests
+[help documentation]: https://help.github.com/articles/using-pull-requests/
index 99151db..2fcf203 100644 (file)
--- a/README.md
+++ b/README.md
@@ -1,4 +1,9 @@
-# JabRef version 2.11 beta 2
+# JabRef 2.11 beta 3
+
+[![Build Status](https://api.travis-ci.org/JabRef/jabref.png?branch=master)](https://travis-ci.org/JabRef/jabref)
+[![Dependency Status](https://www.versioneye.com/user/projects/557f2723386664002000009c/badge.svg?style=flat)](https://www.versioneye.com/user/projects/557f2723386664002000009c)
+[![Coverage Status](https://coveralls.io/repos/JabRef/jabref/badge.svg)](https://coveralls.io/r/JabRef/jabref)
+[![Join the chat at https://gitter.im/JabRef/jabref](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/JabRef/jabref?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
 
 This version is a beta version. Features may not work as expected.
 
@@ -12,6 +17,7 @@ JabRef can import from and export to several formats, and you can customize expo
 JabRef can be run as a command line application to convert from any import format to any export format.
 
 * Homepage: http://jabref.sourceforge.net/
+* Development mailinglist: https://lists.sourceforge.net/lists/listinfo/jabref-devel
 * Development page: https://github.com/JabRef
 * Main git repository: https://github.com/JabRef/jabref
 * CI Server: https://travis-ci.org/JabRef/jabref
@@ -34,9 +40,7 @@ The "old" trackers at sourceforge still remain intact:
 
 Do *not* file patches using https://sourceforge.net/p/jabref/patches/.
 Just fork JabRef and create a pull request.
-
-For newcomers, [FLOSS Coach](http://www.flosscoach.com/) might be helpful. It contains steps to get start with JabRef development.
-
+For details see [CONTRIBUTING.md](CONTRIBUTING.md).
 
 ### Next Steps
 
@@ -47,39 +51,31 @@ For newcomers, [FLOSS Coach](http://www.flosscoach.com/) might be helpful. It co
 
 ## Requirements
 
-JabRef runs on any system equipped with the Java Virtual Machine (1.6 or newer), which can be downloaded at no cost from http://java.sun.com.
+JabRef runs on any system equipped with the Java Virtual Machine (1.6 or newer), which can be downloaded at no cost from [Oracle](http://www.oracle.com/technetwork/java/javase/downloads/index.html).
 If you do not plan to compile JabRef, the Java Runtime Environment may be a better choice than the Java Development Kit.
 
 
+## Installing and running, Mac OS X:
+
+Please see our [Mac OS X FAQ](http://jabref.sourceforge.net/faq.php#osx).
+
+
 ## Installing and running, Windows:
 
-JabRef is available in Windows Installer (`.msi`) format. To install,
-double-click the .msi file. A shortcut to JabRef will be added to your
-start menu.
+JabRef offers an installer, which also adds a shortcut to JabRef to your start menu.
 
-The Windows installation was made by Dale Visser, using the following open-source tools:
-JSmooth (.exe wrapper for Java apps), available at http://jsmooth.sf.net/
-Wix (tool for compiling MSI files from an XML specification), available at http://wix.sf.net/
+Please also see our [Windows FAQ](http://jabref.sourceforge.net/faq.php#windows)
 
 
 ## Installing and running, general:
 
-JabRef can be downloaded as an executable .jar file. Run the
-program as follows:
-If you are using the Java Development Kit:
+JabRef can be downloaded as an executable .jar file.
+Try to doubleclick the `jar` file or execute the follwing command:
      `java -jar <path to jar>`
-or, if you are using the Java Runtime Environment:
-     `jre -new -jar <path to jar>` or
-     `jrew -new -jar <path to jar>`
 
 If you run JabRef under Java 1.5, you can add the option `-Dswing.aatext=true` before the
 `-jar` option, to activate antialiased text throughout the application.
 
-The jar file containing JabRef can be unpacked with the command:
-    `jar xf <path to jar>`
-or  `jar xf <path to jar> <list of files to extract>`.
-Unpacking the jar file is not necessary to run the program.
-
 
 ## Documentation
 
@@ -108,8 +104,9 @@ and then generate the Eclipse `gradlew eclipse` or IntelliJ IDEA `gradlew idea`
 Requires
  * [launch4j](http://launch4j.sourceforge.net/)
  * [NSIS](http://nsis.sourceforge.net) with the [WinShell plug-in](http://nsis.sourceforge.net/WinShell_plug-in).
+ * Eventually a `user.properties` with correct setting of `launch4j.dir` and `nsis.executable`. See [build.xml](build.xml) for defaults.
 
-Replace `ANY_ANT_TARGET` with the Ant Target of your choice, and the system will build your binaries.
+Replace `ANY_ANT_TARGET` with the Ant Target of your choice (e.g., `macbundle`), and the system will build your binaries.
 To get a list of all targets, use `gradlew tasks`.
 
 `gradlew generateSource antTargets.ANY_ANT_TARGET`
@@ -120,11 +117,12 @@ named `JabRef-$VERSION.jar` (where $VERSION is the current version of the
 source tree) in the `buildant\lib` directory. Enjoy!
 The setup files are created by invoking the command `gradlew generateSource antTargets.release`.
 
-On Mac OS X you should include the targets osx and osxjar,
-making the correct command `gradlew generateSource antTargets.compile antTargets.unjarlib antTargets.osx antTargets.jars antTargets.osxjar`.
-After the build is finished, you will find the OS X application
-`JabRef.app` in the `buildant/lib` directory along with the executable
-jar.
+
+### Releasing on Linux
+
+Run `gradlew antTargets.release.linux`
+
+All binaries (including OSX) and the installer are generated in the directory `buildant/lib`.
 
 
 ### Releasing on Windows
@@ -138,8 +136,8 @@ All binaries (including OSX) and the installer are generated in the directory `b
 
 JabRef is free software: you can redistribute it and/or modify it under the
 terms of the GNU General Public License as published by the Free Software
-Foundation, either version 3 of the License, or (at your option) any later
+Foundation, either version 2 of the License, or (at your option) any later
 version.
-See the enclosed text files 'gpl3.txt' for full details.
+See the enclosed text files [gpl2.txt](gpl2.txt) and [gpl3.txt](gpl3.txt) for full details.
 
 JabRef also uses libraries distributed by other parties; see the About box for details.
index 64e5d5b..c380c2b 100644 (file)
@@ -8,7 +8,7 @@ apply plugin: 'project-report'
 // enables fatjar, the creation of a jar with all dependencies bundled inside
 buildscript {
     repositories {
-        mavenCentral()
+        jcenter()
     }
     dependencies {
         classpath 'eu.appsatori:gradle-fatjar-plugin:0.2'
@@ -28,10 +28,10 @@ test {
     }
 }
 
-version = "2.11b2"
+version = "2.11b3"
 
 repositories {
-    mavenCentral()
+    jcenter()
 }
 
 sourceSets {
@@ -60,8 +60,7 @@ dependencies {
     compile 'org.apache.pdfbox:fontbox:1.7.1'
     compile 'org.apache.pdfbox:jempbox:1.7.1'
 
-    // option parser
-    compile fileTree(dir: 'lib/ritopt/', includes: ['*.jar']) // instead of having the source code inside
+    compile 'commons-cli:commons-cli:1.3.1'
 
     compile 'org.openoffice:juh:3.2.1'
     compile 'org.openoffice:jurt:3.2.1'
@@ -75,29 +74,41 @@ dependencies {
     compile 'mysql:mysql-connector-java:5.0.7'
     compile 'org.postgresql:postgresql:9.2-1002-jdbc4'
 
-    compile fileTree(dir: 'lib', includes: ['glazedlists-1.8.0_java15.jar', 'jayatana-1.2.4.jar', 'microba.jar', 'spin.jar'])
+    compile 'net.java.dev.glazedlists:glazedlists_java15:1.8.0'
+    compile fileTree(dir: 'lib', includes: ['microba.jar', 'spin.jar'])
 
     compile 'net.java.dev.jna:jna:4.1.0'
 
+    compile 'commons-logging:commons-logging:1.0.2'
     // not available in maven repository
-    compile fileTree(dir: 'lib/plugin', includes: ['jpf.jar', 'jpf-boot.jar', 'commons-logging.jar', 'JPFCodeGenerator-rt.jar'])
+    compile fileTree(dir: 'lib/plugin', includes: ['jpf.jar', 'jpf-boot.jar', 'JPFCodeGenerator-rt.jar'])
+
+    compile 'com.sun.jersey:jersey-client:1.14'
+    compile 'com.sun.jersey:jersey-core:1.14'
+    compile 'com.sun.jersey.contribs:jersey-multipart:1.14'
 
-    compile fileTree(dir: 'lib/spl/jersey', includes: ['*.jar'])
     compile fileTree(dir: 'lib/spl/sciplore', includes: ['*.jar'])
 
-    compile 'junit:junit:4.11'
+    compile 'junit:junit:4.12'
 
     generateClasspath fileTree(dir: 'lib/plugin', includes: ['jpf.jar', 'jpf-boot.jar', 'JPFCodeGenerator.jar', 'velocity-dep-1.5.jar'])
 }
 
 // use ant targets with prefix antTargets.XXXXX
 ant.importBuild "build-wrapper.xml"
+// add jars from this classpath to the classpath for the ant build
+if (org.gradle.internal.os.OperatingSystem.current().windows) {
+    // according to the discussion at https://github.com/JabRef/jabref/pull/58, the separators are different on Windows and Linux
+    ant.references.jars.setFiles(configurations.compile.asPath.replace(";"," "))
+} else {
+    ant.references.jars.setFiles(configurations.compile.asPath.replace(":"," "))
+}
 
 sourceCompatibility = 1.6
 mainClassName = "net.sf.jabref.JabRefMain"
 
 task wrapper(type: Wrapper) {
-    gradleVersion = '2.1'
+    gradleVersion = '2.4'
 }
 
 compileJava {
@@ -125,12 +136,12 @@ compileJava.dependsOn "generateSource"
 
 task generateSource(dependsOn: ["generatePluginSource", "generateBstGrammarSource", "generateSearchTreeParserSource"]) {
     group = 'JabRef'
-    description 'Generates all Java source files.'
+    description 'Generates all Java source files.'
 }
 
 task generatePluginSource(type: JavaExec) {
-    group 'JabRef'
-    description 'Generates _JabRefPlugin.java with JPF.'
+    group 'JabRef'
+    description 'Generates _JabRefPlugin.java with JPF.'
 
     ext.pluginsDir = "src/main/resources/plugins"
 
@@ -143,8 +154,8 @@ task generatePluginSource(type: JavaExec) {
 }
 
 task generateBstGrammarSource(type: JavaExec) {
-    group 'JabRef'
-    description = 'Generates BstLexer.java and BstParser.java from the Bst.g grammar file using antlr.'
+    group 'JabRef'
+    description 'Generates BstLexer.java and BstParser.java from the Bst.g grammar file using antlr3.'
 
     File antlrSource = file('src/main/antlr3/net/sf/jabref/bst/Bst.g')
 
@@ -160,8 +171,8 @@ task generateBstGrammarSource(type: JavaExec) {
 task generateSearchLexerSource(type: JavaExec) {
     String grammarFile = "Lexer"
 
-    group 'JabRef'
-    description "Generates java files for ${grammarFile}.g antlr2."
+    group 'JabRef'
+    description "Generates java files for ${grammarFile}.g antlr2."
 
     String packagePath = "net/sf/jabref/search"
     File antlr2Path = file("src/main/antlr2")
@@ -184,8 +195,8 @@ task generateSearchLexerSource(type: JavaExec) {
 task generateSearchParserSource(type: JavaExec, dependsOn: "generateSearchLexerSource") {
     String grammarFile = "Parser"
 
-    group 'JabRef'
-    description "Generates java files for ${grammarFile}.g antlr2."
+    group 'JabRef'
+    description "Generates java files for ${grammarFile}.g antlr2."
 
     String packagePath = "net/sf/jabref/search"
     File antlr2Path = file("src/main/antlr2")
@@ -208,8 +219,8 @@ task generateSearchParserSource(type: JavaExec, dependsOn: "generateSearchLexerS
 task generateSearchTreeParserSource(type: JavaExec, dependsOn: "generateSearchParserSource") {
     String grammarFile = "TreeParser"
 
-    group 'JabRef'
-    description "Generates java files for ${grammarFile}.g antlr2."
+    group 'JabRef'
+    description "Generates java files for ${grammarFile}.g antlr2."
 
     String packagePath = "net/sf/jabref/search"
     File antlr2Path = file("src/main/antlr2")
@@ -234,4 +245,24 @@ idea.project.ipr {
     withXml { provider ->
         provider.node.component.find { it.@name == 'VcsDirectoryMappings' }.mapping.@vcs = 'Git'
     }
-}
\ No newline at end of file
+}
+
+apply plugin: 'jacoco'
+apply plugin: 'com.github.kt3k.coveralls'
+
+buildscript {
+    repositories {
+        jcenter()
+    }
+
+    dependencies {
+        classpath 'org.kt3k.gradle.plugin:coveralls-gradle-plugin:2.0.1'
+    }
+}
+
+jacocoTestReport {
+    reports {
+        xml.enabled = true // coveralls plugin depends on xml format report
+        html.enabled = true
+    }
+}
index f014216..7488926 100644 (file)
--- a/build.xml
+++ b/build.xml
@@ -7,10 +7,7 @@
              Ant-Manual:   http://jakarta.apache.org/ant/manual/index.html
 
              Jabref homepage:       http://jabref.sourceforge.net
-             Jabref@SourceForge:    http://sourceforge.net/projects/jabref
-             Jabref@FreeCode:       http://apps.freecode.com/projects/jabref
-             Jabref@Ohloh:          https://www.ohloh.net/p/jabref
-             Jabref git repository: git://jabref.git.sourceforge.net/gitroot/jabref/jabref
+             Jabref@OpenHub:        https://www.openhub.net/p/jabref
 
              Further questions:
                help mailing list:   https://lists.sourceforge.net/lists/listinfo/jabref-users
@@ -35,8 +32,8 @@
      +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-->
 
        <!-- some version information -->
-       <property name="jabref.version" value="2.11b2" />
-       <property name="jabref.version.full" value="2.11.2.0" /> <!-- a version number with 4 places. Required by launch4j -->
+       <property name="jabref.version" value="2.11b3" />
+       <property name="jabref.version.full" value="2.11.3.1" /> <!-- a version number with 4 places. Required by launch4j -->
        <property name="jabref.year" value="2015" />
        <property name="jabref.placeholder.version" value="@version@" />
        <property name="jabref.placeholder.year" value="@year@" />
@@ -47,7 +44,7 @@
        <property name="build.dir" value="buildant" />
        <property name="build.classes" value="${build.dir}/classes" />
        <property name="build.tmp" value="${build.dir}/tmp" />
-       <property name="build.classes.osx" value="${build.dir}/classes/osxadapter" />
+       <property name="build.classes.osx" value="${build.dir}/classes/osx/macadapter" />
        <property name="build.lib" value="${build.dir}/lib" />
        <property name="build.win" value="${build.dir}/windows" />
        <property name="build.images" value="${build.dir}/images" />
          </and>
        </condition>
 
-       <fileset id="jarsFileset" dir="${lib.dir}">
-               <include name="antlr.jar" />
-               <include name="antlr-3.4-complete.jar" />
-        <include name="jgoodies-common-1.4.0.jar" />
-               <include name="jgoodies-looks-2.5.2.jar" />
-               <include name="jgoodies-forms-1.6.0.jar" />
-        <include name="jgoodies/jgoodies-uif-lite.jar" />
-        <include name="jna-4.1.0.jar" />
-        <include name="ritopt/ritopt-0.2.1-bin.jar" />
-               <include name="jayatana-1.2.4.jar" />
-               <include name="spin.jar" />
-               <include name="glazedlists-1.8.0_java15.jar" />
-               <include name="microba.jar" />
-               <include name="pdfbox-1.7.1.jar" />
-               <include name="jempbox-1.7.1.jar" />
-               <include name="fontbox-1.7.1.jar" />
-               <include name="zoom-java.jar" />
-       <include name="mysql-connector-java-5.0.7-bin.jar" />
-               <include name="postgresql-9.2-1002.jdbc4.jar" />
-        <!-- Plugin runtime dependencies -->
-               <include name="plugin/JPFCodeGenerator-rt.jar" />
-               <include name="plugin/jpf.jar" />
-               <include name="plugin/jpf-boot.jar" />
-               <include name="plugin/commons-logging.jar" />
-       </fileset>
-
-    <!-- Openoffice connection dependencies. Compile-time only -->
-    <fileset id="ooFileset" dir="${lib.dir}">
-        <include name="oo/unoil.jar" />
-        <include name="oo/ridl.jar" />
-        <include name="oo/juh.jar" />
-        <include name="oo/jurt.jar" />
-    </fileset>
-
     <!-- Done by MrDlib -->
-    <fileset id="splJars" dir="${lib.dir}">
-        <include name="spl/**/*.jar" />
-    </fileset>
        <fileset id="deletableMeta-InfFiles" dir="${build.tmp}/META-INF">
                <exclude name="services/**/*" />
        </fileset>
     <!-- Done by MrDlib -->
 
        <!-- Build classpath -->
+       <filelist id="jars" />
        <path id="classpath">
                <pathelement path="${build.classes}" />
                <pathelement path="${build.dir}" />
-        <!-- Done by MrDlib -->
-        <fileset refid="splJars" />
-        <!-- Done by MrDlib -->
-               <fileset refid="jarsFileset" />
-        <fileset refid="ooFileset" />
+               <filelist refid="jars" />
        </path>
 
        <target name="run" depends="build">
        </target>
 
        <!-- Builds the OSXAdapter -->
-       <target name="osx">
+       <target name="osx" depends="compile">
                <mkdir dir="${build.classes}" />
-
                <javac srcdir="${osx.dir}" destdir="${build.classes}" target="1.6">
+                       <!-- Hack to force visibility of com.apple.eawt in rt.jar in JDK7 & 8
+                                https://bugs.openjdk.java.net/browse/JDK-8008714 -->
+                       <compilerarg value="-XDignore.symbol.file"/>                    
                </javac>
        </target>
-
-       <!-- Copies in the OSXAdapter class, which is compilable only on Mac  -->
+       
+       <!-- Copies in the OSXAdapter class, which is compilable only on Mac
+                Development on other platforms should also be possible by using the 
+                distributed stub of com.apple.eawt as described in 
+         http://stackoverflow.com/questions/2151174/how-can-i-develop-apple-java-extensions-on-windows -->
        <target name="non_osx">
                <mkdir dir="${build.classes.osx}" />
-               <copy file="${osxbin.dir}/OSXAdapter.class" todir="${build.classes.osx}" />
+               <copy file="${osxbin.dir}/MacAdapter.class" todir="${build.classes.osx}" />
        </target>
 
-       <!-- Jars up project -->
-       <target name="jars" depends="build, unjarlib">
+       <target name="jars" depends="build, unjarlib" description="Jars up project">
                <mkdir dir="${build.lib}" />
 
                <mkdir dir="${build.tmp}" />
@@ -304,7 +265,6 @@ build=${build.number}
 version=${jabref.version}</echo>
        </target>
 
-       <!-- Creates javadocs for the extensions -->
        <target name="extension-javadocs" depends="build" description="Generates the javadocs for the extensions archive">
                <mkdir dir="${build.extension-javadocs}" />
                <copy todir="${build.extension-javadocs}">
@@ -333,10 +293,8 @@ version=${jabref.version}</echo>
                </javadoc>
        </target>
 
-       <!-- Creates javadocs for the extensions -->
        <target name="extensions" depends="extension-javadocs" description="Generates the extensions archive">
-               <!-- copy examples -->
-               <copy todir="${build.extensions}">
+               <copy todir="${build.extensions}" description="copy examples">
                        <fileset dir="${java.dir}">
                                <include name="net/sf/jabref/export/layout/format/CurrentDate.java" />
                                <include name="net/sf/jabref/export/layout/format/ToLowerCase.java" />
@@ -354,8 +312,7 @@ version=${jabref.version}</echo>
                                <filter token="version" value="${jabref.version}" />
                        </filterset>
                </copy>
-               <!-- create extensions-zip file -->
-               <zip destfile="${build.dir}/jabref-extensions.zip">
+               <zip destfile="${build.dir}/jabref-extensions.zip" description="create extensions-zip file">
                        <zipfileset dir="${build.extensions}" prefix="jabref-extensions" />
                </zip>
        </target>
@@ -364,12 +321,10 @@ version=${jabref.version}</echo>
                <delete dir="${build.dir}" />
        </target>
 
-       <!-- Unpacks jar needed jar files from lib directory into temp directory. -->
-       <target name="unjarlib" description="Unpacks jars from library">
+       <target name="unjarlib" description="Unpacks jars from lib directory into temp directory">
                <mkdir dir="${build.tmp}" />
                <unjar dest="${build.tmp}">
-                       <fileset refid="jarsFileset" />
-                       <fileset refid="splJars" />
+                       <filelist refid="jars" />
                </unjar>
                <!-- done by MrDlib -->
                <delete includeEmptyDirs="true">
@@ -380,10 +335,65 @@ version=${jabref.version}</echo>
                <move file="${build.tmp}/license.txt" tofile="${build.tmp}/microba-license.txt" />
        </target>
 
+       <target name="java16test">
+               <condition property="java16">
+                       <equals arg1="${ant.java.version}" arg2="1.6"/>
+               </condition>
+       </target>
 
-       <target name="osxjar" depends="jars">
+       <target name="macbundle" depends="java16test, jars" unless="java16" description="creates a bundle made for the Oracle Apple JVM (1.7+)">
+               <taskdef
+                       name="bundleapp"
+                       classname="com.oracle.appbundler.AppBundlerTask"
+                       classpath="${buildlib.dir}/appbundler-1.0.jar" />
+               <bundleapp
+                       name="JabRef"
+                       mainclassname="net.sf.jabref.JabRef"
+                       outputdirectory="${build.lib}"
+                       displayname="JabRef"
+                       identifier="jabref.JabRef"
+                       icon="${images.dir}/JabRef-Logo.icns"
+                       shortversion="${jabref.version}">
+                       <classpath file="${build.lib}/JabRef-${jabref.version}.jar" />  
+                       <!-- Memory options apparently break the bundle 
+                       <option value="-Xms128m -Xmx512m" /> -->
+               </bundleapp>
+               <!-- We still need to hack the Info.plist to enable high resolution for Retina displays -->
+               <replace file="${build.lib}/JabRef.app/Contents/Info.plist" 
+                       token="&lt;key&gt;JVMOptions&lt;/key&gt;"
+                       value="&lt;key&gt;NSHighResolutionCapable&lt;/key&gt;&#10;
+       &lt;true/&gt;&#10;&lt;key&gt;JVMOptions&lt;/key&gt;"/>
+               <!-- We also need to add native support for bib files in the Info.plist -->
+               <replace file="${build.lib}/JabRef.app/Contents/Info.plist" 
+               token="&lt;key&gt;JVMOptions&lt;/key&gt;"
+               value="&lt;key&gt;CFBundleDocumentTypes&lt;/key&gt;&#10;
+       &lt;array&gt;&#10;
+               &lt;dict&gt;&#10;
+                       &lt;key&gt;CFBundleTypeName&lt;/key&gt;&#10;
+                       &lt;string&gt;BibTeX file&lt;/string&gt;&#10;
+                       &lt;key&gt;CFBundleTypeRole&lt;/key&gt;&#10;
+                       &lt;string&gt;Editor&lt;/string&gt;&#10;
+                       &lt;key&gt;CFBundleTypeIconFile&lt;/key&gt;&#10;
+                       &lt;string&gt;JabRef-Logo.icns&lt;/string&gt;&#10;
+                       &lt;key&gt;CFBundleTypeExtensions&lt;/key&gt;&#10;
+                       &lt;array&gt;&#10;
+                               &lt;string&gt;bib&lt;/string&gt;&#10;
+                       &lt;/array&gt;&#10;
+               &lt;/dict&gt;&#10;
+       &lt;/array&gt;&#10;
+       &lt;key&gt;JVMOptions&lt;/key&gt;"/>
+               <zip basedir="${build.lib}"
+                       destfile="${build.lib}/JabRef-${jabref.version}-OSX.zip"
+                       excludes="JabRef.app/Contents/MacOS/JavaAppLauncher"
+                       includes="JabRef.app/"
+                       level="9">
+                       <zipfileset dir="${build.lib}" includes="JabRef.app/Contents/MacOS/JavaAppLauncher" filemode="755" />
+               </zip>
+       </target>
+       
+       <target name="macbundle_java16" depends="jars" description="creates a bundle made for the Legacy Apple JVM (1.6)">
                <jarbundler dir="${build.lib}"
-                    name="JabRef"
+                    name="JabRef_Java6"
                     mainclass="net.sf.jabref.JabRef"
                     jar="${build.lib}/${build.jar}"
                     icon="${images.dir}/JabRef-Logo.icns"
@@ -396,16 +406,16 @@ version=${jabref.version}</echo>
                           iconFile="${images.dir}/JabRef-Logo.icns"/>
         </jarbundler>
         <!-- After running jarbundler we need to hack the Info.plist file: -->
-        <replace file="${build.lib}/JabRef.app/Contents/Info.plist" token="&lt;key&gt;CFBundleDocumentTypes&lt;/key&gt;"
+        <replace file="${build.lib}/JabRef_Java6.app/Contents/Info.plist" token="&lt;key&gt;CFBundleDocumentTypes&lt;/key&gt;"
             value="&lt;key&gt;NSPrincipalClass&lt;/key&gt;${line.separator}
    &lt;string&gt;NSApplication&lt;/string&gt;${line.separator}
    &lt;key&gt;CFBundleDocumentTypes&lt;/key&gt;"/>
                <zip basedir="${build.lib}"
-                       destfile="${build.lib}/JabRef-${jabref.version}-OSX.zip"
-                       excludes="JabRef.app/Contents/MacOS/JavaApplicationStub"
-                       includes="JabRef.app/"
+                       destfile="${build.lib}/JabRef-${jabref.version}-OSX-Java6.zip"
+                       excludes="JabRef_Java6.app/Contents/MacOS/JavaApplicationStub"
+                       includes="JabRef_Java6.app/"
                        level="9">
-                       <zipfileset dir="${build.lib}" includes="JabRef.app/Contents/MacOS/JavaApplicationStub" filemode="755" />
+                       <zipfileset dir="${build.lib}" includes="JabRef_Java6.app/Contents/MacOS/JavaApplicationStub" filemode="755" />
                </zip>
        </target>
 
@@ -425,8 +435,7 @@ version=${jabref.version}</echo>
                <fail unless="is.windows" message="Not running on windows or NSIS not found. Please make sure that user.properties exists" />
        </target>
 
-       <target name="win.installer.step1">
-               <!-- Gather everything that will go into the installer in dist -->
+       <target name="win.installer.step1" description="Gather everything that will go into the installer in dist">
                <mkdir dir="${win.installer.dir}/dist" />
 
                <copy file="${build.lib}/${build.jar}" todir="${win.installer.dir}/dist" />
@@ -560,8 +569,8 @@ version=${jabref.version}</echo>
                <delete dir="${temp.dir}" failonerror="no"/>
        </target>
 
-       <target name="devsnapshot" depends="clean, addgitinfo, non_osx, win.installer, osxjar" description="creates development snapshot binaries" />
+       <target name="devsnapshot" depends="clean, addgitinfo, non_osx, win.installer, macbundle_java16, macbundle" description="creates development snapshot binaries" />
 
-       <target name="release" depends="clean, win.installer, non_osx, osxjar, bzip2src, zipsrc" description="Do a release on Windows. Creates all distribution files in ${build.lib}"/>
-       <target name="release.linux" depends="clean, win.installer.linux, non_osx, osxjar, bzip2src, zipsrc" description="Do a release on Linux. Creates all distribution files in ${build.lib}" />
+       <target name="release" depends="clean, non_osx, win.installer, macbundle_java16, macbundle, bzip2src, zipsrc" description="Do a release on Windows. Creates all distribution files in ${build.lib}"/>
+       <target name="release.linux" depends="clean, non_osx, win.installer.linux, macbundle_java16, macbundle, bzip2src, zipsrc" description="Do a release on Linux. Creates all distribution files in ${build.lib}" />
 </project>
index fe8dbef..c2afeef 100644 (file)
 package net.sf.jabref;
 
 import java.awt.BorderLayout;
+import java.util.ArrayList;
+import java.util.List;
 
-import javax.swing.*;
+import javax.swing.BorderFactory;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.UIManager;
 import javax.swing.event.ChangeEvent;
 import javax.swing.event.ChangeListener;
 
@@ -40,7 +50,8 @@ public class AdvancedTab extends JPanel implements PrefsTab {
     JLabel lab;
     JCheckBox useDefault, useRemoteServer, useNativeFileDialogOnMac, filechooserDisableRename,
             useIEEEAbrv, biblatexMode;
-    JTextField className, remoteServerPort;
+    JComboBox className;
+    JTextField remoteServerPort;
     JButton def1 = new JButton(Globals.lang("Default")),
         def2 = new JButton(Globals.lang("Default"));
     JPanel p1 = new JPanel(),
@@ -69,8 +80,26 @@ public class AdvancedTab extends JPanel implements PrefsTab {
     useIEEEAbrv = new JCheckBox(Globals.lang("Use IEEE LaTeX abbreviations"));
     biblatexMode = new JCheckBox(Globals.lang("BibLaTeX mode"));
     remoteServerPort = new JTextField();
-    className = new JTextField(50);
-    final JTextField clName = className;
+    String[] possibleLookAndFeels = {
+       "com.jgoodies.plaf.plastic.Plastic3DLookAndFeel",
+       "com.sun.java.swing.plaf.windows.WindowsLookAndFeel",
+       "com.sun.java.swing.plaf.motif.MotifLookAndFeel",
+       "javax.swing.plaf.mac.MacLookAndFeel",
+       "com.sun.java.swing.plaf.gtk.GTKLookAndFeel",
+       "javax.swing.plaf.metal.MetalLookAndFeel"
+    };
+    // Only list L&F which are available
+    List<String> lookAndFeels = new ArrayList<String>();
+    for (String lf : possibleLookAndFeels) {
+       try {
+               // Try to find L&F, throws exception if not successful
+               Class.forName(lf);
+               lookAndFeels.add(lf);
+       } catch(ClassNotFoundException e) {}
+    }
+    className = new JComboBox(lookAndFeels.toArray(new String[lookAndFeels.size()]));
+    className.setEditable(true);
+    final JComboBox clName = className;
     useDefault.addChangeListener(new ChangeListener() {
         public void stateChanged(ChangeEvent e) {
             clName.setEnabled(((JCheckBox)e.getSource()).isSelected());
@@ -173,7 +202,7 @@ public class AdvancedTab extends JPanel implements PrefsTab {
         oldUseDef = _prefs.getBoolean("useDefaultLookAndFeel");
         oldLnf = _prefs.get("lookAndFeel");
         useDefault.setSelected(!oldUseDef);
-        className.setText(oldLnf);
+        className.setSelectedItem(oldLnf);
         className.setEnabled(!oldUseDef);
         useRemoteServer.setSelected(_prefs.getBoolean("useRemoteServer"));
         oldPort = _prefs.getInt("remoteServerPort");
@@ -193,7 +222,7 @@ public class AdvancedTab extends JPanel implements PrefsTab {
 
     public void storeSettings() {
         _prefs.putBoolean("useDefaultLookAndFeel", !useDefault.isSelected());
-        _prefs.put("lookAndFeel", className.getText());
+        _prefs.put("lookAndFeel", className.getSelectedItem().toString());
         _prefs.putBoolean("useNativeFileDialogOnMac", useNativeFileDialogOnMac.isSelected());
         _prefs.putBoolean("filechooserDisableRename", filechooserDisableRename.isSelected());
         UIManager.put("FileChooser.readOnly", filechooserDisableRename.isSelected());
@@ -228,7 +257,7 @@ public class AdvancedTab extends JPanel implements PrefsTab {
         _prefs.putBoolean("biblatexMode", biblatexMode.isSelected());
 
         if ((useDefault.isSelected() == oldUseDef) ||
-            !oldLnf.equals(className.getText())) {
+            !oldLnf.equals(className.getSelectedItem().toString())) {
             JOptionPane.showMessageDialog(null, 
                        Globals.lang("You have changed the look and feel setting.")
                        .concat(" ")
index 900e7c8..7b44b55 100644 (file)
@@ -1,4 +1,4 @@
-/*  Copyright (C) 2003-2012 JabRef contributors.
+/*  Copyright (C) 2003-2015 JabRef contributors.
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
     the Free Software Foundation; either version 2 of the License, or
@@ -16,7 +16,6 @@
 package net.sf.jabref;
 
 import java.awt.BorderLayout;
-import java.awt.Color;
 import java.awt.Component;
 import java.awt.GridBagConstraints;
 import java.awt.GridBagLayout;
@@ -1492,43 +1491,33 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
                       }
                   });
                 */
-              actions.put("markEntries", new AbstractWorker() {
-                  private int besLength = -1;
-                public void run() {
-
-                  NamedCompound ce = new NamedCompound(Globals.lang("Mark entries"));
-                  BibtexEntry[] bes = mainTable.getSelectedEntries();
-                  besLength = bes.length;
-
-                    for (BibtexEntry be : bes) {
-                        Util.markEntry(be, 1, true, ce);
-                    }
-                  ce.end();
-                  undoManager.addEdit(ce);
-                }
-
-                public void update() {
-                  markBaseChanged();
-                  output(Globals.lang("Marked selected")+" "+Globals.lang(besLength>0?"entry":"entries"));
-
-                }
-              });
+              actions.put("markEntries", new MarkEntriesAction(frame, 0));
 
               actions.put("unmarkEntries", new BaseAction() {
                 public void action() {
                     try {
-                  NamedCompound ce = new NamedCompound(Globals.lang("Unmark entries"));
-                  BibtexEntry[] bes = mainTable.getSelectedEntries();
-          if (bes == null)
-              return;
+                        BibtexEntry[] bes = mainTable.getSelectedEntries();
+                        if (bes.length == 0) {
+                            output(Globals.lang("No entries selected."));
+                            return;
+                        }
+                        NamedCompound ce = new NamedCompound(Globals.lang("Unmark entries"));
                         for (BibtexEntry be : bes) {
                             Util.unmarkEntry(be, false, database, ce);
                         }
-                  ce.end();
-                  undoManager.addEdit(ce);
-                  markBaseChanged();
-                  output(Globals.lang("Unmarked selected")+" "+Globals.lang(bes.length>0?"entry":"entries"));
-                    } catch (Throwable ex) { ex.printStackTrace(); }
+                        ce.end();
+                        undoManager.addEdit(ce);
+                        markBaseChanged();
+                        String outputStr;
+                        if (bes.length == 1) {
+                            outputStr = Globals.lang("Unmarked selected entry");
+                        } else {
+                            outputStr = Globals.lang("Unmarked all %0 selected entries", Integer.toString(bes.length));
+                        }
+                        output(outputStr);
+                    } catch (Throwable ex) {
+                        ex.printStackTrace();
+                    }
                 }
               });
 
@@ -1542,15 +1531,17 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
                   ce.end();
                   undoManager.addEdit(ce);
                   markBaseChanged();
+                  output(Globals.lang("Unmarked all entries"));
                 }
               });
-              
+
+              // Note that we can't put the number of entries that have been reverted into the undoText as the concrete number cannot be injected
               actions.put(Relevance.getInstance().getValues().get(0).getActionName(), 
-                  new SpecialFieldAction(frame, Relevance.getInstance(), Relevance.getInstance().getValues().get(0).getFieldValue(), true, Globals.lang("Marked entries as relevant"), "Marked %0 entries as relevant"));
+                  new SpecialFieldAction(frame, Relevance.getInstance(), Relevance.getInstance().getValues().get(0).getFieldValue(), true, Globals.lang("Toggle relevance"), Globals.lang("Toggled relevance for %0 entries")));
               actions.put(Quality.getInstance().getValues().get(0).getActionName(),
-                  new SpecialFieldAction(frame, Quality.getInstance(), Quality.getInstance().getValues().get(0).getFieldValue(), true, Globals.lang("Marked entries' quality as good"), "Set quality of %0 entries to good"));
+                  new SpecialFieldAction(frame, Quality.getInstance(), Quality.getInstance().getValues().get(0).getFieldValue(), true, Globals.lang("Toggle quality"), Globals.lang("Toggled quality for %0 entries")));
               actions.put(Printed.getInstance().getValues().get(0).getActionName(),
-                      new SpecialFieldAction(frame, Printed.getInstance(), Printed.getInstance().getValues().get(0).getFieldValue(), true, Globals.lang("Marked entries as printed"), "Marked %0 entries as printed"));
+                      new SpecialFieldAction(frame, Printed.getInstance(), Printed.getInstance().getValues().get(0).getFieldValue(), true, Globals.lang("Toggle print status"), Globals.lang("Toggled print status for %0 entries")));
               
               for (SpecialFieldValue prio: Priority.getInstance().getValues()) {
                      actions.put(prio.getActionName(), prio.getAction(this.frame));
@@ -2926,8 +2917,9 @@ public class BasePanel extends JPanel implements ClipboardOwner, FileUpdateListe
 
     /**
      * Get an array containing the currently selected entries.
+     * The array is stable and not changed if the selection changes
      *
-     * @return An array containing the selected entries.
+     * @return An array containing the selected entries. Is never null.
      */
     public BibtexEntry[] getSelectedEntries() {
         return mainTable.getSelectedEntries();
index 2c371c4..e18a552 100644 (file)
@@ -279,7 +279,7 @@ public class BibtexDatabase {
         throws KeyCollisionException
     {
        if (hasStringLabel(string.getName())){
-               throw new KeyCollisionException("A string with this label already exists,");
+               throw new KeyCollisionException(Globals.lang("A string with this label already exists"));
         }
 
         if (_strings.containsKey(string.getId()))
@@ -441,12 +441,12 @@ public class BibtexDatabase {
 
         // If we get to this point, the string has obviously not been defined locally.
         // Check if one of the standard BibTeX month strings has been used:
-        Object o;
-        if ((o = Globals.MONTH_STRINGS.get(label.toLowerCase())) != null) {
-            return (String)o;
+        MonthUtil.Month month = MonthUtil.getMonthByShortName(label);
+        if(month.isValid()) {
+            return month.fullName;
+        } else {
+            return null;
         }
-
-        return null;
     }
 
     private String resolveContent(String res, HashSet<String> usedIds) {
index f9d861a..eaad4c6 100644 (file)
@@ -51,109 +51,45 @@ public class BibtexEntry
     public final static String ID_FIELD = "id";
     public static Map<String,String> FieldAliasesOldToNew = new HashMap<String, String>(); // Bibtex to BibLatex
     public static Map<String,String> FieldAliasesNewToOld = new HashMap<String, String>(); // BibLatex to Bibtex
-    
-    private String _id;
-    private BibtexEntryType _type;
-    private Map<String, String> _fields = new HashMap<String, String>();
-    VetoableChangeSupport _changeSupport = new VetoableChangeSupport(this);
-
-    // Search and grouping status is stored in boolean fields for quick reference:
-    private boolean searchHit, groupHit;
 
-    /** Display name map for entry field names. */
-    private static final Map<String, String> tagDisplayNameMap = new HashMap<String, String>();
-    /** The maximum length of a field name to properly make the alignment of the
-     *  equal sign. */
-    private static final int maxFieldLength;
     static{
-        // The field name display map.
-        tagDisplayNameMap.put("bibtexkey", "BibTeXKey");
-        tagDisplayNameMap.put("howpublished", "HowPublished");
-        tagDisplayNameMap.put("lastchecked", "LastChecked");
-        tagDisplayNameMap.put("isbn", "ISBN");
-        tagDisplayNameMap.put("issn", "ISSN");
-        tagDisplayNameMap.put("UNKNOWN", "UNKNOWN");
-
-        // Looking for the longest field name.
-        // XXX JK: Look for all used field names not only defined once, since
-        //         there may be some unofficial field name used.
-        int max = 0;
-        for (BibtexEntryType t : BibtexEntryType.ALL_TYPES.values()) {
-            if (t.getRequiredFields() != null) {
-                for(String field : t.getRequiredFields()) {
-                    max = Math.max(max, field.length());
-                }
-            }
-            if (t.getOptionalFields() != null) {
-                for(String field : t.getOptionalFields()) {
-                    max = Math.max(max, field.length());
-                }
-            }
-        }
-        maxFieldLength = max;
-        
         FieldAliasesOldToNew.put("address", "location");
         FieldAliasesNewToOld.put("location", "address");
-        
+
         FieldAliasesOldToNew.put("annote", "annotation");
         FieldAliasesNewToOld.put("annotation", "annote");
-        
+
         FieldAliasesOldToNew.put("archiveprefix", "eprinttype");
         FieldAliasesNewToOld.put("eprinttype", "archiveprefix");
-        
+
         FieldAliasesOldToNew.put("journal", "journaltitle");
         FieldAliasesNewToOld.put("journaltitle", "journal");
-        
+
         FieldAliasesOldToNew.put("key", "sortkey");
         FieldAliasesNewToOld.put("sortkey", "key");
-        
+
         FieldAliasesOldToNew.put("pdf", "file");
         FieldAliasesNewToOld.put("file", "pdf");
-        
+
         FieldAliasesOldToNew.put("primaryclass", "eprintclass");
         FieldAliasesNewToOld.put("eprintclass", "primaryclass");
-        
+
         FieldAliasesOldToNew.put("school", "institution");
         FieldAliasesNewToOld.put("institution", "school");
     }
 
-    /**
-     * Get display version of a entry field.
-     *
-     * BibTeX is case-insensitive therefore there is no difference between:
-     * howpublished, HOWPUBLISHED, HowPublished, etc. Since the camel case
-     * version is the most easy to read this should be the one written in the
-     * *.bib file. Since there is no way how do detect multi-word strings by
-     * default the first character will be made uppercase. In other characters
-     * case needs to be changed the {@link #tagDisplayNameMap} will be used. 
-     *
-     * @param field The name of the field.
-     * @return The display version of the field name.
-     */
-       private static String getFieldDisplayName(String field) {
-        if (field.length() == 0) {
-            // hard coded "UNKNOWN" is assigned to a field without any name
-            field = "UNKNOWN";
-        }
+    
+    private String _id;
+    private BibtexEntryType _type;
+    private Map<String, String> _fields = new HashMap<String, String>();
+    VetoableChangeSupport _changeSupport = new VetoableChangeSupport(this);
+
+    // Search and grouping status is stored in boolean fields for quick reference:
+    private boolean searchHit, groupHit;
+
+
+
 
-        String suffix = "";
-               if (Globals.prefs.getBoolean(JabRefPreferences.WRITEFIELD_ADDSPACES)) {
-                       for (int i = maxFieldLength - field.length(); i > 0; i--)
-                               suffix += " ";
-               }
-
-               String res;
-               if (Globals.prefs.getBoolean(JabRefPreferences.WRITEFIELD_CAMELCASENAME)) {
-                       if (tagDisplayNameMap.containsKey(field.toLowerCase())) {
-                               res = tagDisplayNameMap.get(field.toLowerCase()) + suffix;
-                       } else {
-                               res = (field.charAt(0)+"").toUpperCase() + field.substring(1) + suffix;
-                       }
-               } else {
-                       res = field + suffix;
-               }
-               return res;
-       }
 
     public BibtexEntry(){
        this(Util.createNeutralId());
@@ -359,14 +295,15 @@ public class BibtexEntry
         if(name.equals("date"))
         {
                String year = getField("year");
-               int month = Globals.ParseMonthToInteger(getField("month"));
+               MonthUtil.Month month = MonthUtil.getMonth(getField("month"));
                if(year != null)
                {
-                       if(month == 0)
-                               return year;
-                       else
-                               return year + "-" + String.format("%02d", month);
-               }
+                if (month.isValid()) {
+                    return year + "-" + month.twoDigitNumber;
+                } else {
+                    return year;
+                }
+            }
         }
         if(name.equals("year") || name.equals("month"))
         {
@@ -551,217 +488,7 @@ public class BibtexEntry
      * isDisplayableField(String).
      */
     public void write(Writer out, FieldFormatter ff, boolean write) throws IOException {
-        switch (Globals.prefs.getInt(JabRefPreferences.WRITEFIELD_SORTSTYLE)) {
-        case 0:
-            writeSorted(out, ff, write);
-            break;
-        case 1:
-            writeUnsorted(out, ff, write);
-            break;
-        case 2:
-            writeUserOrder(out,ff,write);
-            break;
-        }
-        
-        
-    }
-    
-    
-    /**
-     * user defined order
-     * @param out
-     * @param ff A formatter to filter field contents before writing
-     * @param write True if this is a write, false if it is a display. The write will not include non-writeable fields if it is a write, otherwise non-displayable fields will be ignored. Refer to GUIGlobals for isWriteableField(String) and isDisplayableField(String).
-     * @throws IOException
-     */
-    private void writeUserOrder(Writer out, FieldFormatter ff, boolean write) throws IOException {
-     // Write header with type and bibtex-key.
-        out.write("@"+_type.getName()+"{");
-
-        String str = Util.shaveString(getField(BibtexFields.KEY_FIELD));
-        out.write(((str == null) ? "" : str)+","+Globals.NEWLINE);
-        HashMap<String, String> written = new HashMap<String, String>();
-        written.put(BibtexFields.KEY_FIELD, null);
-        boolean hasWritten = false;
-        
-     // Write user defined fields first.
-        String[] s = getUserDefinedFields();
-        if (s != null) {
-            //do not sort, write as it is.
-            for (String value : s) {
-                if (!written.containsKey(value)) { // If field appears both in req. and opt. don't repeat.
-                    hasWritten = hasWritten | writeField(value, out, ff, hasWritten, false);
-                    written.put(value, null);
-                }
-            }
-        }
-        
-        // Then write remaining fields in alphabetic order.
-        boolean first = true, previous = true;
-        previous = false;
-        //STA get remaining fields
-        TreeSet<String> remainingFields = new TreeSet<String>();
-        for (String key : _fields.keySet()){
-            //iterate through all fields
-            boolean writeIt = (write ? BibtexFields.isWriteableField(key) :
-                               BibtexFields.isDisplayableField(key));
-            //find the ones has not been written.
-            if (!written.containsKey(key) && writeIt)
-                       remainingFields.add(key);
-        }
-        //END get remaining fields
-        
-        first = previous;
-        for (String field: remainingFields) {
-            hasWritten = hasWritten | writeField(field, out, ff, hasWritten, hasWritten && first);
-            first = false;
-        }
-
-        // Finally, end the entry.
-        out.write((hasWritten ? Globals.NEWLINE : "")+"}"+Globals.NEWLINE);
-        
-    }
-    
-    /** 
-     * old style ver<=2.9.2, write fields in the order of requiredFields, optionalFields and other fields, but does not sort the fields.
-     * @param out
-     * @param ff A formatter to filter field contents before writing
-     * @param write True if this is a write, false if it is a display. The write will not include non-writeable fields if it is a write, otherwise non-displayable fields will be ignored. Refer to GUIGlobals for isWriteableField(String) and isDisplayableField(String).
-     * @throws IOException
-     */
-    private void writeUnsorted(Writer out, FieldFormatter ff, boolean write) throws IOException {
-        // Write header with type and bibtex-key.
-        out.write("@"+_type.getName().toUpperCase(Locale.US)+"{");
-
-        String str = Util.shaveString(getField(BibtexFields.KEY_FIELD));
-        out.write(((str == null) ? "" : str)+","+Globals.NEWLINE);
-        HashMap<String, String> written = new HashMap<String, String>();
-        written.put(BibtexFields.KEY_FIELD, null);
-        boolean hasWritten = false;
-        // Write required fields first.
-        String[] s = getRequiredFields();
-        if (s != null) for (String value : s) {
-            hasWritten = hasWritten | writeField(value, out, ff, hasWritten, false);
-            written.put(value, null);
-        }
-        // Then optional fields.
-        s = getOptionalFields();
-        if (s != null) for (String value : s) {
-            if (!written.containsKey(value)) { // If field appears both in req. and opt. don't repeat.
-                //writeField(s[i], out, ff);
-                hasWritten = hasWritten | writeField(value, out, ff, hasWritten, false);
-                written.put(value, null);
-            }
-        }
-        // Then write remaining fields in alphabetic order.
-        TreeSet<String> remainingFields = new TreeSet<String>();
-        for (String key : _fields.keySet()){
-            boolean writeIt = (write ? BibtexFields.isWriteableField(key) :
-                               BibtexFields.isDisplayableField(key));
-            if (!written.containsKey(key) && writeIt)
-                       remainingFields.add(key);
-        }
-        for (String field: remainingFields)
-            hasWritten = hasWritten | writeField(field, out, ff, hasWritten,false);
-
-        // Finally, end the entry.
-        out.write((hasWritten ? Globals.NEWLINE : "")+"}"+Globals.NEWLINE);
-    }
-    
-    /**
-     * new style ver>=2.10, sort the field for requiredFields, optionalFields and other fields separately
-     * @param out
-     * @param ff A formatter to filter field contents before writing
-     * @param write True if this is a write, false if it is a display. The write will not include non-writeable fields if it is a write, otherwise non-displayable fields will be ignored. Refer to GUIGlobals for isWriteableField(String) and isDisplayableField(String).
-     * @throws IOException
-     */
-    private void writeSorted(Writer out, FieldFormatter ff, boolean write) throws IOException {
-        // Write header with type and bibtex-key.
-        out.write("@"+_type.getName()+"{");
-
-        String str = Util.shaveString(getField(BibtexFields.KEY_FIELD));
-        out.write(((str == null) ? "" : str)+","+Globals.NEWLINE);
-        HashMap<String, String> written = new HashMap<String, String>();
-        written.put(BibtexFields.KEY_FIELD, null);
-        boolean hasWritten = false;
-        // Write required fields first.
-        // Thereby, write the title field first.
-        hasWritten = hasWritten | writeField("title", out, ff, hasWritten, false);
-        written.put("title", null);
-        String[] s = getRequiredFields();
-        if (s != null) {
-            Arrays.sort(s); // Sorting in alphabetic order.
-            for (String value : s) {
-                if (!written.containsKey(value)) { // If field appears both in req. and opt. don't repeat.
-                    hasWritten = hasWritten | writeField(value, out, ff, hasWritten, false);
-                    written.put(value, null);
-                }
-            }
-        }
-        // Then optional fields.
-        s = getOptionalFields();
-        boolean first = true, previous = true;
-        previous = false;
-        if (s != null) {
-            Arrays.sort(s); // Sorting in alphabetic order.
-            for (String value : s) {
-                if (!written.containsKey(value)) { // If field appears both in req. and opt. don't repeat.
-                    //writeField(s[i], out, ff);
-                    hasWritten = hasWritten | writeField(value, out, ff, hasWritten, hasWritten && first);
-                    written.put(value, null);
-                    first = false;
-                    previous = true;
-                }
-            }
-        }
-        // Then write remaining fields in alphabetic order.
-        TreeSet<String> remainingFields = new TreeSet<String>();
-        for (String key : _fields.keySet()){
-            boolean writeIt = (write ? BibtexFields.isWriteableField(key) :
-                               BibtexFields.isDisplayableField(key));
-            if (!written.containsKey(key) && writeIt)
-                       remainingFields.add(key);
-        }
-        first = previous;
-        for (String field: remainingFields) {
-            hasWritten = hasWritten | writeField(field, out, ff, hasWritten, hasWritten && first);
-            first = false;
-        }
-
-        // Finally, end the entry.
-        out.write((hasWritten ? Globals.NEWLINE : "")+"}"+Globals.NEWLINE);
-    }
-
-    /**
-     * Write a single field, if it has any content.
-     * @param name The field name
-     * @param out The Writer to send it to
-     * @param ff A formatter to filter field contents before writing
-     * @param isNotFirst Indicates whether this is the first field written for
-     *    this entry - if not, start by writing a comma and newline
-     * @return true if this field was written, false if it was skipped because
-     *    it was not set
-     * @throws IOException In case of an IO error
-     */
-    private boolean writeField(String name, Writer out,
-                            FieldFormatter ff, boolean isNotFirst, boolean isNextGroup) throws IOException {
-        String o = getField(name);
-        if (o != null || Globals.prefs.getBoolean("includeEmptyFields")) {
-            if (isNotFirst)
-                out.write(","+Globals.NEWLINE);
-            if (isNextGroup)
-                out.write(Globals.NEWLINE);
-            out.write("  "+ getFieldDisplayName(name) + " = ");
-
-            try {
-                out.write(ff.format(o, name));
-            } catch (Throwable ex) {
-                throw new IOException
-                    (Globals.lang("Error in field")+" '"+name+"': "+ex.getMessage());
-            }
-            return true;
-        } else
-            return false;
+        new BibtexEntryWriter(ff, write).write(this, out);
     }
 
     /**
diff --git a/src/main/java/net/sf/jabref/BibtexEntryWriter.java b/src/main/java/net/sf/jabref/BibtexEntryWriter.java
new file mode 100644 (file)
index 0000000..f67b3cc
--- /dev/null
@@ -0,0 +1,303 @@
+package net.sf.jabref;
+
+import net.sf.jabref.export.FieldFormatter;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.*;
+
+public class BibtexEntryWriter {
+
+    /**
+     * Display name map for entry field names.
+     */
+    private static final Map<String, String> tagDisplayNameMap = new HashMap<String, String>();
+
+    static {
+        // The field name display map.
+        tagDisplayNameMap.put("bibtexkey", "BibTeXKey");
+        tagDisplayNameMap.put("howpublished", "HowPublished");
+        tagDisplayNameMap.put("lastchecked", "LastChecked");
+        tagDisplayNameMap.put("isbn", "ISBN");
+        tagDisplayNameMap.put("issn", "ISSN");
+        tagDisplayNameMap.put("UNKNOWN", "UNKNOWN");
+    }
+
+    /**
+     * The maximum length of a field name to properly make the alignment of the
+     * equal sign.
+     */
+    private static final int maxFieldLength;
+
+    static {
+        // Looking for the longest field name.
+        // XXX JK: Look for all used field names not only defined once, since
+        //         there may be some unofficial field name used.
+        int max = 0;
+        for (BibtexEntryType t : BibtexEntryType.ALL_TYPES.values()) {
+            if (t.getRequiredFields() != null) {
+                for (String field : t.getRequiredFields()) {
+                    max = Math.max(max, field.length());
+                }
+            }
+            if (t.getOptionalFields() != null) {
+                for (String field : t.getOptionalFields()) {
+                    max = Math.max(max, field.length());
+                }
+            }
+        }
+        maxFieldLength = max;
+    }
+
+    private final FieldFormatter fieldFormatter;
+    private final boolean write;
+    private final boolean writeFieldCameCaseName = Globals.prefs.getBoolean(JabRefPreferences.WRITEFIELD_CAMELCASENAME);
+    private final boolean writeFieldAddSpaces = Globals.prefs.getBoolean(JabRefPreferences.WRITEFIELD_ADDSPACES);
+    private final boolean includeEmptyFields = Globals.prefs.getBoolean("includeEmptyFields");
+    private final int writeFieldSortStype = Globals.prefs.getInt(JabRefPreferences.WRITEFIELD_SORTSTYLE);
+
+    public BibtexEntryWriter(FieldFormatter fieldFormatter, boolean write) {
+        this.fieldFormatter = fieldFormatter;
+        this.write = write;
+    }
+
+    public void write(BibtexEntry entry, Writer out) throws IOException {
+        switch (writeFieldSortStype) {
+            case 0:
+                writeSorted(entry, out);
+                break;
+            case 1:
+                writeUnsorted(entry, out);
+                break;
+            case 2:
+                writeUserDefinedOrder(entry, out);
+                break;
+        }
+    }
+
+    /**
+     * new style ver>=2.10, sort the field for requiredFields, optionalFields and other fields separately
+     *
+     * @param entry
+     * @param out
+     * @throws IOException
+     */
+    private void writeSorted(BibtexEntry entry, Writer out) throws IOException {
+        // Write header with type and bibtex-key.
+        out.write("@" + entry.getType().getName() + "{");
+
+        String str = Util.shaveString(entry.getField(BibtexFields.KEY_FIELD));
+        out.write(((str == null) ? "" : str) + "," + Globals.NEWLINE);
+        HashMap<String, String> written = new HashMap<String, String>();
+        written.put(BibtexFields.KEY_FIELD, null);
+        // Write required fields first.
+        // Thereby, write the title field first.
+        boolean hasWritten = writeField(entry, out, "title", false, false);
+        written.put("title", null);
+        String[] s = entry.getRequiredFields();
+        if (s != null) {
+            Arrays.sort(s); // Sorting in alphabetic order.
+            for (String value : s) {
+                if (!written.containsKey(value)) { // If field appears both in req. and opt. don't repeat.
+                    hasWritten = hasWritten | writeField(entry, out, value, hasWritten, false);
+                    written.put(value, null);
+                }
+            }
+        }
+        // Then optional fields.
+        s = entry.getOptionalFields();
+        boolean first = true, previous = true;
+        previous = false;
+        if (s != null) {
+            Arrays.sort(s); // Sorting in alphabetic order.
+            for (String value : s) {
+                if (!written.containsKey(value)) { // If field appears both in req. and opt. don't repeat.
+                    //writeField(s[i], out, fieldFormatter);
+                    hasWritten = hasWritten | writeField(entry, out, value, hasWritten, hasWritten && first);
+                    written.put(value, null);
+                    first = false;
+                    previous = true;
+                }
+            }
+        }
+        // Then write remaining fields in alphabetic order.
+        TreeSet<String> remainingFields = new TreeSet<String>();
+        for (String key : entry.getAllFields()) {
+            boolean writeIt = (write ? BibtexFields.isWriteableField(key) :
+                    BibtexFields.isDisplayableField(key));
+            if (!written.containsKey(key) && writeIt)
+                remainingFields.add(key);
+        }
+        first = previous;
+        for (String field : remainingFields) {
+            hasWritten = hasWritten | writeField(entry, out, field, hasWritten, hasWritten && first);
+            first = false;
+        }
+
+        // Finally, end the entry.
+        out.write((hasWritten ? Globals.NEWLINE : "") + "}" + Globals.NEWLINE);
+    }
+
+    /**
+     * old style ver<=2.9.2, write fields in the order of requiredFields, optionalFields and other fields, but does not sort the fields.
+     *
+     * @param entry
+     * @param out
+     * @throws IOException
+     */
+    private void writeUnsorted(BibtexEntry entry, Writer out) throws IOException {
+        // Write header with type and bibtex-key.
+        out.write("@" + entry.getType().getName().toUpperCase(Locale.US) + "{");
+
+        String str = Util.shaveString(entry.getField(BibtexFields.KEY_FIELD));
+        out.write(((str == null) ? "" : str) + "," + Globals.NEWLINE);
+        HashMap<String, String> written = new HashMap<String, String>();
+        written.put(BibtexFields.KEY_FIELD, null);
+        boolean hasWritten = false;
+        // Write required fields first.
+        String[] s = entry.getRequiredFields();
+        if (s != null) for (String value : s) {
+            hasWritten = hasWritten | writeField(entry, out, value, hasWritten, false);
+            written.put(value, null);
+        }
+        // Then optional fields.
+        s = entry.getOptionalFields();
+        if (s != null) for (String value : s) {
+            if (!written.containsKey(value)) { // If field appears both in req. and opt. don't repeat.
+                //writeField(s[i], out, fieldFormatter);
+                hasWritten = hasWritten | writeField(entry, out, value, hasWritten, false);
+                written.put(value, null);
+            }
+        }
+        // Then write remaining fields in alphabetic order.
+        TreeSet<String> remainingFields = new TreeSet<String>();
+        for (String key : entry.getAllFields()) {
+            boolean writeIt = (write ? BibtexFields.isWriteableField(key) :
+                    BibtexFields.isDisplayableField(key));
+            if (!written.containsKey(key) && writeIt)
+                remainingFields.add(key);
+        }
+        for (String field : remainingFields)
+            hasWritten = hasWritten | writeField(entry, out, field, hasWritten, false);
+
+        // Finally, end the entry.
+        out.write((hasWritten ? Globals.NEWLINE : "") + "}" + Globals.NEWLINE);
+    }
+
+    private void writeUserDefinedOrder(BibtexEntry entry, Writer out) throws IOException {
+        // Write header with type and bibtex-key.
+        out.write("@" + entry.getType().getName() + "{");
+
+        String str = Util.shaveString(entry.getField(BibtexFields.KEY_FIELD));
+        out.write(((str == null) ? "" : str) + "," + Globals.NEWLINE);
+        HashMap<String, String> written = new HashMap<String, String>();
+        written.put(BibtexFields.KEY_FIELD, null);
+        boolean hasWritten = false;
+
+        // Write user defined fields first.
+        String[] s = entry.getUserDefinedFields();
+        if (s != null) {
+            //do not sort, write as it is.
+            for (String value : s) {
+                if (!written.containsKey(value)) { // If field appears both in req. and opt. don't repeat.
+                    hasWritten = hasWritten | writeField(entry, out, value, hasWritten, false);
+                    written.put(value, null);
+                }
+            }
+        }
+
+        // Then write remaining fields in alphabetic order.
+        boolean first = true, previous = true;
+        previous = false;
+        //STA get remaining fields
+        TreeSet<String> remainingFields = new TreeSet<String>();
+        for (String key : entry.getAllFields()) {
+            //iterate through all fields
+            boolean writeIt = (write ? BibtexFields.isWriteableField(key) :
+                    BibtexFields.isDisplayableField(key));
+            //find the ones has not been written.
+            if (!written.containsKey(key) && writeIt)
+                remainingFields.add(key);
+        }
+        //END get remaining fields
+
+        first = previous;
+        for (String field : remainingFields) {
+            hasWritten = hasWritten | writeField(entry, out, field, hasWritten, hasWritten && first);
+            first = false;
+        }
+
+        // Finally, end the entry.
+        out.write((hasWritten ? Globals.NEWLINE : "") + "}" + Globals.NEWLINE);
+
+    }
+
+    /**
+     * Write a single field, if it has any content.
+     *
+     * @param entry      the entry to write
+     * @param out        the target of the write
+     * @param name       The field name
+     * @param isNotFirst Indicates whether this is the first field written for
+     *                   this entry - if not, start by writing a comma and newline   @return true if this field was written, false if it was skipped because
+     *                   it was not set
+     * @throws IOException In case of an IO error
+     */
+    private boolean writeField(BibtexEntry entry, Writer out, String name, boolean isNotFirst, boolean isNextGroup) throws IOException {
+        String o = entry.getField(name);
+        if (o != null || includeEmptyFields) {
+            if (isNotFirst)
+                out.write("," + Globals.NEWLINE);
+            if (isNextGroup)
+                out.write(Globals.NEWLINE);
+            out.write("  " + getFieldDisplayName(name) + " = ");
+
+            try {
+                out.write(fieldFormatter.format(o, name));
+            } catch (Throwable ex) {
+                throw new IOException
+                        (Globals.lang("Error in field") + " '" + name + "': " + ex.getMessage());
+            }
+            return true;
+        } else
+            return false;
+    }
+
+    /**
+     * Get display version of a entry field.
+     * <p/>
+     * BibTeX is case-insensitive therefore there is no difference between:
+     * howpublished, HOWPUBLISHED, HowPublished, etc. Since the camel case
+     * version is the most easy to read this should be the one written in the
+     * *.bib file. Since there is no way how do detect multi-word strings by
+     * default the first character will be made uppercase. In other characters
+     * case needs to be changed the {@link #tagDisplayNameMap} will be used.
+     *
+     * @param field The name of the field.
+     * @return The display version of the field name.
+     */
+    private String getFieldDisplayName(String field) {
+        if (field.length() == 0) {
+            // hard coded "UNKNOWN" is assigned to a field without any name
+            field = "UNKNOWN";
+        }
+
+        String suffix = "";
+        if (writeFieldAddSpaces) {
+            for (int i = maxFieldLength - field.length(); i > 0; i--)
+                suffix += " ";
+        }
+
+        String res;
+        if (writeFieldCameCaseName) {
+            if (tagDisplayNameMap.containsKey(field.toLowerCase())) {
+                res = tagDisplayNameMap.get(field.toLowerCase()) + suffix;
+            } else {
+                res = (field.charAt(0) + "").toUpperCase() + field.substring(1) + suffix;
+            }
+        } else {
+            res = field + suffix;
+        }
+        return res;
+    }
+}
index 2388a56..7a446ce 100644 (file)
 */
 package net.sf.jabref;
 
-import java.awt.*;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.Window;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.FocusAdapter;
 import java.awt.event.FocusEvent;
-import java.util.*;
-
-import javax.swing.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.Vector;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.BorderFactory;
+import javax.swing.DefaultListModel;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JList;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextField;
 import javax.swing.event.ListSelectionEvent;
 import javax.swing.event.ListSelectionListener;
 
@@ -56,16 +73,16 @@ public class ContentSelectorDialog2 extends JDialog {
        ok = new JButton(Globals.lang("Ok")),
        cancel = new JButton(),
        apply = new JButton(Globals.lang("Apply"));
-    DefaultListModel<String> fieldListModel = new DefaultListModel<String>(),
-       wordListModel = new DefaultListModel<String>();
-    JList<String> fieldList = new JList<String>(fieldListModel),
-       wordList = new JList<String>(wordListModel);
+       DefaultListModel fieldListModel = new DefaultListModel(),
+                       wordListModel = new DefaultListModel();
+       JList fieldList = new JList(fieldListModel),
+                       wordList = new JList(wordListModel);
     JTextField fieldNameField = new JTextField("", 20),
        wordEditField = new JTextField("", 20);
     JScrollPane fPane = new JScrollPane(fieldList),
        wPane = new JScrollPane(wordList);
 
-    HashMap<String, DefaultListModel<String>> wordListModels = new HashMap<String, DefaultListModel<String>>();
+       HashMap<String, DefaultListModel> wordListModels = new HashMap<String, DefaultListModel>();
     ArrayList<String> removedFields = new ArrayList<String>();
 
     /**
@@ -108,7 +125,7 @@ public class ContentSelectorDialog2 extends JDialog {
 
        wordList.addListSelectionListener(new ListSelectionListener() {
                public void valueChanged(ListSelectionEvent e) {
-                   wordEditField.setText(wordList.getSelectedValue());
+                               wordEditField.setText((String) wordList.getSelectedValue());
                    wordEditField.selectAll();
                    new FocusRequester(wordEditField);
                }
@@ -123,7 +140,7 @@ public class ContentSelectorDialog2 extends JDialog {
         wordEditFieldListener = new ActionListener() {
             public void actionPerformed(ActionEvent e) {
                 int index = wordList.getSelectedIndex();
-                String old = wordList.getSelectedValue(),
+                               String old = (String) wordList.getSelectedValue(),
                newVal = wordEditField.getText();
                 if (newVal.equals("") || newVal.equals(old)) {
                     return; // Empty string or no change.
@@ -166,7 +183,7 @@ public class ContentSelectorDialog2 extends JDialog {
 
        fieldList.addListSelectionListener(new ListSelectionListener() {
                public void valueChanged(ListSelectionEvent e) {
-                   currentField = fieldList.getSelectedValue();
+                               currentField = (String) fieldList.getSelectedValue();
                    fieldNameField.setText("");
                    setupWordSelector();
                }
@@ -233,7 +250,7 @@ public class ContentSelectorDialog2 extends JDialog {
                    int index = fieldList.getSelectedIndex();
                    if (index == -1)
                        return;
-                   String fieldName = fieldListModel.get(index);
+                               String fieldName = (String) fieldListModel.get(index);
                    removedFields.add(fieldName);
                    fieldListModel.remove(index);
                    wordListModels.remove(fieldName);
@@ -313,7 +330,7 @@ public class ContentSelectorDialog2 extends JDialog {
             // For each field name, store the values:
             if ((fieldName == null) || FIELD_FIRST_LINE.equals(fieldName))
                 continue;
-            DefaultListModel<String> lm = wordListModels.get(fieldName);
+                       DefaultListModel lm = wordListModels.get(fieldName);
             int start = 0;
             // Avoid storing the <new word> marker if it is there:
             if (lm.size() > 0)
@@ -329,7 +346,7 @@ public class ContentSelectorDialog2 extends JDialog {
             } else
                 data.clear();
             for (int wrd = start; wrd < lm.size(); wrd++) {
-                String word = lm.get(wrd);
+                               String word = (String) lm.get(wrd);
                 data.add(word);
             }
             if (newField)
@@ -396,7 +413,7 @@ public class ContentSelectorDialog2 extends JDialog {
                if (wordListModel != null) {
                        wordList.setModel(wordListModel);
                } else {
-                       wordListModel = new DefaultListModel<String>();
+                       wordListModel = new DefaultListModel();
                        wordList.setModel(wordListModel);
                        wordListModels.put(currentField, wordListModel);
                        // wordListModel.addElement(WORD_FIRSTLINE_TEXT);
@@ -412,9 +429,9 @@ public class ContentSelectorDialog2 extends JDialog {
                }
        }
 
-    private int findPos(DefaultListModel<String> lm, String item) {
+       private int findPos(DefaultListModel lm, String item) {
        for (int i=0; i<lm.size(); i++) {
-           String s = lm.get(i);
+                       String s = (String) lm.get(i);
            if (item.compareToIgnoreCase(s) < 0) { // item precedes s
                return i;
            }
index 4cc6588..b3d9e6b 100644 (file)
@@ -75,6 +75,7 @@ import net.sf.jabref.gui.*;
 import net.sf.jabref.gui.date.DatePickerButton;
 import net.sf.jabref.help.HelpAction;
 import net.sf.jabref.imports.BibtexParser;
+import net.sf.jabref.imports.ParserResult;
 import net.sf.jabref.journals.JournalAbbreviations;
 import net.sf.jabref.labelPattern.LabelPatternUtil;
 import net.sf.jabref.specialfields.SpecialFieldUpdateListener;
@@ -597,8 +598,7 @@ public class EntryEditor extends JPanel implements VetoableChangeListener, Entry
             StringWriter sw = new StringWriter(200);
 
             try {
-                LatexFieldFormatter formatter = new LatexFieldFormatter();
-                formatter.setNeverFailOnHashes(true);
+                LatexFieldFormatter formatter = LatexFieldFormatter.buildIgnoreHashes();
                 entry.write(sw, formatter, false);
 
                 String srcString = sw.getBuffer().toString();
@@ -818,7 +818,7 @@ public class EntryEditor extends JPanel implements VetoableChangeListener, Entry
 
     /**
      * Returns false if the contents of the source panel has not been validated,
-     * true othervise.
+     * true otherwise.
      */
     public boolean lastSourceAccepted() {
         if (tabbed.getSelectedComponent() == srcPanel)
@@ -836,13 +836,20 @@ public class EntryEditor extends JPanel implements VetoableChangeListener, Entry
         BibtexParser bp = new BibtexParser(new java.io.StringReader(source.getText()));
 
         try {
-            BibtexDatabase db = bp.parse().getDatabase();
+            ParserResult parserResult = bp.parse();
+            BibtexDatabase db = parserResult.getDatabase();
 
             if (db.getEntryCount() > 1)
                 throw new Exception("More than one entry found.");
 
-            if (db.getEntryCount() < 1)
-                throw new Exception("No entries found.");
+            if (db.getEntryCount() < 1) {
+                if (parserResult.hasWarnings()) {
+                    // put the warning into as exception text -> it will be displayed to the user
+                    throw new Exception(parserResult.warnings()[0]);
+                } else {
+                    throw new Exception("No entries found.");
+                }
+            }
 
             NamedCompound compound = new NamedCompound(Globals.lang("source edit"));
             BibtexEntry nu = db.getEntryById(db.getKeySet().iterator().next());
index c2e248d..93d8e20 100644 (file)
@@ -125,20 +125,20 @@ public class FieldComparator implements Comparator<BibtexEntry> {
                         * 
                         * http://sourceforge.net/tracker/index.php?func=detail&aid=1535044&group_id=92314&atid=600306
                         */
-                       f1 = Util.getMonthNumber((String) f1);
-                       f2 = Util.getMonthNumber((String) f2);
+                       f1 = MonthUtil.getMonth((String) f1).number;
+                       f2 = MonthUtil.getMonth((String) f2).number;
                }
 
         if (isNumeric) {
             Integer i1 = null, i2 = null;
             try {
-                i1 = Integer.parseInt((String)f1);
+                i1 = Util.intValueOf((String)f1);
             } catch (NumberFormatException ex) {
                 // Parsing failed.
             }
 
             try {
-                i2 = Integer.parseInt((String)f2);
+                i2 = Util.intValueOf((String) f2);
             } catch (NumberFormatException ex) {
                 // Parsing failed.
             }
index e42e590..8473dd3 100644 (file)
 */
 package net.sf.jabref;
 
-import java.awt.*;
+import java.awt.Dimension;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Window;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.util.Vector;
 
-import javax.swing.*;
+import javax.swing.AbstractAction;
+import javax.swing.Box;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.KeyStroke;
 
 import com.jgoodies.forms.layout.Sizes;
 import com.jgoodies.looks.Options;
@@ -37,7 +45,7 @@ import com.jgoodies.looks.Options;
  */
 public class FieldContentSelector extends JComponent {
 
-       JComboBox<String> comboBox;
+       JComboBox comboBox;
 
        FieldEditor editor;
 
@@ -89,7 +97,7 @@ public class FieldContentSelector extends JComponent {
         this.action = action;
         this.delimiter = delimiter;
 
-               comboBox = new JComboBox<String>() {
+               comboBox = new JComboBox() {
                        public Dimension getPreferredSize() {
                                Dimension parents = super.getPreferredSize();
                                if (parents.width > GUIGlobals.MAX_CONTENT_SELECTOR_WIDTH)
index 644e280..2c5b51e 100644 (file)
  */
 package net.sf.jabref;
 
-import java.awt.*;
-
-import javax.swing.*;
-
-import com.jgoodies.forms.builder.DefaultFormBuilder;
-import com.jgoodies.forms.layout.FormLayout;
-
+import java.awt.BorderLayout;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.ArrayList;
+
+import javax.swing.BorderFactory;
+import javax.swing.ButtonGroup;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.JTextField;
+
+import com.jgoodies.forms.builder.DefaultFormBuilder;
+import com.jgoodies.forms.layout.FormLayout;
 
 /**
  * Preference tab for file sorting options.
@@ -39,12 +45,12 @@ public class FileSortTab extends JPanel implements PrefsTab {
     private JRadioButton saveInOriginalOrder, saveInTableOrder, saveInSpecifiedOrder;
     private JCheckBox savePriDesc, saveSecDesc, saveTerDesc;
     private JTextField savePriField, saveSecField, saveTerField;
-    private JComboBox<String> savePriSort, saveSecSort, saveTerSort;
+       private JComboBox savePriSort, saveSecSort, saveTerSort;
 
     private JRadioButton exportInOriginalOrder, exportInTableOrder, exportInSpecifiedOrder;
     private JCheckBox exportPriDesc, exportSecDesc, exportTerDesc;
     private JTextField exportPriField, exportSecField, exportTerField;
-    private JComboBox<String> exportPriSort, exportSecSort, exportTerSort;
+       private JComboBox exportPriSort, exportSecSort, exportTerSort;
 
     public FileSortTab(JabRefFrame frame, JabRefPreferences prefs) {
         this._prefs = prefs;
@@ -86,9 +92,9 @@ public class FileSortTab extends JPanel implements PrefsTab {
             v.add(BibtexFields.KEY_FIELD);
             Collections.sort(v);
             String[] allPlusKey = v.toArray(new String[v.size()]);
-            savePriSort = new JComboBox<String>(allPlusKey);
-            saveSecSort = new JComboBox<String>(allPlusKey);
-            saveTerSort = new JComboBox<String>(allPlusKey);
+                       savePriSort = new JComboBox(allPlusKey);
+                       saveSecSort = new JComboBox(allPlusKey);
+                       saveTerSort = new JComboBox(allPlusKey);
 
             savePriField = new JTextField(10);
             saveSecField = new JTextField(10);
@@ -198,9 +204,9 @@ public class FileSortTab extends JPanel implements PrefsTab {
             v.add(BibtexFields.KEY_FIELD);
             Collections.sort(v);
             String[] allPlusKey = v.toArray(new String[v.size()]);
-            exportPriSort = new JComboBox<String>(allPlusKey);
-            exportSecSort = new JComboBox<String>(allPlusKey);
-            exportTerSort = new JComboBox<String>(allPlusKey);
+                       exportPriSort = new JComboBox(allPlusKey);
+                       exportSecSort = new JComboBox(allPlusKey);
+                       exportTerSort = new JComboBox(allPlusKey);
 
             exportPriField = new JTextField(10);
             exportSecField = new JTextField(10);
index 336916d..fdc3473 100644 (file)
 */
 package net.sf.jabref;
 
-import java.awt.*;
+import java.awt.BorderLayout;
+import java.awt.Dimension;
 import java.util.ArrayList;
 import java.util.Enumeration;
 
-import javax.swing.*;
-import javax.swing.event.ChangeListener;
+import javax.swing.AbstractButton;
+import javax.swing.BorderFactory;
+import javax.swing.ButtonGroup;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.JSpinner;
+import javax.swing.JTextField;
+import javax.swing.SpinnerNumberModel;
 import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
 
 import net.sf.jabref.help.HelpAction;
 
@@ -39,7 +51,7 @@ public class FileTab extends JPanel implements PrefsTab {
 
     private JCheckBox backup, openLast, autoDoubleBraces, autoSave,
             promptBeforeUsingAutoSave, includeEmptyFields, camelCase, sameColumn;
-    private JComboBox<String> valueDelimiter, newlineSeparator;
+       private JComboBox valueDelimiter, newlineSeparator;
     private JRadioButton
         resolveStringsStandard, resolveStringsAll;
     private JTextField bracesAroundCapitalsFields, nonWrappableFields,
@@ -66,7 +78,7 @@ public class FileTab extends JPanel implements PrefsTab {
         autoSave = new JCheckBox(Globals.lang("Autosave"));
         promptBeforeUsingAutoSave = new JCheckBox(Globals.lang("Prompt before recovering a database from an autosave file"));
         autoSaveInterval = new JSpinner(new SpinnerNumberModel(1, 1, 60, 1));
-        valueDelimiter = new JComboBox<String>(new String[]{
+               valueDelimiter = new JComboBox(new String[] {
                 Globals.lang("Quotes") + ": \", \"",
                 Globals.lang("Curly Brackets") + ": {, }" });
         includeEmptyFields = new JCheckBox(Globals.lang("Include empty fields"));
@@ -91,7 +103,7 @@ public class FileTab extends JPanel implements PrefsTab {
         
         
         // This is sort of a quick hack
-        newlineSeparator = new JComboBox<String>(new String[] {"CR", "CR/LF", "LF"});
+               newlineSeparator = new JComboBox(new String[] {"CR", "CR/LF", "LF"});
 
         bracesAroundCapitalsFields = new JTextField(25);
         nonWrappableFields = new JTextField(25);
index 06f3b0f..0463145 100644 (file)
@@ -23,7 +23,13 @@ import java.awt.event.WindowEvent;
 import java.io.File;
 import java.io.FileFilter;
 import java.io.IOException;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.TreeMap;
+import java.util.Vector;
 
 import javax.swing.AbstractAction;
 import javax.swing.Action;
@@ -55,13 +61,13 @@ import javax.swing.tree.TreeModel;
 import javax.swing.tree.TreeNode;
 import javax.swing.tree.TreePath;
 
-import com.jgoodies.forms.builder.ButtonBarBuilder;
-
 import net.sf.jabref.imports.EntryFromFileCreator;
 import net.sf.jabref.imports.EntryFromFileCreatorManager;
 import net.sf.jabref.imports.UnlinkedFilesCrawler;
 import net.sf.jabref.imports.UnlinkedPDFFileFilter;
 
+import com.jgoodies.forms.builder.ButtonBarBuilder;
+
 /**
  * GUI Dialog for the feature "Find unlinked files".
  * 
@@ -78,6 +84,7 @@ public class FindUnlinkedFilesDialog extends JDialog {
        public static final String ACTION_COMMAND = "findUnlinkedFiles";
        public static final String ACTION_TITLE = Globals.lang("Find unlinked files") + "..."; // this entry is NOT in Menu_en.properties as the same string also appears in JabRef_en.properties
        public static final String ACTION_ICON = "toggleSearch";
+       public static final String ACTION_KEYBINDING_ACTION = "Find unlinked files";
        public static final String ACTION_SHORT_DESCRIPTION = Globals.lang("Searches for unlinked PDF files on the file system");
 
        private static final String GLOBAL_PREFS_WORKING_DIRECTORY_KEY = "findUnlinkedFilesWD";
@@ -124,8 +131,8 @@ public class FindUnlinkedFilesDialog extends JDialog {
 
        protected JTree tree;
        protected JScrollPane scrollpaneTree;
-       protected JComboBox<FileFilter> comboBoxFileTypeSelection;
-       protected JComboBox<BibtexEntryTypeWrapper> comboBoxEntryTypeSelection;
+       protected JComboBox comboBoxFileTypeSelection;
+       protected JComboBox comboBoxEntryTypeSelection;
        
        private JProgressBar progressBarSearching;
        private JProgressBar progressBarImporting;
@@ -999,7 +1006,7 @@ public class FindUnlinkedFilesDialog extends JDialog {
                for (FileFilter fileFilter : fileFilterList) {
                        vector.add(fileFilter);
                }
-               comboBoxFileTypeSelection = new JComboBox<FileFilter>(vector);
+               comboBoxFileTypeSelection = new JComboBox(vector);
                
                comboBoxFileTypeSelection.setRenderer(new DefaultListCellRenderer() {
                        private static final long serialVersionUID = 8503499454763947465L;
@@ -1034,7 +1041,7 @@ public class FindUnlinkedFilesDialog extends JDialog {
                while(iterator.hasNext()) {
                        list.add(new BibtexEntryTypeWrapper(iterator.next()));
                }
-               comboBoxEntryTypeSelection = new JComboBox<BibtexEntryTypeWrapper>(list);
+               comboBoxEntryTypeSelection = new JComboBox(list);
        }
        
        /**
index d4c2ad1..e23dc10 100644 (file)
@@ -48,12 +48,30 @@ modified slightly by nizar batada for JabRef
  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
 
-import java.awt.*;
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.GridLayout;
+import java.awt.RenderingHints;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.util.Vector;
 
-import javax.swing.*;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextField;
 import javax.swing.border.EmptyBorder;
 import javax.swing.border.TitledBorder;
 import javax.swing.event.ListSelectionEvent;
@@ -196,14 +214,14 @@ public class FontSelectorDialog extends JDialog {
                 JPanel familyPanel = createTextFieldAndListPanel(
                                                                  Globals.lang("Font Family"),
                                                                  familyField = new JTextField(),
                                                                familyList = new JList<String>(getFontList()));
familyList = new JList(getFontList()));
                 listPanel.add(familyPanel);
 
                 String[] sizes = { "9", "10", "12", "14", "16", "18", "24" };
                 JPanel sizePanel = createTextFieldAndListPanel(
                                                                Globals.lang("Font Size"),
                                        sizeField = new JTextField(),
                                      sizeList = new JList<String>(sizes));
sizeList = new JList(sizes));
                 listPanel.add(sizePanel);
 
                 String[] styles = {PLAIN,BOLD,ITALIC,BOLD_ITALIC};
@@ -211,7 +229,7 @@ public class FontSelectorDialog extends JDialog {
                 JPanel stylePanel = createTextFieldAndListPanel(
                                                                 Globals.lang("Font Style"),
                                         styleField = new JTextField(),
                                       styleList = new JList<String>(styles));
styleList = new JList(styles));
                 styleField.setEditable(false);
                 listPanel.add(stylePanel);
 
@@ -220,7 +238,7 @@ public class FontSelectorDialog extends JDialog {
                 sizeList.setSelectedValue(String.valueOf(font.getSize()),true);
                 sizeField.setText(String.valueOf(font.getSize()));
                 styleList.setSelectedIndex(font.getStyle());
-                styleField.setText(styleList.getSelectedValue());
+               styleField.setText((String) styleList.getSelectedValue());
 
                 ListHandler listHandler = new ListHandler();
                 familyList.addListSelectionListener(listHandler);
@@ -312,11 +330,11 @@ public class FontSelectorDialog extends JDialog {
         // private members
         private boolean isOK;
         private JTextField familyField;
-        private JList<String> familyList;
+       private JList familyList;
         private JTextField sizeField;
-        private JList<String> sizeList;
+       private JList sizeList;
         private JTextField styleField;
-        private JList<String> styleList;
+       private JList styleList;
         private JLabel preview;
         private JButton ok;
         private JButton cancel;
@@ -354,7 +372,7 @@ public class FontSelectorDialog extends JDialog {
                 }
         }
 
-        private JPanel createTextFieldAndListPanel(String label,JTextField textField, JList<String> list){
+       private JPanel createTextFieldAndListPanel(String label, JTextField textField, JList list) {
                 GridBagLayout layout = new GridBagLayout();
                 JPanel panel = new JPanel(layout);
 
@@ -417,17 +435,17 @@ public class FontSelectorDialog extends JDialog {
                 {
                         Object source = evt.getSource();
                         if(source == familyList) {
-                                String family = familyList.getSelectedValue();
+                               String family = (String) familyList.getSelectedValue();
                                 if(family != null)
                                         familyField.setText(family);
                         }
                         else if(source == sizeList) {
-                                String size = sizeList.getSelectedValue();
+                               String size = (String) sizeList.getSelectedValue();
                                 if(size != null)
                                         sizeField.setText(size);
                         }
                         else if(source == styleList) {
-                                String style = styleList.getSelectedValue();
+                               String style = (String) styleList.getSelectedValue();
                                 if(style != null)
                                         styleField.setText(style);
                         }
index 490ee5c..e288473 100644 (file)
@@ -48,8 +48,8 @@ public class GeneralTab extends JPanel implements PrefsTab {
     private JTextField defOwnerField, timeStampFormat, timeStampField;
     JabRefPreferences _prefs;
     JabRefFrame _frame;
-    private JComboBox<String> language = new JComboBox<String>(GUIGlobals.LANGUAGES.keySet().toArray(new String[0])),
-    encodings = new JComboBox<String>(Globals.ENCODINGS);
+       private JComboBox language = new JComboBox(GUIGlobals.LANGUAGES.keySet().toArray(new String[0])),
+                       encodings = new JComboBox(Globals.ENCODINGS);
 
     public GeneralTab(JabRefFrame frame, JabRefPreferences prefs) {
         _prefs = prefs;
index 3448485..1cce4cb 100644 (file)
@@ -24,14 +24,7 @@ import java.io.InputStreamReader;
 import java.net.URL;
 import java.net.URLConnection;
 import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.MissingResourceException;
-import java.util.PropertyResourceBundle;
-import java.util.ResourceBundle;
+import java.util.*;
 import java.util.ResourceBundle.Control;
 import java.util.logging.ConsoleHandler;
 import java.util.logging.Filter;
@@ -161,57 +154,7 @@ public class Globals {
                        "ISO8859_6", "ISO8859_7", "ISO8859_8", "ISO8859_9", "ISO8859_13", "ISO8859_15" };
     public static Map<String,String> ENCODING_NAMES_LOOKUP;
 
-    /**
-     * Parses month expressions (like 1, jan, #jan#) to the numerical representation 
-     * (with January corresponding to 1)
-     * Returns 0 if the month could not be parsed.
-     * TODO: Move this method along with the two arrays 'MONTHS' and 'MONTH_STRINGS' to a seperate class?
-     */
-    public static int ParseMonthToInteger(String value)
-    {
-       // implementation based on patch 3470076 by Mathias Walter
-       // originally, this code was present in the CleanUp-doCleanUpMonth method
-       if (value == null) 
-               return 0;
-       
-               try {
-                       return Integer.parseInt(value);
-               } catch (NumberFormatException e) {
-                       // Much more liberal matching covering most known abbreviations etc.
-                       String testString = value.replace("#", "").trim().substring(0, 3).toLowerCase();
-                       if (Globals.MONTH_STRINGS.containsKey(testString)) {
-                               int i = 0;
-                               for(String month : MONTHS)
-                               {
-                                       if(testString.equals(MONTHS[i]))
-                                               return i + 1;
-                                       i++;
-                               }
-                       }
-               }
-               return 0;
-    }
-    
-    // String array that maps from month number to month string label:
-       public static String[] MONTHS = new String[] { "jan", "feb", "mar", "apr", "may", "jun", "jul",
-               "aug", "sep", "oct", "nov", "dec" };
-       
-       // Map that maps from month string labels to
-       public static Map<String, String> MONTH_STRINGS = new HashMap<String, String>();
        static {
-               MONTH_STRINGS.put("jan", "January");
-               MONTH_STRINGS.put("feb", "February");
-               MONTH_STRINGS.put("mar", "March");
-               MONTH_STRINGS.put("apr", "April");
-               MONTH_STRINGS.put("may", "May");
-               MONTH_STRINGS.put("jun", "June");
-               MONTH_STRINGS.put("jul", "July");
-               MONTH_STRINGS.put("aug", "August");
-               MONTH_STRINGS.put("sep", "September");
-               MONTH_STRINGS.put("oct", "October");
-               MONTH_STRINGS.put("nov", "November");
-               MONTH_STRINGS.put("dec", "December");
-
                // Build list of encodings, by filtering out all that are not supported
                // on this system:
                List<String> encodings = new ArrayList<String>();
index ed94c70..a664278 100644 (file)
@@ -194,7 +194,13 @@ public class JabRef {
             //System.out.println(getCurrentProcessExplicitAppUserModelID());
         }
 
-               openWindow(processArguments(args, true));
+        Vector<ParserResult> loaded = processArguments(args, true);
+
+        if (graphicFailure || cli.isDisableGui() || cli.isShowVersion()) {
+            System.exit(0);
+        }
+
+               openWindow(loaded);
        }
     
     // Do not use this code in release version, it contains some memory leaks
@@ -235,25 +241,15 @@ public class JabRef {
         cli = new JabRefCLI(args);
 
         if (initialStartup && cli.isShowVersion()) {
-            cli.options.displayVersion();
-            cli.disableGui.setInvoked(true);
+            cli.displayVersion();
         }
 
         if (initialStartup && cli.isHelp()) {
-            System.out.println("jabref [options] [bibtex-file]\n");
-            System.out.println(cli.getHelp());
-
-            String importFormats = Globals.importFormatReader.getImportFormatList();
-            System.out.println(Globals.lang("Available import formats") + ":\n"
-                + importFormats);
-
-            String outFormats = ExportFormats.getConsoleExportList(70, 20, "\t");
-            System.out.println(Globals.lang("Available export formats") + ": " + outFormats
-                + ".");
+            cli.printUsage();
             System.exit(0);
         }
         
-        boolean commandmode = cli.isDisableGui() || cli.fetcherEngine.isInvoked();
+        boolean commandmode = cli.isDisableGui() || cli.isFetcherEngine();
         
         // First we quickly scan the command line parameters for any that signal
         // that the GUI
@@ -270,8 +266,8 @@ public class JabRef {
         }
 
         // Check if we should reset all preferences to default values:
-        if (cli.defPrefs.isInvoked()) {
-            String value = cli.defPrefs.getStringValue();
+        if (cli.isPreferencesReset()) {
+            String value = cli.getPreferencesReset();
             if (value.trim().equals("all")) {
                 try {
                     System.out.println(Globals.lang("Setting all preferences to default values."));
@@ -295,9 +291,9 @@ public class JabRef {
         }
 
         // Check if we should import preferences from a file:
-        if (cli.importPrefs.isInvoked()) {
+        if (cli.isPreferencesImport()) {
             try {
-                Globals.prefs.importPreferences(cli.importPrefs.getStringValue());
+                Globals.prefs.importPreferences(cli.getPreferencesImport());
                 BibtexEntryType.loadCustomEntryTypes(Globals.prefs);
                 ExportFormats.initAllExports();
             }
@@ -305,6 +301,10 @@ public class JabRef {
             Util.pr(ex.getMessage());
             }
         }
+        
+        // Set up custom or default icon theme
+        // Has to be done here as openBibFile requires an initialized icon theme (due to the implementation of special fields)
+        GUIGlobals.setUpIconTheme();
 
         // Vector to put imported/loaded database(s) in.
         Vector<ParserResult> loaded = new Vector<ParserResult>();
@@ -341,8 +341,8 @@ public class JabRef {
             }
         }
 
-        if (!cli.isBlank() && cli.importFile.isInvoked()) {
-            toImport.add(cli.importFile.getStringValue());
+        if (!cli.isBlank() && cli.isFileImport()) {
+            toImport.add(cli.getFileImport());
         }
 
         for (String filenameString : toImport) {
@@ -351,22 +351,22 @@ public class JabRef {
                                loaded.add(pr);
                }
 
-        if (!cli.isBlank() && cli.importToOpenBase.isInvoked()) {
-            ParserResult res = importToOpenBase(cli.importToOpenBase.getStringValue());
+        if (!cli.isBlank() && cli.isImportToOpenBase()) {
+            ParserResult res = importToOpenBase(cli.getImportToOpenBase());
             if (res != null)
                 loaded.add(res);
         }
 
-        if (!cli.isBlank() && cli.fetcherEngine.isInvoked()) {
-            ParserResult res = fetch(cli.fetcherEngine.getStringValue());
+        if (!cli.isBlank() && cli.isFetcherEngine()) {
+            ParserResult res = fetch(cli.getFetcherEngine());
             if (res != null)
                 loaded.add(res);
         }
 
 
-        if(cli.exportMatches.isInvoked()) {
+        if(cli.isExportMatches()) {
             if (loaded.size() > 0) {
-                String[] data = cli.exportMatches.getStringValue().split(",");
+                String[] data = cli.getExportMatches().split(",");
                 String searchTerm = data[0].replace("\\$"," "); //enables blanks within the search term:
                                                                 //? stands for a blank
                 ParserResult pr =
@@ -393,7 +393,7 @@ public class JabRef {
                                        break;
                                }
                                default:{
-                                       System.err.println(Globals.lang("Output file missing").concat(". \n \t ").concat("Usage").concat(": ") + JabRefCLI.exportMatchesSyntax);
+                                       System.err.println(Globals.lang("Output file missing").concat(". \n \t ").concat("Usage").concat(": ") + JabRefCLI.getExportMatchesSyntax());
                                        System.exit(0);
                                }
                        } //end switch
@@ -421,9 +421,9 @@ public class JabRef {
         } //end exportMatches invoked 
 
 
-        if (cli.exportFile.isInvoked()) {
+        if (cli.isFileExport()) {
             if (loaded.size() > 0) {
-                String[] data = cli.exportFile.getStringValue().split(",");
+                String[] data = cli.getFileExport().split(",");
 
                 if (data.length == 1) {
                     // This signals that the latest import should be stored in BibTeX
@@ -490,21 +490,21 @@ public class JabRef {
 
         //Util.pr(": Finished export");
 
-        if (cli.exportPrefs.isInvoked()) {
+        if (cli.isPreferencesExport()) {
             try {
-                Globals.prefs.exportPreferences(cli.exportPrefs.getStringValue());
+                Globals.prefs.exportPreferences(cli.getPreferencesExport());
             } catch (IOException ex) {
                 Util.pr(ex.getMessage());
             }
         }
 
 
-        if (!cli.isBlank() && cli.auxImExport.isInvoked()) {
+        if (!cli.isBlank() && cli.isAuxImport()) {
             boolean usageMsg = false;
 
             if (loaded.size() > 0) // bibtex file loaded
              {
-                String[] data = cli.auxImExport.getStringValue().split(",");
+                String[] data = cli.getAuxImport().split(",");
 
                 if (data.length == 2) {
                     ParserResult pr = loaded.firstElement();
@@ -614,24 +614,36 @@ public class JabRef {
     
     private void setLookAndFeel() {
         try {
-            String systemLnF;
-            // * Look first into the Preferences
-            // * Fallback to the System Look & Fell
+            String lookFeel;
+               String systemLnF = UIManager.getSystemLookAndFeelClassName();
+            
             if (Globals.prefs.getBoolean("useDefaultLookAndFeel")) {
-                systemLnF = UIManager.getSystemLookAndFeelClassName();
+               // Use system Look & Feel by default
+               lookFeel = systemLnF;
             } else {
-                systemLnF = Globals.prefs.get("lookAndFeel");
+               lookFeel = Globals.prefs.get("lookAndFeel");
             }
 
             // At all cost, avoid ending up with the Metal look and feel:
-            if (systemLnF.equals("javax.swing.plaf.metal.MetalLookAndFeel")) {
+            if (lookFeel.equals("javax.swing.plaf.metal.MetalLookAndFeel")) {
                 Plastic3DLookAndFeel lnf = new Plastic3DLookAndFeel();
                 Plastic3DLookAndFeel.setCurrentTheme(new SkyBluer());
                 com.jgoodies.looks.Options.setPopupDropShadowEnabled(true);
                 UIManager.setLookAndFeel(lnf);
             }
             else {
-                UIManager.setLookAndFeel(systemLnF);
+               try {
+                       UIManager.setLookAndFeel(lookFeel);
+               } catch (Exception e) { // javax.swing.UnsupportedLookAndFeelException (sure; see bug #1278) or ClassNotFoundException (unsure) may be thrown
+                       // specified look and feel does not exist on the classpath, so use system l&f
+                       UIManager.setLookAndFeel(systemLnF);
+                       // also set system l&f as default
+                       Globals.prefs.put("lookAndFeel", systemLnF);
+                       // notify the user
+                       JOptionPane.showMessageDialog(jrf, Globals.lang("Unable to find the requested Look & Feel and thus the default one is used."),
+                            Globals.lang("Warning"),
+                            JOptionPane.WARNING_MESSAGE);
+               }
             }
         } catch (Exception e) {
             e.printStackTrace();
@@ -663,15 +675,13 @@ public class JabRef {
     }
 
        public void openWindow(Vector<ParserResult> loaded) {
-        if (!graphicFailure && !cli.isDisableGui()) {
             // Call the method performCompatibilityUpdate(), which does any
             // necessary changes for users with a preference set from an older
             // Jabref version.
             Util.performCompatibilityUpdate();
 
-
             // Set up custom or default icon theme:
-            GUIGlobals.setUpIconTheme();
+            // This is now done at processArguments
 
             // TODO: remove temporary registering of external file types?
             Globals.prefs.updateExternalFileTypes();
@@ -857,8 +867,6 @@ public class JabRef {
                 jrf.tabbedPane.setSelectedIndex(0);
                 new FocusRequester(((BasePanel) jrf.tabbedPane.getComponentAt(0)).mainTable);
             }
-        } else
-            System.exit(0);
     }
 
     /**
@@ -932,6 +940,7 @@ public class JabRef {
             pr.setFile(file);
             pr.setInvalid(true);
             pr.setErrorMessage(ex.getMessage());
+            ex.printStackTrace();
             return pr;
         }
 
index 34f1f59..f836634 100644 (file)
 package net.sf.jabref;
 
-import gnu.dtools.ritopt.BooleanOption;
-import gnu.dtools.ritopt.Options;
-import gnu.dtools.ritopt.StringOption;
+import net.sf.jabref.export.ExportFormats;
+import org.apache.commons.cli.*;
 
 public class JabRefCLI {
 
-    public final static String exportMatchesSyntax = "[".concat(Globals.lang("field")).concat("]")
-            .concat("searchTerm").concat(",").concat("outputFile").concat(": ").
-                    concat(Globals.lang("file")).concat("[,").concat(Globals.lang("exportFormat")).concat("]");
-
-    public final StringOption importFile, exportFile, exportPrefs, importPrefs, auxImExport, importToOpenBase,
-            fetcherEngine, exportMatches, defPrefs;
-
-    public final BooleanOption helpO, disableGui, blank, loadSess, showVersion, disableSplash;
-    public final Options options;
     private String[] leftOver;
+    private final CommandLine cl;
 
     public boolean isHelp() {
-        return helpO.isInvoked();
+        return cl.hasOption("help");
     }
 
     public boolean isShowVersion() {
-        return showVersion.isInvoked();
+        return cl.hasOption("version");
     }
 
     public boolean isDisableSplash() {
-        return disableSplash.isInvoked();
+        return cl.hasOption("nosplash");
     }
 
     public boolean isBlank() {
-        return blank.isInvoked();
+        return cl.hasOption("blank");
     }
 
     public boolean isLoadSession() {
-        return loadSess.isInvoked();
+        return cl.hasOption("loads");
     }
 
     public boolean isDisableGui() {
-        return disableGui.isInvoked();
+        return cl.hasOption("nogui");
     }
 
-    public String getHelp() {
-        return options.getHelp();
+    public JabRefCLI(String[] args) {
+
+        Options options = getOptions();
+
+        try {
+            this.cl = new DefaultParser().parse(options, args);
+            this.leftOver = cl.getArgs();
+        } catch (ParseException e) {
+            e.printStackTrace();
+
+            this.printUsage();
+            throw new RuntimeException();
+        }
     }
 
-    public JabRefCLI(String[] args) {
-        importFile = new StringOption("");
-        exportFile = new StringOption("");
-        helpO = new BooleanOption();
-        disableGui = new BooleanOption();
-        disableSplash = new BooleanOption();
-        blank = new BooleanOption();
-        loadSess = new BooleanOption();
-        showVersion = new BooleanOption();
-        exportPrefs = new StringOption("jabref_prefs.xml");
-        importPrefs = new StringOption("jabref_prefs.xml");
-        defPrefs = new StringOption("");
-        auxImExport = new StringOption("");
-        importToOpenBase = new StringOption("");
-        fetcherEngine = new StringOption("");
-        exportMatches = new StringOption("");
-
-        options = new Options("JabRef ");
-        options.setVersion(GUIGlobals.version);
-
-        importFile.setDescription("imopoepuoeu"); //Globals.lang);
-        options.register("version", 'v',
-                Globals.lang("Display version"), showVersion);
-        options.register("nogui", 'n',
-                Globals.lang("No GUI. Only process command line options."), disableGui);
-        options.register("nosplash", 's',
-                Globals.lang("Do not show splash window at startup"), disableSplash);
-        options.register("import", 'i',
-                Globals.lang("Import file") + ": " + Globals.lang("filename")
-                        + "[,import format]", importFile
-        );
-        options.register("output", 'o',
-                Globals.lang("Output or export file") + ": " + Globals.lang("filename")
-                        + "[,export format]", exportFile
-        );
-        options.register("help", 'h',
-                Globals.lang("Display help on command line options"), helpO);
-        options.register("loads", 'l', Globals.lang("Load session"), loadSess);
-        options.register("prexp", 'x', Globals.lang("Export preferences to file"),
-                exportPrefs);
-        options.register("primp", 'p', Globals.lang("Import preferences from file"),
-                importPrefs);
-        options.register("prdef", 'd', Globals.lang("Reset preferences (key1,key2,... or 'all')"),
-                defPrefs);
-        options.register("aux", 'a',
-                Globals.lang("Subdatabase from aux") + ": " + Globals.lang("file") + "[.aux]" + "," + Globals.lang("new") + "[.bib]",
-                auxImExport);
-        options.register("blank", 'b', Globals.lang("Do not open any files at startup"), blank);
-
-        options.register("importToOpen", '\0', Globals.lang("Import to open tab"), importToOpenBase);
-
-        options.register("fetch", 'f', Globals.lang("Run Fetcher, e.g. \"--fetch=Medline:cancer\""), fetcherEngine);
-
-        options.register("exportMatches", 'm', exportMatchesSyntax, exportMatches);
-
-        options.setUseMenu(false);
-
-        parse(args);
-    }
-
-    private void parse(String[] args) {
-        leftOver = options.process(args);
+    public boolean isPreferencesExport() {
+        return cl.hasOption("prexp");
+    }
+
+    public String getPreferencesExport() {
+        return cl.getOptionValue("prexp", "jabref_prefs.xml");
+    }
+
+    public boolean isPreferencesImport() {
+        return cl.hasOption("primp");
+    }
+
+    public String getPreferencesImport() {
+        return cl.getOptionValue("primp", "jabref_prefs.xml");
+    }
+
+    public boolean isPreferencesReset() {
+        return cl.hasOption("prdef");
+    }
+
+    public String getPreferencesReset() {
+        return cl.getOptionValue("prdef");
+    }
+
+
+    public boolean isFileExport() {
+        return cl.hasOption("output");
+    }
+
+    public String getFileExport() {
+        return cl.getOptionValue("output");
+    }
+
+    public boolean isFileImport() {
+        return cl.hasOption("import");
+    }
+
+    public String getFileImport() {
+        return cl.getOptionValue("import");
+    }
+
+    public boolean isAuxImport() {
+        return cl.hasOption("aux");
+    }
+
+    public String getAuxImport() {
+        return cl.getOptionValue("aux");
+    }
+
+    public boolean isImportToOpenBase() {
+        return cl.hasOption("importToOpen");
+    }
+
+    public String getImportToOpenBase() {
+        return cl.getOptionValue("importToOpen");
+    }
+
+    public boolean isFetcherEngine() {
+        return cl.hasOption("fetch");
+    }
+
+    public String getFetcherEngine() {
+        return cl.getOptionValue("fetch");
+    }
+
+    public boolean isExportMatches() {
+        return cl.hasOption("exportMatches");
+    }
+
+    public String getExportMatches() {
+        return cl.getOptionValue("exportMatches");
+    }
+
+    private Options getOptions() {
+        Options options = new Options();
+
+        // boolean options
+        options.addOption("v", "version", false, Globals.lang("Display version"));
+        options.addOption("n", "nogui", false, Globals.lang("No GUI. Only process command line options."));
+        options.addOption("s", "nosplash", false, Globals.lang("Do not show splash window at startup"));
+        options.addOption("h", "help", false, Globals.lang("Display help on command line options"));
+        options.addOption("l", "loads", false, Globals.lang("Load session"));
+        options.addOption("b", "blank", false, Globals.lang("Do not open any files at startup"));
+
+        options.addOption(Option.builder("i").
+                longOpt("import").
+                desc(String.format("%s: %s[,import format]", Globals.lang("Import file"), Globals.lang("filename"))).
+                hasArg().
+                argName("FILE").build());
+
+        options.addOption(Option.builder("o").
+                longOpt("output").
+                desc(String.format("%s: %s[,export format]", Globals.lang("Output or export file"), Globals.lang("filename"))).
+                hasArg().
+                argName("FILE").
+                build());
+
+        options.addOption(Option.builder("x").
+                longOpt("prexp").
+                desc(Globals.lang("Export preferences to file")).
+                hasArg().
+                argName("FILE").
+                build());
+
+        options.addOption(Option.builder("p").
+                longOpt("primp").
+                desc(Globals.lang("Import preferences from file")).
+                hasArg().
+                argName("FILE").
+                build());
+        options.addOption(Option.builder("d").
+                longOpt("prdef").
+                desc(Globals.lang("Reset preferences (key1,key2,... or 'all')")).
+                hasArg().
+                argName("FILE").
+                build());
+
+        options.addOption(Option.builder("a").
+                longOpt("aux").
+                desc(String.format("%s: %s[.aux],%s[.bib]", Globals.lang("Subdatabase from aux"), Globals.lang("file"), Globals.lang("new"))).
+                hasArg().
+                argName("FILE").
+                build());
+
+        options.addOption(Option.builder().
+                longOpt("importToOpen").
+                desc(Globals.lang("Import to open tab")).
+                hasArg().
+                argName("FILE").
+                build());
+
+        options.addOption(Option.builder("f").
+                longOpt("fetch").
+                desc(Globals.lang("Run Fetcher, e.g. \"--fetch=Medline:cancer\"")).
+                hasArg().
+                argName("FILE").
+                build());
+
+        options.addOption(Option.builder("m").
+                longOpt("exportMatches").
+                desc(getExportMatchesSyntax()).
+                hasArg().
+                argName("FILE").
+                build());
+
+        return options;
+    }
+
+    public void displayVersion() {
+        System.out.println(getVersionInfo());
+    }
+
+    public void printUsage() {
+        String header = "";
+
+        String importFormats = Globals.importFormatReader.getImportFormatList();
+        String importFormatsList = String.format("%s:%n%s%n", Globals.lang("Available import formats"), importFormats);
+
+        String outFormats = ExportFormats.getConsoleExportList(70, 20, "");
+        String outFormatsList = String.format("%s: %s%n", Globals.lang("Available export formats"), outFormats);
+
+        String footer = "\n" + importFormatsList + outFormatsList + "\nPlease report issues at http://sourceforge.net/p/jabref/bugs/";
+
+        HelpFormatter formatter = new HelpFormatter();
+        formatter.printHelp("jabref [OPTIONS] [BIBTEX_FILE]\n\nOptions:", header, getOptions(), footer, true);
+    }
+
+    private String getVersionInfo() {
+        return String.format("JabRef %s", GUIGlobals.version);
     }
 
     public String[] getLeftOver() {
         return leftOver;
     }
-}
+
+    public static String getExportMatchesSyntax() {
+        return String.format("[%s]searchTerm,outputFile: %s[,%s]", Globals.lang("field"), Globals.lang("file"), Globals.lang("exportFormat"));
+    }
+}
\ No newline at end of file
index e189c5e..748fa7e 100644 (file)
@@ -1,4 +1,4 @@
-/*  Copyright (C) 2003-2012 JabRef contributors.
+/*  Copyright (C) 2003-2015 JabRef contributors.
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
     the Free Software Foundation; either version 2 of the License, or
@@ -39,14 +39,13 @@ import javax.swing.*;
 import javax.swing.event.ChangeEvent;
 import javax.swing.event.ChangeListener;
 
-import org.java.ayatana.ApplicationMenu;
-
 import net.sf.jabref.export.*;
 import net.sf.jabref.external.ExternalFileTypeEditor;
 import net.sf.jabref.external.PushToApplicationButton;
 import net.sf.jabref.groups.EntryTableTransferHandler;
 import net.sf.jabref.groups.GroupSelector;
 import net.sf.jabref.gui.*;
+import net.sf.jabref.gui.menus.help.ForkMeOnGitHubAction;
 import net.sf.jabref.help.HelpAction;
 import net.sf.jabref.help.HelpDialog;
 import net.sf.jabref.imports.EntryFetcher;
@@ -160,6 +159,7 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
       newDatabaseAction = new NewDatabaseAction(),
       newSubDatabaseAction = new NewSubDatabaseAction(),
       integrityCheckAction = new IntegrityCheckAction(),
+            forkMeOnGitHubAction = new ForkMeOnGitHubAction(),
       help = new HelpAction("JabRef help", helpDiag,
                             GUIGlobals.baseFrameHelp, Globals.lang("JabRef help"),
                             prefs.getKey("Help")),
@@ -394,7 +394,7 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
                        FindUnlinkedFilesDialog.ACTION_TITLE,
                        FindUnlinkedFilesDialog.ACTION_SHORT_DESCRIPTION,
                        FindUnlinkedFilesDialog.ACTION_ICON,
-                       prefs.getKey(FindUnlinkedFilesDialog.ACTION_COMMAND)
+                       prefs.getKey(FindUnlinkedFilesDialog.ACTION_KEYBINDING_ACTION)
        );
 
        AutoLinkFilesAction autoLinkFile = new AutoLinkFilesAction();
@@ -451,8 +451,6 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
   private void init() {
            tabbedPane = new DragDropPopupPane(manageSelectors, databaseProperties, bibtexKeyPattern);
 
-        macOSXRegistration();
-
         UIManager.put("FileChooser.readOnly", Globals.prefs.getBoolean("filechooserDisableRename"));
 
         MyGlassPane glassPane = new MyGlassPane();
@@ -465,7 +463,11 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
         setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
         addWindowListener(new WindowAdapter() {
             public void windowClosing(WindowEvent e) {
-                (new CloseAction()).actionPerformed(null);
+                if (Globals.ON_MAC){
+                    setState(Frame.ICONIFIED);
+                } else {
+                    (new CloseAction()).actionPerformed(null);
+                }
             }
         });
 
@@ -578,13 +580,20 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
                 }
             }
         });
-
-        // The following sets up integration with Unity's global menu, but currently (Nov 18, 2012)
-        // this doesn't work with OpenJDK 6 (leads to crash), only with 7.
-        String javaVersion = System.getProperty("java.version", null);
-        if (javaVersion.compareTo("1.7") >= 0)
-            ApplicationMenu.tryInstall(this);
-
+        
+        //Note: The registration of Apple event is at the end of initialization, because
+        //if the events happen too early (ie when the window is not initialized yet), the
+        //opened (double-clicked) documents are not displayed.
+        if (Globals.ON_MAC) {
+               try {
+                       Class<? > macreg = Class.forName("osx.macadapter.MacAdapter"); 
+                       Method method = macreg.getMethod("registerMacEvents", JabRefFrame.class);
+                       method.invoke(macreg.newInstance(), this);
+               }
+               catch (Exception e) {
+                       System.err.println("Exception ("+e.getClass().toString()+"): "+e.getMessage());
+               }
+        }
     }
 
     public void setWindowTitle() {
@@ -637,7 +646,7 @@ public class JabRefFrame extends JFrame implements OutputPrinter {
             sidePaneManager.show("search");
     }
 
-    // The OSXAdapter calls this method when a ".bib" file has been double-clicked from the Finder.
+    // The MacAdapter calls this method when a ".bib" file has been double-clicked from the Finder.
     public void openAction(String filePath) {
        File file = new File(filePath);
        
@@ -677,7 +686,7 @@ AboutAction aboutAction = new AboutAction();
   }
 
 
-  // General info dialog.  The OSXAdapter calls this method when "About OSXAdapter"
+  // General info dialog.  The MacAdapter calls this method when "About"
   // is selected from the application menu.
   public void about() {
     JDialog about = new JDialog(JabRefFrame.this, Globals.lang("About JabRef"),
@@ -715,7 +724,7 @@ AboutAction aboutAction = new AboutAction();
 
   }
 
-  // General preferences dialog.  The OSXAdapter calls this method when "Preferences..."
+  // General preferences dialog.  The MacAdapter calls this method when "Preferences..."
   // is selected from the application menu.
   public void preferences() {
     //PrefsDialog.showPrefsDialog(JabRefFrame.this, prefs);
@@ -743,9 +752,78 @@ public JabRefPreferences prefs() {
   return prefs;
 }
 
-  // General info dialog.  The OSXAdapter calls this method when "Quit OSXAdapter"
-  // is selected from the application menu, Cmd-Q is pressed, or "Quit" is selected from the Dock.
-  public void quit() {
+/**
+ * Tears down all things started by JabRef
+ * 
+ * FIXME: Currently some threads remain and therefore hinder JabRef to be closed properly
+ * 
+ * @param filenames the file names of all currently opened files - used for storing them if prefs openLastEdited is set to true
+ */
+  private void tearDownJabRef(Vector<String> filenames) {
+      dispose();
+
+      if (basePanel() != null)
+        basePanel().saveDividerLocation();
+      prefs.putInt("posX", JabRefFrame.this.getLocation().x);
+      prefs.putInt("posY", JabRefFrame.this.getLocation().y);
+      prefs.putInt("sizeX", JabRefFrame.this.getSize().width);
+      prefs.putInt("sizeY", JabRefFrame.this.getSize().height);
+      //prefs.putBoolean("windowMaximised", (getExtendedState()&MAXIMIZED_BOTH)>0);
+      prefs.putBoolean("windowMaximised", (getExtendedState() == Frame.MAXIMIZED_BOTH));
+      
+      prefs.putBoolean("toolbarVisible", tlb.isVisible());
+      prefs.putBoolean("searchPanelVisible", sidePaneManager.isComponentVisible("search"));
+      // Store divider location for side pane:
+      int width = contentPane.getDividerLocation();
+      if (width > 0) 
+          prefs.putInt("sidePaneWidth", width);
+      if (prefs.getBoolean("openLastEdited")) {
+        // Here we store the names of all current files. If
+        // there is no current file, we remove any
+        // previously stored file name.
+        if (filenames.size() == 0) {
+          prefs.remove("lastEdited");
+        }
+        else {
+          String[] names = new String[filenames.size()];
+          for (int i = 0; i < filenames.size(); i++) {
+            names[i] = filenames.elementAt(i);
+          }
+          prefs.putStringArray("lastEdited", names);
+        }
+
+      }
+
+      fileHistory.storeHistory();
+      prefs.customExports.store();
+      prefs.customImports.store();
+      BibtexEntryType.saveCustomEntryTypes(prefs);
+
+      // Clear autosave files:
+      if (Globals.autoSaveManager != null)
+        Globals.autoSaveManager.clearAutoSaves();
+
+      // Let the search interface store changes to prefs.
+      // But which one? Let's use the one that is visible.
+      if (basePanel() != null) {
+        (searchManager).updatePrefs();
+      }
+      
+      prefs.flush();
+  }
+  
+  /**
+    * General info dialog.  The MacAdapter calls this method when "Quit"
+    * is selected from the application menu, Cmd-Q is pressed, or "Quit" is selected from the Dock.
+    * The function returns a boolean indicating if quitting is ok or not.
+    * 
+    * Non-OSX JabRef calls this when choosing "Quit" from the menu
+    * 
+    * SIDE EFFECT: tears down JabRef
+    * 
+    * @return true if the user chose to quit; false otherwise
+    */
+  public boolean quit() {
     // Ask here if the user really wants to close, if the base
     // has not been saved since last save.
     boolean close = true;
@@ -764,7 +842,7 @@ public JabRefPreferences prefs() {
           if ( (answer == JOptionPane.CANCEL_OPTION) ||
               (answer == JOptionPane.CLOSED_OPTION)) {
             close = false; // The user has cancelled.
-              return;
+              return false;
           }
           if (answer == JOptionPane.YES_OPTION) {
             // The user wants to save.
@@ -802,117 +880,18 @@ public JabRefPreferences prefs() {
               WaitForSaveOperation w = new WaitForSaveOperation(this);
               w.show(); // This method won't return until cancelled or the save operation is done.
               if (w.cancelled())
-                  return; // The user clicked cancel.
-          }
-      }
-
-
-      dispose();
-
-      if (basePanel() != null)
-        basePanel().saveDividerLocation();
-      prefs.putInt("posX", JabRefFrame.this.getLocation().x);
-      prefs.putInt("posY", JabRefFrame.this.getLocation().y);
-      prefs.putInt("sizeX", JabRefFrame.this.getSize().width);
-      prefs.putInt("sizeY", JabRefFrame.this.getSize().height);
-      //prefs.putBoolean("windowMaximised", (getExtendedState()&MAXIMIZED_BOTH)>0);
-      prefs.putBoolean("windowMaximised", (getExtendedState() == Frame.MAXIMIZED_BOTH));
-      
-      prefs.putBoolean("toolbarVisible", tlb.isVisible());
-      prefs.putBoolean("searchPanelVisible", sidePaneManager.isComponentVisible("search"));
-      // Store divider location for side pane:
-      int width = contentPane.getDividerLocation();
-      if (width > 0) 
-          prefs.putInt("sidePaneWidth", width);
-      if (prefs.getBoolean("openLastEdited")) {
-        // Here we store the names of allcurrent filea. If
-        // there is no current file, we remove any
-        // previously stored file name.
-        if (filenames.size() == 0) {
-          prefs.remove("lastEdited");
-        }
-        else {
-          String[] names = new String[filenames.size()];
-          for (int i = 0; i < filenames.size(); i++) {
-            names[i] = filenames.elementAt(i);
-
+                  return false; // The user clicked cancel.
           }
-          prefs.putStringArray("lastEdited", names);
-        }
-
       }
 
-      fileHistory.storeHistory();
-      prefs.customExports.store();
-      prefs.customImports.store();
-      BibtexEntryType.saveCustomEntryTypes(prefs);
-
-      // Clear autosave files:
-      if (Globals.autoSaveManager != null)
-        Globals.autoSaveManager.clearAutoSaves();
 
-      // Let the search interface store changes to prefs.
-      // But which one? Let's use the one that is visible.
-      if (basePanel() != null) {
-        (searchManager).updatePrefs();
-      }
-      
-      prefs.flush();
-      
-      System.exit(0); // End program.
+      tearDownJabRef(filenames);
+      return true;
     }
-  }
-
     
-
-  private void macOSXRegistration() {
-    if (Globals.osName.equals(Globals.MAC)) {
-      try {
-         Class<?> osxAdapter = Class.forName("osxadapter.OSXAdapter");
-                 
-                 Class<?>[] defArgs = {Object.class, Method.class};
-                 Class<?> thisClass = JabRefFrame.class;
-                 Method registerMethod = osxAdapter.getDeclaredMethod("setAboutHandler", defArgs);
-                 if (registerMethod != null) {
-                         Object[] args = {this, thisClass.getDeclaredMethod("about", (Class[])null)};
-                         registerMethod.invoke(osxAdapter, args);
-                 }
-                 registerMethod = osxAdapter.getDeclaredMethod("setPreferencesHandler", defArgs);
-                 if (registerMethod != null) {
-                         Object[] args = {this, thisClass.getDeclaredMethod("preferences", (Class[])null)};
-                         registerMethod.invoke(osxAdapter, args);
-                 }
-                 registerMethod = osxAdapter.getDeclaredMethod("setQuitHandler", defArgs);
-                 if (registerMethod != null) {
-                         Object[] args = {this, thisClass.getDeclaredMethod("quit", (Class[])null)};
-                         registerMethod.invoke(osxAdapter, args);
-                 }
-                 registerMethod = osxAdapter.getDeclaredMethod("setFileHandler", defArgs);
-                 if (registerMethod != null) {
-                         Object[] args = {this, thisClass.getDeclaredMethod("openAction", String.class)};
-                         registerMethod.invoke(osxAdapter, args);
-                 }
-      }
-      catch (NoClassDefFoundError e) {
-        // This will be thrown first if the OSXAdapter is loaded on a system without the EAWT
-        // because OSXAdapter extends ApplicationAdapter in its def
-        System.err.println("This version of Mac OS X does not support the Apple EAWT.  Application Menu handling has been disabled (" +
-                           e + ")");
-      }
-      catch (ClassNotFoundException e) {
-        // This shouldn't be reached; if there's a problem with the OSXAdapter we should get the
-        // above NoClassDefFoundError first.
-        System.err.println("This version of Mac OS X does not support the Apple EAWT.  Application Menu handling has been disabled (" +
-                           e + ")");
-      }
-      catch (Exception e) {
-        System.err.println("Exception while loading the OSXAdapter:");
-        e.printStackTrace();
-      }
-    }
+    return false;
   }
 
-
   private void initLayout() {
     tabbedPane.putClientProperty(Options.NO_CONTENT_BORDER_KEY, Boolean.TRUE);
 
@@ -1160,8 +1139,13 @@ public JabRefPreferences prefs() {
         }
       }
       else {
-        Util.pr("Action '" + command + "' must be disabled when no "
-                + "database is open.");
+          // QUICK HACK to solve bug #1277
+          if (e.getActionCommand().equals("Hide/show toolbar")) {
+              // code copied from BasePanel.java, action "toggleToolbar"
+              tlb.setVisible(! tlb.isVisible());
+          } else {
+              Util.pr("Action '" + command + "' must be disabled when no database is open.");
+          }
       }
     }
   }
@@ -1503,6 +1487,7 @@ public JabRefPreferences prefs() {
       helpMenu.add(contents);
       helpMenu.addSeparator();
       helpMenu.add(errorConsole);
+        helpMenu.add(forkMeOnGitHubAction);
       helpMenu.addSeparator();
       helpMenu.add(about);
       mb.add(helpMenu);
@@ -1686,7 +1671,7 @@ public JabRefPreferences prefs() {
     protected void initActions() {
         openDatabaseOnlyActions = new LinkedList<Object>();
         openDatabaseOnlyActions.addAll(Arrays.asList(manageSelectors,
-                mergeDatabaseAction, newSubDatabaseAction, close, save, saveAs, saveSelectedAs, undo,
+                mergeDatabaseAction, newSubDatabaseAction, close, save, saveAs, saveSelectedAs, saveSelectedAsPlain, undo,
                 redo, cut, delete, copy, paste, mark, unmark, unmarkAll, editEntry,
                 selectAll, copyKey, copyCiteKey, copyKeyAndTitle, editPreamble, editStrings, toggleGroups, toggleSearch,
                 makeKeyAction, normalSearch,
@@ -1867,7 +1852,11 @@ public JabRefPreferences prefs() {
     }
 
     public void actionPerformed(ActionEvent e) {
-      quit();
+      if (quit()) {
+          // FIXME: tearDownJabRef() does not cancel all threads. Therefore, some threads remain running and prevent JabRef from beeing unloaded completely
+          // QUICKHACK: finally tear down all existing threads
+          System.exit(0);
+      }
     }
   }
 
@@ -2358,7 +2347,7 @@ class SaveSessionAction
     }
 
     public void actionPerformed(ActionEvent e) {
-      // Here we store the names of allcurrent filea. If
+      // Here we store the names of all current files. If
       // there is no current file, we remove any
       // previously stored file name.
       Vector<String> filenames = new Vector<String>();
index ab89ba2..d0c07c3 100644 (file)
@@ -59,7 +59,7 @@ public class JabRefPreferences {
             EMACS_23 = "emacsUseV23InsertString",
             EDIT_GROUP_MEMBERSHIP_MODE = "groupEditGroupMembershipMode",
             PDF_PREVIEW = "pdfPreview",
-            SHOWONELETTERHEADINGFORICONCOLUMNS = "showOneLetterHeadingForIconColumns",
+            SHOW_ONE_LETTER_HEADING_FOR_ICON_COLUMNS = "showOneLetterHeadingForIconColumns",
             EDITOR_EMACS_KEYBINDINGS = "editorEMACSkeyBindings",
             EDITOR_EMACS_KEYBINDINGS_REBIND_CA = "editorEMACSkeyBindingsRebindCA",
             SHORTEST_TO_COMPLETE = "shortestToComplete",
@@ -448,7 +448,7 @@ public class JabRefPreferences {
         defaults.put(SpecialFieldsUtils.PREF_AUTOSYNCSPECIALFIELDSTOKEYWORDS, SpecialFieldsUtils.PREF_AUTOSYNCSPECIALFIELDSTOKEYWORDS_DEFAULT);
         defaults.put(SpecialFieldsUtils.PREF_SERIALIZESPECIALFIELDS, SpecialFieldsUtils.PREF_SERIALIZESPECIALFIELDS_DEFAULT);
 
-        defaults.put(SHOWONELETTERHEADINGFORICONCOLUMNS, Boolean.FALSE);
+        defaults.put(SHOW_ONE_LETTER_HEADING_FOR_ICON_COLUMNS, Boolean.FALSE);
 
         defaults.put("useOwner", Boolean.FALSE);
         defaults.put("overwriteOwner", Boolean.FALSE);
@@ -888,11 +888,16 @@ public class JabRefPreferences {
         // new version where new bindings have been introduced.
         if (s == null) {
             s = defKeyBinds.get(bindName);
-            // So, if this happens, we add the default value to the current
+            if (s == null) {
+                // there isn't even a default value
+                // Output error
+                Globals.logger("Could not get key binding for \"" + bindName + "\"");
+                // fall back to a default value
+                s = "Not associated";
+            }
+            // So, if there is no configured key binding, we add the fallback value to the current
             // hashmap, so this doesn't happen again, and so this binding
             // will appear in the KeyBindingsDialog.
-            Globals.logger("Could not get key binding for \"" + bindName + "\"");
-            s = "Not associated"; // if the item of menu not in defKeyBind list
             keyBinds.put(bindName, s);
         }
 
@@ -1129,6 +1134,7 @@ public class JabRefPreferences {
         defKeyBinds.put("Replace string", "ctrl R");
         defKeyBinds.put("Delete", "DELETE");
         defKeyBinds.put("Open file", "F4");
+        defKeyBinds.put("Open folder", "ctrl shift O");
         defKeyBinds.put("Open PDF or PS", "shift F5");
         defKeyBinds.put("Open URL or DOI", "F3");
         defKeyBinds.put("Open SPIRES entry", "ctrl F3");
@@ -1161,7 +1167,7 @@ public class JabRefPreferences {
         defKeyBinds.put("Forward", "alt RIGHT");
         defKeyBinds.put("Import into current database", "ctrl I");
         defKeyBinds.put("Import into new database", "ctrl alt I");
-        defKeyBinds.put(FindUnlinkedFilesDialog.ACTION_COMMAND, "");
+        defKeyBinds.put(FindUnlinkedFilesDialog.ACTION_KEYBINDING_ACTION, "shift F7");
         defKeyBinds.put("Increase table font size", "ctrl PLUS");
         defKeyBinds.put("Decrease table font size", "ctrl MINUS");
         defKeyBinds.put("Automatically link files", "alt F");
@@ -1170,6 +1176,7 @@ public class JabRefPreferences {
         defKeyBinds.put("File list editor, move entry up", "ctrl UP");
         defKeyBinds.put("File list editor, move entry down", "ctrl DOWN");
         defKeyBinds.put("Minimize to system tray", "ctrl alt W");
+        defKeyBinds.put("Hide/show toolbar", "ctrl alt T");
     }
 
     private String getNextUnit(Reader data) throws IOException {
index 9b4bf33..4c977e0 100644 (file)
@@ -17,11 +17,29 @@ package net.sf.jabref;
 
 import java.awt.BorderLayout;
 import java.awt.Dimension;
-import java.awt.event.*;
-import java.util.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.util.HashMap;
+import java.util.Iterator;
 import java.util.Map.Entry;
-
-import javax.swing.*;
+import java.util.Set;
+import java.util.TreeMap;
+
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JOptionPane;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.JTextField;
+import javax.swing.ListSelectionModel;
 import javax.swing.event.ListSelectionEvent;
 import javax.swing.event.ListSelectionListener;
 import javax.swing.table.AbstractTableModel;
@@ -194,10 +212,10 @@ class KeyBindingsDialog extends JDialog {
       // When the user release the mouse button and completes the selection,
       // getValueIsAdjusting() becomes false
       if (!evt.getValueIsAdjusting()) {
-        JList<?> list = (JList<?>) evt.getSource();
+                               JList list = (JList) evt.getSource();
 
         // Get all selected items
-        List<?> selected = list.getSelectedValuesList();
+                               Object[] selected = list.getSelectedValues();
 
         // Iterate all selected items
           for (Object sel : selected) {
index 99591e3..4f6c9e1 100644 (file)
@@ -18,6 +18,7 @@ package net.sf.jabref;
 import net.sf.jabref.undo.NamedCompound;
 
 import javax.swing.*;
+
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 
@@ -59,20 +60,37 @@ public class MarkEntriesAction extends AbstractWorker implements ActionListener
 
     public void run() {
         BasePanel panel = frame.basePanel();
-        NamedCompound ce = new NamedCompound(Globals.lang("Mark entries"));
         BibtexEntry[] bes = panel.getSelectedEntries();
+
+        // used at update() to determine output string
         besLength = bes.length;
 
-        for (BibtexEntry be : bes) {
-            Util.markEntry(be, level + 1, false, ce);
+        if (bes.length != 0) {
+            NamedCompound ce = new NamedCompound(Globals.lang("Mark entries"));
+            for (BibtexEntry be : bes) {
+                Util.markEntry(be, level + 1, false, ce);
+            }
+            ce.end();
+            panel.undoManager.addEdit(ce);
         }
-        ce.end();
-        panel.undoManager.addEdit(ce);
     }
 
     @Override
     public void update() {
-        frame.basePanel().markBaseChanged();
-        frame.output(Globals.lang("Marked selected")+" "+Globals.lang(besLength>0?"entry":"entries"));
+        String outputStr;
+        switch (besLength) {
+        case 0:
+            outputStr = Globals.lang("No entries selected.");
+            break;
+        case 1:
+            frame.basePanel().markBaseChanged();
+            outputStr = Globals.lang("Marked selected entry");
+            break;
+        default:
+            frame.basePanel().markBaseChanged();
+            outputStr = Globals.lang("Marked all %0 selected entries", Integer.toString(besLength));
+            break;
+        }
+        frame.output(outputStr);
     }
 }
diff --git a/src/main/java/net/sf/jabref/MonthUtil.java b/src/main/java/net/sf/jabref/MonthUtil.java
new file mode 100644 (file)
index 0000000..1fd0ccf
--- /dev/null
@@ -0,0 +1,135 @@
+package net.sf.jabref;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Utility class for everything related to months.
+ */
+public class MonthUtil {
+
+    public static class Month {
+
+        public final String fullName;
+        public final String shortName;
+        public final String twoDigitNumber;
+        public final String bibtexFormat;
+        public final int number;
+        public final int index;
+
+        public Month(String fullName, String shortName, String twoDigitNumber, String bibtexFormat, int number, int index) {
+            this.fullName = fullName;
+            this.shortName = shortName;
+            this.twoDigitNumber = twoDigitNumber;
+            this.bibtexFormat = bibtexFormat;
+            this.number = number;
+            this.index = index;
+        }
+
+        public boolean isValid() {
+            return true;
+        }
+    }
+
+    private static class UnknownMonth extends Month {
+
+        public UnknownMonth() {
+            super(null, null, null, null, 0, -1);
+        }
+
+        @Override
+        public boolean isValid() {
+            return false;
+        }
+    }
+
+    private static final Month NULL_OBJECT = new UnknownMonth();
+
+    private static final List<Month> months = Arrays.asList(
+            new Month("January", "jan", "01", "#jan#", 1, 0),
+            new Month("February", "feb", "02", "#feb#", 2, 1),
+            new Month("March", "mar", "03", "#mar#", 3, 2),
+            new Month("April", "apr", "04", "#apr#", 4, 3),
+            new Month("May", "may", "05", "#may#", 5, 4),
+            new Month("June", "jun", "06", "#jun#", 6, 5),
+            new Month("July", "jul", "07", "#jul#", 7, 6),
+            new Month("August", "aug", "08", "#aug#", 8, 7),
+            new Month("September", "sep", "09", "#sep#", 9, 8),
+            new Month("October", "oct", "10", "#oct#", 10, 9),
+            new Month("November", "nov", "11", "#nov#", 11, 10),
+            new Month("December", "dec", "12", "#dec#", 12, 11)
+    );
+
+    /**
+     * Find month by number
+     *
+     * @param number 1-12 is valid
+     * @return if valid number -> month.isValid() == true, else otherwise
+     */
+    public static Month getMonthByNumber(int number) {
+        return getMonthByIndex(number - 1);
+    }
+
+    /**
+     * Find month by index
+     *
+     * @param index 0-11 is valid
+     * @return if valid index -> month.isValid() == true, else otherwise
+     */
+    public static Month getMonthByIndex(int index) {
+        for (Month month : months) {
+            if (month.index == index) {
+                return month;
+            }
+        }
+        return NULL_OBJECT;
+    }
+
+    /**
+     * Find month by shortName (3 letters) case insensitive
+     *
+     * @param shortName "jan", "feb", ...
+     * @return if valid shortName -> month.isValid() == true, else otherwise
+     */
+    public static Month getMonthByShortName(String shortName) {
+        for (Month month : months) {
+            if (month.shortName.equalsIgnoreCase(shortName)) {
+                return month;
+            }
+        }
+        return NULL_OBJECT;
+    }
+
+    /**
+     * This method accepts three types of months given:
+     * - Single and Double Digit months from 1 to 12 (01 to 12)
+     * - 3 Digit BibTex strings (jan, feb, mar...)
+     * - Full English Month identifiers.
+     *
+     * @param value the given value
+     * @return the corresponding Month instance
+     */
+    public static Month getMonth(String value) {
+        if (value == null) {
+            return NULL_OBJECT;
+        }
+
+        // Much more liberal matching covering most known abbreviations etc.
+        String testString = value.replace("#", "").trim();
+        if (testString.length() > 3) {
+            testString = testString.substring(0, 3);
+        }
+        Month m = getMonthByShortName(testString);
+        if (m.isValid()) {
+            return m;
+        }
+
+        try {
+            int number = Util.intValueOf(value);
+            return getMonthByNumber(number);
+        } catch (NumberFormatException e) {
+            return NULL_OBJECT;
+        }
+    }
+
+}
index dde6a53..9f3df0a 100644 (file)
@@ -25,14 +25,22 @@ import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Iterator;
 
-import javax.swing.*;
+import javax.swing.AbstractAction;
+import javax.swing.BorderFactory;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JFileChooser;
+import javax.swing.JList;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.ListSelectionModel;
 import javax.swing.event.ListSelectionEvent;
 import javax.swing.event.ListSelectionListener;
 
 import net.sf.jabref.export.ExportFormats;
 import net.sf.jabref.groups.GroupsPrefsTab;
-import net.sf.jabref.gui.MainTable;
 import net.sf.jabref.gui.FileDialogs;
+import net.sf.jabref.gui.MainTable;
 
 import com.jgoodies.forms.builder.ButtonBarBuilder;
 
@@ -56,7 +64,7 @@ public class PrefsDialog3 extends JDialog {
                final JabRefPreferences prefs = JabRefPreferences.getInstance();
                frame = parent;
 
-               final JList<String> chooser;
+               final JList chooser;
 
                JButton importPrefs = new JButton(Globals.lang("Import preferences"));
                JButton exportPrefs = new JButton(Globals.lang("Export preferences"));
@@ -105,7 +113,7 @@ public class PrefsDialog3 extends JDialog {
 
                upper.setBorder(BorderFactory.createEtchedBorder());
 
-               chooser = new JList<String>(names);
+               chooser = new JList(names);
                chooser.setBorder(BorderFactory.createEtchedBorder());
                // Set a prototype value to control the width of the list:
                chooser.setPrototypeCellValue("This should be wide enough");
@@ -118,7 +126,7 @@ public class PrefsDialog3 extends JDialog {
                        public void valueChanged(ListSelectionEvent e) {
                                if (e.getValueIsAdjusting())
                                        return;
-                               String o = chooser.getSelectedValue();
+                               String o = (String) chooser.getSelectedValue();
                                cardLayout.show(main, o);
                        }
                });
index e7997e4..515566f 100644 (file)
@@ -160,8 +160,9 @@ public class RightClickMenu extends JPopupMenu
             });
             addSeparator();
         } else if (be != null) {
-            if (be.getField(BibtexFields.MARKED) == null) {
-
+            String marked = be.getField(BibtexFields.MARKED);
+            // We have to check for "" too as the marked field may be empty
+            if ((marked == null) || (marked.isEmpty())) {
                 add(new AbstractAction(Globals.lang("Mark entry"), GUIGlobals.getImage("markEntries")) {
                     public void actionPerformed(ActionEvent e) {
                         try {
index 8bec2dd..4e13338 100644 (file)
@@ -65,10 +65,11 @@ public class SendAsEMailAction extends AbstractWorker {
                BibtexEntry[] bes = panel.getSelectedEntries();
 
                // write the entries using sw, which is used later to form the email content
-               LatexFieldFormatter ff = new LatexFieldFormatter();
+               BibtexEntryWriter bibtexEntryWriter = new BibtexEntryWriter(new LatexFieldFormatter(), true);
+
                for (BibtexEntry entry: bes) {
                    try {
-                entry.write(sw, ff, true);
+                               bibtexEntryWriter.write(entry, sw);
             } catch (IOException e) {
                 e.printStackTrace();
             }
index 13c0191..68108fe 100644 (file)
@@ -210,7 +210,7 @@ public class SidePaneManager {
                        int pos1 = (preferredPositions.containsKey(comp1Name) ? preferredPositions.get(comp1Name) : 0);
                        int pos2 = (preferredPositions.containsKey(comp2Name) ? preferredPositions.get(comp2Name) : 0);
                        
-                       return Integer.compare(pos1, pos2);
+                       return Integer.valueOf(pos1).compareTo(Integer.valueOf(pos2));
                }
        }
        
index aad3f1d..39af20b 100644 (file)
@@ -18,22 +18,39 @@ package net.sf.jabref;
 import java.awt.BorderLayout;
 import java.awt.Dimension;
 import java.awt.event.ActionEvent;
-import java.util.*;
-
-import javax.swing.*;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Vector;
+
+import javax.swing.AbstractAction;
+import javax.swing.BorderFactory;
+import javax.swing.ButtonGroup;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JList;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.JToolBar;
+import javax.swing.SwingConstants;
 import javax.swing.event.ChangeEvent;
 import javax.swing.event.ChangeListener;
 import javax.swing.table.AbstractTableModel;
 import javax.swing.table.TableColumnModel;
 import javax.swing.table.TableModel;
 
+import net.sf.jabref.external.ExternalFileType;
 import net.sf.jabref.help.HelpAction;
 import net.sf.jabref.specialfields.SpecialFieldsUtils;
 
 import com.jgoodies.forms.builder.DefaultFormBuilder;
 import com.jgoodies.forms.layout.CellConstraints;
 import com.jgoodies.forms.layout.FormLayout;
-import net.sf.jabref.external.ExternalFileType;
 
 class TableColumnsTab extends JPanel implements PrefsTab {
 
@@ -47,7 +64,7 @@ class TableColumnsTab extends JPanel implements PrefsTab {
     private JCheckBox pdfColumn, urlColumn, fileColumn, arxivColumn;
 
     private JCheckBox extraFileColumns;
-    private JList<String> listOfFileColumns;
+       private JList listOfFileColumns;
 
     private JRadioButton preferUrl, preferDoi;
 
@@ -216,7 +233,7 @@ class TableColumnsTab extends JPanel implements PrefsTab {
                 for(int i=0;i<fileTypes.length;i++) {
                     fileTypeNames[i]=fileTypes[i].getName();
                 }
-                listOfFileColumns = new JList<String>(fileTypeNames);
+               listOfFileColumns = new JList(fileTypeNames);
                 JScrollPane listOfFileColumnsScrollPane = new JScrollPane(listOfFileColumns);
                 listOfFileColumns.setVisibleRowCount(3);
 
@@ -386,7 +403,7 @@ class TableColumnsTab extends JPanel implements PrefsTab {
                
         /*** end: special fields ***/
 
-        boolean oldShowOneLetterHeadingForIconColumns = _prefs.getBoolean(JabRefPreferences.SHOWONELETTERHEADINGFORICONCOLUMNS);
+        boolean oldShowOneLetterHeadingForIconColumns = _prefs.getBoolean(JabRefPreferences.SHOW_ONE_LETTER_HEADING_FOR_ICON_COLUMNS);
                showOneLetterHeadingForIconColumns.setSelected(oldShowOneLetterHeadingForIconColumns);
 
                tableRows.clear();
@@ -623,7 +640,7 @@ class TableColumnsTab extends JPanel implements PrefsTab {
                 if(extraFileColumns.isSelected()&&!listOfFileColumns.isSelectionEmpty()) {
                     String[] selections = new String[listOfFileColumns.getSelectedIndices().length];
                     for(int i=0;i<selections.length;i++) {
-                        selections[i]= listOfFileColumns.getModel().getElementAt(
+                        selections[i]= (String) listOfFileColumns.getModel().getElementAt(
                                 listOfFileColumns.getSelectedIndices()[i]);
                     }
                     _prefs.putStringArray("listOfFileColumns", selections);
@@ -632,7 +649,7 @@ class TableColumnsTab extends JPanel implements PrefsTab {
                     _prefs.putStringArray("listOfFileColumns", new String[] {});
                 }
                
-               _prefs.putBoolean(JabRefPreferences.SHOWONELETTERHEADINGFORICONCOLUMNS, showOneLetterHeadingForIconColumns.isSelected());
+               _prefs.putBoolean(JabRefPreferences.SHOW_ONE_LETTER_HEADING_FOR_ICON_COLUMNS, showOneLetterHeadingForIconColumns.isSelected());
 
         /*** begin: special fields ***/
         
index 2dc2339..1e2e4b4 100644 (file)
@@ -22,7 +22,15 @@ import java.util.Arrays;
 import java.util.Collections;
 import java.util.Vector;
 
-import javax.swing.*;
+import javax.swing.BorderFactory;
+import javax.swing.ButtonGroup;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.JTable;
+import javax.swing.JTextField;
 import javax.swing.event.ChangeEvent;
 import javax.swing.event.ChangeListener;
 
@@ -39,7 +47,7 @@ class TablePrefsTab extends JPanel implements PrefsTab {
                lastNamesOnly;
 
        private JTextField priField, secField, terField, numericFields;
-       private JComboBox<String> priSort, secSort, terSort;
+       private JComboBox priSort, secSort, terSort;
 
        /**
         * Customization of external program paths.
@@ -62,9 +70,9 @@ class TablePrefsTab extends JPanel implements PrefsTab {
                v.add(BibtexFields.KEY_FIELD);
                Collections.sort(v);
                String[] allPlusKey = v.toArray(new String[v.size()]);
-               priSort = new JComboBox<String>(allPlusKey);
-               secSort = new JComboBox<String>(allPlusKey);
-               terSort = new JComboBox<String>(allPlusKey);
+               priSort = new JComboBox(allPlusKey);
+               secSort = new JComboBox(allPlusKey);
+               terSort = new JComboBox(allPlusKey);
 
                autoResizeMode = new JCheckBox(Globals.lang("Fit table horizontally on screen"));
 
index 39791d8..b486c7a 100644 (file)
 */
 package net.sf.jabref;
 
+import net.sf.jabref.export.LatexFieldFormatter;
+
+import javax.swing.*;
 import java.awt.datatransfer.DataFlavor;
 import java.awt.datatransfer.Transferable;
 import java.awt.datatransfer.UnsupportedFlavorException;
 import java.io.IOException;
 import java.io.StringWriter;
 
-import javax.swing.JOptionPane;
-
-import net.sf.jabref.export.LatexFieldFormatter;
-
 /*
  * A transferable object containing an array of BibtexEntry objects. Used
  * for copy-paste operations.
@@ -35,36 +34,38 @@ public class TransferableBibtexEntry implements Transferable {
     public static DataFlavor entryFlavor = new DataFlavor(BibtexEntry.class, "JabRef entry");
 
     public TransferableBibtexEntry(BibtexEntry[] data) {
-       this.data = data;
+        this.data = data;
     }
 
     public DataFlavor[] getTransferDataFlavors() {
-       return new DataFlavor[] {TransferableBibtexEntry.entryFlavor,
-                                DataFlavor.stringFlavor};
+        return new DataFlavor[]{TransferableBibtexEntry.entryFlavor,
+                DataFlavor.stringFlavor};
     }
 
     public boolean isDataFlavorSupported(DataFlavor flavor) {
-       return (flavor.equals(entryFlavor) ||
-               flavor.equals(DataFlavor.stringFlavor));
+        return (flavor.equals(entryFlavor) ||
+                flavor.equals(DataFlavor.stringFlavor));
     }
 
     public Object getTransferData(DataFlavor flavor)
-       throws UnsupportedFlavorException {
-       if (flavor.equals(entryFlavor))
-           return data;
-       else if (flavor.equals(DataFlavor.stringFlavor)) {
-           try {
-               StringWriter sw = new StringWriter();
-               LatexFieldFormatter ff = new LatexFieldFormatter();
-            for (BibtexEntry aData : data) aData.write(sw, ff, false);
-               return sw.toString();
-           } catch (IOException ex) {
-               JOptionPane.showMessageDialog
-                   (null, "Could not paste entry as text:\n"+ex.getMessage(),
-                    "Clipboard", JOptionPane.ERROR_MESSAGE);
-               return "";
-           }
-       } else
-           throw new UnsupportedFlavorException(flavor);
+            throws UnsupportedFlavorException {
+        if (flavor.equals(entryFlavor))
+            return data;
+        else if (flavor.equals(DataFlavor.stringFlavor)) {
+            try {
+                StringWriter sw = new StringWriter();
+                BibtexEntryWriter bibtexEntryWriter = new BibtexEntryWriter(new LatexFieldFormatter(), false);
+                for (BibtexEntry entry : data) {
+                    bibtexEntryWriter.write(entry, sw);
+                }
+                return sw.toString();
+            } catch (IOException ex) {
+                JOptionPane.showMessageDialog
+                        (null, "Could not paste entry as text:\n" + ex.getMessage(),
+                                "Clipboard", JOptionPane.ERROR_MESSAGE);
+                return "";
+            }
+        } else
+            throw new UnsupportedFlavorException(flavor);
     }
 }
index 5c7ee92..949c2b9 100644 (file)
@@ -163,10 +163,8 @@ public class UrlDragDrop implements DropTargetListener {
                             .get("pdfDirectory")), editor.getEntry()
                             .getField(BibtexFields.KEY_FIELD)
                             + ".pdf");
-                    URLDownload udl = new URLDownload(editor, url,
-                            file);
                     frame.output(Globals.lang("Downloading..."));
-                    udl.download();
+                    URLDownload.buildMonitoredDownload(editor, url).downloadToFile(file);
                     frame.output(Globals.lang("Download completed"));
                     feditor.setText(file.toURI().toURL().toString());
                     editor.updateField(feditor);
index 23d7a3a..d15cf64 100644 (file)
@@ -1,4 +1,6 @@
 /*  Copyright (C) 2003-2012 JabRef contributors.
+    Copyright (C) 2015 Oliver Kopp
+
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
     the Free Software Foundation; either version 2 of the License, or
@@ -45,8 +47,6 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -236,9 +236,9 @@ public class Util {
 
                o = entry.getField("month");
                if (o != null) {
-                       int month = Util.getMonthNumber(o.toString());
-                       if (month != -1) {
-                               return year + "-" + (month + 1 < 10 ? "0" : "") + (month + 1);
+                       MonthUtil.Month month = MonthUtil.getMonth(o.toString());
+                       if (month.isValid()) {
+                               return year + "-" + month.twoDigitNumber;
                        }
                }
                return year;
@@ -604,10 +604,7 @@ public class Util {
 
                if (fieldName.equals("url")) { // html
                        try {
-                link = sanitizeUrl(link);
-                ExternalFileType fileType = Globals.prefs.getExternalFileTypeByExt("html");
-                openExternalFilePlatformIndependent(fileType, link);
-
+                openBrowser(link);
             } catch (IOException e) {
                 System.err.println(Globals.lang("Error_opening_file_'%0'.", link));
                 e.printStackTrace();
@@ -787,6 +784,9 @@ public class Util {
     }
 
     private static void openExternalFilePlatformIndependent(ExternalFileType fileType, String filePath) throws IOException {
+        // For URLs, other solutions are
+        //  * https://github.com/rajing/browserlauncher2, but it is not available in maven
+        //  * a the solution combining http://stackoverflow.com/a/5226244/873282 and http://stackoverflow.com/a/28807079/873282
         if (Globals.ON_MAC) {
             // Use "-a <application>" if the app is specified, and just "open <filename>" otherwise:
             String[] cmd = ((fileType.getOpenWith() != null) && (fileType.getOpenWith().length() > 0)) ?
@@ -822,8 +822,7 @@ public class Util {
             temp = File.createTempFile("jabref-link", "."+fileType.getExtension());
             temp.deleteOnExit();
             System.out.println("Downloading to '"+temp.getPath()+"'");
-            URLDownload ud = new URLDownload(null, new URL(link), temp);
-            ud.download();
+                       new URLDownload(new URL(link)).downloadToFile(temp);
             System.out.println("Done");
         } catch (MalformedURLException ex) {
             ex.printStackTrace();
@@ -969,114 +968,6 @@ public static boolean openExternalFileUnknown(JabRefFrame frame, BibtexEntry ent
                }
        }
 
-       /**
-        * Searches the given directory and subdirectories for a pdf file with name
-        * as given + ".pdf"
-        */
-       public static String findPdf(String key, String extension, String directory, OpenFileFilter off) {
-               // String filename = key + "."+extension;
-
-               /*
-                * Simon Fischer's patch for replacing a regexp in keys before
-                * converting to filename:
-                * 
-                * String regex = Globals.prefs.get("basenamePatternRegex"); if ((regex !=
-                * null) && (regex.trim().length() > 0)) { String replacement =
-                * Globals.prefs.get("basenamePatternReplacement"); key =
-                * key.replaceAll(regex, replacement); }
-                */
-               if (!directory.endsWith(System.getProperty("file.separator")))
-                       directory += System.getProperty("file.separator");
-               String found = findInDir(key, directory, off, 0);
-               if (found != null)
-                       return found.substring(directory.length());
-               else
-                       return null;
-       }
-
-       public static Map<BibtexEntry, List<File>> findAssociatedFiles(Collection<BibtexEntry> entries, Collection<String> extensions, Collection<File> directories){
-               HashMap<BibtexEntry, List<File>> result = new HashMap<BibtexEntry, List<File>>();
-       
-               // First scan directories
-               Set<File> filesWithExtension = findFiles(extensions, directories);
-               
-               // Initialize Result-Set
-               for (BibtexEntry entry : entries){
-                       result.put(entry, new ArrayList<File>());
-               }
-
-        boolean exactOnly = Globals.prefs.getBoolean(JabRefPreferences.AUTOLINK_EXACT_KEY_ONLY);
-        // Now look for keys
-               nextFile:
-               for (File file : filesWithExtension){
-                       
-                       String name = file.getName();
-            int dot = name.lastIndexOf('.');
-            // First, look for exact matches:
-            for (BibtexEntry entry : entries){
-                String citeKey = entry.getCiteKey();
-                if ((citeKey != null) && (citeKey.length() > 0)) {
-                    if (dot > 0) {
-                        if (name.substring(0, dot).equals(citeKey)) {
-                            result.get(entry).add(file);
-                            continue nextFile;
-                        }
-                    }
-                }
-            }
-            // If we get here, we didn't find any exact matches. If non-exact
-            // matches are allowed, try to find one:
-            if (!exactOnly) {
-                for (BibtexEntry entry : entries){
-                    String citeKey = entry.getCiteKey();
-                    if ((citeKey != null) && (citeKey.length() > 0)) {
-                        if (name.startsWith(citeKey)){
-                            result.get(entry).add(file);
-                            continue nextFile;
-                        }
-                    }
-                }
-            }
-               }
-               
-               return result;
-       }
-       
-       public static Set<File> findFiles(Collection<String> extensions, Collection<File> directories) {
-               Set<File> result = new HashSet<File>();
-               
-               for (File directory : directories){
-                       result.addAll(findFiles(extensions, directory));
-               }
-               
-               return result;
-       }
-
-       private static Collection<? extends File> findFiles(Collection<String> extensions, File directory) {
-               Set<File> result = new HashSet<File>();
-               
-               File[] children = directory.listFiles();
-               if (children == null)
-                       return result; // No permission?
-
-               for (File child : children){
-                       if (child.isDirectory()) {
-                               result.addAll(findFiles(extensions, child));
-                       } else {
-                               
-                               String extension = getFileExtension(child);
-                                       
-                               if (extension != null){
-                                       if (extensions.contains(extension)){
-                                               result.add(child);
-                                       }
-                               }
-                       }
-               }
-               
-               return result;
-       }
-
        /**
         * Returns the extension of a file or null if the file does not have one (no . in name).
         * 
@@ -1092,117 +983,6 @@ public static boolean openExternalFileUnknown(JabRefFrame frame, BibtexEntry ent
                return extension;
        }
 
-       /**
-        * New version of findPdf that uses findFiles.
-        * 
-        * The search pattern will be read from the preferences.
-        * 
-        * The [extension]-tags in this pattern will be replace by the given
-        * extension parameter.
-        * 
-        */
-       public static String findPdf(BibtexEntry entry, String extension, String directory) {
-               return findPdf(entry, extension, new String[] { directory });
-       }
-
-       /**
-        * Convenience method for findPDF. Can search multiple PDF directories.
-        */
-       public static String findPdf(BibtexEntry entry, String extension, String[] directories) {
-
-               String regularExpression;
-               if (Globals.prefs.getBoolean(JabRefPreferences.USE_REG_EXP_SEARCH_KEY)) {
-                       regularExpression = Globals.prefs.get(JabRefPreferences.REG_EXP_SEARCH_EXPRESSION_KEY);
-               } else {
-                       regularExpression = Globals.prefs
-                               .get(JabRefPreferences.DEFAULT_REG_EXP_SEARCH_EXPRESSION_KEY);
-               }
-               regularExpression = regularExpression.replaceAll("\\[extension\\]", extension);
-
-               return findFile(entry, null, directories, regularExpression, true);
-       }
-
-    /**
-     * Convenience menthod for findPDF. Searches for a file of the given type.
-     * @param entry The BibtexEntry to search for a link for.
-     * @param fileType The file type to search for.
-     * @return The link to the file found, or null if not found.
-     */
-    public static String findFile(BibtexEntry entry, ExternalFileType fileType, List<String> extraDirs) {
-
-        List<String> dirs = new ArrayList<String>();
-        dirs.addAll(extraDirs);
-        if (Globals.prefs.hasKey(fileType.getExtension()+"Directory")) {
-            dirs.add(Globals.prefs.get(fileType.getExtension()+"Directory"));
-        }
-        String [] directories = dirs.toArray(new String[dirs.size()]);
-        return findPdf(entry, fileType.getExtension(), directories);
-    }
-
-    /**
-        * Searches the given directory and file name pattern for a file for the
-        * bibtexentry.
-        *
-        * Used to fix:
-        *
-        * http://sourceforge.net/tracker/index.php?func=detail&aid=1503410&group_id=92314&atid=600309
-        *
-        * Requirements:
-        *  - Be able to find the associated PDF in a set of given directories.
-        *  - Be able to return a relative path or absolute path.
-        *  - Be fast.
-        *  - Allow for flexible naming schemes in the PDFs.
-        *
-        * Syntax scheme for file:
-        * <ul>
-        * <li>* Any subDir</li>
-        * <li>** Any subDir (recursiv)</li>
-        * <li>[key] Key from bibtex file and database</li>
-        * <li>.* Anything else is taken to be a Regular expression.</li>
-        * </ul>
-        *
-        * @param entry
-        *            non-null
-        * @param database
-        *            non-null
-        * @param directory
-        *            A set of root directories to start the search from. Paths are
-        *            returned relative to these directories if relative is set to
-        *            true. These directories will not be expanded or anything. Use
-        *            the file attribute for this.
-        * @param file
-        *            non-null
-        *
-        * @param relative
-        *            whether to return relative file paths or absolute ones
-        *
-        * @return Will return the first file found to match the given criteria or
-        *         null if none was found.
-        */
-       public static String findFile(BibtexEntry entry, BibtexDatabase database, String[] directory,
-               String file, boolean relative) {
-
-        for (String aDirectory : directory) {
-            String result = findFile(entry, database, aDirectory, file, relative);
-            if (result != null) {
-                return result;
-            }
-        }
-               return null;
-       }
-
-       /**
-        * Removes optional square brackets from the string s
-        *
-        * @param s
-        * @return
-        */
-       public static String stripBrackets(String s) {
-               int beginIndex = (s.startsWith("[") ? 1 : 0);
-               int endIndex = (s.endsWith("]") ? s.length() - 1 : s.length());
-               return s.substring(beginIndex, endIndex);
-       }
-
        public static ArrayList<String[]> parseMethodsCalls(String calls) throws RuntimeException {
 
                ArrayList<String[]> result = new ArrayList<String[]>();
@@ -1280,243 +1060,6 @@ public static boolean openExternalFileUnknown(JabRefFrame frame, BibtexEntry ent
                return result;
        }
 
-       /**
-        * Accepts a string like [author:lower] or [title:abbr] or [auth],
-        * whereas the first part signifies the bibtex-field to get, or the key generator
-     * field marker to use, while the others are the modifiers that will be applied.
-        *
-        * @param fieldAndFormat
-        * @param entry
-        * @param database
-        * @return
-        */
-       public static String getFieldAndFormat(String fieldAndFormat, BibtexEntry entry,
-               BibtexDatabase database) {
-
-               fieldAndFormat = stripBrackets(fieldAndFormat);
-
-               int colon = fieldAndFormat.indexOf(':');
-
-               String beforeColon, afterColon;
-               if (colon == -1) {
-                       beforeColon = fieldAndFormat;
-                       afterColon = null;
-               } else {
-                       beforeColon = fieldAndFormat.substring(0, colon);
-                       afterColon = fieldAndFormat.substring(colon + 1);
-               }
-               beforeColon = beforeColon.trim();
-
-               if (beforeColon.length() == 0) {
-                       return null;
-               }
-
-               String fieldValue = BibtexDatabase.getResolvedField(beforeColon, entry, database);
-
-        // If no field value was found, try to interpret it as a key generator field marker:
-        if (fieldValue == null)
-            fieldValue =  LabelPatternUtil.makeLabel(entry, beforeColon);
-
-               if (fieldValue == null)
-                       return null;
-
-               if (afterColon == null || afterColon.length() == 0)
-                       return fieldValue;
-
-        String[] parts = afterColon.split(":");
-        fieldValue = LabelPatternUtil.applyModifiers(fieldValue, parts, 0);
-        
-               return fieldValue;
-       }
-
-       /**
-        * Convenience function for absolute search.
-        *
-        * Uses findFile(BibtexEntry, BibtexDatabase, (String)null, String, false).
-        */
-       public static String findFile(BibtexEntry entry, BibtexDatabase database, String file) {
-               return findFile(entry, database, (String) null, file, false);
-       }
-
-       /**
-        * Internal Version of findFile, which also accepts a current directory to
-        * base the search on.
-        *
-        */
-       public static String findFile(BibtexEntry entry, BibtexDatabase database, String directory,
-               String file, boolean relative) {
-
-               File root;
-               if (directory == null) {
-                       root = new File(".");
-               } else {
-                       root = new File(directory);
-               }
-               if (!root.exists())
-                       return null;
-
-               String found = findFile(entry, database, root, file);
-
-               if (directory == null || !relative) {
-                       return found;
-               }
-
-               if (found != null) {
-                       try {
-                               /**
-                                * [ 1601651 ] PDF subdirectory - missing first character
-                                *
-                                * http://sourceforge.net/tracker/index.php?func=detail&aid=1601651&group_id=92314&atid=600306
-                                */
-                // Changed by M. Alver 2007.01.04:
-                // Remove first character if it is a directory separator character:
-                String tmp = found.substring(root.getCanonicalPath().length());
-                if ((tmp.length() > 1) && (tmp.charAt(0) == File.separatorChar))
-                    tmp = tmp.substring(1);
-                return tmp;
-                //return found.substring(root.getCanonicalPath().length());
-                       } catch (IOException e) {
-                               return null;
-                       }
-               }
-               return null;
-       }
-
-       /**
-        * The actual work-horse. Will find absolute filepaths starting from the
-        * given directory using the given regular expression string for search.
-        */
-       protected static String findFile(BibtexEntry entry, BibtexDatabase database, File directory,
-               String file) {
-
-               if (file.startsWith("/")) {
-                       directory = new File(".");
-                       file = file.substring(1);
-               }
-
-               // Escape handling...
-               Matcher m = Pattern.compile("([^\\\\])\\\\([^\\\\])").matcher(file);
-               StringBuffer s = new StringBuffer();
-               while (m.find()) {
-                       m.appendReplacement(s, m.group(1) + "/" + m.group(2));
-               }
-               m.appendTail(s);
-               file = s.toString();
-               String[] fileParts = file.split("/");
-
-               if (fileParts.length == 0)
-                       return null;
-
-               if (fileParts.length > 1) {
-
-                       for (int i = 0; i < fileParts.length - 1; i++) {
-
-                               String dirToProcess = fileParts[i];
-
-                               dirToProcess = expandBrackets(dirToProcess, entry, database);
-
-                               if (dirToProcess.matches("^.:$")) { // Windows Drive Letter
-                                       directory = new File(dirToProcess + "/");
-                                       continue;
-                               }
-                               if (dirToProcess.equals(".")) { // Stay in current directory
-                                       continue;
-                               }
-                               if (dirToProcess.equals("..")) {
-                                       directory = new File(directory.getParent());
-                                       continue;
-                               }
-                               if (dirToProcess.equals("*")) { // Do for all direct subdirs
-
-                                       File[] subDirs = directory.listFiles();
-                                       if (subDirs == null)
-                                               return null; // No permission?
-
-                                       String restOfFileString = join(fileParts, "/", i + 1, fileParts.length);
-
-                    for (File subDir : subDirs) {
-                        if (subDir.isDirectory()) {
-                            String result = findFile(entry, database, subDir,
-                                    restOfFileString);
-                            if (result != null)
-                                return result;
-                        }
-                    }
-                                       return null;
-                               }
-                               // Do for all direct and indirect subdirs
-                               if (dirToProcess.equals("**")) {
-                                       List<File> toDo = new LinkedList<File>();
-                                       toDo.add(directory);
-
-                                       String restOfFileString = join(fileParts, "/", i + 1, fileParts.length);
-
-                                       // Before checking the subdirs, we first check the current
-                                       // dir
-                                       String result = findFile(entry, database, directory, restOfFileString);
-                                       if (result != null)
-                                               return result;
-
-                                       while (!toDo.isEmpty()) {
-
-                                               // Get all subdirs of each of the elements found in toDo
-                                               File[] subDirs = toDo.remove(0).listFiles();
-                                               if (subDirs == null) // No permission?
-                                                       continue;
-
-                                               toDo.addAll(Arrays.asList(subDirs));
-
-                        for (File subDir : subDirs) {
-                            if (!subDir.isDirectory())
-                                continue;
-                            result = findFile(entry, database, subDir, restOfFileString);
-                            if (result != null)
-                                return result;
-                        }
-                                       }
-                                       // We already did the currentDirectory
-                                       return null;
-                               }
-
-                               final Pattern toMatch = Pattern
-                                       .compile(dirToProcess.replaceAll("\\\\\\\\", "\\\\"));
-
-                               File[] matches = directory.listFiles(new FilenameFilter() {
-                                       public boolean accept(File arg0, String arg1) {
-                                               return toMatch.matcher(arg1).matches();
-                                       }
-                               });
-                               if (matches == null || matches.length == 0)
-                                       return null;
-
-                               directory = matches[0];
-
-                               if (!directory.exists())
-                                       return null;
-
-                       } // End process directory information
-               }
-               // Last step check if the given file can be found in this directory
-               String filenameToLookFor = expandBrackets(fileParts[fileParts.length - 1], entry, database);
-
-               final Pattern toMatch = Pattern.compile("^"
-                       + filenameToLookFor.replaceAll("\\\\\\\\", "\\\\") + "$");
-
-               File[] matches = directory.listFiles(new FilenameFilter() {
-                       public boolean accept(File arg0, String arg1) {
-                               return toMatch.matcher(arg1).matches();
-                       }
-               });
-               if (matches == null || matches.length == 0)
-                       return null;
-
-               try {
-                       return matches[0].getCanonicalPath();
-               } catch (IOException e) {
-                       return null;
-               }
-       }
-
        static Pattern squareBracketsPattern = Pattern.compile("\\[.*?\\]");
 
        /**
@@ -1736,33 +1279,7 @@ public static boolean openExternalFileUnknown(JabRefFrame frame, BibtexEntry ent
        }
 
 
-       private static String findInDir(String key, String dir, OpenFileFilter off, int count) {
-        if (count > 20)
-            return null; // Make sure an infinite loop doesn't occur.
-        File f = new File(dir);
-               File[] all = f.listFiles();
-               if (all == null)
-                       return null; // An error occured. We may not have
-               // permission to list the files.
-
-               int numFiles = all.length;
-
-        for (File curFile : all) {
-            if (curFile.isFile()) {
-                String name = curFile.getName();
-                if (name.startsWith(key + ".") && off.accept(name))
-                    return curFile.getPath();
-
-            } else if (curFile.isDirectory()) {
-                String found = findInDir(key, curFile.getPath(), off, count + 1);
-                if (found != null)
-                    return found;
-            }
-        }
-               return null;
-       }
-
-    /**
+       /**
      * This methods assures all words in the given entry are recorded in their
      * respective Completers, if any.
      */
@@ -2434,6 +1951,9 @@ public static boolean openExternalFileUnknown(JabRefFrame frame, BibtexEntry ent
                return dateFormatter.format(date);
        }
 
+       /**
+        * @param increment whether the given increment should be added to the current one. Currently never used in JabRef
+        */
     public static void markEntry(BibtexEntry be, int markIncrement, boolean increment, NamedCompound ce) {
                Object o = be.getField(BibtexFields.MARKED);
         int prevMarkLevel = 0;
@@ -2475,6 +1995,9 @@ public static boolean openExternalFileUnknown(JabRefFrame frame, BibtexEntry ent
                be.setField(BibtexFields.MARKED, newValue);
        }
 
+    /**
+     * SIDE EFFECT: Unselectes given entry
+     */
        public static void unmarkEntry(BibtexEntry be, boolean onlyMaxLevel,
                                    BibtexDatabase database, NamedCompound ce) {
                Object o = be.getField(BibtexFields.MARKED);
@@ -2757,33 +2280,29 @@ public static boolean openExternalFileUnknown(JabRefFrame frame, BibtexEntry ent
        }
 
        /**
-        * Will return an integer indicating the month of the entry from 0 to 11.
-        * 
-        * -1 signals a unknown month string.
-        * 
-        * This method accepts three types of months given:
-        *  - Single and Double Digit months from 1 to 12 (01 to 12)
-        *  - 3 Digit BibTex strings (jan, feb, mar...)
-        *  - Full English Month identifiers.
-        * 
-        * @param month
+        * From http://stackoverflow.com/questions/1030479/most-efficient-way-of-converting-string-to-integer-in-java
+        *
+        * @param str
         * @return
         */
-       public static int getMonthNumber(String month) {
+       public static int intValueOf( String str )      {
+               int ival = 0, idx = 0, end;
+               boolean sign = false;
+               char ch;
 
-               month = month.replaceAll("#", "").toLowerCase();
-
-               for (int i = 0; i < Globals.MONTHS.length; i++) {
-                       if (month.startsWith(Globals.MONTHS[i])) {
-                               return i;
-                       }
-               }
+               if( str == null || ( end = str.length() ) == 0 ||
+                               ( ( ch = str.charAt( 0 ) ) < '0' || ch > '9' )
+                                               && ( !( sign = ch == '-' ) || ++idx == end || ( ( ch = str.charAt( idx ) ) < '0' || ch > '9' ) ) )
+                       throw new NumberFormatException( str );
 
-               try {
-                       return Integer.parseInt(month) - 1;
-               } catch (NumberFormatException ignored) {
+               for(;; ival *= 10 )
+               {
+                       ival += '0'- ch;
+                       if( ++idx == end )
+                               return sign ? ival : -ival;
+                       if( ( ch = str.charAt( idx ) ) < '0' || ch > '9' )
+                               throw new NumberFormatException( str );
                }
-               return -1;
        }
 
 
@@ -3063,10 +2582,7 @@ public static boolean openExternalFileUnknown(JabRefFrame frame, BibtexEntry ent
         * Check if the String matches a DOI (with http://...)
         */
     public static boolean checkForDOIwithHTTPprefix(String check) {
-       if (check == null)
-               return false;
-
-       return check.matches(".*" + REGEXP_DOI_WITH_HTTP_PREFIX + ".*");
+               return check != null && check.matches(".*" + REGEXP_DOI_WITH_HTTP_PREFIX + ".*");
        }
     
     /**
@@ -3075,11 +2591,8 @@ public static boolean openExternalFileUnknown(JabRefFrame frame, BibtexEntry ent
      * @return true if "check" contains a DOI
      */
     public static boolean checkForPlainDOI(String check) {
-       if (check == null)
-               return false;
-
-       return check.matches(".*" + REGEXP_PLAINDOI + ".*");
-    }
+               return check != null && check.matches(".*" + REGEXP_PLAINDOI + ".*");
+       }
        
     /**
         * Remove the http://... from DOI
@@ -3328,7 +2841,7 @@ public static boolean openExternalFileUnknown(JabRefFrame frame, BibtexEntry ent
                     String regExp = Globals.prefs.get(JabRefPreferences.REG_EXP_SEARCH_EXPRESSION_KEY);
                     result = RegExpFileSearch.findFilesForSet(entries, extensions, dirs, regExp);
                 } else {
-                    result = Util.findAssociatedFiles(entries, extensions, dirs);
+                    result = findAssociatedFiles(entries, extensions, dirs);
                 }
 
 
@@ -3510,5 +3023,127 @@ public static boolean openExternalFileUnknown(JabRefFrame frame, BibtexEntry ent
         }
         return res;
     }
+
+       public static Map<BibtexEntry, List<File>> findAssociatedFiles(Collection<BibtexEntry> entries, Collection<String> extensions, Collection<File> directories){
+               HashMap<BibtexEntry, List<File>> result = new HashMap<BibtexEntry, List<File>>();
+
+               // First scan directories
+               Set<File> filesWithExtension = UtilFindFiles.findFiles(extensions, directories);
+
+               // Initialize Result-Set
+               for (BibtexEntry entry : entries){
+                       result.put(entry, new ArrayList<File>());
+               }
+
+        boolean exactOnly = Globals.prefs.getBoolean(JabRefPreferences.AUTOLINK_EXACT_KEY_ONLY);
+        // Now look for keys
+               nextFile:
+               for (File file : filesWithExtension){
+
+                       String name = file.getName();
+            int dot = name.lastIndexOf('.');
+            // First, look for exact matches:
+            for (BibtexEntry entry : entries){
+                String citeKey = entry.getCiteKey();
+                if ((citeKey != null) && (citeKey.length() > 0)) {
+                    if (dot > 0) {
+                        if (name.substring(0, dot).equals(citeKey)) {
+                            result.get(entry).add(file);
+                            continue nextFile;
+                        }
+                    }
+                }
+            }
+            // If we get here, we didn't find any exact matches. If non-exact
+            // matches are allowed, try to find one:
+            if (!exactOnly) {
+                for (BibtexEntry entry : entries){
+                    String citeKey = entry.getCiteKey();
+                    if ((citeKey != null) && (citeKey.length() > 0)) {
+                        if (name.startsWith(citeKey)){
+                            result.get(entry).add(file);
+                            continue nextFile;
+                        }
+                    }
+                }
+            }
+               }
+
+               return result;
+       }
+
+       /**
+        * Accepts a string like [author:lower] or [title:abbr] or [auth],
+        * whereas the first part signifies the bibtex-field to get, or the key generator
+     * field marker to use, while the others are the modifiers that will be applied.
+        *
+        * @param fieldAndFormat
+        * @param entry
+        * @param database
+        * @return
+        */
+       public static String getFieldAndFormat(String fieldAndFormat, BibtexEntry entry,
+               BibtexDatabase database) {
+
+               fieldAndFormat = stripBrackets(fieldAndFormat);
+
+               int colon = fieldAndFormat.indexOf(':');
+
+               String beforeColon, afterColon;
+               if (colon == -1) {
+                       beforeColon = fieldAndFormat;
+                       afterColon = null;
+               } else {
+                       beforeColon = fieldAndFormat.substring(0, colon);
+                       afterColon = fieldAndFormat.substring(colon + 1);
+               }
+               beforeColon = beforeColon.trim();
+
+               if (beforeColon.length() == 0) {
+                       return null;
+               }
+
+               String fieldValue = BibtexDatabase.getResolvedField(beforeColon, entry, database);
+
+        // If no field value was found, try to interpret it as a key generator field marker:
+        if (fieldValue == null)
+            fieldValue =  LabelPatternUtil.makeLabel(entry, beforeColon);
+
+               if (fieldValue == null)
+                       return null;
+
+               if (afterColon == null || afterColon.length() == 0)
+                       return fieldValue;
+
+        String[] parts = afterColon.split(":");
+        fieldValue = LabelPatternUtil.applyModifiers(fieldValue, parts, 0);
+
+               return fieldValue;
+       }
+
+       /**
+        * Removes optional square brackets from the string s
+        *
+        * @param s
+        * @return
+        */
+       public static String stripBrackets(String s) {
+               int beginIndex = (s.startsWith("[") ? 1 : 0);
+               int endIndex = (s.endsWith("]") ? s.length() - 1 : s.length());
+               return s.substring(beginIndex, endIndex);
+       }
+
+    /**
+     * Opens the given URL using the system browser
+     * 
+     * @param url the URL to open
+     * @throws IOException
+     */
+    public static void openBrowser(String url) throws IOException {
+        url = sanitizeUrl(url);
+        ExternalFileType fileType = Globals.prefs.getExternalFileTypeByExt("html");
+        openExternalFilePlatformIndependent(fileType, url);
+    }
+
 }
 
diff --git a/src/main/java/net/sf/jabref/UtilFindFiles.java b/src/main/java/net/sf/jabref/UtilFindFiles.java
new file mode 100644 (file)
index 0000000..ba190bf
--- /dev/null
@@ -0,0 +1,387 @@
+package net.sf.jabref;
+
+import net.sf.jabref.*;
+import net.sf.jabref.external.ExternalFileType;
+import net.sf.jabref.labelPattern.LabelPatternUtil;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class UtilFindFiles {
+       /**
+        * Searches the given directory and subdirectories for a pdf file with name
+        * as given + ".pdf"
+        */
+       public static String findPdf(String key, String extension, String directory, OpenFileFilter off) {
+               // String filename = key + "."+extension;
+
+               /*
+                * Simon Fischer's patch for replacing a regexp in keys before
+                * converting to filename:
+                *
+                * String regex = Globals.prefs.get("basenamePatternRegex"); if ((regex !=
+                * null) && (regex.trim().length() > 0)) { String replacement =
+                * Globals.prefs.get("basenamePatternReplacement"); key =
+                * key.replaceAll(regex, replacement); }
+                */
+               if (!directory.endsWith(System.getProperty("file.separator")))
+                       directory += System.getProperty("file.separator");
+               String found = findInDir(key, directory, off, 0);
+               if (found != null)
+                       return found.substring(directory.length());
+               else
+                       return null;
+       }
+
+       public static Set<File> findFiles(Collection<String> extensions, Collection<File> directories) {
+               Set<File> result = new HashSet<File>();
+
+               for (File directory : directories){
+                       result.addAll(findFiles(extensions, directory));
+               }
+
+               return result;
+       }
+
+       private static Collection<? extends File> findFiles(Collection<String> extensions, File directory) {
+               Set<File> result = new HashSet<File>();
+
+               File[] children = directory.listFiles();
+               if (children == null)
+                       return result; // No permission?
+
+               for (File child : children){
+                       if (child.isDirectory()) {
+                               result.addAll(findFiles(extensions, child));
+                       } else {
+
+                               String extension = Util.getFileExtension(child);
+
+                               if (extension != null){
+                                       if (extensions.contains(extension)){
+                                               result.add(child);
+                                       }
+                               }
+                       }
+               }
+
+               return result;
+       }
+
+       /**
+        * New version of findPdf that uses findFiles.
+        *
+        * The search pattern will be read from the preferences.
+        *
+        * The [extension]-tags in this pattern will be replace by the given
+        * extension parameter.
+        *
+        */
+       public static String findPdf(BibtexEntry entry, String extension, String directory) {
+               return findPdf(entry, extension, new String[] { directory });
+       }
+
+       /**
+        * Convenience method for findPDF. Can search multiple PDF directories.
+        */
+       public static String findPdf(BibtexEntry entry, String extension, String[] directories) {
+
+               String regularExpression;
+               if (Globals.prefs.getBoolean(JabRefPreferences.USE_REG_EXP_SEARCH_KEY)) {
+                       regularExpression = Globals.prefs.get(JabRefPreferences.REG_EXP_SEARCH_EXPRESSION_KEY);
+               } else {
+                       regularExpression = Globals.prefs
+                               .get(JabRefPreferences.DEFAULT_REG_EXP_SEARCH_EXPRESSION_KEY);
+               }
+               regularExpression = regularExpression.replaceAll("\\[extension\\]", extension);
+
+               return findFile(entry, null, directories, regularExpression, true);
+       }
+
+       /**
+     * Convenience menthod for findPDF. Searches for a file of the given type.
+     * @param entry The BibtexEntry to search for a link for.
+     * @param fileType The file type to search for.
+     * @return The link to the file found, or null if not found.
+     */
+    public static String findFile(BibtexEntry entry, ExternalFileType fileType, List<String> extraDirs) {
+
+        List<String> dirs = new ArrayList<String>();
+        dirs.addAll(extraDirs);
+        if (Globals.prefs.hasKey(fileType.getExtension()+"Directory")) {
+            dirs.add(Globals.prefs.get(fileType.getExtension()+"Directory"));
+        }
+        String [] directories = dirs.toArray(new String[dirs.size()]);
+        return findPdf(entry, fileType.getExtension(), directories);
+    }
+
+       /**
+        * Searches the given directory and file name pattern for a file for the
+        * bibtexentry.
+        *
+        * Used to fix:
+        *
+        * http://sourceforge.net/tracker/index.php?func=detail&aid=1503410&group_id=92314&atid=600309
+        *
+        * Requirements:
+        *  - Be able to find the associated PDF in a set of given directories.
+        *  - Be able to return a relative path or absolute path.
+        *  - Be fast.
+        *  - Allow for flexible naming schemes in the PDFs.
+        *
+        * Syntax scheme for file:
+        * <ul>
+        * <li>* Any subDir</li>
+        * <li>** Any subDir (recursiv)</li>
+        * <li>[key] Key from bibtex file and database</li>
+        * <li>.* Anything else is taken to be a Regular expression.</li>
+        * </ul>
+        *
+        * @param entry
+        *            non-null
+        * @param database
+        *            non-null
+        * @param directory
+        *            A set of root directories to start the search from. Paths are
+        *            returned relative to these directories if relative is set to
+        *            true. These directories will not be expanded or anything. Use
+        *            the file attribute for this.
+        * @param file
+        *            non-null
+        *
+        * @param relative
+        *            whether to return relative file paths or absolute ones
+        *
+        * @return Will return the first file found to match the given criteria or
+        *         null if none was found.
+        */
+       public static String findFile(BibtexEntry entry, BibtexDatabase database, String[] directory,
+               String file, boolean relative) {
+
+        for (String aDirectory : directory) {
+            String result = findFile(entry, database, aDirectory, file, relative);
+            if (result != null) {
+                return result;
+            }
+        }
+               return null;
+       }
+
+       /**
+        * Convenience function for absolute search.
+        *
+        * Uses findFile(BibtexEntry, BibtexDatabase, (String)null, String, false).
+        */
+       public static String findFile(BibtexEntry entry, BibtexDatabase database, String file) {
+               return findFile(entry, database, (String) null, file, false);
+       }
+
+       /**
+        * Internal Version of findFile, which also accepts a current directory to
+        * base the search on.
+        *
+        */
+       public static String findFile(BibtexEntry entry, BibtexDatabase database, String directory,
+               String file, boolean relative) {
+
+               File root;
+               if (directory == null) {
+                       root = new File(".");
+               } else {
+                       root = new File(directory);
+               }
+               if (!root.exists())
+                       return null;
+
+               String found = findFile(entry, database, root, file);
+
+               if (directory == null || !relative) {
+                       return found;
+               }
+
+               if (found != null) {
+                       try {
+                               /**
+                                * [ 1601651 ] PDF subdirectory - missing first character
+                                *
+                                * http://sourceforge.net/tracker/index.php?func=detail&aid=1601651&group_id=92314&atid=600306
+                                */
+                // Changed by M. Alver 2007.01.04:
+                // Remove first character if it is a directory separator character:
+                String tmp = found.substring(root.getCanonicalPath().length());
+                if ((tmp.length() > 1) && (tmp.charAt(0) == File.separatorChar))
+                    tmp = tmp.substring(1);
+                return tmp;
+                //return found.substring(root.getCanonicalPath().length());
+                       } catch (IOException e) {
+                               return null;
+                       }
+               }
+               return null;
+       }
+
+       /**
+        * The actual work-horse. Will find absolute filepaths starting from the
+        * given directory using the given regular expression string for search.
+        */
+       protected static String findFile(BibtexEntry entry, BibtexDatabase database, File directory,
+               String file) {
+
+               if (file.startsWith("/")) {
+                       directory = new File(".");
+                       file = file.substring(1);
+               }
+
+               // Escape handling...
+               Matcher m = Pattern.compile("([^\\\\])\\\\([^\\\\])").matcher(file);
+               StringBuffer s = new StringBuffer();
+               while (m.find()) {
+                       m.appendReplacement(s, m.group(1) + "/" + m.group(2));
+               }
+               m.appendTail(s);
+               file = s.toString();
+               String[] fileParts = file.split("/");
+
+               if (fileParts.length == 0)
+                       return null;
+
+               if (fileParts.length > 1) {
+
+                       for (int i = 0; i < fileParts.length - 1; i++) {
+
+                               String dirToProcess = fileParts[i];
+
+                               dirToProcess = Util.expandBrackets(dirToProcess, entry, database);
+
+                               if (dirToProcess.matches("^.:$")) { // Windows Drive Letter
+                                       directory = new File(dirToProcess + "/");
+                                       continue;
+                               }
+                               if (dirToProcess.equals(".")) { // Stay in current directory
+                                       continue;
+                               }
+                               if (dirToProcess.equals("..")) {
+                                       directory = new File(directory.getParent());
+                                       continue;
+                               }
+                               if (dirToProcess.equals("*")) { // Do for all direct subdirs
+
+                                       File[] subDirs = directory.listFiles();
+                                       if (subDirs == null)
+                                               return null; // No permission?
+
+                                       String restOfFileString = Util.join(fileParts, "/", i + 1, fileParts.length);
+
+                    for (File subDir : subDirs) {
+                        if (subDir.isDirectory()) {
+                            String result = findFile(entry, database, subDir,
+                                    restOfFileString);
+                            if (result != null)
+                                return result;
+                        }
+                    }
+                                       return null;
+                               }
+                               // Do for all direct and indirect subdirs
+                               if (dirToProcess.equals("**")) {
+                                       List<File> toDo = new LinkedList<File>();
+                                       toDo.add(directory);
+
+                                       String restOfFileString = Util.join(fileParts, "/", i + 1, fileParts.length);
+
+                                       // Before checking the subdirs, we first check the current
+                                       // dir
+                                       String result = findFile(entry, database, directory, restOfFileString);
+                                       if (result != null)
+                                               return result;
+
+                                       while (!toDo.isEmpty()) {
+
+                                               // Get all subdirs of each of the elements found in toDo
+                                               File[] subDirs = toDo.remove(0).listFiles();
+                                               if (subDirs == null) // No permission?
+                                                       continue;
+
+                                               toDo.addAll(Arrays.asList(subDirs));
+
+                        for (File subDir : subDirs) {
+                            if (!subDir.isDirectory())
+                                continue;
+                            result = findFile(entry, database, subDir, restOfFileString);
+                            if (result != null)
+                                return result;
+                        }
+                                       }
+                                       // We already did the currentDirectory
+                                       return null;
+                               }
+
+                               final Pattern toMatch = Pattern
+                                       .compile(dirToProcess.replaceAll("\\\\\\\\", "\\\\"));
+
+                               File[] matches = directory.listFiles(new FilenameFilter() {
+                                       public boolean accept(File arg0, String arg1) {
+                                               return toMatch.matcher(arg1).matches();
+                                       }
+                               });
+                               if (matches == null || matches.length == 0)
+                                       return null;
+
+                               directory = matches[0];
+
+                               if (!directory.exists())
+                                       return null;
+
+                       } // End process directory information
+               }
+               // Last step check if the given file can be found in this directory
+               String filenameToLookFor = Util.expandBrackets(fileParts[fileParts.length - 1], entry, database);
+
+               final Pattern toMatch = Pattern.compile("^"
+                       + filenameToLookFor.replaceAll("\\\\\\\\", "\\\\") + "$");
+
+               File[] matches = directory.listFiles(new FilenameFilter() {
+                       public boolean accept(File arg0, String arg1) {
+                               return toMatch.matcher(arg1).matches();
+                       }
+               });
+               if (matches == null || matches.length == 0)
+                       return null;
+
+               try {
+                       return matches[0].getCanonicalPath();
+               } catch (IOException e) {
+                       return null;
+               }
+       }
+
+       private static String findInDir(String key, String dir, OpenFileFilter off, int count) {
+        if (count > 20)
+            return null; // Make sure an infinite loop doesn't occur.
+        File f = new File(dir);
+               File[] all = f.listFiles();
+               if (all == null)
+                       return null; // An error occured. We may not have
+               // permission to list the files.
+
+               int numFiles = all.length;
+
+        for (File curFile : all) {
+            if (curFile.isFile()) {
+                String name = curFile.getName();
+                if (name.startsWith(key + ".") && off.accept(name))
+                    return curFile.getPath();
+
+            } else if (curFile.isDirectory()) {
+                String found = findInDir(key, curFile.getPath(), off, count + 1);
+                if (found != null)
+                    return found;
+            }
+        }
+               return null;
+       }
+}
index 7f4bf0d..4d3b731 100644 (file)
@@ -19,7 +19,11 @@ import java.awt.Toolkit;
 import java.awt.datatransfer.Clipboard;
 import java.awt.datatransfer.ClipboardOwner;
 import java.awt.datatransfer.Transferable;
-import java.io.*;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
 import java.util.HashSet;
 import java.util.Map;
 
@@ -28,7 +32,13 @@ import javax.swing.JList;
 import javax.swing.JOptionPane;
 import javax.swing.ListSelectionModel;
 
-import net.sf.jabref.*;
+import net.sf.jabref.AbstractWorker;
+import net.sf.jabref.BasePanel;
+import net.sf.jabref.BibtexDatabase;
+import net.sf.jabref.BibtexEntry;
+import net.sf.jabref.GUIGlobals;
+import net.sf.jabref.Globals;
+import net.sf.jabref.JabRefFrame;
 
 /**
  * Created by IntelliJ IDEA.
@@ -67,7 +77,7 @@ public class ExportToClipboardAction extends AbstractWorker {
                        piv++;
                }
         
-        JList<String> list = new JList<String>(array);
+               JList list = new JList(array);
         list.setBorder(BorderFactory.createEtchedBorder());
         list.setSelectionInterval(0, 0);
         list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
index b8f8908..327e839 100644 (file)
@@ -35,24 +35,8 @@ import java.util.Vector;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import net.sf.jabref.BibtexDatabase;
-import net.sf.jabref.BibtexEntry;
-import net.sf.jabref.BibtexEntryType;
-import net.sf.jabref.BibtexFields;
-import net.sf.jabref.BibtexString;
-import net.sf.jabref.BibtexStringComparator;
-import net.sf.jabref.CrossRefEntryComparator;
-import net.sf.jabref.CustomEntryType;
-import net.sf.jabref.FieldComparator;
-import net.sf.jabref.FieldComparatorStack;
-import net.sf.jabref.GUIGlobals;
-import net.sf.jabref.Globals;
-import net.sf.jabref.IdComparator;
-import net.sf.jabref.JabRefPreferences;
-import net.sf.jabref.MetaData;
+import net.sf.jabref.*;
 import net.sf.jabref.config.SaveOrderConfig;
-import ca.odell.glazedlists.BasicEventList;
-import ca.odell.glazedlists.SortedList;
 
 public class FileActions {
        
@@ -221,7 +205,7 @@ public class FileActions {
             // sorted as they appear on the screen.
             List<BibtexEntry> sorter = getSortedEntries(database, metaData, null, true);
 
-            FieldFormatter ff = new LatexFieldFormatter();
+            BibtexEntryWriter bibtexEntryWriter = new BibtexEntryWriter(new LatexFieldFormatter(), true);
 
             for (BibtexEntry be : sorter) {
                 exceptionCause = be;
@@ -247,7 +231,7 @@ public class FileActions {
                 }
 
                 if (write) {
-                    be.write(fw, ff, true);
+                    bibtexEntryWriter.write(be, fw);
                     fw.write(Globals.NEWLINE);
                 }
             }
@@ -404,14 +388,11 @@ public class FileActions {
             List<Comparator<BibtexEntry>> comparators = getSaveComparators(true, metaData);
 
             // Use glazed lists to get a sorted view of the entries:
-            BasicEventList<BibtexEntry> entryList = new BasicEventList<BibtexEntry>();
-            SortedList<BibtexEntry> sorter = new SortedList<BibtexEntry>(entryList, new FieldComparatorStack<BibtexEntry>(comparators));
+            List<BibtexEntry> sorter = new ArrayList<BibtexEntry>(bes.length);
+            Collections.addAll(sorter, bes);
+            Collections.sort(sorter, new FieldComparatorStack<BibtexEntry>(comparators));
 
-            if ((bes != null) && (bes.length > 0)) {
-                Collections.addAll(sorter, bes);
-            }
-
-            FieldFormatter ff = new LatexFieldFormatter();
+            BibtexEntryWriter bibtexEntryWriter = new BibtexEntryWriter(new LatexFieldFormatter(), true);
 
             for (BibtexEntry aSorter : sorter) {
                 be = (aSorter);
@@ -424,7 +405,7 @@ public class FileActions {
                     types.put(tp.getName(), tp);
                 }
 
-                be.write(fw, ff, true);
+                bibtexEntryWriter.write(be, fw);
                 fw.write(Globals.NEWLINE);
             }
 
@@ -514,10 +495,8 @@ public class FileActions {
             comparators = getSaveComparators(isSaveOperation, metaData);
         }
 
-        // Use glazed lists to get a sorted view of the entries:
         FieldComparatorStack<BibtexEntry> comparatorStack = new FieldComparatorStack<BibtexEntry>(comparators);
-        BasicEventList<BibtexEntry> entryList = new BasicEventList<BibtexEntry>();
-        SortedList<BibtexEntry> sorter = new SortedList<BibtexEntry>(entryList, comparatorStack);
+        List<BibtexEntry> sorter = new ArrayList<BibtexEntry>();
 
         if (keySet == null) {
             keySet = database.getKeySet();
@@ -530,6 +509,9 @@ public class FileActions {
                 sorter.add(database.getEntryById((i.next())));
             }
         }
+
+        Collections.sort(sorter, comparatorStack);
+
         return sorter;
     }
 
index 0fb9cce..254a5ad 100644 (file)
 */
 package net.sf.jabref.export;
 
-import java.util.Vector;
+import net.sf.jabref.*;
 
-import net.sf.jabref.BibtexFields;
-import net.sf.jabref.GUIGlobals;
-import net.sf.jabref.Globals;
-import net.sf.jabref.JabRefPreferences;
-import net.sf.jabref.Util;
+import java.util.Vector;
 
 public class LatexFieldFormatter implements FieldFormatter {
 
+    public static LatexFieldFormatter buildIgnoreHashes() {
+        return new LatexFieldFormatter(true);
+    }
+
     StringBuffer sb;
     int col; // First line usually starts about so much further to the right.
     final int STARTCOL = 4;
-    private boolean neverFailOnHashes = false;
 
-    public void setNeverFailOnHashes(boolean neverFailOnHashes) {
+    private final boolean neverFailOnHashes;
+
+    private final boolean resolveStringsAllFields;
+    private final char valueDelimitersZero;
+    private final char valueDelimitersOne;
+    private final boolean writefieldWrapfield;
+    private final String[] doNotResolveStringsFors;
+
+    public LatexFieldFormatter() {
+        this(true);
+    }
+
+    private LatexFieldFormatter(boolean neverFailOnHashes) {
         this.neverFailOnHashes = neverFailOnHashes;
+
+        this.resolveStringsAllFields = Globals.prefs.getBoolean("resolveStringsAllFields");
+        valueDelimitersZero = Globals.prefs.getValueDelimiters(0);
+        valueDelimitersOne = Globals.prefs.getValueDelimiters(1);
+        doNotResolveStringsFors = Globals.prefs.getStringArray("doNotResolveStringsFor");
+        writefieldWrapfield = Globals.prefs.getBoolean(JabRefPreferences.WRITEFIELD_WRAPFIELD);
     }
 
     public String format(String text, String fieldName)
             throws IllegalArgumentException {
-        if (text == null) return Globals.prefs.getValueDelimiters(0)
-                + "" + Globals.prefs.getValueDelimiters(1);
+
+        if (text == null) return valueDelimitersZero + "" + valueDelimitersOne;
 
         if (Globals.prefs.putBracesAroundCapitals(fieldName) && !Globals.BIBTEX_STRING.equals(fieldName)) {
             text = Util.putBracesAroundCapitals(text);
@@ -53,9 +70,10 @@ public class LatexFieldFormatter implements FieldFormatter {
         // If the field is non-standard, we will just append braces,
         // wrap and write.
         boolean resolveStrings = true;
-        if (Globals.prefs.getBoolean("resolveStringsAllFields")) {
+        if (resolveStringsAllFields) {
             // Resolve strings for all fields except some:
-            String[] exceptions = Globals.prefs.getStringArray("doNotResolveStringsFor");
+
+            String[] exceptions = doNotResolveStringsFors;
             for (String exception : exceptions) {
                 if (exception.equals(fieldName)) {
                     resolveStrings = false;
@@ -86,24 +104,26 @@ public class LatexFieldFormatter implements FieldFormatter {
                 throw new IllegalArgumentException("Curly braces { and } must be balanced.");
 
             sb = new StringBuffer(
-                    Globals.prefs.getValueDelimiters(0) + "");
+                    valueDelimitersZero + "");
             // No formatting at all for these fields, to allow custom formatting?
 //            if (Globals.prefs.getBoolean("preserveFieldFormatting"))
 //              sb.append(text);
 //            else
 //             currently, we do not do any more wrapping
-            if (Globals.prefs.getBoolean(JabRefPreferences.WRITEFIELD_WRAPFIELD)&&!Globals.prefs.isNonWrappableField(fieldName))
+            if (writefieldWrapfield && !Globals.prefs.isNonWrappableField(fieldName))
                 sb.append(Util.wrap2(text, GUIGlobals.LINE_LENGTH));
             else
                 sb.append(text);
 
-            sb.append(Globals.prefs.getValueDelimiters(1));
+            sb.append(valueDelimitersOne);
 
             return sb.toString();
         }
 
         sb = new StringBuffer();
-        int pivot = 0, pos1, pos2;
+        int pivot = 0;
+        int pos1;
+        int pos2;
         col = STARTCOL;
         // Here we assume that the user encloses any bibtex strings in #, e.g.:
         // #jan# - #feb#
@@ -156,10 +176,10 @@ public class LatexFieldFormatter implements FieldFormatter {
         }
 
         // currently, we do not add newlines and new formatting
-        if (Globals.prefs.getBoolean(JabRefPreferences.WRITEFIELD_WRAPFIELD)&&!Globals.prefs.isNonWrappableField(fieldName)) {
+        if (writefieldWrapfield && !Globals.prefs.isNonWrappableField(fieldName)) {
 //             introduce a line break to be read at the parser
-             return Util.wrap2(sb.toString(), GUIGlobals.LINE_LENGTH);//, but that lead to ugly .tex
-             
+            return Util.wrap2(sb.toString(), GUIGlobals.LINE_LENGTH);//, but that lead to ugly .tex
+
         } else
             return sb.toString();
 
@@ -171,7 +191,7 @@ public class LatexFieldFormatter implements FieldFormatter {
         /*sb.append("{");
         sb.append(text.substring(start_pos, end_pos));
         sb.append("}");*/
-        sb.append(Globals.prefs.getValueDelimiters(0));
+        sb.append(valueDelimitersZero);
         boolean escape = false, inCommandName = false, inCommand = false,
                 inCommandOption = false;
         int nestedEnvironments = 0;
@@ -236,7 +256,7 @@ public class LatexFieldFormatter implements FieldFormatter {
                 sb.append(c);
             escape = (c == '\\');
         }
-        sb.append(Globals.prefs.getValueDelimiters(1));
+        sb.append(valueDelimitersOne);
     }
 
     private void writeStringLabel(String text, int start_pos, int end_pos,
index 3d6609f..83e37e5 100644 (file)
 */
 package net.sf.jabref.export.layout.format;
 
-import net.sf.jabref.*;
-import net.sf.jabref.export.layout.*;
+import net.sf.jabref.MonthUtil;
+import net.sf.jabref.export.layout.LayoutFormatter;
 
 public class RisMonth implements LayoutFormatter {
-       
-       public String format(String s) {
-               if (s == null)
-                       return "";
-               s = s.toLowerCase();
-               if (Globals.MONTH_STRINGS.get(s) != null)
-                   s = Globals.MONTH_STRINGS.get(s).toLowerCase();
 
-               if (s.equals("january"))
-                   return "01";
-               else if (s.equals("february"))
-                   return "02";
-               else if (s.equals("march"))
-                   return "03";
-               else if (s.equals("april"))
-                   return "04";
-               else if (s.equals("may"))
-                   return "05";
-               else if (s.equals("june"))
-                   return "06";
-               else if (s.equals("july"))
-                   return "07";
-               else if (s.equals("august"))
-                   return "08";
-               else if (s.equals("august"))
-                   return "09";
-               else if (s.equals("september"))
-                   return "10";
-               else if (s.equals("december"))
-                   return "12";
-               else
-                   return s;
-       }
-       
+    public String format(String month) {
+        if (month == null)
+            return "";
+
+        MonthUtil.Month m = MonthUtil.getMonthByShortName(month);
+        if(m.isValid()) {
+            return m.twoDigitNumber;
+        } else {
+            return month.toLowerCase();
+        }
+    }
+
 }
index 53d859b..259bda3 100644 (file)
 */
 package net.sf.jabref.external;
 
-import java.io.File;
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URL;
-
-import javax.swing.JOptionPane;
-import javax.swing.SwingUtilities;
-
 import net.sf.jabref.*;
 import net.sf.jabref.gui.FileListEntry;
 import net.sf.jabref.gui.FileListEntryEditor;
 import net.sf.jabref.net.URLDownload;
 
+import javax.swing.*;
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+
 /**
  * This class handles the download of an external file. Typically called when the user clicks
  * the "Download" button in a FileListEditor shown in an EntryEditor.
@@ -74,7 +72,7 @@ public class DownloadExternalFile {
             url = new URL(res);
         } catch (MalformedURLException ex1) {
             JOptionPane.showMessageDialog(frame, Globals.lang("Invalid URL"),
-                Globals.lang("Download file"), JOptionPane.ERROR_MESSAGE);
+                    Globals.lang("Download file"), JOptionPane.ERROR_MESSAGE);
             return;
         }
 
@@ -91,20 +89,24 @@ public class DownloadExternalFile {
     public void download(URL url, final DownloadCallback callback) throws IOException {
 
         String res = url.toString();
-        URLDownload udl = null;
+
+
+        String mimeType;
 
         // First of all, start the download itself in the background to a temporary file:
         final File tmp = File.createTempFile("jabref_download", "tmp");
         tmp.deleteOnExit();
+
+        URLDownload udl = URLDownload.buildMonitoredDownload(frame, url);
+
         //long time = System.currentTimeMillis();
         try {
-            udl = new URLDownload(frame, url, tmp);
             // TODO: what if this takes long time?
             // TODO: stop editor dialog if this results in an error:
-            udl.openConnectionOnly(); // Read MIME type
+            mimeType = udl.determineMimeType(); // Read MIME type
         } catch (IOException ex) {
-            JOptionPane.showMessageDialog(frame, Globals.lang("Invalid URL")+": "
-                    + ex.getMessage(), Globals.lang("Download file"),
+            JOptionPane.showMessageDialog(frame, Globals.lang("Invalid URL") + ": "
+                            + ex.getMessage(), Globals.lang("Download file"),
                     JOptionPane.ERROR_MESSAGE);
             Globals.logger("Error while downloading " + "'" + res + "'");
             return;
@@ -116,15 +118,15 @@ public class DownloadExternalFile {
             public void run() {
 
                 try {
-                    udlF.download();
+                    udlF.downloadToFile(tmp);
                 } catch (IOException e2) {
                     dontShowDialog = true;
                     if ((editor != null) && (editor.isVisible()))
                         editor.setVisible(false, false);
-                    JOptionPane.showMessageDialog(frame, Globals.lang("Invalid URL")+": "
-                            + e2.getMessage(), Globals.lang("Download file"),
+                    JOptionPane.showMessageDialog(frame, Globals.lang("Invalid URL") + ": "
+                                    + e2.getMessage(), Globals.lang("Download file"),
                             JOptionPane.ERROR_MESSAGE);
-                    Globals.logger("Error while downloading " + "'" + urlF.toString()+ "'");
+                    Globals.logger("Error while downloading " + "'" + urlF.toString() + "'");
                     return;
                 }
 
@@ -138,18 +140,17 @@ public class DownloadExternalFile {
         }).start();
 
         ExternalFileType suggestedType = null;
-        if (udl.getMimeType() != null) {
-            System.out.println("mimetype:"+udl.getMimeType());
-            suggestedType = Globals.prefs.getExternalFileTypeByMimeType(udl.getMimeType());
+        if (mimeType != null) {
+            System.out.println("mimetype:" + mimeType);
+            suggestedType = Globals.prefs.getExternalFileTypeByMimeType(mimeType);
             /*if (suggestedType != null)
                 System.out.println("Found type '"+suggestedType.getName()+"' by MIME type '"+udl.getMimeType()+"'");*/
         }
         // Then, while the download is proceeding, let the user choose the details of the file:
         String suffix;
         if (suggestedType != null) {
-            suffix = suggestedType.getExtension();   
-        }
-        else {
+            suffix = suggestedType.getExtension();
+        } else {
             // If we didn't find a file type from the MIME type, try based on extension:
             suffix = getSuffix(res);
             suggestedType = Globals.prefs.getExternalFileTypeByExt(suffix);
@@ -181,8 +182,8 @@ public class DownloadExternalFile {
                 }
                 if (f.exists()) {
                     return JOptionPane.showConfirmDialog
-                        (frame, "'"+f.getName()+"' "+Globals.lang("exists. Overwrite file?"),
-                        Globals.lang("Download file"), JOptionPane.OK_CANCEL_OPTION)
+                            (frame, "'" + f.getName() + "' " + Globals.lang("exists. Overwrite file?"),
+                                    Globals.lang("Download file"), JOptionPane.OK_CANCEL_OPTION)
                             == JOptionPane.OK_OPTION;
                 } else
                     return true;
@@ -199,7 +200,7 @@ public class DownloadExternalFile {
             String dirPrefix;
             if (directory != null) {
                 if (!directory.endsWith(System.getProperty("file.separator")))
-                    dirPrefix = directory+System.getProperty("file.separator");
+                    dirPrefix = directory + System.getProperty("file.separator");
                 else
                     dirPrefix = directory;
             } else
@@ -225,8 +226,7 @@ public class DownloadExternalFile {
             }
 
             tmp.delete();
-        }
-        else {
+        } else {
             // Cancelled. Just delete the temp file:
             if (downloadFinished)
                 tmp.delete();
@@ -237,16 +237,17 @@ public class DownloadExternalFile {
     /**
      * Construct a File object pointing to the file linked, whether the link is
      * absolute or relative to the main directory.
+     *
      * @param directory The main directory.
-     * @param link The absolute or relative link.
+     * @param link      The absolute or relative link.
      * @return The expanded File.
      */
     private File expandFilename(String directory, String link) {
         File toFile = new File(link);
         // If this is a relative link, we should perhaps append the directory:
-        String dirPrefix = directory+System.getProperty("file.separator");
+        String dirPrefix = directory + System.getProperty("file.separator");
         if (!toFile.isAbsolute()) {
-            toFile = new File(dirPrefix+link);
+            toFile = new File(dirPrefix + link);
         }
         return toFile;
     }
@@ -263,7 +264,7 @@ public class DownloadExternalFile {
     }
 
     public String getSuggestedFileName(String suffix) {
-        
+
         String plannedName = bibtexKey;
         if (suffix.length() > 0)
             plannedName += "." + suffix;
@@ -296,8 +297,8 @@ public class DownloadExternalFile {
         try {
             // Try to strip the query string, if any, to get the correct suffix:
             URL url = new URL(link);
-            if ((url.getQuery() != null) && (url.getQuery().length() < link.length()-1)) {
-                strippedLink = link.substring(0, link.length()-url.getQuery().length()-1);
+            if ((url.getQuery() != null) && (url.getQuery().length() < link.length() - 1)) {
+                strippedLink = link.substring(0, link.length() - url.getQuery().length() - 1);
             }
         } catch (MalformedURLException e) {
             // Don't report this error, since this getting the suffix is a non-critical
@@ -311,8 +312,7 @@ public class DownloadExternalFile {
         else suffix = strippedLink.substring(index + 1);
         if (Globals.prefs.getExternalFileTypeByExt(suffix) != null) {
             return suffix;
-        }
-        else {
+        } else {
             // If the suffix doesn't seem to give any reasonable file type, try
             // with the non-stripped link:
             index = link.lastIndexOf('.');
@@ -324,9 +324,8 @@ public class DownloadExternalFile {
                     return "";
                 else
                     return suffix; // return the first one we found, anyway.
-            }
-            else {
-                 // Check if there are path separators in the suffix - if so, it is definitely
+            } else {
+                // Check if there are path separators in the suffix - if so, it is definitely
                 // not a proper suffix, so we should give up:
                 if (link.substring(index + 1).indexOf('/') > 0)
                     return "";
index 7f2d79a..c6af65d 100644 (file)
@@ -36,17 +36,7 @@ import javax.swing.JPanel;
 import javax.swing.SwingUtilities;
 import javax.xml.transform.TransformerException;
 
-import net.sf.jabref.BibtexDatabase;
-import net.sf.jabref.BibtexEntry;
-import net.sf.jabref.BibtexFields;
-import net.sf.jabref.EntryEditor;
-import net.sf.jabref.FieldEditor;
-import net.sf.jabref.Globals;
-import net.sf.jabref.JabRefFrame;
-import net.sf.jabref.MetaData;
-import net.sf.jabref.OpenFileFilter;
-import net.sf.jabref.UrlDragDrop;
-import net.sf.jabref.Util;
+import net.sf.jabref.*;
 import net.sf.jabref.gui.FileDialogs;
 import net.sf.jabref.net.URLDownload;
 import net.sf.jabref.util.XMPUtil;
@@ -336,9 +326,8 @@ public class ExternalFilePanel extends JPanel {
 
                                        URL url = new URL(res);
 
-                                       URLDownload udl = new URLDownload(parent, url, file);
                                        try {
-                                               udl.download();
+                                               URLDownload.buildMonitoredDownload(parent, url).downloadToFile(file);
                                        } catch (IOException e2) {
                                                JOptionPane.showMessageDialog(parent, Globals.lang("Invalid URL")+": "
                                                        + e2.getMessage(), Globals.lang("Download file"),
@@ -446,8 +435,8 @@ public class ExternalFilePanel extends JPanel {
                 String[] dirs = metaData.getFileDirectory(fieldName);
                 Collections.addAll(list, dirs);
 
-                               String found = Util.findPdf(getEntry(), fieldName, list
-                                       .toArray(new String[list.size()]));// , off);
+                               String found = UtilFindFiles.findPdf(getEntry(), fieldName, list
+                                               .toArray(new String[list.size()]));// , off);
                                         
                                 
                                // To activate findFile:
index 7d16457..1a4d2be 100644 (file)
@@ -97,16 +97,12 @@ public class FindFullText {
                         // Check the MIME type of this URL to see if it is a PDF. If not,
                         // it could be because the user doesn't have access:
                         try {
-                            URLDownload udl = new URLDownload(null, result, null);
-                            udl.openConnectionOnly();
-
-                            String mimeType = udl.getMimeType();
+                            String mimeType = new URLDownload(result).determineMimeType();
                             if ((mimeType != null) && (mimeType.toLowerCase().equals("application/pdf"))) {
                                 return new FindResult(result, url);
                             }
                             else {
-                                udl = new URLDownload(null, result, new File("page.html"));
-                                udl.download();
+                                new URLDownload(result).downloadToFile(new File("page.html"));
                                 return new FindResult(WRONG_MIME_TYPE, url);
                             }
                         } catch (IOException ex) {
index b022b02..88a2869 100644 (file)
@@ -19,9 +19,22 @@ import java.awt.BorderLayout;
 import java.awt.Component;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
-import java.util.*;
-
-import javax.swing.*;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+
+import javax.swing.BorderFactory;
+import javax.swing.DefaultListModel;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JScrollPane;
+import javax.swing.ListCellRenderer;
+import javax.swing.ListSelectionModel;
 
 import net.sf.jabref.GUIGlobals;
 import net.sf.jabref.Globals;
@@ -33,9 +46,9 @@ import com.jgoodies.forms.builder.ButtonBarBuilder;
  */
 public class IconSelection extends JDialog {
 
-    JList<JLabel> icons;
+       JList icons;
     List<String> iconKeys;
-    DefaultListModel<JLabel> listModel;
+       DefaultListModel listModel;
     JButton ok = new JButton(Globals.lang("Ok")),
         cancel = new JButton(Globals.lang("Cancel"));
     private boolean okPressed = false;
@@ -88,12 +101,12 @@ public class IconSelection extends JDialog {
 
         }
 
-        listModel = new DefaultListModel<JLabel>();
-        icons = new JList<JLabel>(listModel);
+               listModel = new DefaultListModel();
+               icons = new JList(listModel);
         for (ImageIcon anIconSet : iconSet) {
             listModel.addElement(new JLabel(anIconSet));
         }
-        class MyRenderer implements ListCellRenderer<JLabel> {
+               class MyRenderer implements ListCellRenderer {
             JLabel comp = new JLabel();
             public MyRenderer() {
                 comp.setOpaque(true);
@@ -101,11 +114,11 @@ public class IconSelection extends JDialog {
                 comp.setHorizontalAlignment(JLabel.CENTER);
             }
 
-            public Component getListCellRendererComponent(JList<? extends JLabel> list, JLabel value, int i,
+                       public Component getListCellRendererComponent(JList list, Object value, int i,
                                                           boolean isSelected, 
                                                           boolean hasFocus) {
                 comp.setText(null);
-                comp.setIcon(value.getIcon());
+                               comp.setIcon(((JLabel) value).getIcon());
                 if (isSelected) {
                     comp.setBackground(list.getSelectionBackground());
                     comp.setForeground(list.getSelectionForeground());
index 9b50fad..39923af 100644 (file)
@@ -515,7 +515,7 @@ public class EntryTableTransferHandler extends TransferHandler {
                // System.out.println("Import url: " + dropLink.toString());
                // System.out.println("Temp file: "+tmpfile.getAbsolutePath());
 
-               new URLDownload(entryTable, dropLink, tmpfile).download();
+               URLDownload.buildMonitoredDownload(entryTable, dropLink).downloadToFile(tmpfile);
 
                // Import into new if entryTable==null, otherwise into current database:
                ImportMenuItem importer = new ImportMenuItem(frame, (entryTable == null));
index e371534..bf5b991 100644 (file)
@@ -344,8 +344,8 @@ public class KeywordGroup extends AbstractGroup implements SearchRule {
                 : Globals.lang(
                 "This group contains entries whose <b>%0</b> field contains the keyword <b>%1</b>",
                 field, Util.quoteForHTML(expr))) + " (" + (caseSensitive ? Globals.lang("case sensitive")
-                : Globals.lang("case insensitive")) + "). " + (regExp ? Globals.lang(
-                "Entries cannot be manually assigned to or removed from this group.")
+                : Globals.lang("case insensitive")) + "). " + (regExp ?
+                Globals.lang("Entries cannot be manually assigned to or removed from this group.")
                 : Globals.lang(
                 "Additionally, entries whose <b>%0</b> field does not contain "
                         + "<b>%1</b> can be assigned manually to this group by selecting them "
index 2d17841..a86257b 100644 (file)
@@ -30,15 +30,7 @@ import javax.swing.event.ChangeListener;
 
 import com.jgoodies.forms.factories.Borders;
 
-import net.sf.jabref.AbstractWorker;
-import net.sf.jabref.BasePanel;
-import net.sf.jabref.BibtexEntry;
-import net.sf.jabref.CheckBoxMessage;
-import net.sf.jabref.GUIGlobals;
-import net.sf.jabref.Globals;
-import net.sf.jabref.ImportSettingsTab;
-import net.sf.jabref.JabRefFrame;
-import net.sf.jabref.Util;
+import net.sf.jabref.*;
 import net.sf.jabref.external.ExternalFileType;
 import net.sf.jabref.imports.HTMLConverter;
 import net.sf.jabref.imports.CaseKeeper;
@@ -396,10 +388,10 @@ public class CleanUpAction extends AbstractWorker {
                     return;
                 }
                String newValue = oldValue;
-               int month = Globals.ParseMonthToInteger(oldValue);
-               if(month > 0)
+               MonthUtil.Month month = MonthUtil.getMonth(oldValue);
+               if(month.isValid())
                {
-                       newValue = "#" + Globals.MONTHS[month - 1] + '#';
+                       newValue = month.bibtexFormat;
                }
 
        if (!oldValue.equals(newValue)) {
index 0e0aa81..b9edce6 100644 (file)
@@ -61,7 +61,7 @@ public class DatabasePropertiesDialog extends JDialog {
 
     MetaData metaData;
     BasePanel panel = null;
-    JComboBox<String> encoding;
+       JComboBox encoding;
     JButton ok, cancel;
     JTextField fileDir = new JTextField(40),
  fileDirIndv = new JTextField(40),
@@ -73,7 +73,7 @@ public class DatabasePropertiesDialog extends JDialog {
     
        private JRadioButton saveAsConfiguredGlobally, saveInOriginalOrder,
                        saveInSpecifiedOrder;
-    private JComboBox<String> savePriSort, saveSecSort, saveTerSort;
+       private JComboBox savePriSort, saveSecSort, saveTerSort;
     private JTextField savePriField, saveSecField, saveTerField;
     private JCheckBox savePriDesc, saveSecDesc, saveTerDesc;
        
@@ -84,7 +84,7 @@ public class DatabasePropertiesDialog extends JDialog {
 
     public DatabasePropertiesDialog(JFrame parent) {
         super(parent, Globals.lang("Database properties"), true);
-        encoding = new JComboBox<String>(Globals.ENCODINGS);
+               encoding = new JComboBox(Globals.ENCODINGS);
         ok = new JButton(Globals.lang("Ok"));
         cancel = new JButton(Globals.lang("Cancel"));
         init(parent);
@@ -238,9 +238,9 @@ public class DatabasePropertiesDialog extends JDialog {
                v.add(BibtexFields.KEY_FIELD);
                Collections.sort(v);
                String[] allPlusKey = v.toArray(new String[v.size()]);
-               savePriSort = new JComboBox<String>(allPlusKey);
-               saveSecSort = new JComboBox<String>(allPlusKey);
-               saveTerSort = new JComboBox<String>(allPlusKey);
+               savePriSort = new JComboBox(allPlusKey);
+               saveSecSort = new JComboBox(allPlusKey);
+               saveTerSort = new JComboBox(allPlusKey);
                
                savePriSort.insertItemAt(Globals.lang("<select>"), 0);
                saveSecSort.insertItemAt(Globals.lang("<select>"), 0);
index 461c1c7..83ef47b 100644 (file)
@@ -85,7 +85,7 @@ public class EntryTypeList extends FieldSetComponent implements ListSelectionLis
         if (selected.length > 0)
             changesMade = true;
         for (int i=0; i<selected.length; i++) {
-            String typeName = listModel.get(selected[selected.length-1-i]);
+                       String typeName = (String) listModel.get(selected[selected.length - 1 - i]);
             BibtexEntryType type = BibtexEntryType.getType(typeName);
             
             // If it is a custom entry type, we can remove it. If type == null, it means
index afd7fd2..9515ce5 100644 (file)
@@ -53,10 +53,10 @@ import net.sf.jabref.Util;
 public class FieldSetComponent extends JPanel implements ActionListener {
 
     protected Set<ActionListener> additionListeners = new HashSet<ActionListener>();
-    protected JList<String> list;
+       protected JList list;
     protected JScrollPane sp = null;
-    protected DefaultListModel<String> listModel;
-    protected JComboBox<String> sel;
+       protected DefaultListModel listModel;
+       protected JComboBox sel;
     protected JTextField input;
     protected JLabel title = null;
     protected JButton add, remove, up=null, down=null;
@@ -86,13 +86,13 @@ public class FieldSetComponent extends JPanel implements ActionListener {
         this.forceLowerCase = forceLowerCase;                
         add = new JButton(Globals.lang(addText));
         remove = new JButton(Globals.lang(removeText));
-        listModel = new DefaultListModel<String>();
+               listModel = new DefaultListModel();
         if (title != null)
             this.title = new JLabel(title);
         
         for (String field : fields)
             listModel.addElement(field);
-        list = new JList<String>(listModel);
+               list = new JList(listModel);
         list.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
         // Set up GUI:
         add.addActionListener(this);
@@ -149,7 +149,7 @@ public class FieldSetComponent extends JPanel implements ActionListener {
         con.gridwidth = 3;
         con.weightx = 1;
         if (preset != null) {
-            sel = new JComboBox<String>(preset.toArray(new String[preset.size()]));
+                       sel = new JComboBox(preset.toArray(new String[preset.size()]));
             sel.setEditable(true);
             //sel.addActionListener(this);
             gbl.setConstraints(sel, con);
@@ -205,7 +205,7 @@ public class FieldSetComponent extends JPanel implements ActionListener {
     }
     
     public void setFields(List<String> fields) {
-        DefaultListModel<String> newListModel = new DefaultListModel<String>();
+               DefaultListModel newListModel = new DefaultListModel();
         for (String field : fields)
             newListModel.addElement(field);
         this.listModel = newListModel;
@@ -275,9 +275,9 @@ public class FieldSetComponent extends JPanel implements ActionListener {
      */
        public List<String> getFields() {
                ArrayList<String> res = new ArrayList<String>(listModel.getSize());
-               Enumeration<String> elements = listModel.elements();
+               Enumeration elements = listModel.elements();
                while (elements.hasMoreElements()) {
-                       res.add(elements.nextElement());
+                       res.add((String) elements.nextElement());
                }
                return res;
     }
@@ -313,7 +313,7 @@ public class FieldSetComponent extends JPanel implements ActionListener {
         int oldIdx = list.getSelectedIndex();
         if  (oldIdx < 0)
             return;
-        String o = listModel.get(oldIdx);
+               String o = (String) listModel.get(oldIdx);
         // Compute the new index:
         int newInd = Math.max(0, Math.min(listModel.size()-1, oldIdx+dy));
         listModel.remove(oldIdx);
index 5757132..8c260b8 100644 (file)
 package net.sf.jabref.gui;
 
 import java.awt.BorderLayout;
-import java.awt.event.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
 import java.io.File;
 import java.io.IOException;
 import java.util.regex.Pattern;
 
-import javax.swing.*;
+import javax.swing.AbstractAction;
+import javax.swing.ActionMap;
+import javax.swing.BorderFactory;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.InputMap;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JDialog;
+import javax.swing.JFileChooser;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JProgressBar;
+import javax.swing.JTextField;
+import javax.swing.SwingUtilities;
 import javax.swing.event.DocumentEvent;
 import javax.swing.event.DocumentListener;
 
@@ -57,7 +76,7 @@ public class FileListEntryEditor {
             open = new JButton(Globals.lang("Open"));
 
 
-    JComboBox<ExternalFileType> types;
+       JComboBox types;
     JProgressBar prog = new JProgressBar(JProgressBar.HORIZONTAL);
     JLabel downloadLabel = new JLabel(Globals.lang("Downloading..."));
     ConfirmCloseFileListEntryEditor externalConfirm = null;
@@ -92,7 +111,7 @@ public class FileListEntryEditor {
                 okPressed = true;
             }
         };
-        types = new JComboBox<ExternalFileType>();
+               types = new JComboBox();
         types.addItemListener(new ItemListener() {
             public void itemStateChanged(ItemEvent itemEvent) {
                 if (!okDisabledExternally)
@@ -265,7 +284,7 @@ public class FileListEntryEditor {
         link.setText(entry.getLink());
         //if (link.getText().length() > 0)
         //    checkExtension();
-        types.setModel(new DefaultComboBoxModel<ExternalFileType>(Globals.prefs.getExternalFileTypeSelection()));
+               types.setModel(new DefaultComboBoxModel(Globals.prefs.getExternalFileTypeSelection()));
         types.setSelectedIndex(-1);
         // See what is a reasonable selection for the type combobox:
         if ((entry.getType() != null) && !(entry.getType() instanceof UnknownExternalFileType))
index f3ebc03..bf56b7d 100644 (file)
@@ -328,6 +328,9 @@ public class MainTable extends JTable {
         return sortedForGrouping.get(row);
     }
 
+    /**
+     * @return the return value is never null
+     */
     public BibtexEntry[] getSelectedEntries() {
         final BibtexEntry[] BE_ARRAY = new BibtexEntry[0];
         return getSelected().toArray(BE_ARRAY);
@@ -472,6