commit 0e6a3ac40427ec3107cb88aa678fbe92473e7d45
Author: Juergen Spitzmueller <sp...@lyx.org>
Date:   Fri Dec 30 16:22:08 2016 +0100

    Disentangle CiteEngines and Modules
    
    These two are different beasts and thus should be handled differently.
---
 lib/Makefile.am                    |    9 +-
 lib/chkconfig.ltx                  |    1 +
 lib/citeengines/basic.citeengine   |   43 ++++++
 lib/citeengines/jurabib.citeengine |  105 ++++++++++++++
 lib/citeengines/natbib.citeengine  |  106 ++++++++++++++
 lib/configure.py                   |  131 +++++++++++++++++-
 lib/layouts/basic.module           |   44 ------
 lib/layouts/jurabib.module         |  106 --------------
 lib/layouts/natbib.module          |  107 --------------
 po/Rules-lyx                       |    2 +-
 po/lyx_pot.py                      |    7 +
 src/BufferParams.cpp               |    5 +-
 src/CiteEnginesList.cpp            |  280 ++++++++++++++++++++++++++++++++++++
 src/CiteEnginesList.h              |  156 ++++++++++++++++++++
 src/LyX.cpp                        |    8 +-
 src/Makefile.am                    |    2 +
 src/TextClass.cpp                  |   40 +++++
 src/TextClass.h                    |    3 +
 src/tex2lyx/Makefile.am            |    1 +
 src/tex2lyx/tex2lyx.cpp            |    3 +-
 20 files changed, 891 insertions(+), 268 deletions(-)

diff --git a/lib/Makefile.am b/lib/Makefile.am
index ee7e2b1..36c9c0c 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -2107,7 +2107,6 @@ dist_layouts_DATA =\
        layouts/arab-article.layout \
        layouts/article.layout \
        layouts/article-beamer.layout \
-       layouts/basic.module \
        layouts/beamer.layout \
        layouts/beamerposter.layout \
        layouts/bicaption.module \
@@ -2185,7 +2184,6 @@ dist_layouts_DATA =\
        layouts/jsarticle.layout \
        layouts/jsbook.layout \
        layouts/jss.layout \
-       layouts/jurabib.module \
        layouts/kluwer.layout \
        layouts/knitr.module \
        layouts/latex8.layout \
@@ -2205,7 +2203,6 @@ dist_layouts_DATA =\
        layouts/mwart.layout \
        layouts/mwbk.layout \
        layouts/mwrep.layout \
-       layouts/natbib.module \
        layouts/natbibapa.module \
        layouts/noweb.module \
        layouts/numarticle.inc \
@@ -2302,6 +2299,12 @@ dist_layouts_DATA =\
        layouts/tufte-handout.layout \
        layouts/varwidth.module
 
+citeenginesdir = $(pkgdatadir)/citeengines
+dist_citeengines_DATA = \
+       citeengines/basic.citeengine \
+        citeengines/jurabib.citeengine \
+        citeengines/natbib.citeengine
+
 scriptsdir = $(pkgdatadir)/scripts
 dist_scripts_DATA = \
        scripts/bash_completion \
diff --git a/lib/chkconfig.ltx b/lib/chkconfig.ltx
index 140014a..9daca8f 100644
--- a/lib/chkconfig.ltx
+++ b/lib/chkconfig.ltx
@@ -492,6 +492,7 @@
 % configure script.
 \input{chklayouts}
 \input{chkmodules}
+\input{chkciteengines}
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %%%%% END ACTUAL CONFIGURATION INSPECTION CODE %%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/citeengines/basic.citeengine b/lib/citeengines/basic.citeengine
new file mode 100644
index 0000000..dc4941b
--- /dev/null
+++ b/lib/citeengines/basic.citeengine
@@ -0,0 +1,43 @@
+# \DeclareLyXCiteEngine{BibTeX (basic)}
+# DescriptionBegin
+#   Use the basic citation capabilities provided by plain LaTeX.
+# DescriptionEnd
+# Excludes: jurabib | natbib
+
+# Author: Julien Rioux <jri...@lyx.org>
+
+Format 62
+
+CiteEngineType default
+DefaultBiblio  plain
+
+CiteEngine default
+       cite[]
+       nocite
+End
+
+CiteFormat default
+       # translatable bits
+       _notcited not cited
+       _addtobib Add to bibliography only.
+
+       # macros
+       !open [
+       !sep ,
+       !close ]
+
+       !startlink {!<a href='#LyXCite-%clean:key%'>!}
+       !endlink {!</a>!}
+
+       !cite 
%!startlink%{%label%[[%label%]][[{%numericallabel%[[%numericallabel%]][[#%key%]]}]]}%!endlink%%!nextcite%
+
+       !nextcite {%next%[[%!sep% %!cite%]]}
+       !nexthashkey {%next%[[%!sep% #%key%%!nexthashkey%]]}
+       !nextkey {%next%[[%!sep% %key%%!nextkey%]]}
+
+       !textafter {%textafter%[[, %textafter%]]}
+
+       # cite styles
+       cite %!open%{%dialog%[[#ID]][[%!cite%]]}%!textafter%%!close%
+       nocite {%dialog%[[%_addtobib%]][[%key%%!nextkey% (%_notcited%)]]}
+End
diff --git a/lib/citeengines/jurabib.citeengine 
b/lib/citeengines/jurabib.citeengine
new file mode 100644
index 0000000..13bbc6f
--- /dev/null
+++ b/lib/citeengines/jurabib.citeengine
@@ -0,0 +1,105 @@
+# \DeclareLyXCiteEngine[jurabib.sty]{Jurabib}
+# DescriptionBegin
+#   Loads the LaTeX package jurabib, a citation engine. Jurabib supports 
annotations,
+#   author-year style citations and hyphenation patterns for bibliography 
entries in
+#   English, German, French, Dutch, Spanish and Italian.
+# DescriptionEnd
+# Excludes: basic | natbib
+
+# Author: Julien Rioux <jri...@lyx.org>
+
+Format 62
+
+Requires jurabib
+
+CiteEngineType authoryear
+DefaultBiblio  jurabib
+
+# FIXME: support for these jurabib styles (fileformat)
+# citefield []{}
+# footcite [][]
+# footcitetitle [][]
+# footcitet [][]
+# footcitep [][]
+# footcitealt [][]
+# footcitealp [][]
+# footciteauthor [][]
+# footciteyear [][]
+# footciteyearpar [][]
+# footfullcite [][]
+
+CiteEngine authoryear
+       # \cite* is not implemented: use \cite instead, it's the same
+       cite [][]
+       citetitle [][]
+       citet [][]
+       citep [][]
+       citealt [][]
+       citealp [][]
+       citeauthor [][]
+       citeyear [][]
+       citeyearpar [][]
+       fullcite [][]
+       nocite
+End
+
+CiteFormat authoryear
+       # translatable bits
+       _notcited not cited
+       _addtobib Add to bibliography only.
+       _fullcite bibliography entry
+       _bibentry Bibliography entry.
+       _before before
+       _shorttitle short title
+
+       # macros
+       !open (
+       !sep ;
+       !close )
+
+       !startlink {!<a href='#LyXCite-%clean:key%'>!}
+       !endlink {!</a>!}
+
+       !cite 
%!startlink%%!shortauthor%%!endlink%%!textbefore2%%!textafter2%%!nextcite%
+       !citetitle 
%!startlink%%!shortauthor%%!endlink%%!textbefore2%%!shorttitle%%!textafter2%%!nextcitetitle%
+       !citet %!textbefore%%!startlink%%!shortauthor%%!endlink% 
%!open%%!year%%!textafter%%!close%%!nextcitet%
+       !citep %!open%%!citealp%%!close%
+       !citealt %!textbefore%%!startlink%%!shortauthor% 
%!year%%!endlink%%!textafter%%!nextcitealt%
+       !citealp %!textbefore%%!startlink%%!shortauthor%, 
%!year%%!endlink%%!textafter%%!nextcitealp%
+       !citeauthor 
%!textbefore%%!startlink%%!shortauthor%%!endlink%%!textafter%%!nextauthor%
+       !citeyear 
%!textbefore%%!startlink%%!year%%!endlink%%!textafter%%!nextyear%
+       !citeyearpar 
%!textbefore%%!open%%!startlink%%!year%%!endlink%%!close%%!textafter%%!nextyearpar%
+       !fullcite {%textbefore%[[%textbefore% in: ]]}%bibentry%{%textafter%[[ 
%textafter%]]}%!nextfullcite%
+
+       !nextcite {%next%[[%!sep% 
%!startlink%%!shortauthor%%!endlink%%!textafter2%%!nextcite%]]}
+       !nextcitetitle {%next%[[%!sep% 
%!startlink%%!shortauthor%%!endlink%%!shorttitle%%!textafter2%%!nextcitetitle%]]}
+       !nextcitet {%next%[[%!sep% %!citet%]]}
+       !nextcitealt {%next%[[%!sep% %!citealt%]]}
+       !nextcitealp {%next%[[%!sep% %!citealp%]]}
+       !nextauthor {%next%[[%!sep% %!citeauthor%]]}
+       !nextyear {%next%[[%!sep% %!citeyear%]]}
+       !nextyearpar {%next%[[%!sep% %!citeyearpar%]]}
+       !nextfullcite {%next%[[%!sep% %bibentry%{%textafter%[[ 
%textafter%]]}%!nextfullcite%]]}
+       !nextkey {%next%[[%!sep% %key%%!nextkey%]]}
+
+       !shortauthor {%shortauthor%[[%shortauthor%]][[??]]}
+       !shorttitle {%shorttitle%[[ %shorttitle%]][[{%dialog%[[ 
<%_shorttitle%>]]}]]}
+       !textbefore {%textbefore%[[%textbefore% ]]}
+       !textbefore2 
{%textbefore%[[/%textbefore%]][[{%dialog%[[/<%_before%>]]}]]}
+       !textafter {%textafter%[[, %textafter%]]}
+       !textafter2 {%textafter%[[ %textafter%]]}
+       !year {%year%[[%year%]][[??]]}{%modifier%[[%modifier%]]}
+
+       # cite styles
+       cite %!cite%
+       citetitle %!citetitle%
+       citet %!citet%
+       citep %!citep%
+       citealt %!citealt%
+       citealp %!citealp%
+       citeauthor %!citeauthor%
+       citeyear %!citeyear%
+       citeyearpar %!citeyearpar%
+       fullcite 
{%dialog%[[%_bibentry%]][[{%label%[[%!fullcite%]][[%key%%!nextkey% 
(%_fullcite%)]]}]]}
+       nocite {%dialog%[[%_addtobib%]][[%key%%!nextkey% (%_notcited%)]]}
+End
diff --git a/lib/citeengines/natbib.citeengine 
b/lib/citeengines/natbib.citeengine
new file mode 100644
index 0000000..63bf1cb
--- /dev/null
+++ b/lib/citeengines/natbib.citeengine
@@ -0,0 +1,106 @@
+# \DeclareLyXCiteEngine[natbib.sty]{Natbib}
+# DescriptionBegin
+#   Loads the LaTeX package natbib, a citation engine. Natbib supports
+#   both author-year and numerical styles for citations, automatic sorting
+#   and merging of numerical citations, annotations, capitalization of the
+#   `van' part of author names, shortened and full author lists, and more.
+# DescriptionEnd
+# Excludes: basic | jurabib
+
+# Author: Julien Rioux <jri...@lyx.org>
+
+Format 62
+
+Requires natbib
+
+CiteEngineType authoryear|numerical
+DefaultBiblio  plainnat
+
+CiteEngine authoryear
+       Citet*[][]
+       Citep*[][]
+       Citealt*[][]
+       Citealp*[][]
+       Citeauthor*[]
+       citeyear[]
+       citeyearpar[][]
+       nocite
+End
+
+CiteEngine numerical
+       Citep*[][]
+       Citealp*[][]
+       Citet*[][]
+       Citealt*[][]
+       Citeauthor*
+       citeyearpar[][]
+       citeyear
+       nocite
+End
+
+CiteFormat default
+       # translatable bits
+       _notcited not cited
+       _addtobib Add to bibliography only.
+
+       # macros
+       !startlink {!<a href='#LyXCite-%clean:key%'>!}
+       !endlink {!</a>!}
+
+       !nextauthor {%next%[[%!sep% 
%!startlink%%!abbrvauthor%%!endlink%%!nextauthor%]]}
+       !nextkey {%next%[[%!sep% %key%%!nextkey%]]}
+       !nextyear {%next%[[%!sep% %!startlink%%!year%%!endlink%%!nextyear%]]}
+
+       !abbrvauthor {%abbrvauthor%[[%abbrvauthor%]][[??]]}
+       !textbefore {%textbefore%[[%textbefore% ]]}
+       !textafter {%textafter%[[, %textafter%]]}
+       !year {%year%[[%year%]][[??]]}{%modifier%[[%modifier%]]}
+
+       # cite styles
+       citet %!citet%%!textafter%%!close%
+       citealt %!citealt%%!textafter%
+       citeyearpar 
%!open%%!textbefore%%!startlink%%!year%%!endlink%%!nextyear%%!textafter%%!close%
+       nocite {%dialog%[[%_addtobib%]][[%key%%!nextkey% (%_notcited%)]]}
+End
+
+CiteFormat authoryear
+       !open (
+       !sep ;
+       !close )
+
+       !citet %!startlink%%!abbrvauthor%%!endlink% 
%!open%%!textbefore%%!year%%!nextcitet%
+       !citealt %!startlink%%!abbrvauthor% 
%!textbefore%%!year%%!endlink%%!nextcitealt%
+       !citealp %!startlink%%!abbrvauthor%, %!year%%!endlink%%!nextcitealp%
+
+       !nextcitet {%next%[[%!close%%!sep% %!citet%]]}
+       !nextcitealt {%next%[[%!sep% %!citealt%]]}
+       !nextcitealp {%next%[[%!sep% %!citealp%]]}
+
+       cite %!citet%%!textafter%%!close%
+       citep %!open%%!textbefore%%!citealp%%!textafter%%!close%
+       citealp %!textbefore%%!citealp%%!textafter%
+       citeauthor %!startlink%%!abbrvauthor%%!endlink%%!nextauthor%%!textafter%
+       citeyear %!startlink%%!year%%!endlink%%!nextyear%%!textafter%
+End
+
+CiteFormat numerical
+       !open [
+       !sep ,
+       !close ]
+
+       !citet %!abbrvauthor% 
%!open%%!textbefore%{%dialog%[[#ID]][[%!startlink%{%numericallabel%[[%numericallabel%]][[#%key%]]}%!endlink%]]}%!nextcitet%
+       !citealt %!abbrvauthor% 
%!textbefore%{%dialog%[[#ID]][[%!startlink%{%numericallabel%[[%numericallabel%]][[#%key%]]}%!endlink%]]}%!nextcitealt%
+
+       !hashkey 
{%dialog%[[#ID]][[%!startlink%{%numericallabel%[[%numericallabel%]][[#%key%]]}%!endlink%%!nexthashkey%]]}
+
+       !nextcitet {%next%[[%!close%%!sep% %!citet%]]}
+       !nextcitealt {%next%[[%!sep% %!citealt%]]}
+       !nexthashid {%next%[[%!sep% #ID%!nexthashid%]]}
+       !nexthashkey {%next%[[%!sep% 
%!startlink%{%numericallabel%[[%numericallabel%]][[#%key%]]}%!endlink%%!nexthashkey%]]}
+
+       cite %!open%%!textbefore%%!hashkey%%!textafter%%!close%
+       citep %!open%%!textbefore%%!hashkey%%!textafter%%!close%
+       citealp %!textbefore%%!hashkey%%!textafter%
+       citeauthor %!startlink%%!abbrvauthor%%!endlink%%!nextauthor%
+       citeyear %!startlink%%!year%%!endlink%%!nextyear%
+End
diff --git a/lib/configure.py b/lib/configure.py
index fb1abd3..680e32a 100644
--- a/lib/configure.py
+++ b/lib/configure.py
@@ -1502,6 +1502,132 @@ def processModuleFile(file, filename, bool_docbook):
     return '"%s" "%s" "%s" "%s" "%s" "%s" "%s"\n' % (modname, filename, desc, 
pkgs, req, excl, catgy)
 
 
+def checkCiteEnginesConfig():
+  removeFiles(['lyxciteengines.lst', 'chkciteengines.tex'])
+
+  logger.info('+checking list of cite engines... ')
+  tx = open('lyxciteengines.lst', 'w')
+  tx.write('''## This file declares cite engines and their associated 
definition files.
+## It has been automatically generated by configure
+## Use "Options/Reconfigure" if you need to update it after a
+## configuration change.
+## "CiteEngineName" "filename" "CiteEngineType" "Description" "Packages" 
"Requires" "Excludes"
+''')
+
+  # build the list of available modules
+  seen = []
+  # note that this searches the local directory first, then the
+  # system directory. that way, we pick up the user's version first.
+  for file in glob.glob( os.path.join('citeengines', '*.citeengine') ) + \
+      glob.glob( os.path.join(srcdir, 'citeengines', '*.citeengine' ) ) :
+      # valid file?
+      logger.info(file)
+      if not os.path.isfile(file):
+          continue
+
+      filename = file.split(os.sep)[-1]
+      filename = filename[:-11]
+      if seen.count(filename):
+          continue
+
+      seen.append(filename)
+      retval = processCiteEngineFile(file, filename, bool_docbook)
+      if retval != "":
+          tx.write(retval)
+  tx.close()
+  logger.info('\tdone')
+
+
+def processCiteEngineFile(file, filename, bool_docbook):
+    ''' process cite engines file and get a line of result
+
+        The top of a cite engine file should look like this:
+          #\DeclareLyXCiteEngine[LaTeX Packages]{CiteEngineName}
+          #DescriptionBegin
+          #...body of description...
+          #DescriptionEnd
+          #Requires: [list of required engines]
+          #Excludes: [list of excluded engines]
+        The last two lines are optional.
+        We expect output:
+          "CiteEngineName" "filename" "CiteEngineType" "Description" 
"Packages" "Requires" "Excludes"
+    '''
+    remods = re.compile(r'\DeclareLyXCiteEngine\s*(?:\[([^]]*?)\])?{(.*)}')
+    rereqs = re.compile(r'#+\s*Requires: (.*)')
+    reexcs = re.compile(r'#+\s*Excludes: (.*)')
+    redbeg = re.compile(r'#+\s*DescriptionBegin\s*$')
+    redend = re.compile(r'#+\s*DescriptionEnd\s*$')
+    recet = re.compile(r'\s*CiteEngineType (.*)')
+
+    modname = desc = pkgs = req = excl = cet = ""
+    readingDescription = False
+    descLines = []
+
+    for line in open(file).readlines():
+      if readingDescription:
+        res = redend.search(line)
+        if res != None:
+          readingDescription = False
+          desc = " ".join(descLines)
+          # Escape quotes.
+          desc = desc.replace('"', '\\"')
+          continue
+        descLines.append(line[1:].strip())
+        continue
+      res = redbeg.search(line)
+      if res != None:
+        readingDescription = True
+        continue
+      res = remods.search(line)
+      if res != None:
+          (pkgs, modname) = res.groups()
+          if pkgs == None:
+            pkgs = ""
+          else:
+            tmp = [s.strip() for s in pkgs.split(",")]
+            pkgs = ",".join(tmp)
+          continue
+      res = rereqs.search(line)
+      if res != None:
+        req = res.group(1)
+        tmp = [s.strip() for s in req.split("|")]
+        req = "|".join(tmp)
+        continue
+      res = reexcs.search(line)
+      if res != None:
+        excl = res.group(1)
+        tmp = [s.strip() for s in excl.split("|")]
+        excl = "|".join(tmp)
+        continue
+      res = recet.search(line)
+      if res != None:
+        cet = res.group(1)
+        continue
+
+    if modname == "":
+      logger.warning("Cite Engine File file without \DeclareLyXCiteEngine 
line. ")
+      return ""
+
+    if pkgs != "":
+        # this cite engine has some latex dependencies:
+        # append the dependencies to chkciteengines.tex,
+        # which is \input'ed by chkconfig.ltx
+        testpackages = list()
+        for pkg in pkgs.split(","):
+            if "->" in pkg:
+                # this is a converter dependency: skip
+                continue
+            if pkg.endswith(".sty"):
+                pkg = pkg[:-4]
+            testpackages.append("\\TestPackage{%s}" % (pkg,))
+        cm = open('chkciteengines.tex', 'a')
+        for line in testpackages:
+            cm.write(line + '\n')
+        cm.close()
+
+    return '"%s" "%s" "%s" "%s" "%s" "%s" "%s"\n' % (modname, filename, cet, 
desc, pkgs, req, excl)
+
+
 def checkTeXAllowSpaces():
     ''' Let's check whether spaces are allowed in TeX file names '''
     tex_allows_spaces = 'false'
@@ -1543,8 +1669,8 @@ def removeTempFiles():
     # Final clean-up
     if not lyx_keep_temps:
         removeFiles(['chkconfig.vars', 'chklatex.ltx', 'chklatex.log',
-            'chklayouts.tex', 'chkmodules.tex', 'missfont.log',
-            'wrap_chkconfig.ltx', 'wrap_chkconfig.log'])
+            'chklayouts.tex', 'chkmodules.tex', 'chkciteengines.tex',
+            'missfont.log', 'wrap_chkconfig.ltx', 'wrap_chkconfig.log'])
 
 
 if __name__ == '__main__':
@@ -1623,6 +1749,7 @@ Format %i
     if lyx_kpsewhich:
         rescanTeXFiles()
     checkModulesConfig()
+    checkCiteEnginesConfig()
     # --without-latex-config can disable lyx_check_config
     ret = checkLatexConfig(lyx_check_config and LATEX != '', bool_docbook)
     removeTempFiles()
diff --git a/lib/layouts/basic.module b/lib/layouts/basic.module
deleted file mode 100644
index 8e0ed1c..0000000
--- a/lib/layouts/basic.module
+++ /dev/null
@@ -1,44 +0,0 @@
-# \DeclareLyXModule{Default (basic)}
-# DescriptionBegin
-#   Use the basic citation capabilities provided by plain LaTeX.
-# DescriptionEnd
-# Excludes: jurabib | natbib
-# Category: Citation engine
-
-# Author: Julien Rioux <jri...@lyx.org>
-
-Format 62
-
-CiteEngineType default
-DefaultBiblio  plain
-
-CiteEngine default
-       cite[]
-       nocite
-End
-
-CiteFormat default
-       # translatable bits
-       _notcited not cited
-       _addtobib Add to bibliography only.
-
-       # macros
-       !open [
-       !sep ,
-       !close ]
-
-       !startlink {!<a href='#LyXCite-%clean:key%'>!}
-       !endlink {!</a>!}
-
-       !cite 
%!startlink%{%label%[[%label%]][[{%numericallabel%[[%numericallabel%]][[#%key%]]}]]}%!endlink%%!nextcite%
-
-       !nextcite {%next%[[%!sep% %!cite%]]}
-       !nexthashkey {%next%[[%!sep% #%key%%!nexthashkey%]]}
-       !nextkey {%next%[[%!sep% %key%%!nextkey%]]}
-
-       !textafter {%textafter%[[, %textafter%]]}
-
-       # cite styles
-       cite %!open%{%dialog%[[#ID]][[%!cite%]]}%!textafter%%!close%
-       nocite {%dialog%[[%_addtobib%]][[%key%%!nextkey% (%_notcited%)]]}
-End
diff --git a/lib/layouts/jurabib.module b/lib/layouts/jurabib.module
deleted file mode 100644
index 63bae5a..0000000
--- a/lib/layouts/jurabib.module
+++ /dev/null
@@ -1,106 +0,0 @@
-# \DeclareLyXModule[jurabib.sty]{Jurabib}
-# DescriptionBegin
-#   Loads the LaTeX package jurabib, a citation engine. Jurabib supports 
annotations,
-#   author-year style citations and hyphenation patterns for bibliography 
entries in
-#   English, German, French, Dutch, Spanish and Italian.
-# DescriptionEnd
-# Excludes: basic | natbib
-# Category: Citation engine
-
-# Author: Julien Rioux <jri...@lyx.org>
-
-Format 62
-
-Requires jurabib
-
-CiteEngineType authoryear
-DefaultBiblio  jurabib
-
-# FIXME: support for these jurabib styles (fileformat)
-# citefield []{}
-# footcite [][]
-# footcitetitle [][]
-# footcitet [][]
-# footcitep [][]
-# footcitealt [][]
-# footcitealp [][]
-# footciteauthor [][]
-# footciteyear [][]
-# footciteyearpar [][]
-# footfullcite [][]
-
-CiteEngine authoryear
-       # \cite* is not implemented: use \cite instead, it's the same
-       cite [][]
-       citetitle [][]
-       citet [][]
-       citep [][]
-       citealt [][]
-       citealp [][]
-       citeauthor [][]
-       citeyear [][]
-       citeyearpar [][]
-       fullcite [][]
-       nocite
-End
-
-CiteFormat authoryear
-       # translatable bits
-       _notcited not cited
-       _addtobib Add to bibliography only.
-       _fullcite bibliography entry
-       _bibentry Bibliography entry.
-       _before before
-       _shorttitle short title
-
-       # macros
-       !open (
-       !sep ;
-       !close )
-
-       !startlink {!<a href='#LyXCite-%clean:key%'>!}
-       !endlink {!</a>!}
-
-       !cite 
%!startlink%%!shortauthor%%!endlink%%!textbefore2%%!textafter2%%!nextcite%
-       !citetitle 
%!startlink%%!shortauthor%%!endlink%%!textbefore2%%!shorttitle%%!textafter2%%!nextcitetitle%
-       !citet %!textbefore%%!startlink%%!shortauthor%%!endlink% 
%!open%%!year%%!textafter%%!close%%!nextcitet%
-       !citep %!open%%!citealp%%!close%
-       !citealt %!textbefore%%!startlink%%!shortauthor% 
%!year%%!endlink%%!textafter%%!nextcitealt%
-       !citealp %!textbefore%%!startlink%%!shortauthor%, 
%!year%%!endlink%%!textafter%%!nextcitealp%
-       !citeauthor 
%!textbefore%%!startlink%%!shortauthor%%!endlink%%!textafter%%!nextauthor%
-       !citeyear 
%!textbefore%%!startlink%%!year%%!endlink%%!textafter%%!nextyear%
-       !citeyearpar 
%!textbefore%%!open%%!startlink%%!year%%!endlink%%!close%%!textafter%%!nextyearpar%
-       !fullcite {%textbefore%[[%textbefore% in: ]]}%bibentry%{%textafter%[[ 
%textafter%]]}%!nextfullcite%
-
-       !nextcite {%next%[[%!sep% 
%!startlink%%!shortauthor%%!endlink%%!textafter2%%!nextcite%]]}
-       !nextcitetitle {%next%[[%!sep% 
%!startlink%%!shortauthor%%!endlink%%!shorttitle%%!textafter2%%!nextcitetitle%]]}
-       !nextcitet {%next%[[%!sep% %!citet%]]}
-       !nextcitealt {%next%[[%!sep% %!citealt%]]}
-       !nextcitealp {%next%[[%!sep% %!citealp%]]}
-       !nextauthor {%next%[[%!sep% %!citeauthor%]]}
-       !nextyear {%next%[[%!sep% %!citeyear%]]}
-       !nextyearpar {%next%[[%!sep% %!citeyearpar%]]}
-       !nextfullcite {%next%[[%!sep% %bibentry%{%textafter%[[ 
%textafter%]]}%!nextfullcite%]]}
-       !nextkey {%next%[[%!sep% %key%%!nextkey%]]}
-
-       !shortauthor {%shortauthor%[[%shortauthor%]][[??]]}
-       !shorttitle {%shorttitle%[[ %shorttitle%]][[{%dialog%[[ 
<%_shorttitle%>]]}]]}
-       !textbefore {%textbefore%[[%textbefore% ]]}
-       !textbefore2 
{%textbefore%[[/%textbefore%]][[{%dialog%[[/<%_before%>]]}]]}
-       !textafter {%textafter%[[, %textafter%]]}
-       !textafter2 {%textafter%[[ %textafter%]]}
-       !year {%year%[[%year%]][[??]]}{%modifier%[[%modifier%]]}
-
-       # cite styles
-       cite %!cite%
-       citetitle %!citetitle%
-       citet %!citet%
-       citep %!citep%
-       citealt %!citealt%
-       citealp %!citealp%
-       citeauthor %!citeauthor%
-       citeyear %!citeyear%
-       citeyearpar %!citeyearpar%
-       fullcite 
{%dialog%[[%_bibentry%]][[{%label%[[%!fullcite%]][[%key%%!nextkey% 
(%_fullcite%)]]}]]}
-       nocite {%dialog%[[%_addtobib%]][[%key%%!nextkey% (%_notcited%)]]}
-End
diff --git a/lib/layouts/natbib.module b/lib/layouts/natbib.module
deleted file mode 100644
index d4d250e..0000000
--- a/lib/layouts/natbib.module
+++ /dev/null
@@ -1,107 +0,0 @@
-# \DeclareLyXModule[natbib.sty]{Natbib}
-# DescriptionBegin
-#   Loads the LaTeX package natbib, a citation engine. Natbib supports
-#   both author-year and numerical styles for citations, automatic sorting
-#   and merging of numerical citations, annotations, capitalization of the
-#   `van' part of author names, shortened and full author lists, and more.
-# DescriptionEnd
-# Excludes: basic | jurabib
-# Category: Citation engine
-
-# Author: Julien Rioux <jri...@lyx.org>
-
-Format 62
-
-Requires natbib
-
-CiteEngineType authoryear|numerical
-DefaultBiblio  plainnat
-
-CiteEngine authoryear
-       Citet*[][]
-       Citep*[][]
-       Citealt*[][]
-       Citealp*[][]
-       Citeauthor*[]
-       citeyear[]
-       citeyearpar[][]
-       nocite
-End
-
-CiteEngine numerical
-       Citep*[][]
-       Citealp*[][]
-       Citet*[][]
-       Citealt*[][]
-       Citeauthor*
-       citeyearpar[][]
-       citeyear
-       nocite
-End
-
-CiteFormat default
-       # translatable bits
-       _notcited not cited
-       _addtobib Add to bibliography only.
-
-       # macros
-       !startlink {!<a href='#LyXCite-%clean:key%'>!}
-       !endlink {!</a>!}
-
-       !nextauthor {%next%[[%!sep% 
%!startlink%%!abbrvauthor%%!endlink%%!nextauthor%]]}
-       !nextkey {%next%[[%!sep% %key%%!nextkey%]]}
-       !nextyear {%next%[[%!sep% %!startlink%%!year%%!endlink%%!nextyear%]]}
-
-       !abbrvauthor {%abbrvauthor%[[%abbrvauthor%]][[??]]}
-       !textbefore {%textbefore%[[%textbefore% ]]}
-       !textafter {%textafter%[[, %textafter%]]}
-       !year {%year%[[%year%]][[??]]}{%modifier%[[%modifier%]]}
-
-       # cite styles
-       citet %!citet%%!textafter%%!close%
-       citealt %!citealt%%!textafter%
-       citeyearpar 
%!open%%!textbefore%%!startlink%%!year%%!endlink%%!nextyear%%!textafter%%!close%
-       nocite {%dialog%[[%_addtobib%]][[%key%%!nextkey% (%_notcited%)]]}
-End
-
-CiteFormat authoryear
-       !open (
-       !sep ;
-       !close )
-
-       !citet %!startlink%%!abbrvauthor%%!endlink% 
%!open%%!textbefore%%!year%%!nextcitet%
-       !citealt %!startlink%%!abbrvauthor% 
%!textbefore%%!year%%!endlink%%!nextcitealt%
-       !citealp %!startlink%%!abbrvauthor%, %!year%%!endlink%%!nextcitealp%
-
-       !nextcitet {%next%[[%!close%%!sep% %!citet%]]}
-       !nextcitealt {%next%[[%!sep% %!citealt%]]}
-       !nextcitealp {%next%[[%!sep% %!citealp%]]}
-
-       cite %!citet%%!textafter%%!close%
-       citep %!open%%!textbefore%%!citealp%%!textafter%%!close%
-       citealp %!textbefore%%!citealp%%!textafter%
-       citeauthor %!startlink%%!abbrvauthor%%!endlink%%!nextauthor%%!textafter%
-       citeyear %!startlink%%!year%%!endlink%%!nextyear%%!textafter%
-End
-
-CiteFormat numerical
-       !open [
-       !sep ,
-       !close ]
-
-       !citet %!abbrvauthor% 
%!open%%!textbefore%{%dialog%[[#ID]][[%!startlink%{%numericallabel%[[%numericallabel%]][[#%key%]]}%!endlink%]]}%!nextcitet%
-       !citealt %!abbrvauthor% 
%!textbefore%{%dialog%[[#ID]][[%!startlink%{%numericallabel%[[%numericallabel%]][[#%key%]]}%!endlink%]]}%!nextcitealt%
-
-       !hashkey 
{%dialog%[[#ID]][[%!startlink%{%numericallabel%[[%numericallabel%]][[#%key%]]}%!endlink%%!nexthashkey%]]}
-
-       !nextcitet {%next%[[%!close%%!sep% %!citet%]]}
-       !nextcitealt {%next%[[%!sep% %!citealt%]]}
-       !nexthashid {%next%[[%!sep% #ID%!nexthashid%]]}
-       !nexthashkey {%next%[[%!sep% 
%!startlink%{%numericallabel%[[%numericallabel%]][[#%key%]]}%!endlink%%!nexthashkey%]]}
-
-       cite %!open%%!textbefore%%!hashkey%%!textafter%%!close%
-       citep %!open%%!textbefore%%!hashkey%%!textafter%%!close%
-       citealp %!textbefore%%!hashkey%%!textafter%
-       citeauthor %!startlink%%!abbrvauthor%%!endlink%%!nextauthor%
-       citeyear %!startlink%%!year%%!endlink%%!nextyear%
-End
diff --git a/po/Rules-lyx b/po/Rules-lyx
index 42998f2..23d4c06 100644
--- a/po/Rules-lyx
+++ b/po/Rules-lyx
@@ -34,7 +34,7 @@ layouts_l10n.pot: $(top_srcdir)/lib/layouts/*.layout \
 # Read translatable strings from layouts and translations from the po files and
 # create the layouttranslations file containing all LaTeX relevant translations
 $(top_srcdir)/lib/layouttranslations: $(POFILES) 
$(top_srcdir)/lib/layouts/*.layout \
-                $(top_srcdir)/lib/layouts/*.inc 
$(top_srcdir)/lib/layouts/*.module
+                $(top_srcdir)/lib/layouts/*.inc 
$(top_srcdir)/lib/layouts/*.module $(top_srcdir)/lib/citeengines/*.citeengines
        $(LYX_POT) -o $@ -t layouttranslations 
${top_srcdir}/lib/layouts/*.layout ${top_srcdir}/lib/layouts/*.inc 
${top_srcdir}/lib/layouts/*.module
 
 languages_l10n.pot: $(top_srcdir)/lib/languages
diff --git a/po/lyx_pot.py b/po/lyx_pot.py
index 761e3dd..0fc7ee4 100755
--- a/po/lyx_pot.py
+++ b/po/lyx_pot.py
@@ -91,6 +91,7 @@ def layouts_l10n(input_files, output, base, 
layouttranslations):
     ListName = re.compile(r'^\s*ListName\s+(.*\S)\s*$', re.IGNORECASE)
     CategoryName = re.compile(r'^\s*Category\s+(.*\S)\s*$', re.IGNORECASE)
     NameRE = re.compile(r'^\s*#\s*\\DeclareLyXModule.*{(.*)}$', re.IGNORECASE)
+    CiteNameRE = re.compile(r'^\s*#\s*\\DeclareLyXCiteEngine.*{(.*)}$', 
re.IGNORECASE)
     InsetLayout = re.compile(r'^InsetLayout\s+\"?(.*)\"?\s*$', re.IGNORECASE)
     FlexCheck = re.compile(r'^Flex:(.*)', re.IGNORECASE)
     CaptionCheck = re.compile(r'^Caption:(.*)', re.IGNORECASE)
@@ -234,6 +235,12 @@ def layouts_l10n(input_files, output, base, 
layouttranslations):
                 if not layouttranslations:
                     writeString(out, src, base, lineno + 1, string)
                 continue
+            res = CiteNameRE.search(line)
+            if res != None:
+                string = res.group(1)
+                if not layouttranslations:
+                    writeString(out, src, base, lineno + 1, string)
+                continue
             res = Style.search(line)
             if res != None:
                 string = res.group(1)
diff --git a/src/BufferParams.cpp b/src/BufferParams.cpp
index fa0b7c3..326d487 100644
--- a/src/BufferParams.cpp
+++ b/src/BufferParams.cpp
@@ -2333,6 +2333,7 @@ void BufferParams::makeDocumentClass(bool const clone)
 
        invalidateConverterCache();
        LayoutModuleList mods;
+       LayoutModuleList ces;
        LayoutModuleList::iterator it = layout_modules_.begin();
        LayoutModuleList::iterator en = layout_modules_.end();
        for (; it != en; ++it)
@@ -2341,9 +2342,9 @@ void BufferParams::makeDocumentClass(bool const clone)
        it = cite_engine_.begin();
        en = cite_engine_.end();
        for (; it != en; ++it)
-               mods.push_back(*it);
+               ces.push_back(*it);
 
-       doc_class_ = getDocumentClass(*baseClass(), mods, clone);
+       doc_class_ = getDocumentClass(*baseClass(), mods, ces, clone);
 
        TextClass::ReturnValues success = TextClass::OK;
        if (!forced_local_layout_.empty())
diff --git a/src/CiteEnginesList.cpp b/src/CiteEnginesList.cpp
new file mode 100644
index 0000000..48222cb
--- /dev/null
+++ b/src/CiteEnginesList.cpp
@@ -0,0 +1,280 @@
+// -*- C++ -*-
+/**
+ * \file CiteEnginesList.cpp
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author Richard Heck
+ * \author Jürgen Spitzmüller
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+#include <config.h>
+
+#include "CiteEnginesList.h"
+
+#include "LaTeXFeatures.h"
+#include "Lexer.h"
+
+#include "support/debug.h"
+#include "support/FileName.h"
+#include "support/gettext.h"
+#include "support/filetools.h"
+#include "support/lstrings.h"
+
+#include <algorithm>
+
+using namespace std;
+using namespace lyx::support;
+
+namespace lyx {
+
+
+//global variable: cite engine list
+CiteEnginesList theCiteEnginesList;
+
+
+LyXCiteEngine::LyXCiteEngine(string const & n, string const & i,
+                            vector<string> const & cet, string const & d,
+                            vector<string> const & p,
+                            vector<string> const & r, vector<string> const & 
e):
+       name_(n), id_(i), engine_types_(cet), description_(d), package_list_(p),
+       required_engines_(r), excluded_engines_(e),
+       checked_(false), available_(false)
+{
+       filename_ = id_ + ".citeengine";
+}
+
+
+vector<string> LyXCiteEngine::prerequisites() const
+{
+       if (!checked_)
+               isAvailable();
+       return prerequisites_;
+}
+
+
+bool LyXCiteEngine::isAvailable() const
+{
+       if (package_list_.empty())
+               return true;
+       if (checked_)
+               return available_;
+       checked_ = true;
+       available_ = true;
+       //check whether all of the required packages are available
+       vector<string>::const_iterator it  = package_list_.begin();
+       vector<string>::const_iterator end = package_list_.end();
+       for (; it != end; ++it) {
+               if (!LaTeXFeatures::isAvailable(*it)) {
+                       available_ = false;
+                       prerequisites_.push_back(*it);
+               }
+       }
+       return available_;
+}
+
+
+bool LyXCiteEngine::isCompatible(string const & cename) const
+{
+       // do we exclude it?
+       if (find(excluded_engines_.begin(), excluded_engines_.end(), cename) !=
+                       excluded_engines_.end())
+               return false;
+
+       LyXCiteEngine const * const lm = theCiteEnginesList[cename];
+       if (!lm)
+               return true;
+
+       // does it exclude us?
+       vector<string> const excengs = lm->getExcludedEngines();
+       if (find(excengs.begin(), excengs.end(), id_) != excengs.end())
+               return false;
+
+       return true;
+}
+
+
+bool LyXCiteEngine::areCompatible(string const & eng1, string const & eng2)
+{
+       LyXCiteEngine const * const lm1 = theCiteEnginesList[eng1];
+       if (lm1)
+               return lm1->isCompatible(eng2);
+       LyXCiteEngine const * const lm2 = theCiteEnginesList[eng2];
+       if (lm2)
+               return lm2->isCompatible(eng1);
+       // Can't check it either way.
+       return true;
+}
+
+
+// used when sorting the cite engine list.
+class EngineSorter {
+public:
+       int operator()(LyXCiteEngine const & ce1, LyXCiteEngine const & ce2) 
const
+       {
+               return _(ce1.getName()) < _(ce2.getName());
+       }
+};
+
+
+// Much of this is borrowed from LayoutFileList::read()
+bool CiteEnginesList::read()
+{
+       FileName const real_file = libFileSearch("", "lyxciteengines.lst");
+       LYXERR(Debug::TCLASS, "Reading cite engines from `" << real_file << 
'\'');
+
+       if (real_file.empty()) {
+               LYXERR0("unable to find cite engines file `citeengines.lst'.\n"
+                       << "No cite engines will be available.");
+               return false;
+       }
+
+       Lexer lex;
+       if (!lex.setFile(real_file)) {
+               LYXERR0("lyxlex was not able to set file: "
+                       << real_file << ".\nNo cite engines will be 
available.");
+               return false;
+       }
+
+       if (!lex.isOK()) {
+               LYXERR0("unable to open cite engines file  `"
+                       << to_utf8(makeDisplayPath(real_file.absFileName(), 
1000))
+                       << "'\nNo cite engines will be available.");
+               return false;
+       }
+
+       bool finished = false;
+       // Parse cite engines files
+       LYXERR(Debug::TCLASS, "Starting parsing of lyxciteengines.lst");
+       while (lex.isOK() && !finished) {
+               LYXERR(Debug::TCLASS, "\tline by line");
+               switch (lex.lex()) {
+               case Lexer::LEX_FEOF:
+                       finished = true;
+                       break;
+               default:
+                       string const cename = lex.getString();
+                       LYXERR(Debug::TCLASS, "Engine name: " << cename);
+                       if (!lex.next())
+                               break;
+                       string const fname = lex.getString();
+                       LYXERR(Debug::TCLASS, "Filename: " << fname);
+                       if (!lex.next(true))
+                               break;
+                       string cet = lex.getString();
+                       LYXERR(Debug::TCLASS, "Engine Type: " << cet);
+                       vector<string> cets;
+                       while (!cet.empty()) {
+                               string p;
+                               cet = split(cet, p, '|');
+                               cets.push_back(p);
+                       }
+                       if (!lex.next(true))
+                               break;
+                       string const desc = lex.getString();
+                       LYXERR(Debug::TCLASS, "Description: " << desc);
+                       //FIXME Add packages
+                       if (!lex.next())
+                               break;
+                       string str = lex.getString();
+                       LYXERR(Debug::TCLASS, "Packages: " << str);
+                       vector<string> pkgs;
+                       while (!str.empty()) {
+                               string p;
+                               str = split(str, p, ',');
+                               pkgs.push_back(p);
+                       }
+                       if (!lex.next())
+                               break;
+                       str = lex.getString();
+                       LYXERR(Debug::TCLASS, "Required: " << str);
+                       vector<string> req;
+                       while (!str.empty()) {
+                               string p;
+                               str = split(str, p, '|');
+                               req.push_back(p);
+                       }
+                       if (!lex.next())
+                               break;
+                       str = lex.getString();
+                       LYXERR(Debug::TCLASS, "Excluded: " << str);
+                       vector<string> exc;
+                       while (!str.empty()) {
+                               string p;
+                               str = split(str, p, '|');
+                               exc.push_back(p);
+                       }
+                       // This code is run when we have
+                       // cename, fname, desc, pkgs, req and exc
+                       addCiteEngine(cename, fname, cets, desc, pkgs, req, 
exc);
+               } // end switch
+       } //end while
+
+       LYXERR(Debug::TCLASS, "End of parsing of lyxciteengines.lst");
+
+       if (!theCiteEnginesList.empty())
+               sort(theCiteEnginesList.begin(), theCiteEnginesList.end(), 
EngineSorter());
+       return true;
+}
+
+
+void CiteEnginesList::addCiteEngine(string const & cename,
+       string const & filename, vector<string> const & cets, string const & 
description,
+       vector<string> const & pkgs, vector<string> const & req,
+       vector<string> const & exc)
+{
+       LyXCiteEngine ce(cename, filename, cets, description, pkgs, req, exc);
+       englist_.push_back(ce);
+}
+
+
+LyXCiteEnginesList::const_iterator CiteEnginesList::begin() const
+{
+       return englist_.begin();
+}
+
+
+LyXCiteEnginesList::iterator CiteEnginesList::begin()
+{
+       return englist_.begin();
+}
+
+
+LyXCiteEnginesList::const_iterator CiteEnginesList::end() const
+{
+       return englist_.end();
+}
+
+
+LyXCiteEnginesList::iterator CiteEnginesList::end()
+{
+       return englist_.end();
+}
+
+
+LyXCiteEngine const * CiteEnginesList::operator[](string const & str) const
+{
+       LyXCiteEnginesList::const_iterator it = englist_.begin();
+       for (; it != englist_.end(); ++it)
+               if (it->getID() == str) {
+                       LyXCiteEngine const & eng = *it;
+                       return &eng;
+               }
+       return 0;
+}
+
+
+LyXCiteEngine * CiteEnginesList::operator[](string const & str)
+{
+       LyXCiteEnginesList::iterator it = englist_.begin();
+       for (; it != englist_.end(); ++it)
+               if (it->getID() == str) {
+                       LyXCiteEngine & eng = *it;
+                       return &eng;
+               }
+       return 0;
+}
+
+} // namespace lyx
diff --git a/src/CiteEnginesList.h b/src/CiteEnginesList.h
new file mode 100644
index 0000000..0e6d119
--- /dev/null
+++ b/src/CiteEnginesList.h
@@ -0,0 +1,156 @@
+// -*- C++ -*-
+/**
+ * \file CiteEnginesList.h
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author Richard Heck
+ * \author Jürgen Spitzmüller
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+#ifndef CITEENGINESLIST_H
+#define CITEENGINESLIST_H
+
+#include <string>
+#include <vector>
+
+namespace lyx {
+
+/**
+ *  This class represents a particular LyX "cite engine", which defines the 
features
+ * of a particular citation backend such as natbib or biblatex. In that sense, 
it is more like
+ *  a LaTeX package, where a layout file corresponds to a LaTeX class.
+ *
+ *  In general, a given cite engine can be used with any document class. That 
said,
+ *  one cite engine may `require' another, or it may `exclude' some other cite 
engine.
+ *  The requires and excludes are given in comments within the cite engine 
file,
+ *  which must begin roughly so:
+ *  # \DeclareLyXCiteEngine[natbib.sty]{Natbib}
+ *  # DescriptionBegin
+ *  #   Loads the LaTeX package natbib, a citation engine. Natbib supports
+ *  #   both author-year and numerical styles for citations, automatic sorting
+ *  #   and merging of numerical citations, annotations, capitalization of the
+ *  #   `van' part of author names, shortened and full author lists, and more.
+ *  # DescriptionEnd
+ *  # Excludes: basic | jurabib
+ *  The description might be used in the gui to give information to the user. 
The
+ *  Requires and Excludes lines are read by the configuration script
+ *  and written to a file citeengines.lst in the user configuration directory.
+ *  That file is then read on startup to populate the CiteEnginesList, below.
+ *
+ *  Engines can also be "provided" or "excluded" by document classes, using
+ *  the ProvidesEngine and ExcludesEngine tags.
+ */
+
+class LyXCiteEngine {
+public:
+       ///
+       LyXCiteEngine(std::string const & name, std::string const & id,
+                     std::vector<std::string> const & enginetypes,
+                     std::string const & description,
+                     std::vector<std::string> const & packagelist,
+                     std::vector<std::string> const & requires,
+                     std::vector<std::string> const & excludes);
+       /// whether the required packages are available
+       bool isAvailable() const;
+       /// the missing prerequisites, if any
+       std::vector<std::string> prerequisites() const;
+       ///
+       std::string const & getName() const { return name_; }
+       ///
+       std::string const & getID() const { return id_; }
+       ///
+       std::string const & getFilename() const { return filename_; }
+       ///
+       std::vector<std::string> const & getEngineType() const { return 
engine_types_; }
+       ///
+       std::string const & getDescription() const { return description_; }
+       ///
+       std::vector<std::string> const & getPackageList() const
+               { return package_list_; }
+       ///
+       std::vector<std::string> const & getRequiredEngines() const
+               { return required_engines_; }
+       /// Engines this one excludes: the list should be treated disjunctively
+       std::vector<std::string> const & getExcludedEngines() const
+               { return excluded_engines_; }
+       /// \return true if the engine is compatible with this one, i.e.,
+       /// it does not exclude us and we do not exclude it.
+       /// this will also return true if cename is unknown and we do not
+       /// exclude it, since in that case we cannot check its exclusions.
+       bool isCompatible(std::string const & cename) const;
+       ///
+       static bool areCompatible(std::string const & eng1, std::string const & 
eng2);
+private:
+       /// what appears in the ui
+       std::string name_;
+       /// the engine's unique identifier
+       /// at present, this is the filename, without the extension
+       std::string id_;
+       /// the filename
+       std::string filename_;
+       /// the engine type(s)
+       std::vector<std::string> engine_types_;
+       /// a short description for use in the ui
+       std::string description_;
+       /// the LaTeX packages on which this depends, if any
+       std::vector<std::string> package_list_;
+       /// Engines this one requires: at least one
+       std::vector<std::string> required_engines_;
+       /// Engines this one excludes: none of these
+       std::vector<std::string> excluded_engines_;
+       // these are mutable because they are used to cache the results
+       // or an otherwise const operation.
+       ///
+       mutable bool checked_;
+       ///
+       mutable bool available_;
+       ///
+       mutable std::vector<std::string> prerequisites_;
+};
+
+typedef std::vector<LyXCiteEngine> LyXCiteEnginesList;
+
+/**
+ *  The CiteEnginesList represents the various LyXCiteEngine's that are 
available at
+ *  present.
+ */
+class CiteEnginesList {
+public:
+       ///
+       CiteEnginesList() {}
+       /// reads the engines from a file generated by configure.py
+       bool read();
+       ///
+       LyXCiteEnginesList::const_iterator begin() const;
+       ///
+       LyXCiteEnginesList::iterator begin();
+       ///
+       LyXCiteEnginesList::const_iterator end() const;
+       ///
+       LyXCiteEnginesList::iterator end();
+       ///
+       bool empty() const { return englist_.empty(); }
+       /// Returns a pointer to the LyXCiteEngine with filename str.
+       /// Returns a null pointer if no such engine is found.
+       LyXCiteEngine const * operator[](std::string const & str) const;
+       ///
+       LyXCiteEngine * operator[](std::string const & str);
+       private:
+       /// noncopyable
+       CiteEnginesList(CiteEnginesList const &);
+       ///
+       void operator=(CiteEnginesList const &);
+       /// add an engine to the list
+       void addCiteEngine(std::string const &, std::string const &,
+               std::vector<std::string> const &, std::string const &, 
std::vector<std::string> const &,
+               std::vector<std::string> const &, std::vector<std::string> 
const &);
+       ///
+       std::vector<LyXCiteEngine> englist_;
+};
+
+extern CiteEnginesList theCiteEnginesList;
+}
+#endif
diff --git a/src/LyX.cpp b/src/LyX.cpp
index 047e265..157d432 100644
--- a/src/LyX.cpp
+++ b/src/LyX.cpp
@@ -22,6 +22,7 @@
 #include "Buffer.h"
 #include "BufferList.h"
 #include "CmdDef.h"
+#include "CiteEnginesList.h"
 #include "ColorSet.h"
 #include "ConverterCache.h"
 #include "Converter.h"
@@ -935,8 +936,10 @@ bool LyX::init()
        LYXERR(Debug::INIT, "Reading layouts...");
        // Load the layouts
        LayoutFileList::get().read();
-       //...and the modules
+       //... the modules
        theModuleList.read();
+       //... and the cite engines
+       theCiteEnginesList.read();
 
        // read keymap and ui files in batch mode as well
        // because InsetInfo needs to know these to produce
@@ -1020,7 +1023,8 @@ bool LyX::queryUserLyXDir(bool explicit_userdir)
                return configFileNeedsUpdate("lyxrc.defaults")
                        || configFileNeedsUpdate("lyxmodules.lst")
                        || configFileNeedsUpdate("textclass.lst")
-                       || configFileNeedsUpdate("packages.lst");
+                       || configFileNeedsUpdate("packages.lst")
+                       || configFileNeedsUpdate("lyxciteengines.lst");
        }
 
        first_start = !explicit_userdir;
diff --git a/src/Makefile.am b/src/Makefile.am
index f87d029..4cb38b5 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -108,6 +108,7 @@ SOURCEFILESCORE = \
        Bullet.cpp \
        Changes.cpp \
        Chktex.cpp \
+       CiteEnginesList.cpp \
        CmdDef.cpp \
        Color.cpp \
        ConverterCache.cpp \
@@ -201,6 +202,7 @@ HEADERFILESCORE = \
        BufferView.h \
        Bullet.h \
        Citation.h \
+       CiteEnginesList.h \
        Changes.h \
        Chktex.h \
        CmdDef.h \
diff --git a/src/TextClass.cpp b/src/TextClass.cpp
index 46a96e4..d14ef29 100644
--- a/src/TextClass.cpp
+++ b/src/TextClass.cpp
@@ -17,6 +17,7 @@
 #include "TextClass.h"
 
 #include "LayoutFile.h"
+#include "CiteEnginesList.h"
 #include "Color.h"
 #include "Counters.h"
 #include "Floating.h"
@@ -123,6 +124,8 @@ string translateReadType(TextClass::ReadType rt)
                return "input file";
        case TextClass::MODULE:
                return "module file";
+       case TextClass::CITE_ENGINE:
+               return "cite engine";
        case TextClass::VALIDATION:
                return "validation";
        }
@@ -1585,6 +1588,7 @@ Layout TextClass::createBasicLayout(docstring const & 
name, bool unknown) const
 
 DocumentClassPtr getDocumentClass(
                LayoutFile const & baseClass, LayoutModuleList const & modlist,
+               LayoutModuleList const & celist,
                bool const clone)
 {
        DocumentClassPtr doc_class =
@@ -1623,6 +1627,42 @@ DocumentClassPtr getDocumentClass(
                        frontend::Alert::warning(_("Read Error"), msg);
                }
        }
+
+       LayoutModuleList::const_iterator cit = celist.begin();
+       LayoutModuleList::const_iterator cen = celist.end();
+       for (; cit != cen; ++cit) {
+               string const ceName = *cit;
+               LyXCiteEngine * ce = theCiteEnginesList[ceName];
+               if (!ce) {
+                       docstring const msg =
+                                               bformat(_("The cite engine %1$s 
has been requested by\n"
+                                               "this document but has not been 
found in the list of\n"
+                                               "available engines. If you 
recently installed it, you\n"
+                                               "probably need to reconfigure 
LyX.\n"), from_utf8(ceName));
+                       if (!clone)
+                               frontend::Alert::warning(_("Cite Engine not 
available"), msg);
+                       continue;
+               }
+               if (!ce->isAvailable() && !clone) {
+                       docstring const prereqs = 
from_utf8(getStringFromVector(ce->prerequisites(), "\n\t"));
+                       docstring const msg =
+                               bformat(_("The cite engine %1$s requires a 
package that is not\n"
+                                       "available in your LaTeX installation, 
or a converter that\n"
+                                       "you have not installed. LaTeX output 
may not be possible.\n"
+                                       "Missing prerequisites:\n"
+                                               "\t%2$s\n"
+                                       "See section 3.1.2.3 (Modules) of the 
User's Guide for more information."),
+                               from_utf8(ceName), prereqs);
+                       frontend::Alert::warning(_("Package not available"), 
msg, true);
+               }
+               FileName layout_file = libFileSearch("citeengines", 
ce->getFilename());
+               if (!doc_class->read(layout_file, TextClass::CITE_ENGINE)) {
+                       docstring const msg =
+                                               bformat(_("Error reading cite 
engine %1$s\n"), from_utf8(ceName));
+                       frontend::Alert::warning(_("Read Error"), msg);
+               }
+       }
+
        return doc_class;
 }
 
diff --git a/src/TextClass.h b/src/TextClass.h
index 22d426c..d082e10 100644
--- a/src/TextClass.h
+++ b/src/TextClass.h
@@ -151,6 +151,7 @@ public:
                BASECLASS, //>This is a base class, i.e., top-level layout file
                MERGE, //>This is a file included in a layout file
                MODULE, //>This is a layout module
+               CITE_ENGINE, //>This is a cite engine
                VALIDATION //>We're just validating
        };
        /// return values for read()
@@ -498,6 +499,7 @@ private:
        /// The only way to make a DocumentClass is to call this function.
        friend DocumentClassPtr
                getDocumentClass(LayoutFile const &, LayoutModuleList const &,
+                                LayoutModuleList const &,
                                 bool const clone);
 };
 
@@ -508,6 +510,7 @@ private:
 /// on the CutStack.
 DocumentClassPtr getDocumentClass(LayoutFile const & baseClass,
                        LayoutModuleList const & modlist,
+                       LayoutModuleList const & celist,
                        bool const clone = false);
 
 /// convert page sides option to text 1 or 2
diff --git a/src/tex2lyx/Makefile.am b/src/tex2lyx/Makefile.am
index bf2d66d..a4a5fdc 100644
--- a/src/tex2lyx/Makefile.am
+++ b/src/tex2lyx/Makefile.am
@@ -83,6 +83,7 @@ updatetests: tex2lyx
 
 LINKED_FILES = \
        ../Author.cpp \
+       ../CiteEnginesList.cpp \
        ../Color.cpp \
        ../Counters.cpp \
        ../Encoding.cpp \
diff --git a/src/tex2lyx/tex2lyx.cpp b/src/tex2lyx/tex2lyx.cpp
index 7a6bbb0..3f6fe73 100644
--- a/src/tex2lyx/tex2lyx.cpp
+++ b/src/tex2lyx/tex2lyx.cpp
@@ -282,10 +282,11 @@ void initModules()
                for (; it != end; ++it) {
                        string const module = it->getID();
                        LayoutModuleList m;
+                       LayoutModuleList c;
                        vector<string> v;
                        if (!addModule(module, baseClass, m, v))
                                continue;
-                       modules[module] = getDocumentClass(baseClass, m);
+                       modules[module] = getDocumentClass(baseClass, m, c);
                }
                init = false;
        }

Reply via email to