]> git.lyx.org Git - lyx.git/blobdiff - src/TextClass.cpp
Natbib authoryear uses (Ref1; Ref2) by default.
[lyx.git] / src / TextClass.cpp
index 70390da289fcf7d1223aae4db8178a037885c47a..b55e8a2f0a4863acad97e02bd82e38059dcf4dab 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "support/lassert.h"
 #include "support/debug.h"
+#include "support/ExceptionMessage.h"
 #include "support/FileName.h"
 #include "support/filetools.h"
 #include "support/gettext.h"
@@ -57,10 +58,10 @@ namespace lyx {
 // could. See LayoutFileList::addEmptyClass() and, especially, the
 // definition of the layoutpost string.
 // You should also run (or ask someone who has bash to run) the
-// development/updatelayouts.sh script, to update the format of
+// development/tools/updatelayouts.sh script, to update the format of
 // all of our layout files.
 //
-int const LAYOUT_FORMAT = 35;
+int const LAYOUT_FORMAT = 45; // rgh: New Tag "NoInsetLayout"
 
 namespace {
 
@@ -147,8 +148,10 @@ TextClass::TextClass()
        tocdepth_ = 3;
        pagestyle_ = "default";
        defaultfont_ = sane_font;
+       opt_enginetype_ = "authoryear|numerical";
        opt_fontsize_ = "10|11|12";
        opt_pagestyle_ = "empty|plain|headings|fancy";
+       cite_full_author_list_ = true;
        titletype_ = TITLE_COMMAND_AFTER;
        titlename_ = "maketitle";
        loaded_ = false;
@@ -180,6 +183,7 @@ enum TextClassTags {
        TC_IFSTYLE,
        TC_DEFAULTSTYLE,
        TC_INSETLAYOUT,
+       TC_NOINSETLAYOUT,
        TC_NOSTYLE,
        TC_COLUMNS,
        TC_SIDES,
@@ -190,6 +194,7 @@ enum TextClassTags {
        TC_CLASSOPTIONS,
        TC_PREAMBLE,
        TC_HTMLPREAMBLE,
+       TC_HTMLSTYLES,
        TC_PROVIDES,
        TC_REQUIRES,
        TC_LEFTMARGIN,
@@ -204,54 +209,66 @@ enum TextClassTags {
        TC_FORMAT,
        TC_ADDTOPREAMBLE,
        TC_ADDTOHTMLPREAMBLE,
+       TC_ADDTOHTMLSTYLES,
        TC_DEFAULTMODULE,
        TC_PROVIDESMODULE,
        TC_EXCLUDESMODULE,
        TC_HTMLTOCSECTION,
-       TC_CITEFORMAT
+       TC_CITEENGINE,
+       TC_CITEENGINETYPE,
+       TC_CITEFORMAT,
+       TC_DEFAULTBIBLIO,
+       TC_FULLAUTHORLIST,
 };
 
 
 namespace {
 
-       LexerKeyword textClassTags[] = {
-               { "addtohtmlpreamble", TC_ADDTOHTMLPREAMBLE },
-               { "addtopreamble",     TC_ADDTOPREAMBLE },
-               { "citeformat",        TC_CITEFORMAT },
-               { "classoptions",      TC_CLASSOPTIONS },
-               { "columns",           TC_COLUMNS },
-               { "counter",           TC_COUNTER },
-               { "defaultfont",       TC_DEFAULTFONT },
-               { "defaultmodule",     TC_DEFAULTMODULE },
-               { "defaultstyle",      TC_DEFAULTSTYLE },
-               { "excludesmodule",    TC_EXCLUDESMODULE },
-               { "float",             TC_FLOAT },
-               { "format",            TC_FORMAT },
-               { "htmlpreamble",      TC_HTMLPREAMBLE },
-               { "htmltocsection",    TC_HTMLTOCSECTION },
-               { "ifcounter",         TC_IFCOUNTER },
-               { "ifstyle",           TC_IFSTYLE },
-               { "input",             TC_INPUT },
-               { "insetlayout",       TC_INSETLAYOUT },
-               { "leftmargin",        TC_LEFTMARGIN },
-               { "nocounter",         TC_NOCOUNTER },
-               { "nofloat",           TC_NOFLOAT },
-               { "nostyle",           TC_NOSTYLE },
-               { "outputformat",      TC_OUTPUTFORMAT },
-               { "outputtype",        TC_OUTPUTTYPE },
-               { "pagestyle",         TC_PAGESTYLE },
-               { "preamble",          TC_PREAMBLE },
-               { "provides",          TC_PROVIDES },
-               { "providesmodule",    TC_PROVIDESMODULE },
-               { "requires",          TC_REQUIRES },
-               { "rightmargin",       TC_RIGHTMARGIN },
-               { "secnumdepth",       TC_SECNUMDEPTH },
-               { "sides",             TC_SIDES },
-               { "style",             TC_STYLE },
-               { "titlelatexname",    TC_TITLELATEXNAME },
-               { "titlelatextype",    TC_TITLELATEXTYPE },
-               { "tocdepth",          TC_TOCDEPTH }
-       };
+LexerKeyword textClassTags[] = {
+       { "addtohtmlpreamble", TC_ADDTOHTMLPREAMBLE },
+       { "addtohtmlstyles",   TC_ADDTOHTMLSTYLES },
+       { "addtopreamble",     TC_ADDTOPREAMBLE },
+       { "citeengine",        TC_CITEENGINE },
+       { "citeenginetype",    TC_CITEENGINETYPE },
+       { "citeformat",        TC_CITEFORMAT },
+       { "classoptions",      TC_CLASSOPTIONS },
+       { "columns",           TC_COLUMNS },
+       { "counter",           TC_COUNTER },
+       { "defaultbiblio",     TC_DEFAULTBIBLIO },
+       { "defaultfont",       TC_DEFAULTFONT },
+       { "defaultmodule",     TC_DEFAULTMODULE },
+       { "defaultstyle",      TC_DEFAULTSTYLE },
+       { "excludesmodule",    TC_EXCLUDESMODULE },
+       { "float",             TC_FLOAT },
+       { "format",            TC_FORMAT },
+       { "fullauthorlist",    TC_FULLAUTHORLIST },
+       { "htmlpreamble",      TC_HTMLPREAMBLE },
+       { "htmlstyles",        TC_HTMLSTYLES },
+       { "htmltocsection",    TC_HTMLTOCSECTION },
+       { "ifcounter",         TC_IFCOUNTER },
+       { "ifstyle",           TC_IFSTYLE },
+       { "input",             TC_INPUT },
+       { "insetlayout",       TC_INSETLAYOUT },
+       { "leftmargin",        TC_LEFTMARGIN },
+       { "nocounter",         TC_NOCOUNTER },
+       { "nofloat",           TC_NOFLOAT },
+       { "noinsetlayout",     TC_NOINSETLAYOUT },
+       { "nostyle",           TC_NOSTYLE },
+       { "outputformat",      TC_OUTPUTFORMAT },
+       { "outputtype",        TC_OUTPUTTYPE },
+       { "pagestyle",         TC_PAGESTYLE },
+       { "preamble",          TC_PREAMBLE },
+       { "provides",          TC_PROVIDES },
+       { "providesmodule",    TC_PROVIDESMODULE },
+       { "requires",          TC_REQUIRES },
+       { "rightmargin",       TC_RIGHTMARGIN },
+       { "secnumdepth",       TC_SECNUMDEPTH },
+       { "sides",             TC_SIDES },
+       { "style",             TC_STYLE },
+       { "titlelatexname",    TC_TITLELATEXNAME },
+       { "titlelatextype",    TC_TITLELATEXTYPE },
+       { "tocdepth",          TC_TOCDEPTH }
+};
 
 } //namespace anon
 
@@ -511,6 +528,16 @@ TextClass::ReturnValues TextClass::read(Lexer & lexrc, ReadType rt)
                        }
                        break;
 
+               case TC_NOINSETLAYOUT:
+                       if (lexrc.next()) {
+                               docstring const style = from_utf8(subst(lexrc.getString(),
+                                                                '_', ' '));
+                               if (!deleteInsetLayout(style))
+                                       LYXERR0("Style `" << style << "' cannot be removed\n"
+                                               "because it was not found!");
+                       }
+                       break;
+
                case TC_COLUMNS:
                        if (lexrc.next())
                                columns_ = lexrc.getInteger();
@@ -568,6 +595,10 @@ TextClass::ReturnValues TextClass::read(Lexer & lexrc, ReadType rt)
                        htmlpreamble_ = from_utf8(lexrc.getLongString("EndPreamble"));
                        break;
 
+               case TC_HTMLSTYLES:
+                       htmlstyles_ = from_utf8(lexrc.getLongString("EndStyles"));
+                       break;
+
                case TC_HTMLTOCSECTION:
                        html_toc_section_ = from_utf8(trim(lexrc.getString()));
                        break;
@@ -580,6 +611,10 @@ TextClass::ReturnValues TextClass::read(Lexer & lexrc, ReadType rt)
                        htmlpreamble_ += from_utf8(lexrc.getLongString("EndPreamble"));
                        break;
 
+               case TC_ADDTOHTMLSTYLES:
+                       htmlstyles_ += from_utf8(lexrc.getLongString("EndStyles"));
+                       break;
+
                case TC_PROVIDES: {
                        lexrc.next();
                        string const feature = lexrc.getString();
@@ -672,8 +707,27 @@ TextClass::ReturnValues TextClass::read(Lexer & lexrc, ReadType rt)
                        error = !readFloat(lexrc);
                        break;
 
+               case TC_CITEENGINE:
+                       error = !readCiteEngine(lexrc);
+                       break;
+
+               case TC_CITEENGINETYPE:
+                       if (lexrc.next())
+                               opt_enginetype_ = rtrim(lexrc.getString());
+                       break;
+
                case TC_CITEFORMAT:
-                       readCiteFormat(lexrc);
+                       error = !readCiteFormat(lexrc);
+                       break;
+
+               case TC_DEFAULTBIBLIO:
+                       if (lexrc.next())
+                               cite_default_biblio_style_ = rtrim(lexrc.getString());
+                       break;
+
+               case TC_FULLAUTHORLIST:
+                       if (lexrc.next())
+                               cite_full_author_list_ &= lexrc.getBool();
                        break;
 
                case TC_NOCOUNTER:
@@ -901,25 +955,109 @@ void TextClass::readClassOptions(Lexer & lexrc)
 }
 
 
-void TextClass::readCiteFormat(Lexer & lexrc)
+bool TextClass::readCiteEngine(Lexer & lexrc)
+{
+       int const type = readCiteEngineType(lexrc);
+       if (type & ENGINE_TYPE_AUTHORYEAR)
+               cite_styles_[ENGINE_TYPE_AUTHORYEAR].clear();
+       if (type & ENGINE_TYPE_NUMERICAL)
+               cite_styles_[ENGINE_TYPE_NUMERICAL].clear();
+       string def;
+       bool getout = false;
+       while (!getout && lexrc.isOK()) {
+               lexrc.eatLine();
+               def = lexrc.getString();
+               def = subst(def, " ", "");
+               def = subst(def, "\t", "");
+               if (compare_ascii_no_case(def, "end") == 0) {
+                       getout = true;
+                       continue;
+               }
+               string cmd;
+               CitationStyle cs;
+               char ichar = def[0];
+               if (ichar == '#')
+                       continue;
+               if (ichar == 'C') {
+                       cs.forceUpperCase = true;
+                       def[0] = 'c';
+               }
+
+               size_t const n = def.size();
+               for (size_t i = 0; i != n; ++i) {
+                       ichar = def[i];
+                       if (ichar == '*')
+                               cs.fullAuthorList = true;
+                       else if (ichar == '[' && cs.textAfter)
+                               cs.textBefore = true;
+                       else if (ichar == '[')
+                               cs.textAfter = true;
+                       else if (ichar != ']')
+                               cmd += ichar;
+               }
+
+               cs.cmd = cmd;
+               if (type & ENGINE_TYPE_AUTHORYEAR)
+                       cite_styles_[ENGINE_TYPE_AUTHORYEAR].push_back(cs);
+               if (type & ENGINE_TYPE_NUMERICAL)
+                       cite_styles_[ENGINE_TYPE_NUMERICAL].push_back(cs);
+       }
+       return getout;
+}
+
+
+int TextClass::readCiteEngineType(Lexer & lexrc) const
 {
+       int const ENGINE_TYPE_DEFAULT =
+               ENGINE_TYPE_AUTHORYEAR | ENGINE_TYPE_NUMERICAL;
+       if (!lexrc.next()) {
+               lexrc.printError("No cite engine type given for token: `$$Token'.");
+               return ENGINE_TYPE_DEFAULT;
+       }
+       string const type = rtrim(lexrc.getString());
+       if (compare_ascii_no_case(type, "authoryear") == 0)
+               return ENGINE_TYPE_AUTHORYEAR;
+       else if (compare_ascii_no_case(type, "numerical") == 0)
+               return ENGINE_TYPE_NUMERICAL;
+       else if (compare_ascii_no_case(type, "default") != 0) {
+               string const s = "Unknown cite engine type `" + type
+                       + "' given for token: `$$Token',";
+               lexrc.printError(s);
+       }
+       return ENGINE_TYPE_DEFAULT;
+}
+
+
+bool TextClass::readCiteFormat(Lexer & lexrc)
+{
+       int const type = readCiteEngineType(lexrc);
        string etype;
        string definition;
        while (lexrc.isOK()) {
                lexrc.next();
                etype = lexrc.getString();
-               if (!lexrc.isOK() || compare_ascii_no_case(etype, "end") == 0)
+               if (compare_ascii_no_case(etype, "end") == 0)
                        break;
+               if (!lexrc.isOK())
+                       return false;
                lexrc.eatLine();
                definition = lexrc.getString();
                char initchar = etype[0];
                if (initchar == '#')
                        continue;
-               if (initchar == '!' || initchar == '_')
-                       cite_macros_[etype] = definition;
-               else
-                       cite_formats_[etype] = definition;
+               if (initchar == '!' || initchar == '_') {
+                       if (type & ENGINE_TYPE_AUTHORYEAR)
+                               cite_macros_[ENGINE_TYPE_AUTHORYEAR][etype] = definition;
+                       if (type & ENGINE_TYPE_NUMERICAL)
+                               cite_macros_[ENGINE_TYPE_NUMERICAL][etype] = definition;
+               } else {
+                       if (type & ENGINE_TYPE_AUTHORYEAR)
+                               cite_formats_[ENGINE_TYPE_AUTHORYEAR][etype] = definition;
+                       if (type & ENGINE_TYPE_NUMERICAL)
+                               cite_formats_[ENGINE_TYPE_NUMERICAL][etype] = definition;
+               }
        }
+       return true;
 }
 
 
@@ -1103,15 +1241,16 @@ bool TextClass::readFloat(Lexer & lexrc)
 }
 
 
-string const & TextClass::prerequisites() const
+string const & TextClass::prerequisites(string const & sep) const
 {
        if (contains(prerequisites_, ',')) {
                vector<string> const pres = getVectorFromString(prerequisites_);
-               prerequisites_ = getStringFromVector(pres, "\n\t");
+               prerequisites_ = getStringFromVector(pres, sep);
        }
        return prerequisites_;
 }
 
+
 bool TextClass::hasLayout(docstring const & n) const
 {
        docstring const name = n.empty() ? defaultLayoutName() : n;
@@ -1126,31 +1265,27 @@ bool TextClass::hasInsetLayout(docstring const & n) const
 {
        if (n.empty())
                return false;
-       InsetLayouts::const_iterator it = insetlayoutlist_.begin();
-       InsetLayouts::const_iterator en = insetlayoutlist_.end();
-       for (; it != en; ++it)
-               if (n == it->first)
-                       return true;
-       return false;
+       InsetLayouts::const_iterator it = insetlayoutlist_.find(n);
+       return it != insetlayoutlist_.end();
 }
 
 
 Layout const & TextClass::operator[](docstring const & name) const
 {
-       LASSERT(!name.empty(), /**/);
+       LATTEST(!name.empty());
 
        const_iterator it =
                find_if(begin(), end(), LayoutNamesEqual(name));
 
        if (it == end()) {
-               lyxerr << "We failed to find the layout '" << to_utf8(name)
-                      << "' in the layout list. You MUST investigate!"
-                      << endl;
+               LYXERR0("We failed to find the layout '" << name
+                      << "' in the layout list. You MUST investigate!");
                for (const_iterator cit = begin(); cit != end(); ++cit)
                        lyxerr  << " " << to_utf8(cit->name()) << endl;
 
-               // we require the name to exist
-               LASSERT(false, /**/);
+               // We require the name to exist
+               static const Layout dummy;
+               LASSERT(false, return dummy);
        }
 
        return *it;
@@ -1159,7 +1294,8 @@ Layout const & TextClass::operator[](docstring const & name) const
 
 Layout & TextClass::operator[](docstring const & name)
 {
-       LASSERT(!name.empty(), /**/);
+       LATTEST(!name.empty());
+       // Safe to continue, given what we do below.
 
        iterator it = find_if(begin(), end(), LayoutNamesEqual(name));
 
@@ -1170,7 +1306,10 @@ Layout & TextClass::operator[](docstring const & name)
                        LYXERR0(" " << to_utf8(cit->name()));
 
                // we require the name to exist
-               LASSERT(false, /**/);
+               LATTEST(false);
+               // we are here only in release mode
+               layoutlist_.push_back(createBasicLayout(name, true));
+               it = find_if(begin(), end(), LayoutNamesEqual(name));
        }
 
        return *it;
@@ -1193,6 +1332,12 @@ bool TextClass::deleteLayout(docstring const & name)
 }
 
 
+bool TextClass::deleteInsetLayout(docstring const & name)
+{
+       return insetlayoutlist_.erase(name);
+}
+
+
 // Load textclass info if not loaded yet
 bool TextClass::load(string const & path) const
 {
@@ -1300,47 +1445,20 @@ Layout TextClass::createBasicLayout(docstring const & name, bool unknown) const
        if (!readStyle(lex, *defaultLayout)) {
                // The only way this happens is because the hardcoded layout above
                // is wrong.
-               LASSERT(false, /**/);
+               LATTEST(false);
        };
        return *defaultLayout;
 }
 
 
-/////////////////////////////////////////////////////////////////////////
-//
-// DocumentClassBundle
-//
-/////////////////////////////////////////////////////////////////////////
-
-DocumentClassBundle::~DocumentClassBundle()
-{
-       for (size_t i = 0; i != documentClasses_.size(); ++i)
-               delete documentClasses_[i];
-       documentClasses_.clear();
-}
-
-DocumentClass & DocumentClassBundle::newClass(LayoutFile const & baseClass)
-{
-       DocumentClass * dc = new DocumentClass(baseClass);
-       documentClasses_.push_back(dc);
-       return *documentClasses_.back();
-}
-
-
-DocumentClassBundle & DocumentClassBundle::get()
-{
-       static DocumentClassBundle singleton;
-       return singleton;
-}
-
-
-DocumentClass & DocumentClassBundle::makeDocumentClass(
+DocumentClassPtr getDocumentClass(
                LayoutFile const & baseClass, LayoutModuleList const & modlist)
 {
-       DocumentClass & doc_class = newClass(baseClass);
+       DocumentClassPtr doc_class =
+           DocumentClassPtr(new DocumentClass(baseClass));
        LayoutModuleList::const_iterator it = modlist.begin();
        LayoutModuleList::const_iterator en = modlist.end();
-       for (; it != en; it++) {
+       for (; it != en; ++it) {
                string const modName = *it;
                LyXModule * lm = theModuleList[modName];
                if (!lm) {
@@ -1365,7 +1483,7 @@ DocumentClass & DocumentClassBundle::makeDocumentClass(
                        frontend::Alert::warning(_("Package not available"), msg, true);
                }
                FileName layout_file = libFileSearch("layouts", lm->getFilename());
-               if (!doc_class.read(layout_file, TextClass::MODULE)) {
+               if (!doc_class->read(layout_file, TextClass::MODULE)) {
                        docstring const msg =
                                                bformat(_("Error reading module %1$s\n"), from_utf8(modName));
                        frontend::Alert::warning(_("Read Error"), msg);
@@ -1409,50 +1527,91 @@ bool DocumentClass::hasTocLevels() const
 }
 
 
-Layout const & DocumentClass::htmlTOCLayout() const
+Layout const & DocumentClass::getTOCLayout() const
 {
-       if (html_toc_section_.empty()) {
-               // we're going to look for the layout with the minimum toclevel
-               TextClass::LayoutList::const_iterator lit = begin();
-               TextClass::LayoutList::const_iterator const len = end();
-               int minlevel = 1000;
-               Layout const * lay = NULL;
-               for (; lit != len; ++lit) {
-                       int const level = lit->toclevel;
-                       // we don't want Part
-                       if (level == Layout::NOT_IN_TOC || level < 0 || level >= minlevel)
-                               continue;
-                       lay = &*lit;
-                       minlevel = level;
-               }
-               if (lay)
-                       html_toc_section_ = lay->name();
-               else
-                       // hmm. that is very odd, so we'll do our best
-                       html_toc_section_ = defaultLayoutName();
+       // we're going to look for the layout with the minimum toclevel
+       TextClass::LayoutList::const_iterator lit = begin();
+       TextClass::LayoutList::const_iterator const len = end();
+       int minlevel = 1000;
+       Layout const * lay = NULL;
+       for (; lit != len; ++lit) {
+               int const level = lit->toclevel;
+               // we don't want Part or unnumbered sections
+               if (level == Layout::NOT_IN_TOC || level < 0 
+                   || level >= minlevel || lit->counter.empty())
+                       continue;
+               lay = &*lit;
+               minlevel = level;
        }
+       if (lay)
+               return *lay;
+       // hmm. that is very odd, so we'll do our best.
+       return operator[](defaultLayoutName());
+}
+
+
+Layout const & DocumentClass::htmlTOCLayout() const
+{
+       if (html_toc_section_.empty())
+               html_toc_section_ = getTOCLayout().name();
        return operator[](html_toc_section_);
 }
 
 
-string const & DocumentClass::getCiteFormat(string const & entry_type) const
+string const & DocumentClass::getCiteFormat(CiteEngineType const & type,
+       string const & entry, string const & fallback) const
 {
        static string default_format = "{%author%[[%author%, ]][[{%editor%[[%editor%, ed., ]]}]]}\"%title%\"{%journal%[[, {!<i>!}%journal%{!</i>!}]][[{%publisher%[[, %publisher%]][[{%institution%[[, %institution%]]}]]}]]}{%year%[[ (%year%)]]}{%pages%[[, %pages%]]}.";
 
-       map<string, string>::const_iterator it = cite_formats_.find(entry_type);
-       if (it != cite_formats_.end())
-               return it->second;
-       return default_format;
+       map<CiteEngineType, map<string, string> >::const_iterator itype = cite_formats_.find(type);
+       if (itype == cite_formats_.end())
+               return default_format;
+       map<string, string>::const_iterator it = itype->second.find(entry);
+       if (it == itype->second.end() && !fallback.empty())
+               it = itype->second.find(fallback);
+       if (it == itype->second.end())
+               return default_format;
+       return it->second;
 }
 
 
-string const & DocumentClass::getCiteMacro(string const & macro) const
+string const & DocumentClass::getCiteMacro(CiteEngineType const & type,
+       string const & macro) const
 {
        static string empty;
-       map<string, string>::const_iterator it = cite_macros_.find(macro);
-       if (it != cite_macros_.end())
-               return it->second;
-       return empty;
+       map<CiteEngineType, map<string, string> >::const_iterator itype = cite_macros_.find(type);
+       if (itype == cite_macros_.end())
+               return empty;
+       map<string, string>::const_iterator it = itype->second.find(macro);
+       if (it == itype->second.end())
+               return empty;
+       return it->second;
+}
+
+
+vector<string> const DocumentClass::citeCommands(
+       CiteEngineType const & type) const
+{
+       vector<CitationStyle> const styles = citeStyles(type);
+       vector<CitationStyle>::const_iterator it = styles.begin();
+       vector<CitationStyle>::const_iterator end = styles.end();
+       vector<string> cmds;
+       for (; it != end; ++it) {
+               CitationStyle const cite = *it;
+               cmds.push_back(cite.cmd);
+       }
+       return cmds;
+}
+
+
+vector<CitationStyle> const & DocumentClass::citeStyles(
+       CiteEngineType const & type) const
+{
+       static vector<CitationStyle> empty;
+       map<CiteEngineType, vector<CitationStyle> >::const_iterator it = cite_styles_.find(type);
+       if (it == cite_styles_.end())
+               return empty;
+       return it->second;
 }