diff --git a/lib/Makefile.am b/lib/Makefile.am index 4b9f83edd7..d2473d948d 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1334,6 +1334,7 @@ dist_layouts_DATA =\ layouts/armenian-article.layout \ layouts/article.layout \ layouts/article-beamer.layout \ + layouts/basic.module \ layouts/beamer.layout \ layouts/bicaption.module \ layouts/book.layout \ @@ -1401,6 +1402,7 @@ dist_layouts_DATA =\ layouts/jsarticle.layout \ layouts/jsbook.layout \ layouts/jss.layout \ + layouts/jurabib.module \ layouts/kluwer.layout \ layouts/knitr.module \ layouts/latex8.layout \ @@ -1423,6 +1425,7 @@ dist_layouts_DATA =\ layouts/mwart.layout \ layouts/mwbk.layout \ layouts/mwrep.layout \ + layouts/natbib.module \ layouts/noweb.module \ layouts/numarticle.inc \ layouts/numreport.inc \ diff --git a/lib/layouts/basic.module b/lib/layouts/basic.module new file mode 100644 index 0000000000..59d8c22015 --- /dev/null +++ b/lib/layouts/basic.module @@ -0,0 +1,41 @@ +# \DeclareLyXModule{Default (basic)} +# DescriptionBegin +# Use the basic citation capabilities provided by plain LaTeX. +# DescriptionEnd +# Excludes: jurabib | natbib +# Category: Citation engine + +# Author: Julien Rioux + +Format 37 + +CiteEngineType numerical +DefaultBiblio plain + +CiteEngine default + cite[] + nocite +End + +CiteFormat default + # translatable bits + _notcited not cited + _addtobib Add to bibliography only. + + # macros + !open [ + !sep , + !close ] + + !cite {%label%[[%label%]][[#%key%]]}%!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 new file mode 100644 index 0000000000..053638647a --- /dev/null +++ b/lib/layouts/jurabib.module @@ -0,0 +1,101 @@ +# \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 + +Format 37 + +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 ) + + !cite %!shortauthor%%!textbefore2%%!textafter2%%!nextcite% + !citetitle %!shortauthor%%!textbefore2%%!shorttitle%%!textafter2%%!nextcitetitle% + !citet %!textbefore%%!shortauthor% %!open%%!year%%!textafter%%!close%%!nextcitet% + !citep %!open%%!citealp%%!close% + !citealt %!textbefore%%!shortauthor% %!year%%!textafter%%!nextcitealt% + !citealp %!textbefore%%!shortauthor%, %!year%%!textafter%%!nextcitealp% + !citeauthor %!textbefore%%!shortauthor%%!textafter%%!nextauthor% + !citeyear %!textbefore%%!year%%!textafter%%!nextyear% + !citeyearpar %!textbefore%%!open%%!year%%!close%%!textafter%%!nextyearpar% + + !nextcite {%next%[[%!sep% %!shortauthor%%!textafter2%%!nextcite%]]} + !nextcitetitle {%next%[[%!sep% %!shortauthor%%!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%]]} + !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%]][[??]]} + + # cite styles + cite %!cite% + citetitle %!citetitle% + citet %!citet% + citep %!citep% + citealt %!citealt% + citealp %!citealp% + citeauthor %!citeauthor% + citeyear %!citeyear% + citeyearpar %!citeyearpar% + fullcite {%dialog%[[%_bibentry%]][[%key%%!nextkey% (%_fullcite%)]]} + nocite {%dialog%[[%_addtobib%]][[%key%%!nextkey% (%_notcited%)]]} +End diff --git a/lib/layouts/natbib.module b/lib/layouts/natbib.module new file mode 100644 index 0000000000..e8e816fb4a --- /dev/null +++ b/lib/layouts/natbib.module @@ -0,0 +1,100 @@ +# \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 + +Format 37 + +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 + !open [ + !sep , + !close ] + + !nextauthor {%next%[[%!sep% %!abbrvauthor%%!nextauthor%]]} + !nextkey {%next%[[%!sep% %key%%!nextkey%]]} + !nextyear {%next%[[%!sep% %!year%%!nextyear%]]} + + !abbrvauthor {%abbrvauthor%[[%abbrvauthor%]][[??]]} + !textbefore {%textbefore%[[%textbefore% ]]} + !textafter {%textafter%[[, %textafter%]]} + !year {%year%[[%year%]][[??]]} + + # cite styles + citet %!citet%%!textafter%%!close% + citealt %!citealt%%!textafter% + citeyearpar %!open%%!textbefore%%!year%%!nextyear%%!textafter%%!close% + nocite {%dialog%[[%_addtobib%]][[%key%%!nextkey% (%_notcited%)]]} +End + +CiteFormat authoryear + !citet %!abbrvauthor% %!open%%!textbefore%%!year%%!nextcitet% + !citealt %!abbrvauthor% %!textbefore%%!year%%!nextcitealt% + !citealp %!abbrvauthor%, %!year%%!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 %!abbrvauthor%%!nextauthor%%!textafter% + citeyear %!year%%!nextyear%%!textafter% +End + +CiteFormat numerical + !citet %!abbrvauthor% %!open%%!textbefore%{%dialog%[[#ID]][[#%key%]]}%!nextcitet% + !citealt %!abbrvauthor% %!textbefore%{%dialog%[[#ID]][[#%key%]]}%!nextcitealt% + + !hashkey {%dialog%[[#ID]][[#%key%%!nexthashkey%]]} + + !nextcitet {%next%[[%!close%%!sep% %!citet%]]} + !nextcitealt {%next%[[%!sep% %!citealt%]]} + !nexthashid {%next%[[%!sep% #ID%!nexthashid%]]} + !nexthashkey {%next%[[%!sep% #%key%%!nexthashkey%]]} + + cite %!open%%!textbefore%%!hashkey%%!textafter%%!close% + citep %!open%%!textbefore%%!hashkey%%!textafter%%!close% + citealp %!textbefore%%!hashkey%%!textafter% + citeauthor %!abbrvauthor%%!nextauthor% + citeyear %!year%%!nextyear% +End diff --git a/lib/scripts/layout2layout.py b/lib/scripts/layout2layout.py index 112bf4e9fd..9de6c8372f 100644 --- a/lib/scripts/layout2layout.py +++ b/lib/scripts/layout2layout.py @@ -125,6 +125,10 @@ import os, re, string, sys # Incremented to format 36, 7 December 2011, by rgh # Added HTMLStyles and AddToHTMLStyles tags. +# Incremented to format 37, 29 February 2012 by jrioux +# Implement the citation engine machinery in layouts. +# Change CiteFormat to CiteFormat (default|authoryear|numerical). + # Do not forget to document format change in Customization # Manual (section "Declaring a new text class"). @@ -132,7 +136,7 @@ import os, re, string, sys # development/tools/updatelayouts.sh script to update all # layout files to the new format. -currentFormat = 36 +currentFormat = 37 def usage(prog_name): @@ -206,6 +210,7 @@ def convert(lines): re_End = re.compile(r'^(\s*)(End)(\s*)$', re.IGNORECASE) re_Provides = re.compile(r'^(\s*)Provides(\S+)(\s+)(\S+)', re.IGNORECASE) re_CharStyle = re.compile(r'^(\s*)CharStyle(\s+)(\S+)$', re.IGNORECASE) + re_CiteFormat = re.compile(r'^(\s*)(CiteFormat)(?:(\s*)()|(\s+)(default|authoryear|numerical))', re.IGNORECASE) re_AMSMaths = re.compile(r'^\s*Input ams(?:math|def)s.inc\s*') re_AMSMathsPlain = re.compile(r'^\s*Input amsmaths-plain.inc\s*') re_AMSMathsSeq = re.compile(r'^\s*Input amsmaths-seq.inc\s*') @@ -317,6 +322,13 @@ def convert(lines): i += 1 continue + if format == 36: + match = re_CiteFormat.match(lines[i]); + if match and match.group(4) == "": + lines[i] = match.group(0) + " default" + i += 1 + continue + if format == 35: i += 1 continue diff --git a/src/BiblioInfo.cpp b/src/BiblioInfo.cpp index 82690449ec..470c7ee4f8 100644 --- a/src/BiblioInfo.cpp +++ b/src/BiblioInfo.cpp @@ -206,7 +206,7 @@ BibTeXInfo::BibTeXInfo(docstring const & key, docstring const & type) {} -docstring const BibTeXInfo::getAbbreviatedAuthor() const +docstring const BibTeXInfo::getAbbreviatedAuthor(bool jurabib_style) const { if (!is_bibtex_) { docstring const opt = label(); @@ -226,7 +226,7 @@ docstring const BibTeXInfo::getAbbreviatedAuthor() const if (author.empty()) { author = convertLaTeXCommands(operator[]("editor")); if (author.empty()) - return bib_key_; + return author; } // FIXME Move this to a separate routine that can @@ -237,6 +237,14 @@ docstring const BibTeXInfo::getAbbreviatedAuthor() const vector const authors = getVectorFromString(author, from_ascii(" and ")); + if (jurabib_style && (authors.size() == 2 || authors.size() == 3)) { + docstring shortauthor = familyName(authors[0]) + + "/" + familyName(authors[1]); + if (authors.size() == 3) + shortauthor += "/" + familyName(authors[2]); + return shortauthor; + } + if (authors.size() == 2) return bformat(_("%1$s and %2$s"), familyName(authors[0]), familyName(authors[1])); @@ -391,7 +399,7 @@ namespace { docstring BibTeXInfo::expandFormat(string const & format, BibTeXInfo const * const xref, int & counter, Buffer const & buf, - bool richtext) const + bool richtext, docstring before, docstring after, docstring dialog, bool next) const { // incorrect use of macros could put us in an infinite loop static int max_passes = 5000; @@ -400,6 +408,7 @@ docstring BibTeXInfo::expandFormat(string const & format, bool scanning_key = false; bool scanning_rich = false; + CiteEngineType const engine_type = buf.params().citeEngineType(); string fmt = format; // we'll remove characters from the front of fmt as we // deal with them @@ -419,19 +428,21 @@ docstring BibTeXInfo::expandFormat(string const & format, // so we replace the key with its value, which may be empty if (key[0] == '!') { // macro + // FIXME: instead of passing the buf, just past the macros + // FIXME: and the language code string const val = - buf.params().documentClass().getCiteMacro(key); + buf.params().documentClass().getCiteMacro(engine_type, key); fmt = val + fmt.substr(1); continue; } else if (key[0] == '_') { // a translatable bit string const val = - buf.params().documentClass().getCiteMacro(key); + buf.params().documentClass().getCiteMacro(engine_type, key); docstring const trans = translateIfPossible(from_utf8(val), buf.params().language->code()); ret += trans; } else { - docstring const val = getValueForKey(key, xref); + docstring const val = getValueForKey(key, before, after, dialog, xref); ret += val; } } else { @@ -457,11 +468,15 @@ docstring BibTeXInfo::expandFormat(string const & format, if (newfmt == fmt) // parse error return _("ERROR!"); fmt = newfmt; - docstring const val = getValueForKey(optkey, xref); - if (!val.empty()) - ret += expandFormat(ifpart, xref, counter, buf, richtext); + docstring const val = getValueForKey(optkey, before, after, dialog, xref); + if (optkey == "next" && next) + ret += from_utf8(ifpart); // without expansion + else if (!val.empty()) + ret += expandFormat(ifpart, xref, counter, buf, + richtext, before, after, dialog, next); else if (!elsepart.empty()) - ret += expandFormat(elsepart, xref, counter, buf, richtext); + ret += expandFormat(elsepart, xref, counter, buf, + richtext, before, after, dialog, next); // fmt will have been shortened for us already continue; } @@ -527,8 +542,9 @@ docstring const & BibTeXInfo::getInfo(BibTeXInfo const * const xref, return info_; } + CiteEngineType const engine_type = buf.params().citeEngineType(); DocumentClass const & dc = buf.params().documentClass(); - string const & format = dc.getCiteFormat(to_utf8(entry_type_)); + string const & format = dc.getCiteFormat(engine_type, to_utf8(entry_type_)); int counter = 0; info_ = expandFormat(format, xref, counter, buf, richtext); @@ -538,6 +554,30 @@ docstring const & BibTeXInfo::getInfo(BibTeXInfo const * const xref, } +docstring const BibTeXInfo::getLabel(BibTeXInfo const * const xref, + Buffer const & buf, string const & format, bool richtext, + docstring before, docstring after, docstring dialog, bool next) const +{ + docstring loclabel_; + + /* + if (!is_bibtex_) { + BibTeXInfo::const_iterator it = find(from_ascii("ref")); + label_ = it->second; + return label_; + } + */ + + int counter = 0; + loclabel_ = expandFormat(format, xref, counter, buf, richtext, + before, after, dialog, next); + + if (!loclabel_.empty()) + loclabel_ = convertLaTeXCommands(loclabel_); + return loclabel_; +} + + docstring const & BibTeXInfo::operator[](docstring const & field) const { BibTeXInfo::const_iterator it = find(field); @@ -555,12 +595,48 @@ docstring const & BibTeXInfo::operator[](string const & field) const docstring BibTeXInfo::getValueForKey(string const & key, - BibTeXInfo const * const xref) const + docstring const & before, docstring const & after, docstring const & dialog, + BibTeXInfo const * const xref) const { - docstring const ret = operator[](key); - if (!ret.empty() || !xref) + docstring ret = operator[](key); + if (ret.empty() && xref) + ret = (*xref)[key]; + if (!ret.empty()) return ret; - return (*xref)[key]; + // some special keys + // FIXME: dialog, textbefore and textafter have nothing to do with this + if (key == "dialog") + return dialog; + else if (key == "entrytype") + return entry_type_; + else if (key == "key") + return bib_key_; + else if (key == "label") + return label_; + else if (key == "abbrvauthor") + // Special key to provide abbreviated author names. + return getAbbreviatedAuthor(); + else if (key == "shortauthor") + // When shortauthor is not defined, jurabib automatically + // provides jurabib-style abbreviated author names. We do + // this as well. + return getAbbreviatedAuthor(true); + else if (key == "shorttitle") { + // When shorttitle is not defined, jurabib uses for `article' + // and `periodical' entries the form `journal volume [year]' + // and for other types of entries it uses the `title' field. + if (entry_type_ == "article" || entry_type_ == "periodical") + return operator[]("journal") + " " + operator[]("volume") + + " [" + operator[]("year") + "]"; + else + return operator[]("title"); + } else if (key == "textbefore") + return before; + else if (key == "textafter") + return after; + else if (key == "year") + return getYear(); + return ret; } @@ -679,6 +755,38 @@ docstring const BiblioInfo::getInfo(docstring const & key, } +docstring const BiblioInfo::getLabel(vector const & keys, + Buffer const & buf, string const & style, bool richtext, + docstring const & before, docstring const & after, docstring const & dialog) const +{ + CiteEngineType const engine_type = buf.params().citeEngineType(); + DocumentClass const & dc = buf.params().documentClass(); + string const & format = dc.getCiteFormat(engine_type, style, "cite"); + docstring ret = from_utf8(format); + vector::const_iterator key = keys.begin(); + vector::const_iterator ken = keys.end(); + for (; key != ken; ++key) { + BiblioInfo::const_iterator it = find(*key); + BibTeXInfo empty_data; + empty_data.key(*key); + BibTeXInfo & data = empty_data; + BibTeXInfo const * xrefptr = 0; + if (it != end()) { + data = it->second; + docstring const xref = data.getXRef(); + if (!xref.empty()) { + BiblioInfo::const_iterator const xrefit = find(xref); + if (xrefit != end()) + xrefptr = &(xrefit->second); + } + } + ret = data.getLabel(xrefptr, buf, to_utf8(ret), richtext, + before, after, dialog, key+1 != ken); + } + return ret; +} + + bool BiblioInfo::isBibtex(docstring const & key) const { BiblioInfo::const_iterator it = find(key); @@ -688,141 +796,25 @@ bool BiblioInfo::isBibtex(docstring const & key) const } - vector const BiblioInfo::getCiteStrings( - docstring const & key, Buffer const & buf) const -{ - CiteEngineType const engine_type = buf.params().citeEngineType(); - if (engine_type == ENGINE_TYPE_NUMERICAL) - return getNumericalStrings(key, buf); - else - return getAuthorYearStrings(key, buf); -} - - -vector const BiblioInfo::getNumericalStrings( - docstring const & key, Buffer const & buf) const + vector const & keys, vector const & styles, + Buffer const & buf, bool richtext, docstring const & before, + docstring const & after, docstring const & dialog) const { if (empty()) return vector(); - docstring const author = getAbbreviatedAuthor(key); - docstring const year = getYear(key); - if (author.empty() || year.empty()) - return vector(); - - vector const & styles = citeStyles(buf.params().citeEngine(), - buf.params().citeEngineType()); - + string style; vector vec(styles.size()); for (size_t i = 0; i != vec.size(); ++i) { - docstring str; - - switch (styles[i]) { - case CITE: - case CITEP: - str = from_ascii("[#ID]"); - break; - - case NOCITE: - str = _("Add to bibliography only."); - break; - - case CITET: - str = author + " [#ID]"; - break; - - case CITEALT: - str = author + " #ID"; - break; - - case CITEALP: - str = from_ascii("#ID"); - break; - - case CITEAUTHOR: - str = author; - break; - - case CITEYEAR: - str = year; - break; - - case CITEYEARPAR: - str = '(' + year + ')'; - break; - } - - vec[i] = str; + style = styles[i].cmd; + vec[i] = getLabel(keys, buf, style, richtext, before, after, dialog); } return vec; } -vector const BiblioInfo::getAuthorYearStrings( - docstring const & key, Buffer const & buf) const -{ - if (empty()) - return vector(); - - docstring const author = getAbbreviatedAuthor(key); - docstring const year = getYear(key); - if (author.empty() || year.empty()) - return vector(); - - vector const & styles = citeStyles(buf.params().citeEngine(), - buf.params().citeEngineType()); - - vector vec(styles.size()); - for (size_t i = 0; i != vec.size(); ++i) { - docstring str; - - switch (styles[i]) { - case CITE: - // jurabib only: Author/Annotator - // (i.e. the "before" field, 2nd opt arg) - str = author + "/<" + _("before") + '>'; - break; - - case NOCITE: - str = _("Add to bibliography only."); - break; - - case CITET: - str = author + " (" + year + ')'; - break; - - case CITEP: - str = '(' + author + ", " + year + ')'; - break; - - case CITEALT: - str = author + ' ' + year ; - break; - - case CITEALP: - str = author + ", " + year ; - break; - - case CITEAUTHOR: - str = author; - break; - - case CITEYEAR: - str = year; - break; - - case CITEYEARPAR: - str = '(' + year + ')'; - break; - } - vec[i] = str; - } - return vec; -} - - void BiblioInfo::mergeBiblioInfo(BiblioInfo const & info) { bimap_.insert(info.begin(), info.end()); @@ -947,128 +939,38 @@ void BiblioInfo::makeCitationLabels(Buffer const & buf) // ////////////////////////////////////////////////////////////////////// -namespace { - - -char const * const citeCommands[] = { - "cite", "citet", "citep", "citealt", "citealp", - "citeauthor", "citeyear", "citeyearpar", "nocite" }; - -unsigned int const nCiteCommands = - sizeof(citeCommands) / sizeof(char *); - -CiteStyle const citeStylesArray[] = { - CITE, CITET, CITEP, CITEALT, CITEALP, - CITEAUTHOR, CITEYEAR, CITEYEARPAR, NOCITE }; - -unsigned int const nCiteStyles = - sizeof(citeStylesArray) / sizeof(CiteStyle); - -CiteStyle const citeStylesFull[] = { - CITET, CITEP, CITEALT, CITEALP, CITEAUTHOR }; - -unsigned int const nCiteStylesFull = - sizeof(citeStylesFull) / sizeof(CiteStyle); - -CiteStyle const citeStylesUCase[] = { - CITET, CITEP, CITEALT, CITEALP, CITEAUTHOR }; - -unsigned int const nCiteStylesUCase = - sizeof(citeStylesUCase) / sizeof(CiteStyle); - -} // namespace anon - CitationStyle citationStyleFromString(string const & command) { - CitationStyle s; + CitationStyle cs; if (command.empty()) - return s; + return cs; string cmd = command; if (cmd[0] == 'C') { - s.forceUpperCase = true; + cs.forceUpperCase = true; cmd[0] = 'c'; } size_t const n = cmd.size() - 1; - if (cmd != "cite" && cmd[n] == '*') { - s.full = true; + if (cmd[n] == '*') { + cs.fullAuthorList = true; cmd = cmd.substr(0, n); } - char const * const * const last = citeCommands + nCiteCommands; - char const * const * const ptr = find(citeCommands, last, cmd); - - if (ptr != last) { - size_t idx = ptr - citeCommands; - s.style = citeStylesArray[idx]; - } - return s; + cs.cmd = cmd; + return cs; } -string citationStyleToString(const CitationStyle & s) +string citationStyleToString(const CitationStyle & cs) { - string cite = citeCommands[s.style]; - if (s.full) { - CiteStyle const * last = citeStylesFull + nCiteStylesFull; - if (std::find(citeStylesFull, last, s.style) != last) - cite += '*'; - } - - if (s.forceUpperCase) { - CiteStyle const * last = citeStylesUCase + nCiteStylesUCase; - if (std::find(citeStylesUCase, last, s.style) != last) - cite[0] = 'C'; - } - - return cite; -} - -vector citeStyles(CiteEngine engine, CiteEngineType engine_type) -{ - vector styles(0); - - if (engine_type == ENGINE_TYPE_AUTHORYEAR) { - switch (engine) { - case ENGINE_BASIC: - styles.push_back(CITE); - break; - case ENGINE_JURABIB: - styles.push_back(CITE); - case ENGINE_NATBIB: - styles.push_back(CITET); - styles.push_back(CITEP); - styles.push_back(CITEALT); - styles.push_back(CITEALP); - styles.push_back(CITEAUTHOR); - styles.push_back(CITEYEAR); - styles.push_back(CITEYEARPAR); - break; - } - } else { - switch (engine) { - case ENGINE_BASIC: - styles.push_back(CITE); - break; - case ENGINE_JURABIB: - styles.push_back(CITE); - case ENGINE_NATBIB: - styles.push_back(CITET); - styles.push_back(CITEALT); - styles.push_back(CITEAUTHOR); - styles.push_back(CITEP); - styles.push_back(CITEALP); - styles.push_back(CITEYEAR); - styles.push_back(CITEYEARPAR); - break; - } - } - - styles.push_back(NOCITE); - - return styles; + string cmd = cs.cmd; + if (cs.forceUpperCase) + cmd[0] = 'C'; + if (cs.fullAuthorList) + cmd += '*'; + return cmd; } } // namespace lyx diff --git a/src/BiblioInfo.h b/src/BiblioInfo.h index c84300f31f..65d1b21fe0 100644 --- a/src/BiblioInfo.h +++ b/src/BiblioInfo.h @@ -27,9 +27,6 @@ namespace lyx { class Buffer; -/// FIXME: To Citation.cpp? -/// Returns a vector of available Citation styles. -std::vector citeStyles(CiteEngine, CiteEngineType); /// \param latex_str a LaTeX command, "cite", "Citep*", etc CitationStyle citationStyleFromString(std::string const & latex_str); /// the other way round @@ -54,7 +51,7 @@ public: /// constructor that sets the entryType BibTeXInfo(docstring const & key, docstring const & type); /// \return the short form of an authorlist - docstring const getAbbreviatedAuthor() const; + docstring const getAbbreviatedAuthor(bool jurabib_style = false) const; /// docstring const getYear() const; /// @@ -63,6 +60,10 @@ public: /// \param pointer to crossref information docstring const & getInfo(BibTeXInfo const * const xref, Buffer const & buf, bool richtext) const; + /// \return formatted BibTeX data for a citation label + docstring const getLabel(BibTeXInfo const * const xref, + Buffer const & buf, std::string const & format, bool richtext, + docstring before, docstring after, docstring dialog, bool next = false) const; /// const_iterator find(docstring const & f) const { return bimap_.find(f); } /// @@ -84,6 +85,8 @@ public: /// void label(docstring const & d) { label_= d; } /// + void key(docstring const & d) { bib_key_= d; } + /// docstring const & label() const { return label_; } /// docstring const & key() const { return bib_key_; } @@ -106,7 +109,8 @@ private: /// to get the data from xref BibTeXInfo object, which would normally /// be the one referenced in the crossref field. docstring getValueForKey(std::string const & key, - BibTeXInfo const * const xref = 0) const; + docstring const & before, docstring const & after, docstring const & dialog, + BibTeXInfo const * const xref = 0) const; /// replace %keys% in a format string with their values /// called from getInfo() /// format strings may contain: @@ -122,8 +126,9 @@ private: /// moreover, keys that look like "%_key%" are treated as translatable /// so that things like "pp." and "vol." can be translated. docstring expandFormat(std::string const & fmt, - BibTeXInfo const * const xref, int & counter, - Buffer const & buf, bool richtext) const; + BibTeXInfo const * const xref, int & counter, + Buffer const & buf, bool richtext, docstring before = docstring(), + docstring after = docstring(), docstring dialog = docstring(), bool next = false) const; /// true if from BibTeX; false if from bibliography environment bool is_bibtex_; /// the BibTeX key for this entry @@ -177,38 +182,24 @@ public: /// marked in the citation format and escape < and > elsewhere. docstring const getInfo(docstring const & key, Buffer const & buf, bool richtext = false) const; + /// \return formatted BibTeX data for citation labels. + /// Citation labels can have more than one key. + docstring const getLabel(std::vector const & keys, + Buffer const & buf, std::string const & style, bool richtext = false, + docstring const & before = docstring(), + docstring const & after = docstring(), + docstring const & dialog = docstring()) const; /// Is this a reference from a bibtex database /// or from a bibliography environment? bool isBibtex(docstring const & key) const; - /** - * "Translates" the available Citation Styles into strings for a given key, - * either numerical or author-year depending upon the active engine. (See - * below for those methods.) - */ - std::vector const - getCiteStrings(docstring const & key, Buffer const & buf) const; - /** - * "Translates" the available Citation Styles into strings for a given key. - * The returned string is displayed by the GUI. - * [XX] is used in place of the actual reference - * Eg, the vector will contain: [XX], Jones et al. [XX], ... - * User supplies : - * the key, - * the buffer - */ - std::vector const - getNumericalStrings(docstring const & key, Buffer const & buf) const; - /** - * "Translates" the available Citation Styles into strings for a given key. - * The returned string is displayed by the GUI. - * Eg, the vector will contain: - * Jones et al. (1990), (Jones et al. 1990), Jones et al. 1990, ... - * User supplies : - * the key, - * the buffer - */ - std::vector const - getAuthorYearStrings(docstring const & key, Buffer const & buf) const; + /// Translates the available citation styles into strings for a given + /// list of keys, using either numerical or author-year style depending + /// upon the active engine. + std::vector const getCiteStrings(std::vector const & keys, + std::vector const & styles, Buffer const & buf, bool richtext = false, + docstring const & before = docstring(), + docstring const & after = docstring(), + docstring const & dialog = docstring()) const; /// Collects the cited entries from buf. void collectCitedEntries(Buffer const & buf); /// A list of BibTeX keys cited in the current document, sorted by diff --git a/src/BufferParams.cpp b/src/BufferParams.cpp index d6415415be..2c97acef6b 100644 --- a/src/BufferParams.cpp +++ b/src/BufferParams.cpp @@ -259,25 +259,6 @@ PackageTranslator const & packagetranslator() // Cite engine -typedef Translator CiteEngineTranslator; - - -CiteEngineTranslator const init_citeenginetranslator() -{ - CiteEngineTranslator translator("basic", ENGINE_BASIC); - translator.addPair("natbib", ENGINE_NATBIB); - translator.addPair("jurabib", ENGINE_JURABIB); - return translator; -} - - -CiteEngineTranslator const & citeenginetranslator() -{ - static CiteEngineTranslator translator = init_citeenginetranslator(); - return translator; -} - - typedef Translator CiteEngineTypeTranslator; @@ -378,7 +359,7 @@ BufferParams::BufferParams() papersize = PAPER_DEFAULT; orientation = ORIENTATION_PORTRAIT; use_geometry = false; - cite_engine_ = ENGINE_BASIC; + cite_engine_.push_back("basic"); cite_engine_type_ = ENGINE_TYPE_NUMERICAL; biblio_style = "plain"; use_bibtopic = false; @@ -726,9 +707,9 @@ string BufferParams::readToken(Lexer & lex, string const & token, lex >> use; use_package(package, packagetranslator().find(use)); } else if (token == "\\cite_engine") { - string engine; - lex >> engine; - cite_engine_ = citeenginetranslator().find(engine); + lex.eatLine(); + vector engine = getVectorFromString(lex.getString()); + setCiteEngine(engine); } else if (token == "\\cite_engine_type") { string engine_type; lex >> engine_type; @@ -1037,8 +1018,22 @@ void BufferParams::writeFile(ostream & os) const for (size_t i = 0; i < packages.size(); ++i) os << "\n\\use_package " << packages[i] << ' ' << use_package(packages[i]); - os << "\n\\cite_engine " << citeenginetranslator().find(cite_engine_) - << "\n\\cite_engine_type " << citeenginetypetranslator().find(cite_engine_type_) + + os << "\n\\cite_engine "; + + if (!cite_engine_.empty()) { + LayoutModuleList::const_iterator be = cite_engine_.begin(); + LayoutModuleList::const_iterator en = cite_engine_.end(); + for (LayoutModuleList::const_iterator it = be; it != en; ++it) { + if (it != be) + os << ','; + os << *it; + } + } else { + os << "basic"; + } + + os << "\n\\cite_engine_type " << citeenginetypetranslator().find(cite_engine_type_) << "\n\\biblio_style " << biblio_style << "\n\\use_bibtopic " << convert(use_bibtopic) << "\n\\use_indices " << convert(use_indices) @@ -2024,7 +2019,19 @@ void BufferParams::makeDocumentClass() if (!baseClass()) return; - doc_class_ = &(DocumentClassBundle::get().makeDocumentClass(*baseClass(), layout_modules_)); + LayoutModuleList mods; + LayoutModuleList::iterator it; + LayoutModuleList::iterator en; + + it = layout_modules_.begin(); + en = layout_modules_.end(); + for (; it != en; it++) + mods.push_back(*it); + it = cite_engine_.begin(); + en = cite_engine_.end(); + for (; it != en; it++) + mods.push_back(*it); + doc_class_ = &(DocumentClassBundle::get().makeDocumentClass(*baseClass(), mods)); if (!local_layout.empty()) { TextClass::ReturnValues success = @@ -2039,7 +2046,8 @@ void BufferParams::makeDocumentClass() bool BufferParams::moduleCanBeAdded(string const & modName) const { - return layout_modules_.moduleCanBeAdded(modName, baseClass()); + return cite_engine_.moduleCanBeAdded(modName, baseClass()) && + layout_modules_.moduleCanBeAdded(modName, baseClass()); } @@ -2941,19 +2949,75 @@ Encoding const & BufferParams::encoding() const } -CiteEngine BufferParams::citeEngine() const +bool BufferParams::addCiteEngine(string const & engine) { - // FIXME the class should provide the numerical/ - // authoryear choice - if (documentClass().provides("natbib")) - return ENGINE_NATBIB; - return cite_engine_; + LayoutModuleList::const_iterator it = cite_engine_.begin(); + LayoutModuleList::const_iterator en = cite_engine_.end(); + for (; it != en; ++it) + if (*it == engine) + return false; + cite_engine_.push_back(engine); + return true; } -void BufferParams::setCiteEngine(CiteEngine cite_engine) +bool BufferParams::addCiteEngine(vector const & engine) { - cite_engine_ = cite_engine; + vector::const_iterator it = engine.begin(); + vector::const_iterator en = engine.end(); + bool ret = true; + for (; it != en; ++it) + if (!addCiteEngine(*it)) + ret = false; + return ret; +} + + +string const & BufferParams::defaultBiblioStyle() const +{ + return documentClass().defaultBiblioStyle(); +} + + +bool const & BufferParams::fullAuthorList() const +{ + return documentClass().fullAuthorList(); +} + + +void BufferParams::setCiteEngine(string const & engine) +{ + clearCiteEngine(); + addCiteEngine(engine); +} + + +void BufferParams::setCiteEngine(vector const & engine) +{ + clearCiteEngine(); + addCiteEngine(engine); +} + + +vector BufferParams::citeCommands() const +{ + static CitationStyle const default_style; + vector commands = + documentClass().citeCommands(citeEngineType()); + if (commands.empty()) + commands.push_back(default_style.cmd); + return commands; +} + + +vector BufferParams::citeStyles() const +{ + static CitationStyle const default_style; + vector styles = + documentClass().citeStyles(citeEngineType()); + if (styles.empty()) + styles.push_back(default_style); + return styles; } } // namespace lyx diff --git a/src/BufferParams.h b/src/BufferParams.h index d551955db8..7280506a09 100644 --- a/src/BufferParams.h +++ b/src/BufferParams.h @@ -404,20 +404,37 @@ public: bool const & use_nonlatexfonts, LaTeXFeatures & features) const; - /// get the appropriate cite engine (natbib handling) - CiteEngine citeEngine() const; - /// - void setCiteEngine(CiteEngine const); - + /// the cite engine modules + LayoutModuleList const & citeEngine() const + { return cite_engine_; } /// the type of cite engine (authoryear or numerical) CiteEngineType const & citeEngineType() const { return cite_engine_type_; } + /// add the module to the cite engine modules + bool addCiteEngine(std::string const &); + /// add the modules to the cite engine modules + bool addCiteEngine(std::vector const &); + /// clear the list of cite engine modules + void clearCiteEngine() { cite_engine_.clear(); } + /// set the cite engine module + void setCiteEngine(std::string const &); + /// set the cite engine modules + void setCiteEngine(std::vector const &); /// set the cite engine type void setCiteEngineType(CiteEngineType const & engine_type) { cite_engine_type_ = engine_type; } + /// the available citation commands + std::vector citeCommands() const; + /// the available citation styles + std::vector citeStyles() const; + /// the default BibTeX style file for the document std::string biblio_style; + /// the default BibTeX style file from the TextClass + std::string const & defaultBiblioStyle() const; + /// whether the BibTeX style supports full author lists + bool const & fullAuthorList() const; /// options for pdf output PDFOptions & pdfoptions(); @@ -477,8 +494,8 @@ private: typedef std::map DefaultFlavorCache; /// mutable DefaultFlavorCache default_flavors_; - /// for use with natbib - CiteEngine cite_engine_; + /// the cite engine modules + LayoutModuleList cite_engine_; /// the type of cite engine (authoryear or numerical) CiteEngineType cite_engine_type_; /// diff --git a/src/Citation.h b/src/Citation.h index 1eb4de8ed0..4cac2eb7c5 100644 --- a/src/Citation.h +++ b/src/Citation.h @@ -12,46 +12,36 @@ #ifndef CITATION_H #define CITATION_H +#include + namespace lyx { class Buffer; -enum CiteEngine { - ENGINE_BASIC, - ENGINE_NATBIB, - ENGINE_JURABIB -}; enum CiteEngineType { ENGINE_TYPE_AUTHORYEAR = 1, ENGINE_TYPE_NUMERICAL = 2, }; -enum CiteStyle { - CITE, - CITET, - CITEP, - CITEALT, - CITEALP, - CITEAUTHOR, - CITEYEAR, - CITEYEARPAR, - NOCITE -}; - class CitationStyle { public: /// - CitationStyle() : style(CITE), full(false), forceUpperCase(false) {} + CitationStyle() : cmd("cite"), forceUpperCase(false), fullAuthorList(false), + textAfter(false), textBefore(false) {} - /// - CiteStyle style; - /// - bool full; - /// + /// the LaTeX command + std::string cmd; + /// upper casing author prefixes (van -> Van) bool forceUpperCase; + /// expanding the full author list + bool fullAuthorList; + /// supports text after the citation + bool textAfter; + /// supports text before the citation + bool textBefore; }; } // namespace lyx diff --git a/src/TextClass.cpp b/src/TextClass.cpp index fd8318b713..2d49a4d5f1 100644 --- a/src/TextClass.cpp +++ b/src/TextClass.cpp @@ -60,7 +60,7 @@ namespace lyx { // development/updatelayouts.sh script, to update the format of // all of our layout files. // -int const LAYOUT_FORMAT = 36; +int const LAYOUT_FORMAT = 37; //jrioux : move citation engine stuff into layouts namespace { @@ -147,8 +147,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; @@ -210,7 +212,11 @@ enum TextClassTags { TC_PROVIDESMODULE, TC_EXCLUDESMODULE, TC_HTMLTOCSECTION, - TC_CITEFORMAT + TC_CITEENGINE, + TC_CITEENGINETYPE, + TC_CITEFORMAT, + TC_DEFAULTBIBLIO, + TC_FULLAUTHORLIST, }; @@ -220,16 +226,20 @@ namespace { { "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 }, @@ -684,8 +694,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: @@ -913,25 +942,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; } @@ -1447,24 +1560,60 @@ Layout const & DocumentClass::htmlTOCLayout() const } -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%[[, {!!}%journal%{!!}]][[{%publisher%[[, %publisher%]][[{%institution%[[, %institution%]]}]]}]]}{%year%[[ (%year%)]]}{%pages%[[, %pages%]]}."; - map::const_iterator it = cite_formats_.find(entry_type); - if (it != cite_formats_.end()) - return it->second; - return default_format; + map >::const_iterator itype = cite_formats_.find(type); + if (itype == cite_formats_.end()) + return default_format; + map::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::const_iterator it = cite_macros_.find(macro); - if (it != cite_macros_.end()) - return it->second; - return empty; + map >::const_iterator itype = cite_macros_.find(type); + if (itype == cite_macros_.end()) + return empty; + map::const_iterator it = itype->second.find(macro); + if (it == itype->second.end()) + return empty; + return it->second; +} + + +vector const DocumentClass::citeCommands( + CiteEngineType const & type) const +{ + vector const styles = citeStyles(type); + vector::const_iterator it = styles.begin(); + vector::const_iterator end = styles.end(); + vector cmds; + for (; it != end; ++it) { + CitationStyle const cite = *it; + cmds.push_back(cite.cmd); + } + return cmds; +} + + +vector const & DocumentClass::citeStyles( + CiteEngineType const & type) const +{ + static vector empty; + map >::const_iterator it = cite_styles_.find(type); + if (it == cite_styles_.end()) + return empty; + return it->second; } diff --git a/src/TextClass.h b/src/TextClass.h index a25338f111..a1de81a516 100644 --- a/src/TextClass.h +++ b/src/TextClass.h @@ -10,6 +10,7 @@ #ifndef TEXTCLASS_H #define TEXTCLASS_H +#include "Citation.h" #include "ColorCode.h" #include "Counters.h" #include "FloatList.h" @@ -245,6 +246,8 @@ protected: bool tex_class_avail_; /// document class prerequisites mutable std::string prerequisites_; + /// The possible cite engine types + std::string opt_enginetype_; /// std::string opt_fontsize_; /// @@ -311,9 +314,15 @@ protected: /// The maximal TocLevel of sectioning layouts int max_toclevel_; /// Citation formatting information - std::map cite_formats_; + std::map > cite_formats_; /// Citation macros - std::map cite_macros_; + std::map > cite_macros_; + /// The default BibTeX bibliography style file + std::string cite_default_biblio_style_; + /// Whether full author lists are supported + bool cite_full_author_list_; + /// The possible citation styles + std::map > cite_styles_; private: /////////////////////////////////////////////////////////////////// // helper routines for reading layout files @@ -339,7 +348,11 @@ private: /// bool readFloat(Lexer &); /// - void readCiteFormat(Lexer &); + bool readCiteEngine(Lexer &); + /// + int readCiteEngineType(Lexer &) const; + /// + bool readCiteFormat(Lexer &); }; @@ -390,6 +403,8 @@ public: /// Counters & counters() const { return counters_; } /// + std::string const & opt_enginetype() const { return opt_enginetype_; } + /// std::string const & opt_fontsize() const { return opt_fontsize_; } /// std::string const & opt_pagestyle() const { return opt_pagestyle_; } @@ -439,9 +454,19 @@ public: /// returns true if the class has a ToC structure bool hasTocLevels() const; /// - std::string const & getCiteFormat(std::string const & entry_type) const; + std::string const & getCiteFormat(CiteEngineType const & type, + std::string const & entry, std::string const & fallback = "") const; /// - std::string const & getCiteMacro(std::string const & macro) const; + std::string const & getCiteMacro(CiteEngineType const & type, + std::string const & macro) const; + /// + std::vector const citeCommands(CiteEngineType const &) const; + /// + std::vector const & citeStyles(CiteEngineType const &) const; + /// + std::string const & defaultBiblioStyle() const { return cite_default_biblio_style_; } + /// + bool const & fullAuthorList() const { return cite_full_author_list_; } protected: /// Constructs a DocumentClass based upon a LayoutFile. DocumentClass(LayoutFile const & tc); diff --git a/src/frontends/qt4/GuiBibtex.cpp b/src/frontends/qt4/GuiBibtex.cpp index 92861442e7..6dd8d8f650 100644 --- a/src/frontends/qt4/GuiBibtex.cpp +++ b/src/frontends/qt4/GuiBibtex.cpp @@ -504,19 +504,7 @@ QString GuiBibtex::styleFile() const { // the different bibtex packages have (and need) their // own "plain" stylefiles - CiteEngine const engine = buffer().params().citeEngine(); - QString defaultstyle; - switch (engine) { - case ENGINE_BASIC: - defaultstyle = "plain"; - break; - case ENGINE_NATBIB: - defaultstyle = "plainnat"; - break; - case ENGINE_JURABIB: - defaultstyle = "jurabib"; - break; - } + QString defaultstyle = toqstr(buffer().params().defaultBiblioStyle()); QString bst = toqstr(params_["options"]); if (bibtotoc()){ diff --git a/src/frontends/qt4/GuiCitation.cpp b/src/frontends/qt4/GuiCitation.cpp index 6cd534bf91..13b9345c5e 100644 --- a/src/frontends/qt4/GuiCitation.cpp +++ b/src/frontends/qt4/GuiCitation.cpp @@ -54,7 +54,8 @@ using namespace lyx::support; namespace lyx { namespace frontend { -static vector citeStyles_; +static vector citeCmds_; +static vector citeStyles_; template @@ -96,9 +97,9 @@ GuiCitation::GuiCitation(GuiView & lv) connect(forceuppercaseCB, SIGNAL(clicked()), this, SLOT(changed())); connect(textBeforeED, SIGNAL(textChanged(QString)), - this, SLOT(changed())); + this, SLOT(updateStyles())); connect(textAfterED, SIGNAL(textChanged(QString)), - this, SLOT(changed())); + this, SLOT(updateStyles())); connect(findLE, SIGNAL(returnPressed()), this, SLOT(on_searchPB_clicked())); connect(textBeforeED, SIGNAL(returnPressed()), @@ -191,84 +192,50 @@ void GuiCitation::updateControls() // The main point of separating this out is that the fill*() methods // called in update() do not need to be called for INTERNAL updates, // such as when addPB is pressed, as the list of fields, entries, etc, -// will not have changed. At the moment, however, the division between -// fillStyles() and updateStyle() doesn't lend itself to dividing the -// two methods, though they should be divisible. That is, we should -// not have to call fillStyles() every time through here. +// will not have changed. void GuiCitation::updateControls(BiblioInfo const & bi) { QModelIndex idx = selectionManager->getSelectedIndex(); updateInfo(bi, idx); - setButtons(); - - textBeforeED->setText(toqstr(params_["before"])); - textAfterED->setText(toqstr(params_["after"])); - fillStyles(bi); - updateStyle(); + selectionManager->update(); } -void GuiCitation::updateFormatting(CiteStyle currentStyle) +void GuiCitation::updateFormatting(CitationStyle currentStyle) { - CiteEngine const engine = citeEngine(); - bool const natbib_engine = engine == ENGINE_NATBIB; - bool const basic_engine = engine == ENGINE_BASIC; + bool const force = currentStyle.forceUpperCase; + bool const full = currentStyle.fullAuthorList && + documentBuffer().params().fullAuthorList(); + bool const textbefore = currentStyle.textBefore; + bool const textafter = currentStyle.textAfter; - bool const haveSelection = + bool const haveSelection = selectedLV->model()->rowCount() > 0; - bool const isNocite = currentStyle == NOCITE; - - bool const isCiteyear = - currentStyle == CITEYEAR || - currentStyle == CITEYEARPAR; - - fulllistCB->setEnabled(natbib_engine && haveSelection && !isNocite - && !isCiteyear); - forceuppercaseCB->setEnabled(natbib_engine && haveSelection - && !isNocite && !isCiteyear); - textBeforeED->setEnabled(!basic_engine && haveSelection && !isNocite); - textBeforeLA->setEnabled(!basic_engine && haveSelection && !isNocite); - textAfterED->setEnabled(haveSelection && !isNocite); - textAfterLA->setEnabled(haveSelection && !isNocite); + forceuppercaseCB->setEnabled(force && haveSelection); + fulllistCB->setEnabled(full && haveSelection); + textBeforeED->setEnabled(textbefore && haveSelection); + textBeforeLA->setEnabled(textbefore && haveSelection); + textAfterED->setEnabled(textafter && haveSelection); + textAfterLA->setEnabled(textafter && haveSelection); citationStyleCO->setEnabled(haveSelection); citationStyleLA->setEnabled(haveSelection); } -void GuiCitation::updateStyle() +// Update the styles for the style combo, citationStyleCO, and mark the +// settings as changed. Called upon changing the cited keys (including +// merely reordering the keys) or editing the text before/after fields. +void GuiCitation::updateStyles() { - string const & command = params_.getCmdName(); - - // Find the style of the citekeys - vector const & styles = citeStyles_; - CitationStyle const cs = citationStyleFromString(command); - - vector::const_iterator cit = - std::find(styles.begin(), styles.end(), cs.style); - - if (cit != styles.end()) { - fulllistCB->setChecked(cs.full); - forceuppercaseCB->setChecked(cs.forceUpperCase); - } else { - // restore the last used natbib style - if (style_ >= 0 && style_ < citationStyleCO->count()) { - // the necessary update will be performed later - citationStyleCO->blockSignals(true); - citationStyleCO->setCurrentIndex(style_); - citationStyleCO->blockSignals(false); - } - fulllistCB->setChecked(false); - forceuppercaseCB->setChecked(false); - } - updateFormatting(cs.style); + BiblioInfo const & bi = bibInfo(); + updateStyles(bi); + changed(); } -// This one needs to be called whenever citationStyleCO needs -// to be updated---and this would be on anything that changes the -// selection in selectedLV, or on a general update. -void GuiCitation::fillStyles(BiblioInfo const & bi) +// Update the styles for the style combo, citationStyleCO. +void GuiCitation::updateStyles(BiblioInfo const & bi) { QStringList selected_keys = selected_model_.stringList(); int curr = selectedLV->model()->rowCount() - 1; @@ -283,7 +250,7 @@ void GuiCitation::fillStyles(BiblioInfo const & bi) if (!selectedLV->selectionModel()->selectedIndexes().empty()) curr = selectedLV->selectionModel()->selectedIndexes()[0].row(); - QStringList sty = citationStyles(bi, curr); + QStringList sty = citationStyles(bi); if (sty.isEmpty()) { // some error @@ -347,7 +314,6 @@ bool GuiCitation::isSelected(QModelIndex const & idx) void GuiCitation::setButtons() { - selectionManager->update(); int const srows = selectedLV->model()->rowCount(); applyPB->setEnabled(srows > 0); okPB->setEnabled(srows > 0); @@ -421,8 +387,9 @@ void GuiCitation::on_entriesCO_currentIndexChanged(int /*index*/) void GuiCitation::on_citationStyleCO_currentIndexChanged(int index) { if (index >= 0 && index < citationStyleCO->count()) { - vector const & styles = citeStyles_; + vector const & styles = citeStyles_; updateFormatting(styles[index]); + changed(); } } @@ -479,19 +446,18 @@ void GuiCitation::apply(int const choice, bool full, bool force, if (cited_keys_.isEmpty()) return; - vector const & styles = citeStyles_; - if (styles[choice] == NOCITE) { - full = false; - force = false; + vector const & styles = citeStyles_; + + CitationStyle cs = styles[choice]; + + if (!cs.textBefore) before.clear(); + if (!cs.textAfter) after.clear(); - } - - CitationStyle s; - s.style = styles[choice]; - s.full = full; - s.forceUpperCase = force; - string const command = citationStyleToString(s); + + cs.forceUpperCase &= force; + cs.fullAuthorList &= full; + string const command = citationStyleToString(cs); params_.setCmdName(command); params_["key"] = qstring_to_ucs4(cited_keys_.join(",")); @@ -522,6 +488,23 @@ void GuiCitation::init() else cited_keys_ = str.split(","); selected_model_.setStringList(cited_keys_); + + // Initialize the drop downs + fillEntries(bi); + fillFields(bi); + + // Initialize the citation formatting + string const & cmd = params_.getCmdName(); + CitationStyle const cs = citationStyleFromString(cmd); + forceuppercaseCB->setChecked(cs.forceUpperCase); + fulllistCB->setChecked(cs.fullAuthorList && + documentBuffer().params().fullAuthorList()); + textBeforeED->setText(toqstr(params_["before"])); + textAfterED->setText(toqstr(params_["after"])); + + // Update the interface + updateControls(bi); + updateStyles(bi); if (selected_model_.rowCount()) { selectedLV->blockSignals(true); selectedLV->setFocus(); @@ -530,25 +513,24 @@ void GuiCitation::init() QItemSelectionModel::ClearAndSelect); selectedLV->blockSignals(false); - // set the style combo appropriately - string const & command = params_.getCmdName(); - vector const & styles = citeStyles_; - CitationStyle const cs = citationStyleFromString(command); - - vector::const_iterator cit = - std::find(styles.begin(), styles.end(), cs.style); - if (cit != styles.end()) { - int const i = int(cit - styles.begin()); - // the necessary update will be performed later - citationStyleCO->blockSignals(true); - citationStyleCO->setCurrentIndex(i); - citationStyleCO->blockSignals(false); - } + // Find the citation style + vector const & cmds = citeCmds_; + vector::const_iterator cit = + std::find(cmds.begin(), cmds.end(), cs.cmd); + int i = 0; + if (cit != cmds.end()) + i = int(cit - cmds.begin()); + + // Set the style combo appropriately + citationStyleCO->blockSignals(true); + citationStyleCO->setCurrentIndex(i); + citationStyleCO->blockSignals(false); + updateFormatting(citeStyles_[i]); } else availableLV->setFocus(); - fillFields(bi); - fillEntries(bi); - updateControls(bi); + + applyPB->setEnabled(false); + okPB->setEnabled(false); } @@ -605,25 +587,31 @@ void GuiCitation::findKey(BiblioInfo const & bi, } -QStringList GuiCitation::citationStyles(BiblioInfo const & bi, int sel) +QStringList GuiCitation::citationStyles(BiblioInfo const & bi) { - docstring const key = qstring_to_ucs4(cited_keys_[sel]); - return to_qstring_list(bi.getCiteStrings(key, documentBuffer())); + docstring const before = qstring_to_ucs4(textBeforeED->text()); + docstring const after = qstring_to_ucs4(textAfterED->text()); + vector const keys = to_docstring_vector(cited_keys_); + vector styles = citeStyles_; + // FIXME: pass a dictionary instead of individual before, after, dialog, etc. + vector ret = bi.getCiteStrings(keys, styles, documentBuffer(), + false, before, after, from_utf8("dialog")); + return to_qstring_list(ret); } void GuiCitation::setCitedKeys() { cited_keys_ = selected_model_.stringList(); + updateStyles(); } bool GuiCitation::initialiseParams(string const & data) { InsetCommand::string2params(data, params_); - CiteEngine const engine = citeEngine(); - CiteEngineType const engine_type = citeEngineType(); - citeStyles_ = citeStyles(engine, engine_type); + citeCmds_ = documentBuffer().params().citeCommands(); + citeStyles_ = documentBuffer().params().citeStyles(); init(); return true; } @@ -657,18 +645,6 @@ void GuiCitation::filterByEntryType(BiblioInfo const & bi, } -CiteEngine GuiCitation::citeEngine() const -{ - return documentBuffer().params().citeEngine(); -} - - -CiteEngineType GuiCitation::citeEngineType() const -{ - return documentBuffer().params().citeEngineType(); -} - - // Escape special chars. // All characters are literals except: '.|*?+(){}[]^$\' // These characters are literals when preceded by a "\", which is done here diff --git a/src/frontends/qt4/GuiCitation.h b/src/frontends/qt4/GuiCitation.h index 3ca1b50a94..36675d02f5 100644 --- a/src/frontends/qt4/GuiCitation.h +++ b/src/frontends/qt4/GuiCitation.h @@ -57,8 +57,10 @@ private Q_SLOTS: void on_regexCB_stateChanged(int); void on_asTypeCB_stateChanged(int); void changed(); - /// + /// set the citation keys, mark as changed void setCitedKeys(); + /// update the styles for the style combo, mark as changed + void updateStyles(); /// performs a limited update, suitable for internal call void updateControls(); @@ -93,16 +95,14 @@ private: void updateInfo(BiblioInfo const & bi, QModelIndex const &); /// enable/disable buttons void setButtons(); - /// fill the styles combo - void fillStyles(BiblioInfo const & bi); /// fill the fields combo void fillFields(BiblioInfo const & bi); /// fill the entries combo void fillEntries(BiblioInfo const & bi); /// set the styles combo - void updateStyle(); + void updateStyles(BiblioInfo const & bi); /// set the formatting widgets - void updateFormatting(CiteStyle currentStyle); + void updateFormatting(CitationStyle currentStyle); /// void updateControls(BiblioInfo const & bi); /// @@ -123,7 +123,7 @@ private: ); /// List of example cite strings - QStringList citationStyles(BiblioInfo const & bi, int); + QStringList citationStyles(BiblioInfo const & bi); /// Set the Params variable for the Controller. void apply(int const choice, bool const full, bool const force, @@ -132,10 +132,6 @@ private: /// void filterByEntryType(BiblioInfo const & bi, std::vector & keyVector, docstring entryType); - /// - CiteEngine citeEngine() const; - /// - CiteEngineType citeEngineType() const; /// Search a given string within the passed keys. /// \return the vector of matched keys. diff --git a/src/frontends/qt4/GuiDocument.cpp b/src/frontends/qt4/GuiDocument.cpp index 2a718031a0..a388a86c9f 100644 --- a/src/frontends/qt4/GuiDocument.cpp +++ b/src/frontends/qt4/GuiDocument.cpp @@ -202,6 +202,7 @@ char const * packages_gui[][4] = }; +vector engine_types_; vector > pagestyles; @@ -2065,6 +2066,42 @@ void GuiDocument::setNumerical(bool numerical) } +void GuiDocument::updateEngineType(string const & items, CiteEngineType const & sel) +{ + engine_types_.clear(); + + int nn = 0; + + for (int n = 0; !token(items, '|', n).empty(); ++n) { + nn += 1; + string style = token(items, '|', n); + engine_types_.push_back(style); + } + + switch (sel) { + case ENGINE_TYPE_AUTHORYEAR: + biblioModule->citeStyleCO->setCurrentIndex(0); + break; + case ENGINE_TYPE_NUMERICAL: + biblioModule->citeStyleCO->setCurrentIndex(1); + break; + } + + biblioModule->citationStyleL->setEnabled(nn > 1); + biblioModule->citeStyleCO->setEnabled(nn > 1); + + if (nn != 1) + return; + + // If the textclass allows only one of authoryear or numerical, + // we have no choice but to force that engine type. + if (engine_types_[0] == "authoryear") + biblioModule->citeStyleCO->setCurrentIndex(0); + else + biblioModule->citeStyleCO->setCurrentIndex(1); +} + + namespace { // FIXME unicode // both of these should take a vector @@ -2297,12 +2334,12 @@ void GuiDocument::applyView() bp_.use_refstyle = latexModule->refstyleCB->isChecked(); // biblio - bp_.setCiteEngine(ENGINE_BASIC); - if (biblioModule->citeNatbibRB->isChecked()) - bp_.setCiteEngine(ENGINE_NATBIB); + bp_.setCiteEngine("natbib"); else if (biblioModule->citeJurabibRB->isChecked()) - bp_.setCiteEngine(ENGINE_JURABIB); + bp_.setCiteEngine("jurabib"); + else + bp_.setCiteEngine("basic"); if (biblioModule->citeStyleCO->currentIndex()) bp_.setCiteEngineType(ENGINE_TYPE_NUMERICAL); @@ -2707,17 +2744,22 @@ void GuiDocument::paramsToDialog() latexModule->refstyleCB->setChecked(bp_.use_refstyle); // biblio + string const cite_engine = bp_.citeEngine().list().front(); + biblioModule->citeDefaultRB->setChecked( - bp_.citeEngine() == ENGINE_BASIC); + cite_engine == "basic"); + + biblioModule->citeJurabibRB->setChecked( + cite_engine == "jurabib"); biblioModule->citeNatbibRB->setChecked( - bp_.citeEngine() == ENGINE_NATBIB); + cite_engine == "natbib"); biblioModule->citeStyleCO->setCurrentIndex( bp_.citeEngineType() == ENGINE_TYPE_NUMERICAL); - biblioModule->citeJurabibRB->setChecked( - bp_.citeEngine() == ENGINE_JURABIB); + updateEngineType(documentClass().opt_enginetype(), + bp_.citeEngineType()); biblioModule->bibtopicCB->setChecked( bp_.use_bibtopic); diff --git a/src/frontends/qt4/GuiDocument.h b/src/frontends/qt4/GuiDocument.h index 0d2db66c20..69067df6e7 100644 --- a/src/frontends/qt4/GuiDocument.h +++ b/src/frontends/qt4/GuiDocument.h @@ -75,6 +75,7 @@ public: void updateFontsize(std::string const &, std::string const &); void updateFontlist(); void updateDefaultFormat(); + void updateEngineType(std::string const &, CiteEngineType const &); void updatePagestyle(std::string const &, std::string const &); bool isChildIncluded(std::string const &); diff --git a/src/frontends/qt4/Menus.cpp b/src/frontends/qt4/Menus.cpp index 24651e72df..9e815271de 100644 --- a/src/frontends/qt4/Menus.cpp +++ b/src/frontends/qt4/Menus.cpp @@ -1485,24 +1485,38 @@ void MenuDefinition::expandCiteStyles(BufferView const * bv) static_cast(inset); Buffer const * buf = &bv->buffer(); - docstring key = citinset->getParam("key"); - // we can only handle one key currently - if (contains(key, ',')) - key = qstring_to_ucs4(toqstr(key).split(',')[0]); + string const cmd = citinset->params().getCmdName(); - vector citeStyleList = citeStyles(buf->params().citeEngine(), - buf->params().citeEngineType()); - docstring_list citeStrings = - buf->masterBibInfo().getCiteStrings(key, bv->buffer()); + docstring const & key = citinset->getParam("key"); + if (key.empty()) { + add(MenuItem(MenuItem::Command, + qt_("No citations selected!"), + FuncRequest(LFUN_NOACTION))); + return; + } - docstring_list::const_iterator cit = citeStrings.begin(); - docstring_list::const_iterator end = citeStrings.end(); + docstring const & before = citinset->getParam("before"); + docstring const & after = citinset->getParam("after"); + + size_t const n = cmd.size(); + bool const force = cmd[0] == 'C'; + bool const full = cmd[n] == '*'; + + vector const keys = getVectorFromString(key); + + vector const citeStyleList = buf->params().citeStyles(); + vector citeStrings = + buf->masterBibInfo().getCiteStrings(keys, citeStyleList, bv->buffer(), + false, before, after, from_utf8("dialog")); + + vector::const_iterator cit = citeStrings.begin(); + vector::const_iterator end = citeStrings.end(); for (int ii = 1; cit != end; ++cit, ++ii) { docstring label = *cit; - CitationStyle cs; - CiteStyle cst = citeStyleList[ii - 1]; - cs.style = cst; + CitationStyle cs = citeStyleList[ii - 1]; + cs.forceUpperCase &= force; + cs.fullAuthorList &= full; addWithStatusCheck(MenuItem(MenuItem::Command, toqstr(label), FuncRequest(LFUN_INSET_MODIFY, "changetype " + from_utf8(citationStyleToString(cs))))); diff --git a/src/insets/InsetBibitem.cpp b/src/insets/InsetBibitem.cpp index 779ef7035c..3aaaceacbd 100644 --- a/src/insets/InsetBibitem.cpp +++ b/src/insets/InsetBibitem.cpp @@ -314,8 +314,10 @@ docstring bibitemWidest(Buffer const & buffer, OutputParams const & runparams) void InsetBibitem::collectBibKeys(InsetIterator const & it) const { docstring const key = getParam("key"); + docstring const label = getParam("label"); BibTeXInfo keyvalmap(false); - keyvalmap.label(bibLabel()); + keyvalmap.key(key); + keyvalmap.label(label); DocIterator doc_it(it); doc_it.forwardPos(); keyvalmap[from_ascii("ref")] = doc_it.paragraph().asString( diff --git a/src/insets/InsetCitation.cpp b/src/insets/InsetCitation.cpp index 2406a2ecb6..fdd6e0ba1b 100644 --- a/src/insets/InsetCitation.cpp +++ b/src/insets/InsetCitation.cpp @@ -93,6 +93,8 @@ vector const & possibleCiteCommands() } // anon namespace +// FIXME: use the citeCommands provided by the TextClass +// instead of possibleCiteCommands defined in this file. bool InsetCitation::isCompatibleCommand(string const & cmd) { vector const & possibles = possibleCiteCommands(); @@ -142,71 +144,36 @@ docstring InsetCitation::toolTip(BufferView const & bv, int, int) const namespace { -// FIXME See the header for the issue. -string defaultCiteCommand(CiteEngine engine, CiteEngineType engine_type) -{ - string str; - switch (engine) { - case ENGINE_BASIC: - str = "cite"; - break; - case ENGINE_NATBIB: - if (engine_type == ENGINE_TYPE_AUTHORYEAR) - str = "citet"; - else - str = "citep"; - break; - case ENGINE_JURABIB: - str = "cite"; - break; - } - return str; -} - -string asValidLatexCommand(string const & input, CiteEngine const engine, - CiteEngineType const engine_type) +CitationStyle asValidLatexCommand(string const & input, vector const valid_styles) { - string const default_str = defaultCiteCommand(engine, engine_type); + CitationStyle cs = valid_styles[0]; + cs.forceUpperCase = false; + cs.fullAuthorList = false; if (!InsetCitation::isCompatibleCommand(input)) - return default_str; + return cs; - string output; - switch (engine) { - case ENGINE_BASIC: - if (input == "nocite") - output = input; - else - output = default_str; - break; - - case ENGINE_NATBIB: - if (input == "cite" || input == "citefield" - || input == "citetitle" || input == "cite*") - output = default_str; - else if (prefixIs(input, "foot")) - output = input.substr(4); - else - output = input; - break; - - case ENGINE_JURABIB: { - // Jurabib does not support the 'uppercase' natbib style. - if (input[0] == 'C') - output = string(1, 'c') + input.substr(1); - else - output = input; - - // Jurabib does not support the 'full' natbib style. - string::size_type const n = output.size() - 1; - if (output != "cite*" && output[n] == '*') - output = output.substr(0, n); + string normalized_input = input; + string::size_type const n = input.size() - 1; + if (input[0] == 'C') + normalized_input[0] = 'c'; + if (input[n] == '*') + normalized_input = normalized_input.substr(0, n); + vector::const_iterator it = valid_styles.begin(); + vector::const_iterator end = valid_styles.end(); + for (; it != end; ++it) { + CitationStyle this_cs = *it; + if (this_cs.cmd == normalized_input) { + cs = *it; break; } } - return output; + cs.forceUpperCase &= input[0] == 'C'; + cs.fullAuthorList &= input[n] == '*'; + + return cs; } @@ -247,21 +214,12 @@ docstring InsetCitation::complexLabel(bool for_xhtml) const if (biblist.empty()) return docstring(); - // the natbib citation-styles - // CITET: author (year) - // CITEP: (author,year) - // CITEALT: author year - // CITEALP: author, year - // CITEAUTHOR: author - // CITEYEAR: year - // CITEYEARPAR: (year) - // jurabib supports these plus - // CITE: author/ + docstring const & key = getParam("key"); + if (key.empty()) + return _("No citations selected!"); - CiteEngine const engine = buffer().params().citeEngine(); - CiteEngineType const engine_type = buffer().params().citeEngineType(); // We don't currently use the full or forceUCase fields. - string cite_type = asValidLatexCommand(getCmdName(), engine, engine_type); + string cite_type = getCmdName(); if (cite_type[0] == 'C') // If we were going to use them, this would mean ForceUCase cite_type = string(1, 'c') + cite_type.substr(1); @@ -270,172 +228,16 @@ docstring InsetCitation::complexLabel(bool for_xhtml) const cite_type = cite_type.substr(0, cite_type.size() - 1); docstring const & before = getParam("before"); - docstring before_str; - if (!before.empty()) { - // In CITET and CITEALT mode, the "before" string is - // attached to the label associated with each and every key. - // In CITEP, CITEALP and CITEYEARPAR mode, it is attached - // to the front of the whole only. - // In other modes, it is not used at all. - if (cite_type == "citet" || - cite_type == "citealt" || - cite_type == "citep" || - cite_type == "citealp" || - cite_type == "citeyearpar") - before_str = before + ' '; - // In CITE (jurabib), the "before" string is used to attach - // the annotator (of legal texts) to the author(s) of the - // first reference. - else if (cite_type == "cite") - before_str = '/' + before; - } - docstring const & after = getParam("after"); - docstring after_str; - // The "after" key is appended only to the end of the whole. - if (cite_type == "nocite") - after_str = " (" + _("not cited") + ')'; - else if (!after.empty()) { - after_str = ", " + after; - } - - // One day, these might be tunable (as they are in BibTeX). - char op, cp; // opening and closing parenthesis. - const char * sep; // punctuation mark separating citation entries. - if (engine == ENGINE_BASIC) { - op = '['; - cp = ']'; - sep = ","; - } else { - op = '('; - cp = ')'; - sep = ";"; - } - - docstring const op_str = ' ' + docstring(1, op); - docstring const cp_str = docstring(1, cp) + ' '; - docstring const sep_str = from_ascii(sep) + ' '; + // FIXME: allow to add cite macros + /* + buffer().params().documentClass().addCiteMacro("!textbefore", to_utf8(before)); + buffer().params().documentClass().addCiteMacro("!textafter", to_utf8(after)); + */ docstring label; - vector keys = getVectorFromString(getParam("key")); - vector::const_iterator it = keys.begin(); - vector::const_iterator end = keys.end(); - for (; it != end; ++it) { - // get the bibdata corresponding to the key - docstring const author = biblist.getAbbreviatedAuthor(*it); - docstring const year = biblist.getYear(*it, for_xhtml); - docstring const citenum = for_xhtml ? biblist.getCiteNumber(*it) : *it; - - if (author.empty() || year.empty()) - // We can't construct a "complex" label without that info. - // So fail safely. - return docstring(); - - // authors1/; ... ; - // authors_last, - if (cite_type == "cite") { - if (engine == ENGINE_BASIC) { - label += wrapCitation(*it, citenum, for_xhtml) + sep_str; - } else if (engine == ENGINE_JURABIB) { - if (it == keys.begin()) - label += wrapCitation(*it, author, for_xhtml) + before_str + sep_str; - else - label += wrapCitation(*it, author, for_xhtml) + sep_str; - } - } - // nocite - else if (cite_type == "nocite") { - label += *it + sep_str; - } - // (authors1 ( year); ... ; - // authors_last ( year, ) - else if (cite_type == "citet") { - switch (engine) { - case ENGINE_NATBIB: - if (engine_type == ENGINE_TYPE_AUTHORYEAR) - label += author + op_str + before_str + - wrapCitation(*it, year, for_xhtml) + cp + sep_str; - else - label += author + op_str + before_str + - wrapCitation(*it, citenum, for_xhtml) + cp + sep_str; - break; - case ENGINE_JURABIB: - label += before_str + author + op_str + - wrapCitation(*it, year, for_xhtml) + cp + sep_str; - break; - case ENGINE_BASIC: - break; - } - } - // author, year; author, year; ... - else if (cite_type == "citep" || - cite_type == "citealp") { - if (engine_type == ENGINE_TYPE_NUMERICAL) { - label += wrapCitation(*it, citenum, for_xhtml) + sep_str; - } else { - label += wrapCitation(*it, author + ", " + year, for_xhtml) + sep_str; - } - - } - // (authors1 year; - // authors_last year, ) - else if (cite_type == "citealt") { - switch (engine) { - case ENGINE_NATBIB: - if (engine_type == ENGINE_TYPE_AUTHORYEAR) - label += author + ' ' + before_str + - wrapCitation(*it, year, for_xhtml) + sep_str; - else - label += author + ' ' + before_str + '#' + - wrapCitation(*it, citenum, for_xhtml) + sep_str; - break; - case ENGINE_JURABIB: - label += before_str + - wrapCitation(*it, author + ' ' + year, for_xhtml) + sep_str; - break; - case ENGINE_BASIC: - break; - } - - - } - // author; author; ... - else if (cite_type == "citeauthor") { - label += wrapCitation(*it, author, for_xhtml) + sep_str; - } - // year; year; ... - else if (cite_type == "citeyear" || - cite_type == "citeyearpar") { - label += wrapCitation(*it, year, for_xhtml) + sep_str; - } - } - label = rtrim(rtrim(label), sep); - - if (!after_str.empty()) { - if (cite_type == "citet") { - // insert "after" before last ')' - label.insert(label.size() - 1, after_str); - } else { - bool const add = - !(engine == ENGINE_NATBIB && - engine_type == ENGINE_TYPE_NUMERICAL && - (cite_type == "citeauthor" || - cite_type == "citeyear")); - if (add) - label += after_str; - } - } - - if (!before_str.empty() && (cite_type == "citep" || - cite_type == "citealp" || - cite_type == "citeyearpar")) { - label = before_str + label; - } - - if (cite_type == "citep" || cite_type == "citeyearpar" || - (cite_type == "cite" && engine == ENGINE_BASIC) ) - label = op + label + cp; - + vector const keys = getVectorFromString(key); + label = biblist.getLabel(keys, buffer(), cite_type, for_xhtml, before, after); return label; } @@ -565,15 +367,15 @@ void InsetCitation::forToc(docstring & os, size_t) const // Have to overwrite the default InsetCommand method in order to check that // the \cite command is valid. Eg, the user has natbib enabled, inputs some // citations and then changes his mind, turning natbib support off. The output -// should revert to \cite[]{} +// should revert to the default citation command as provided by the citation +// engine, e.g. \cite[]{} for the basic engine. void InsetCitation::latex(otexstream & os, OutputParams const & runparams) const { - CiteEngine cite_engine = buffer().params().citeEngine(); - CiteEngineType cite_engine_type = buffer().params().citeEngineType(); + vector citation_styles = buffer().params().citeStyles(); + CitationStyle cs = asValidLatexCommand(getCmdName(), citation_styles); BiblioInfo const & bi = buffer().masterBibInfo(); // FIXME UNICODE - docstring const cite_str = from_utf8( - asValidLatexCommand(getCmdName(), cite_engine, cite_engine_type)); + docstring const cite_str = from_utf8(citationStyleToString(cs)); if (runparams.inulemcmd) os << "\\mbox{"; @@ -582,9 +384,9 @@ void InsetCitation::latex(otexstream & os, OutputParams const & runparams) const docstring const & before = getParam("before"); docstring const & after = getParam("after"); - if (!before.empty() && cite_engine != ENGINE_BASIC) + if (!before.empty() && cs.textBefore) os << '[' << before << "][" << after << ']'; - else if (!after.empty()) + else if (!after.empty() && cs.textAfter) os << '[' << after << ']'; if (!bi.isBibtex(getParam("key"))) @@ -598,21 +400,6 @@ void InsetCitation::latex(otexstream & os, OutputParams const & runparams) const } -void InsetCitation::validate(LaTeXFeatures & features) const -{ - switch (features.bufferParams().citeEngine()) { - case ENGINE_BASIC: - break; - case ENGINE_NATBIB: - features.require("natbib"); - break; - case ENGINE_JURABIB: - features.require("jurabib"); - break; - } -} - - string InsetCitation::contextMenuName() const { return "context-citation"; diff --git a/src/insets/InsetCitation.h b/src/insets/InsetCitation.h index 2f7186d63f..0cdde7b2ee 100644 --- a/src/insets/InsetCitation.h +++ b/src/insets/InsetCitation.h @@ -57,7 +57,7 @@ public: /// void forToc(docstring &, size_t) const; /// - void validate(LaTeXFeatures &) const; + void validate(LaTeXFeatures &) const {} /// void updateBuffer(ParIterator const & it, UpdateType); /// @@ -70,10 +70,7 @@ public: //@{ /// static ParamInfo const & findInfo(std::string const &); - // FIXME This is the locus of the design problem we have. - // It really ought to do what default_cite_command() does, - // but to do that it needs to know what CiteEngine we are - // using. + /// static std::string defaultCommand() { return "cite"; } /// static bool isCompatibleCommand(std::string const & cmd);