From 50b65ca806e62f76738a364af6b948d92863aefa Mon Sep 17 00:00:00 2001 From: Angus Leeming Date: Thu, 19 Jul 2001 14:12:37 +0000 Subject: [PATCH] Merge natbib branch into head git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@2286 a592a061-630c-0410-9148-cb99ea01b6c8 --- lib/ChangeLog | 7 + lib/chkconfig.ltx | 1 + lib/doc/LaTeXConfig.lyx.in | 20 + src/ChangeLog | 16 + src/LaTeXFeatures.C | 14 + src/LaTeXFeatures.h | 2 + src/buffer.C | 11 +- src/bufferparams.C | 4 + src/bufferparams.h | 4 + src/frontends/controllers/ChangeLog | 15 + src/frontends/controllers/ControlCitation.C | 33 ++ src/frontends/controllers/ControlCitation.h | 13 + src/frontends/controllers/biblio.C | 466 ++++++++++++++++---- src/frontends/controllers/biblio.h | 103 +++-- src/frontends/controllers/helper_funcs.C | 3 + src/frontends/xforms/ChangeLog | 17 + src/frontends/xforms/FormCitation.C | 238 +++++----- src/frontends/xforms/FormCitation.h | 2 - src/frontends/xforms/FormDocument.C | 20 +- src/frontends/xforms/form_citation.C | 62 ++- src/frontends/xforms/form_citation.h | 2 + src/frontends/xforms/form_document.C | 29 +- src/frontends/xforms/form_document.h | 2 + src/frontends/xforms/forms/form_citation.fd | 104 +++-- src/frontends/xforms/forms/form_document.fd | 67 ++- src/insets/ChangeLog | 5 + src/insets/insetcite.C | 32 +- src/insets/insetcite.h | 4 + 28 files changed, 969 insertions(+), 327 deletions(-) diff --git a/lib/ChangeLog b/lib/ChangeLog index edfdc04c9d..79bbef4a9e 100644 --- a/lib/ChangeLog +++ b/lib/ChangeLog @@ -1,3 +1,10 @@ +2001-07-19 Angus Leeming + + * chkconfig.ltx: test for the presence of natbib. + + * doc/LaTeXConfig.lyx.in: add a subsection about natbib and whether it's + present. + 2001-07-19 Jean-Marc Lasgouttes * bind/xemacs.bind: diff --git a/lib/chkconfig.ltx b/lib/chkconfig.ltx index 720f4be03e..dbdf6d6e3d 100644 --- a/lib/chkconfig.ltx +++ b/lib/chkconfig.ltx @@ -224,6 +224,7 @@ \TestPackage{url} \TestPackage{varioref} \TestPackage{prettyref} +\TestPackage{natbib} % The test for the graphics package is slightly more involved... \newcommand\groption{dvips} diff --git a/lib/doc/LaTeXConfig.lyx.in b/lib/doc/LaTeXConfig.lyx.in index cc22047170..6558da71f8 100644 --- a/lib/doc/LaTeXConfig.lyx.in +++ b/lib/doc/LaTeXConfig.lyx.in @@ -1455,6 +1455,26 @@ longtable is needed by LyX to be able to output correctly multipage tables. \layout Subsection +\layout Subsection + +natbib +\layout Description + +Found: @chk_natbib@ +\layout Description + +CTAN: +\family typewriter +macros/latex/contrib/supported/natbib/natbib.dtx +\layout Description + +Notes: The package +\family sans +natbib +\family default + is needed by LyX to produce a flexible interface to most of the available bibliographic styles. +\layout Subsection + prettyref \layout Description diff --git a/src/ChangeLog b/src/ChangeLog index e51590b368..d47f2a8eb6 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,19 @@ +2001-07-19 Angus Leeming + + * LaTeXFeatures.[Ch]: add variable "bool natbib" and set it + approriately in the c-tor and in require(). + (getPackages): output the appropriate LaTeX for natbib support. + + * buffer.C (parseSingleLyXformat2Token): set the new bufferparams + variables "use_natbib" and "use_numerical_citations" when reading the + LyX file. + (readInset): read the various natbib cite commands. + (validate): white-space change. + + * bufferparams.[Ch]: new variables "bool use_natbib" and + "bool use_numerical_citations". + (writeFile): output them in the LyX file. + 2001-07-19 Jean-Marc Lasgouttes * lyxfunc.C (getStatus): add support for all the inset insertion diff --git a/src/LaTeXFeatures.C b/src/LaTeXFeatures.C index b291666dc2..9b4d15f29a 100644 --- a/src/LaTeXFeatures.C +++ b/src/LaTeXFeatures.C @@ -50,6 +50,7 @@ LaTeXFeatures::LaTeXFeatures(BufferParams const & p, LyXTextClass::size_type n) varioref = false; prettyref = false; chess = false; + natbib = false; // commands lyx = false; @@ -122,6 +123,8 @@ void LaTeXFeatures::require(string const & name) boldsymbol = true; } else if (name == "binom") { binom = true; + } else if (name == "natbib") { + natbib = true; } } @@ -272,7 +275,18 @@ string const LaTeXFeatures::getPackages() const if (use_float) packages << "\\usepackage{float}\n"; } + + // natbib.sty + if (natbib) { + string options("[]"); + if (params.use_numerical_citations) + options.insert(1, "numbers"); + else + options.insert(1, "authoryear"); + packages << "\\usepackage" << options << "{natbib}\n"; + } + packages << externalPreambles; return packages.str().c_str(); diff --git a/src/LaTeXFeatures.h b/src/LaTeXFeatures.h index 5ce3d84982..fa1dbc33b7 100644 --- a/src/LaTeXFeatures.h +++ b/src/LaTeXFeatures.h @@ -93,6 +93,8 @@ struct LaTeXFeatures { bool prettyref; // prettyref.sty /// bool chess; // chess.sty + /// + bool natbib; // natbib.sty /// bool lyx; diff --git a/src/buffer.C b/src/buffer.C index 53893e39d3..78eed77550 100644 --- a/src/buffer.C +++ b/src/buffer.C @@ -762,6 +762,12 @@ Buffer::parseSingleLyXformat2Token(LyXLex & lex, Paragraph *& par, } else if (token == "\\use_amsmath") { lex.nextToken(); params.use_amsmath = lex.GetInteger(); + } else if (token == "\\use_natbib") { + lex.nextToken(); + params.use_natbib = lex.GetInteger(); + } else if (token == "\\use_numerical_citations") { + lex.nextToken(); + params.use_numerical_citations = lex.GetInteger(); } else if (token == "\\paperorientation") { int tmpret = lex.FindToken(string_orientation); if (tmpret == -1) ++tmpret; @@ -1331,7 +1337,9 @@ void Buffer::readInset(LyXLex & lex, Paragraph *& par, string const cmdName = inscmd.getCmdName(); - if (cmdName == "cite") { + // This strange command allows LyX to recognize "natbib" style + // citations: citet, citep, Citet etc. + if (compare_no_case(cmdName, "cite", 4) == 0) { inset = new InsetCitation(inscmd); } else if (cmdName == "bibitem") { lex.printError("Wrong place for bibitem"); @@ -3386,7 +3394,6 @@ void Buffer::validate(LaTeXFeatures & features) const textclasslist.TextClass(params.textclass); // AMS Style is at document level - features.amsstyle = (params.use_amsmath || tclass.provides(LyXTextClass::amsmath)); diff --git a/src/bufferparams.C b/src/bufferparams.C index 1d043af713..157b69fe55 100644 --- a/src/bufferparams.C +++ b/src/bufferparams.C @@ -48,6 +48,8 @@ BufferParams::BufferParams() orientation = ORIENTATION_PORTRAIT; use_geometry = false; use_amsmath = false; + use_natbib = false; + use_numerical_citations = false; secnumdepth = 3; tocdepth = 3; language = default_language; @@ -103,6 +105,8 @@ void BufferParams::writeFile(ostream & os) const << "\n\\paperpackage " << string_paperpackages[paperpackage] << "\n\\use_geometry " << use_geometry << "\n\\use_amsmath " << use_amsmath + << "\n\\use_natbib " << use_natbib + << "\n\\use_numerical_citations " << use_numerical_citations << "\n\\paperorientation " << string_orientation[orientation] << '\n'; if (!paperwidth.empty()) diff --git a/src/bufferparams.h b/src/bufferparams.h index 936553de6e..f912ffe1a8 100644 --- a/src/bufferparams.h +++ b/src/bufferparams.h @@ -201,6 +201,10 @@ public: void readGraphicsDriver(LyXLex &); /// bool use_amsmath; + /// + bool use_natbib; + /// + bool use_numerical_citations; /// Time ago we agreed that this was a buffer property [ale990407] string parentname; private: diff --git a/src/frontends/controllers/ChangeLog b/src/frontends/controllers/ChangeLog index fdc7be4d3c..c4714f0443 100644 --- a/src/frontends/controllers/ChangeLog +++ b/src/frontends/controllers/ChangeLog @@ -1,3 +1,18 @@ +2001-07-19 Angus Leeming + + * ControlCitation.[Ch]: changes associated with adding natbib support. + New public methods, usingNatbib, getCiteStrings and getCiteStyles. + New static variable citeStyles_. + + * biblio.[Ch]: large internal rearrangement. + New public enum CiteStyle. + New public struct CitationStyle. + New public functions getCitationStyle, getCiteCommand, getCiteStyles, + getNumericalStrings, getAuthorYearStrings + (simpleSearch, regexSearch): no longer publicly accessible. + + * helper_funcs.C (getStringFromVector): bug fix. + 2001-07-16 Baruch Even * ControlVCLog.h: Added Lsstream.h to includes. diff --git a/src/frontends/controllers/ControlCitation.C b/src/frontends/controllers/ControlCitation.C index c601db9afb..da27bcf713 100644 --- a/src/frontends/controllers/ControlCitation.C +++ b/src/frontends/controllers/ControlCitation.C @@ -1,3 +1,4 @@ +// -*- C++ -*- /* This file is part of * ====================================================== * @@ -29,6 +30,8 @@ using std::pair; using std::vector; using SigC::slot; +vector ControlCitation::citeStyles_; + ControlCitation::ControlCitation(LyXView & lv, Dialogs & d) : ControlCommand(lv, d, LFUN_CITATION_INSERT) { @@ -55,6 +58,14 @@ void ControlCitation::setDaughterParams() bibkeysInfo_.insert(InfoMapValue(blist[i].first, blist[i].second)); } + + if (citeStyles_.empty()) + citeStyles_ = biblio::getCiteStyles(usingNatbib()); + else { + if ((usingNatbib() && citeStyles_.size() == 1) || + (!usingNatbib() && citeStyles_.size() != 1)) + citeStyles_ = biblio::getCiteStyles(usingNatbib()); + } } @@ -62,3 +73,25 @@ biblio::InfoMap const & ControlCitation::bibkeysInfo() const { return bibkeysInfo_; } + + +bool ControlCitation::usingNatbib() const +{ + return lv_.buffer()->params.use_natbib; +} + + +vector const ControlCitation::getCiteStrings(string const & key) const +{ + vector styles; + + vector const cs = + biblio::getCiteStyles(usingNatbib()); + + if (lv_.buffer()->params.use_numerical_citations) + styles = biblio::getNumericalStrings(key, bibkeysInfo_, cs); + else + styles = biblio::getAuthorYearStrings(key, bibkeysInfo_, cs); + + return styles; +} diff --git a/src/frontends/controllers/ControlCitation.h b/src/frontends/controllers/ControlCitation.h index 04be484e6f..4bbb8979b8 100644 --- a/src/frontends/controllers/ControlCitation.h +++ b/src/frontends/controllers/ControlCitation.h @@ -33,6 +33,15 @@ public: /// Returns a reference to the map of stored keys biblio::InfoMap const & bibkeysInfo() const; + /// + bool usingNatbib() const; + /// Possible citations based on this key + std::vector const getCiteStrings(string const & key) const; + + /// available CiteStyle-s (depends on availability of Natbib + static std::vector const & getCiteStyles() + { return citeStyles_; } + private: /// create the InfoMap of keys and data virtual void setDaughterParams(); @@ -41,6 +50,10 @@ private: /// The info associated with each key biblio::InfoMap bibkeysInfo_; + + /// + static std::vector citeStyles_; }; + #endif // CONTROLCITATION_H diff --git a/src/frontends/controllers/biblio.C b/src/frontends/controllers/biblio.C index f363c8107f..91a4d57fd5 100644 --- a/src/frontends/controllers/biblio.C +++ b/src/frontends/controllers/biblio.C @@ -22,6 +22,7 @@ #include "LString.h" #include "biblio.h" +#include "gettext.h" // for _() #include "helper_funcs.h" #include "support/lstrings.h" #include "support/LAssert.h" @@ -35,102 +36,38 @@ using std::sort; namespace biblio { +namespace { -// A functor for use with std::sort, leading to case insensitive sorting -struct compareNoCase: public std::binary_function -{ - bool operator()(string const & s1, string const & s2) const { - return compare_no_case(s1, s2) < 0; - } -}; - -vector const getKeys(InfoMap const & map) -{ - vector bibkeys; - - for (InfoMap::const_iterator it = map.begin(); it != map.end(); ++it) { - bibkeys.push_back(it->first); - } +using namespace biblio; + +char const * const citeCommands[] = { + "cite", "citet", "citep", "citealt", "citealp", "citeauthor", + "citeyear", "citeyearpar" }; - sort(bibkeys.begin(), bibkeys.end(), compareNoCase()); - return bibkeys; -} +unsigned int const nCiteCommands = + sizeof(citeCommands) / sizeof(char *); +CiteStyle const citeStyles[] = { + CITE, CITET, CITEP, CITEALT, CITEALP, + CITEAUTHOR, CITEYEAR, CITEYEARPAR }; -string const getInfo(InfoMap const & map, string const & key) -{ - lyx::Assert(!map.empty()); +unsigned int const nCiteStyles = + sizeof(citeStyles) / sizeof(CiteStyle); - string result; +CiteStyle const citeStylesFull[] = { + CITET, CITEP, CITEALT, CITEALP, CITEAUTHOR }; - InfoMap::const_iterator it = map.find(key); - if (it != map.end()) { - // Search for all possible "required" keys - string author = parseBibTeX(it->second, "author"); - if (author.empty()) - author = parseBibTeX(it->second, "editor"); +unsigned int const nCiteStylesFull = + sizeof(citeStylesFull) / sizeof(CiteStyle); - string year = parseBibTeX(it->second, "year"); - string title = parseBibTeX(it->second, "title"); - string booktitle = parseBibTeX(it->second, "booktitle"); - string chapter = parseBibTeX(it->second, "chapter"); - string pages = parseBibTeX(it->second, "pages"); - - string media = parseBibTeX(it->second, "journal"); - if (media.empty()) - media = parseBibTeX(it->second, "publisher"); - if (media.empty()) - media = parseBibTeX(it->second, "school"); - if (media.empty()) - media = parseBibTeX(it->second, "institution"); - - result = author; - if (!year.empty()) - result += ", " + year; - if (!title.empty()) - result += ", " + title; - if (!booktitle.empty()) - result += ", in " + booktitle; - if (!chapter.empty()) - result += ", Ch. " + chapter; - if (!media.empty()) - result += ", " + media; - if (!pages.empty()) - result += ", pp. " + pages; - - if (result.empty()) // not a BibTeX record - result = it->second; - } +CiteStyle const citeStylesUCase[] = { + CITET, CITEP, CITEALT, CITEALP, CITEAUTHOR }; - return result; -} +unsigned int const nCiteStylesUCase = + sizeof(citeStylesUCase) / sizeof(CiteStyle); -vector::const_iterator -searchKeys(InfoMap const & theMap, - vector const & keys, - string const & expr, - vector::const_iterator start, - Search type, - Direction dir, - bool caseSensitive) -{ - // Preliminary checks - if(start < keys.begin() || start >= keys.end()) - return keys.end(); - - string search_expr = frontStrip(strip(expr)); - if (search_expr.empty()) - return keys.end(); - - if (type == SIMPLE) - return simpleSearch(theMap, keys, search_expr, start, dir, - caseSensitive); - - return regexSearch(theMap, keys, search_expr, start, dir); -} - - +// The functions doing the dirty work for the search. vector::const_iterator simpleSearch(InfoMap const & theMap, vector const & keys, @@ -153,7 +90,7 @@ simpleSearch(InfoMap const & theMap, (dir == FORWARD) ? (++it) : (--it)) { string data = (*it); - biblio::InfoMap::const_iterator info = theMap.find(*it); + InfoMap::const_iterator info = theMap.find(*it); if (info != theMap.end()) data += " " + info->second; if (!caseSensitive) @@ -176,7 +113,7 @@ simpleSearch(InfoMap const & theMap, return keys.end(); } - + vector::const_iterator regexSearch(InfoMap const & theMap, vector const & keys, @@ -193,7 +130,7 @@ regexSearch(InfoMap const & theMap, (dir == FORWARD) ? (++it) : (--it)) { string data = (*it); - biblio::InfoMap::const_iterator info = theMap.find(*it); + InfoMap::const_iterator info = theMap.find(*it); if (info != theMap.end()) data += " " + info->second; @@ -204,6 +141,175 @@ regexSearch(InfoMap const & theMap, return keys.end(); } +string const familyName(string const & name) +{ + // Very simple parser + string fname = name; + + string::size_type idx = fname.rfind("."); + if (idx != string::npos) + fname = frontStrip(fname.substr(idx+1)); + + return fname; +} + + +string const getAbbreviatedAuthor(InfoMap const & map, string const & key) +{ + lyx::Assert(!map.empty()); + + InfoMap::const_iterator it = map.find(key); + + string author; + if (it != map.end()) { + author = parseBibTeX(it->second, "author"); + if (author.empty()) + author = parseBibTeX(it->second, "editor"); + + vector authors = getVectorFromString(author, "and"); + + if (!authors.empty()) { + author.erase(); + + for (vector::iterator it = authors.begin(); + it != authors.end(); ++it) { + *it = familyName(strip(*it)); + } + + author = authors[0]; + if (authors.size() == 2) + author += _(" and ") + authors[1]; + else if (authors.size() > 2) + author += _(" et al."); + } + } + + if (author.empty()) + author = _("Caesar et al."); + + return author; +} + + +string const getYear(InfoMap const & map, string const & key) +{ + lyx::Assert(!map.empty()); + + InfoMap::const_iterator it = map.find(key); + + string year; + + if (it != map.end()) + year = parseBibTeX(it->second, "year"); + + if (year.empty()) + year = "50BC"; + + return year; +} + +} // namespace anon + + + + + + + +// A functor for use with std::sort, leading to case insensitive sorting +struct compareNoCase: public std::binary_function +{ + bool operator()(string const & s1, string const & s2) const { + return compare_no_case(s1, s2) < 0; + } +}; + +vector const getKeys(InfoMap const & map) +{ + vector bibkeys; + + for (InfoMap::const_iterator it = map.begin(); it != map.end(); ++it) { + bibkeys.push_back(it->first); + } + + sort(bibkeys.begin(), bibkeys.end(), compareNoCase()); + return bibkeys; +} + + +string const getInfo(InfoMap const & map, string const & key) +{ + lyx::Assert(!map.empty()); + + InfoMap::const_iterator it = map.find(key); + if (it == map.end()) return string(); + + // Search for all possible "required" keys + string author = parseBibTeX(it->second, "author"); + if (author.empty()) + author = parseBibTeX(it->second, "editor"); + + string year = parseBibTeX(it->second, "year"); + string title = parseBibTeX(it->second, "title"); + string booktitle = parseBibTeX(it->second, "booktitle"); + string chapter = parseBibTeX(it->second, "chapter"); + string pages = parseBibTeX(it->second, "pages"); + + string media = parseBibTeX(it->second, "journal"); + if (media.empty()) + media = parseBibTeX(it->second, "publisher"); + if (media.empty()) + media = parseBibTeX(it->second, "school"); + if (media.empty()) + media = parseBibTeX(it->second, "institution"); + + ostringstream result; + result << author; + if (!year.empty()) + result << ", " << year; + if (!title.empty()) + result << ", " << title; + if (!booktitle.empty()) + result << ", in " << booktitle; + if (!chapter.empty()) + result << ", Ch. " << chapter; + if (!media.empty()) + result << ", " << media; + if (!pages.empty()) + result << ", pp. " << pages; + + if (result.str().empty()) // not a BibTeX record + result << it->second; + + return result.str(); +} + + +vector::const_iterator +searchKeys(InfoMap const & theMap, + vector const & keys, + string const & expr, + vector::const_iterator start, + Search type, + Direction dir, + bool caseSensitive) +{ + // Preliminary checks + if(start < keys.begin() || start >= keys.end()) + return keys.end(); + + string search_expr = frontStrip(strip(expr)); + if (search_expr.empty()) + return keys.end(); + + if (type == SIMPLE) + return simpleSearch(theMap, keys, search_expr, start, dir, + caseSensitive); + + return regexSearch(theMap, keys, search_expr, start, dir); +} + + string const parseBibTeX(string data, string const & findkey) { string keyvalue; @@ -305,5 +411,185 @@ string const parseBibTeX(string data, string const & findkey) } -} // namespace biblio +CitationStyle const getCitationStyle(string const & command) +{ + if (command.empty()) return CitationStyle(); + + CitationStyle cs; + string cmd = command; + + if (cmd[0] == 'C') { + cs.forceUCase = true; + cmd[0] = 'c'; + } + + size_t n = cmd.size()-1; + if (cmd[n] == '*') { + cs.full = true; + cmd = cmd.substr(0,n); + } + + char const * const * const last = citeCommands + nCiteCommands; + char const * const * const ptr = std::find(citeCommands, last, cmd); + + if (ptr != last) { + size_t idx = ptr - citeCommands; + cs.style = citeStyles[idx]; + } + + return cs; +} + + +string const getCiteCommand(CiteStyle command, bool full, bool forceUCase) +{ + string cite = citeCommands[command]; + if (full) { + CiteStyle const * last = citeStylesFull + nCiteStylesFull; + if (std::find(citeStylesFull, last, command) != last) + cite += "*"; + } + + if (forceUCase) { + CiteStyle const * last = citeStylesUCase + nCiteStylesUCase; + if (std::find(citeStylesUCase, last, command) != last) + cite[0] = 'C'; + } + + return cite; +} + + +vector const getCiteStyles(bool usingNatbib) +{ + unsigned int nStyles = 1; + unsigned int start = 0; + if (usingNatbib) { + nStyles = nCiteStyles - 1; + start = 1; + } + + vector styles(nStyles); + + vector::size_type i = 0; + int j = start; + for (; i != styles.size(); ++i, ++j) { + styles[i] = citeStyles[j]; + } + + return styles; +} + +vector const +getNumericalStrings(string const & key, + InfoMap const & map, vector const & styles) +{ + if (map.empty()) { + vector vec(1); + vec[0] = _("No database"); + return vec; + } + + vector vec(styles.size()); + + string const author = getAbbreviatedAuthor(map, key); + string const year = getYear(map, key); + + for (vector::size_type i = 0; i != vec.size(); ++i) { + string str; + + switch (styles[i]) { + case CITE: + case CITEP: + str = "[#ID]"; + break; + + case CITET: + str = author + " [#ID]"; + break; + + case CITEALT: + str = author + " #ID"; + break; + + case CITEALP: + str = "#ID"; + break; + + case CITEAUTHOR: + str = author; + break; + + case CITEYEAR: + str = year; + break; + + case CITEYEARPAR: + str = "(" + year + ")"; + break; + } + + vec[i] = str; + } + + return vec; +} + + +vector const +getAuthorYearStrings(string const & key, + InfoMap const & map, vector const & styles) +{ + if (map.empty()) { + vector vec(1); + vec[0] = _("No database"); + return vec; + } + + vector vec(styles.size()); + + string const author = getAbbreviatedAuthor(map, key); + string const year = getYear(map, key); + + for (vector::size_type i = 0; i != vec.size(); ++i) { + string str; + + switch (styles[i]) { + case CITET: + str = author + " (" + year + ")"; + break; + + case CITE: + 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; +} + +} // namespace biblio diff --git a/src/frontends/controllers/biblio.h b/src/frontends/controllers/biblio.h index 8ce0b9f359..d1021ded09 100644 --- a/src/frontends/controllers/biblio.h +++ b/src/frontends/controllers/biblio.h @@ -24,6 +24,17 @@ /** Functions of use to citation and bibtex GUI controllers and views */ namespace biblio { + /// + enum CiteStyle { + CITE, + CITET, + CITEP, + CITEALT, + CITEALP, + CITEAUTHOR, + CITEYEAR, + CITEYEARPAR + }; /// enum Search { /// @@ -66,32 +77,74 @@ namespace biblio */ std::vector::const_iterator - searchKeys(InfoMap const & map, - std::vector const & keys_to_search, - string const & search_expression, - std::vector::const_iterator start, - Search, - Direction, - bool caseSensitive=false); - - /** Do the dirty work for the search. - Should use through the function above */ - std::vector::const_iterator - simpleSearch(InfoMap const & map, - std::vector const & keys_to_search, - string const & search_expression, - std::vector::const_iterator start, - Direction, - bool caseSensitive=false); - - /// Should use through the function above - std::vector::const_iterator - regexSearch(InfoMap const & map, - std::vector const & keys_to_search, - string const & search_expression, - std::vector::const_iterator start, - Direction); + searchKeys(InfoMap const & map, + std::vector const & keys_to_search, + string const & search_expression, + std::vector::const_iterator start, + Search, + Direction, + bool caseSensitive=false); + + /// Type returned by getCitationStyle, below + struct CitationStyle { + /// + CitationStyle() : style(CITE), full(false), forceUCase(false) {} + /// + CiteStyle style; + /// + bool full; + /// + bool forceUCase; + }; + /// Given the LaTeX command, return the appropriate CitationStyle + CitationStyle const getCitationStyle(string const & command); + + /** Returns the LaTeX citation command + + User supplies : + The CiteStyle enum, + a flag forcing the full author list, + a flag forcing upper case, e.g. "della Casa" becomes "Della Case" + */ + string const getCiteCommand(CiteStyle, bool full, bool forceUCase); + + /// Returns a vector of available Citation styles. + std::vector const getCiteStyles(bool usingNatbib); + + /** + "Translates" the available Citation Styles into strings for this 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 InfoMap of bibkeys info, + the available citation styles + */ + std::vector const + getNumericalStrings(string const & key, + InfoMap const & map, + std::vector const & styles); + /** + "Translates" the available Citation Styles into strings for this 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 InfoMap of bibkeys info, + the available citation styles + */ + std::vector const + getAuthorYearStrings(string const & key, + InfoMap const & map, + std::vector const & styles); } // namespace biblio #endif // BIBLIOHELPERS_H diff --git a/src/frontends/controllers/helper_funcs.C b/src/frontends/controllers/helper_funcs.C index 147fef18ea..341dcd78ea 100644 --- a/src/frontends/controllers/helper_funcs.C +++ b/src/frontends/controllers/helper_funcs.C @@ -50,6 +50,9 @@ vector const getVectorFromString(string const & str, string const & delim) { vector vec; + if (str.empty()) + return vec; + string keys(str); for(;;) { diff --git a/src/frontends/xforms/ChangeLog b/src/frontends/xforms/ChangeLog index a3bf860288..c38c5db217 100644 --- a/src/frontends/xforms/ChangeLog +++ b/src/frontends/xforms/ChangeLog @@ -1,3 +1,20 @@ +2001-07-19 Angus Leeming + + * FormCitation.[Ch]: changes associated with adding natbib support. + New helper functions, string_width, fillChoice, updateStyle. + (apply): set the citation command appropriately. + (input): deal with the citation command choices. + (update): parse the citation command and deal with it. Nuke the + setSize stuff. + (setSize): nuked! + + * FormDocument.C (build): add options to use natbib. + + * forms/form_citation.fd: add natbib support. Rearrange dialog to + fit onto shorter screens. + + * forms/form_document.fd: add natbib support. + 2001-07-16 Juergen Vigna * form_aboutlyx.C: set default for "Close" button to "ESC"-key. diff --git a/src/frontends/xforms/FormCitation.C b/src/frontends/xforms/FormCitation.C index a66ac30a0e..97886b1b3e 100644 --- a/src/frontends/xforms/FormCitation.C +++ b/src/frontends/xforms/FormCitation.C @@ -1,3 +1,4 @@ +// -*- C++ -*- /* This file is part of * ====================================================== * @@ -35,6 +36,64 @@ using std::pair; using std::sort; using std::vector; +namespace { + +// shamelessly stolen from Menubar_pimpl.C +int string_width(string const & str) +{ + return fl_get_string_widthTAB(FL_NORMAL_STYLE, FL_NORMAL_SIZE, + str.c_str(), + static_cast(str.length())); +} + + +void fillChoice(FL_OBJECT * choice, vector const & vec) +{ + string const str = " " + getStringFromVector(vec, " | ") + " "; + + fl_clear_choice(choice); + fl_addto_choice(choice, str.c_str()); + + int width = 0; + for (vector::const_iterator it = vec.begin(); + it != vec.end(); ++it) { + width = max(width, string_width(*it)); + } + + // Paranoia checks + int const x = max(5, int(choice->x + 0.5 * (choice->w - width))); + if (x + width > choice->form->w) + width = choice->form->w - 10; + + fl_set_object_geometry(choice, x, choice->y, width + 5, choice->h); +} + +void updateStyle(FL_OBJECT * choice, FL_OBJECT * full, FL_OBJECT * force, + string command) +{ + // Find the style of the citekeys + vector const & styles = + ControlCitation::getCiteStyles(); + biblio::CitationStyle cs = biblio::getCitationStyle(command); + + vector::const_iterator cit = + find(styles.begin(), styles.end(), cs.style); + + // Use this to initialise the GUI + if (cit == styles.end()) { + fl_set_choice(choice, 1); + fl_set_button(full, 0); + fl_set_button(force, 0); + } else { + int const i = int(cit - styles.begin()); + fl_set_choice(choice, i+1); + fl_set_button(full, cs.full); + fl_set_button(force, cs.forceUCase); + } +} + +} // namespace anon + typedef FormCB > base_class; FormCitation::FormCitation(ControlCitation & c) @@ -44,7 +103,17 @@ FormCitation::FormCitation(ControlCitation & c) void FormCitation::apply() { - controller().params().setCmdName("cite"); + vector const & styles = + ControlCitation::getCiteStyles(); + + int const choice = fl_get_choice(dialog_->choice_style) - 1; + bool const full = fl_get_button(dialog_->button_full_author_list); + bool const force = fl_get_button(dialog_->button_force_uppercase); + + string const command = + biblio::getCiteCommand(styles[choice], full, force); + + controller().params().setCmdName(command); controller().params().setContents(getStringFromVector(citekeys)); string const after = fl_get_input(dialog_->input_after); @@ -93,6 +162,9 @@ ButtonPolicy::SMInput FormCitation::input(FL_OBJECT * ob, long) biblio::InfoMap const & theMap = controller().bibkeysInfo(); + string topCitekey; + if (!citekeys.empty()) topCitekey = citekeys[0]; + if (ob == dialog_->browser_bib) { fl_deselect_browser(dialog_->browser_cite); @@ -154,7 +226,7 @@ ButtonPolicy::SMInput FormCitation::input(FL_OBJECT * ob, long) fl_clear_browser(dialog_->browser_info); string const tmp = formatted(biblio::getInfo(theMap, - bibkeys[sel-1]), + citekeys[sel-1]), dialog_->browser_info->w-10); fl_add_browser_line(dialog_->browser_info, tmp.c_str()); } @@ -270,11 +342,24 @@ ButtonPolicy::SMInput FormCitation::input(FL_OBJECT * ob, long) input(dialog_->browser_bib, 0); } else if (ob == dialog_->choice_style || + ob == dialog_->button_full_author_list || + ob == dialog_->button_force_uppercase || ob == dialog_->input_before || ob == dialog_->input_after) { activate = ButtonPolicy::SMI_VALID; } + string currentCitekey; + if (!citekeys.empty()) + currentCitekey = citekeys[0]; + + if (topCitekey != currentCitekey) { + int choice = fl_get_choice(dialog_->choice_style); + fillChoice(dialog_->choice_style, + controller().getCiteStrings(currentCitekey)); + fl_set_choice(dialog_->choice_style, choice); + } + return activate; } @@ -289,23 +374,30 @@ void FormCitation::update() citekeys = getVectorFromString(controller().params().getContents()); updateBrowser(dialog_->browser_cite, citekeys); + // Use the first citekey to fill choice_style + string key; + if (!citekeys.empty()) key = citekeys[0]; + + fillChoice(dialog_->choice_style, controller().getCiteStrings(key)); + + // Use the citation command to update the GUI + updateStyle(dialog_->choice_style, + dialog_->button_full_author_list, + dialog_->button_force_uppercase, + controller().params().getCmdName()); + // No keys have been selected yet, so... fl_clear_browser(dialog_->browser_info); setBibButtons(OFF); setCiteButtons(OFF); - int noKeys = int(max(bibkeys.size(), citekeys.size())); - - // Place bounds, so that 4 <= noKeys <= 10 - noKeys = max(4, min(10, noKeys)); - - // Re-size the form to accommodate the new browser size - int const size = 20 * noKeys; - bool const bibPresent = (bibkeys.size() > 0); - setSize(size, bibPresent); - + // Natbib can have comments before and after the citation. + // This is not yet supported. After only. fl_set_input(dialog_->input_after, controller().params().getOptions().c_str()); + + fl_set_input(dialog_->input_before, _("Not yet supported")); + setEnabled(dialog_->input_before, false); } @@ -341,125 +433,3 @@ void FormCitation::setCiteButtons(State status) const setEnabled(dialog_->button_up, activate_up); setEnabled(dialog_->button_down, activate_down); } - - -void FormCitation::setSize(int hbrsr, bool bibPresent) const -{ - bool const natbib = false; // will eventually be input - hbrsr = max(hbrsr, 175); // limit max size of cite/bib brsrs - - // dh1, dh2, dh3 are the vertical separation between elements. - // These can be specified because the browser height is fixed - // so they are not changed by dynamic resizing - static int const dh1 = 30; // top of form to top of cite/bib brsrs; - // bottom of cite/bib brsrs to top of info; - // bottom of info to top search frame; - // bottom of search frame to top next elemnt; - // bottom of style to top input_before; - // bottom of text to top ok/cancel buttons. - static int const dh2 = 10; // bottom of input_before to top input_after; - // bottom of ok/cancel buttons to bottom form - static int const dh3 = 5; // spacing between add/delete/... buttons. - - int const wbrsr = dialog_->browser_cite->w; - static int const hinfo = dialog_->browser_info->h; - static int const hframe = dialog_->frame_search->h; - static int const hstyle = dialog_->choice_style->h; - static int const htext = dialog_->input_after->h; - static int const hok = dialog_->button_ok->h; - - int hform = dh1 + hbrsr + dh1 + hframe + dh1; - if (bibPresent) hform += hinfo + dh1; - if (natbib) hform += hstyle + dh1 + htext + dh2; - hform += htext + dh1 + hok + dh2; - - if (hform != minh_) { - minh_ = hform; - fl_set_form_size(dialog_->form, minw_, minh_); - } else - return; - - int x = 0; - int y = 0; - fl_set_object_geometry(dialog_->box, x, y, minw_, minh_); - - x = dialog_->browser_cite->x; - y += dh1; - fl_set_object_geometry(dialog_->browser_cite, x, y, wbrsr, hbrsr); - x = dialog_->browser_bib->x; - fl_set_object_geometry(dialog_->browser_bib, x, y, wbrsr, hbrsr); - - x = dialog_->button_add->x; - fl_set_object_position(dialog_->button_add, x, y); - y += dh3 + dialog_->button_add->h; - fl_set_object_position(dialog_->button_del, x, y); - y += dh3 + dialog_->button_del->h; - fl_set_object_position(dialog_->button_up, x, y); - y += dh3 + dialog_->button_up->h; - fl_set_object_position(dialog_->button_down, x, y); - - y = dh1 + hbrsr + dh1; // in position for next element - - if (bibPresent) { - x = dialog_->browser_info->x; - fl_set_object_position(dialog_->browser_info, x, y); - fl_show_object(dialog_->browser_info); - y += hinfo + dh1; - } else - fl_hide_object(dialog_->browser_info); - - x = dialog_->frame_search->x; - // ??? The frame height seems to be reduced. Use geometry to enforce it. - fl_set_object_geometry(dialog_->frame_search, x, y, - dialog_->frame_search->w, hframe); - //fl_set_object_position(dialog_->frame_search, x, y); - - x = dialog_->input_search->x; - y += 15; - fl_set_object_position(dialog_->input_search, x, y); - - x = dialog_->button_previous->x; - y += dialog_->input_search->h + 5; - fl_set_object_position(dialog_->button_previous, x, y); - - x = dialog_->button_next->x; - y += dialog_->button_previous->h + 5; - fl_set_object_position(dialog_->button_next, x, y); - - x = dialog_->button_search_type->x; - y = dialog_->button_previous->y; - fl_set_object_position(dialog_->button_search_type, x, y); - - x = dialog_->button_search_case->x; - y = dialog_->button_next->y; - fl_set_object_position(dialog_->button_search_case, x, y); - - y = dialog_->frame_search->y + hframe + dh1; - - if (natbib) { - x = dialog_->choice_style->x; - fl_set_object_position(dialog_->choice_style, x, y); - fl_show_object(dialog_->choice_style); - x = dialog_->input_before->x; - y += hstyle + dh1; - fl_set_object_position(dialog_->input_before, x, y); - fl_show_object(dialog_->input_before); - y += htext + dh2; - } else { - fl_hide_object(dialog_->choice_style); - fl_hide_object(dialog_->input_before); - } - - x = dialog_->input_after->x; - fl_set_object_position(dialog_->input_after, x, y); - - y += htext + dh1; - x = dialog_->button_restore->x; - fl_set_object_position(dialog_->button_restore, x, y); - x = dialog_->button_ok->x; - fl_set_object_position(dialog_->button_ok, x, y); - x = dialog_->button_apply->x; - fl_set_object_position(dialog_->button_apply, x, y); - x = dialog_->button_cancel->x; - fl_set_object_position(dialog_->button_cancel, x, y); -} diff --git a/src/frontends/xforms/FormCitation.h b/src/frontends/xforms/FormCitation.h index 1429269c89..1135006d95 100644 --- a/src/frontends/xforms/FormCitation.h +++ b/src/frontends/xforms/FormCitation.h @@ -60,8 +60,6 @@ private: void setBibButtons(State) const; /// void setCiteButtons(State) const; - /// - void setSize(int, bool) const; /// std::vector citekeys; diff --git a/src/frontends/xforms/FormDocument.C b/src/frontends/xforms/FormDocument.C index f2dc47aa2c..bc179e124c 100644 --- a/src/frontends/xforms/FormDocument.C +++ b/src/frontends/xforms/FormDocument.C @@ -212,12 +212,16 @@ void FormDocument::build() for (n=0; tex_graphics[n][0]; ++n) { fl_addto_choice(options_->choice_postscript_driver, tex_graphics[n]); } + fl_addto_choice(options_->choice_citation_format, + _(" Author-year | Numerical ")); - bc().addReadOnly (options_->slider_secnumdepth); - bc().addReadOnly (options_->slider_tocdepth); - bc().addReadOnly (options_->check_use_amsmath); - bc().addReadOnly (options_->input_float_placement); - bc().addReadOnly (options_->choice_postscript_driver); + bc_.addReadOnly (options_->slider_secnumdepth); + bc_.addReadOnly (options_->slider_tocdepth); + bc_.addReadOnly (options_->check_use_amsmath); + bc_.addReadOnly (options_->check_use_natbib); + bc_.addReadOnly (options_->choice_citation_format); + bc_.addReadOnly (options_->input_float_placement); + bc_.addReadOnly (options_->choice_postscript_driver); // the document bullets form bullets_.reset(build_doc_bullet()); @@ -561,6 +565,9 @@ bool FormDocument::options_apply() params.graphicsDriver = fl_get_choice_text(options_->choice_postscript_driver); params.use_amsmath = fl_get_button(options_->check_use_amsmath); + params.use_natbib = fl_get_button(options_->check_use_natbib); + params.use_numerical_citations = + fl_get_choice(options_->choice_citation_format)-1; int tmpchar = int(fl_get_counter_value(options_->slider_secnumdepth)); if (params.secnumdepth != tmpchar) @@ -704,6 +711,9 @@ void FormDocument::options_update(BufferParams const & params) fl_set_choice_text(options_->choice_postscript_driver, params.graphicsDriver.c_str()); fl_set_button(options_->check_use_amsmath, params.use_amsmath); + fl_set_button(options_->check_use_natbib, params.use_natbib); + fl_set_choice(options_->choice_citation_format, + int(params.use_numerical_citations)+1); fl_set_counter_value(options_->slider_secnumdepth, params.secnumdepth); fl_set_counter_value(options_->slider_tocdepth, params.tocdepth); if (!params.float_placement.empty()) diff --git a/src/frontends/xforms/form_citation.C b/src/frontends/xforms/form_citation.C index a81eb484bf..30ef5e3bc7 100644 --- a/src/frontends/xforms/form_citation.C +++ b/src/frontends/xforms/form_citation.C @@ -22,12 +22,12 @@ FD_form_citation * FormCitation::build_citation() FL_OBJECT *obj; FD_form_citation *fdui = new FD_form_citation; - fdui->form = fl_bgn_form(FL_NO_BOX, 430, 830); + fdui->form = fl_bgn_form(FL_NO_BOX, 860, 510); fdui->form->u_vdata = this; - fdui->box = obj = fl_add_box(FL_UP_BOX, 0, 0, 430, 830, ""); + fdui->box = obj = fl_add_box(FL_UP_BOX, 0, 0, 860, 510, ""); { char const * const dummy = N_("Inset keys|#I"); - fdui->browser_cite = obj = fl_add_browser(FL_HOLD_BROWSER, 10, 30, 180, 300, idex(_(dummy))); + fdui->browser_cite = obj = fl_add_browser(FL_HOLD_BROWSER, 10, 30, 180, 460, idex(_(dummy))); fl_set_button_shortcut(obj, scex(_(dummy)), 1); } fl_set_object_lalign(obj, FL_ALIGN_TOP_LEFT); @@ -36,7 +36,7 @@ FD_form_citation * FormCitation::build_citation() fl_set_object_callback(obj, C_FormBaseInputCB, 0); { char const * const dummy = N_("Bibliography keys|#B"); - fdui->browser_bib = obj = fl_add_browser(FL_HOLD_BROWSER, 240, 30, 180, 300, idex(_(dummy))); + fdui->browser_bib = obj = fl_add_browser(FL_HOLD_BROWSER, 240, 30, 180, 460, idex(_(dummy))); fl_set_button_shortcut(obj, scex(_(dummy)), 1); } fl_set_object_lalign(obj, FL_ALIGN_TOP_LEFT); @@ -63,46 +63,64 @@ FD_form_citation * FormCitation::build_citation() fl_set_object_gravity(obj, FL_North, FL_North); fl_set_object_resize(obj, FL_RESIZE_NONE); fl_set_object_callback(obj, C_FormBaseInputCB, 0); - fdui->browser_info = obj = fl_add_browser(FL_NORMAL_BROWSER, 10, 360, 410, 95, _("Info")); + fdui->browser_info = obj = fl_add_browser(FL_NORMAL_BROWSER, 440, 30, 410, 95, _("Info")); fl_set_object_lalign(obj, FL_ALIGN_TOP_LEFT); fl_set_object_gravity(obj, FL_SouthWest, FL_SouthEast); fl_set_object_resize(obj, FL_RESIZE_NONE); - fdui->frame_search = obj = fl_add_labelframe(FL_ENGRAVED_FRAME, 10, 475, 410, 125, _("Search")); + fdui->frame_search = obj = fl_add_labelframe(FL_ENGRAVED_FRAME, 440, 145, 410, 125, _("Search")); + fl_set_object_lsize(obj, FL_NORMAL_SIZE); + fl_set_object_lstyle(obj, FL_BOLD_STYLE); fl_set_object_gravity(obj, FL_SouthWest, FL_SouthEast); - fdui->input_search = obj = fl_add_input(FL_NORMAL_INPUT, 25, 490, 380, 30, ""); + fdui->input_search = obj = fl_add_input(FL_NORMAL_INPUT, 455, 160, 380, 30, ""); fl_set_object_lalign(obj, FL_ALIGN_TOP); fl_set_object_gravity(obj, FL_SouthWest, FL_SouthEast); fl_set_object_resize(obj, FL_RESIZE_NONE); - fdui->button_search_type = obj = fl_add_checkbutton(FL_PUSH_BUTTON, 25, 525, 30, 30, _("Regular Expression")); + fdui->button_search_type = obj = fl_add_checkbutton(FL_PUSH_BUTTON, 455, 195, 30, 30, _("Regular Expression")); fl_set_object_gravity(obj, FL_SouthWest, FL_SouthWest); - fdui->button_search_case = obj = fl_add_checkbutton(FL_PUSH_BUTTON, 25, 560, 30, 30, _("Case sensitive")); + fdui->button_search_case = obj = fl_add_checkbutton(FL_PUSH_BUTTON, 455, 230, 30, 30, _("Case sensitive")); fl_set_object_gravity(obj, FL_SouthWest, FL_SouthWest); { char const * const dummy = N_("Previous|#P"); - fdui->button_previous = obj = fl_add_button(FL_NORMAL_BUTTON, 315, 525, 90, 30, idex(_(dummy))); + fdui->button_previous = obj = fl_add_button(FL_NORMAL_BUTTON, 745, 195, 90, 30, idex(_(dummy))); fl_set_button_shortcut(obj, scex(_(dummy)), 1); } fl_set_object_gravity(obj, FL_SouthEast, FL_SouthEast); fl_set_object_callback(obj, C_FormBaseInputCB, 0); { char const * const dummy = N_("Next|#N"); - fdui->button_next = obj = fl_add_button(FL_NORMAL_BUTTON, 315, 560, 90, 30, idex(_(dummy))); + fdui->button_next = obj = fl_add_button(FL_NORMAL_BUTTON, 745, 230, 90, 30, idex(_(dummy))); fl_set_button_shortcut(obj, scex(_(dummy)), 1); } fl_set_object_gravity(obj, FL_SouthEast, FL_SouthEast); fl_set_object_callback(obj, C_FormBaseInputCB, 0); - { - char const * const dummy = N_("Citation style|#s"); - fdui->choice_style = obj = fl_add_choice(FL_NORMAL_CHOICE, 160, 630, 130, 30, idex(_(dummy))); - fl_set_button_shortcut(obj, scex(_(dummy)), 1); - } + obj = fl_add_labelframe(FL_ENGRAVED_FRAME, 440, 285, 410, 80, _("Citation style")); + fl_set_object_shortcut(obj, _("frame_style"), 1); + fl_set_object_lsize(obj, FL_NORMAL_SIZE); + fl_set_object_lstyle(obj, FL_BOLD_STYLE); + fdui->choice_style = obj = fl_add_choice(FL_NORMAL_CHOICE, 590, 300, 130, 30, ""); fl_set_object_boxtype(obj, FL_FRAME_BOX); fl_set_object_gravity(obj, FL_SouthWest, FL_SouthEast); fl_set_object_resize(obj, FL_RESIZE_NONE); fl_set_object_callback(obj, C_FormBaseInputCB, 0); + { + char const * const dummy = N_("Full author list|#F"); + fdui->button_full_author_list = obj = fl_add_checkbutton(FL_PUSH_BUTTON, 580, 330, 30, 30, idex(_(dummy))); + fl_set_button_shortcut(obj, scex(_(dummy)), 1); + } + fl_set_object_lsize(obj, FL_NORMAL_SIZE); + fl_set_object_lalign(obj, FL_ALIGN_LEFT); + fl_set_object_callback(obj, C_FormBaseInputCB, 0); + { + char const * const dummy = N_("Force upper case|#u"); + fdui->button_force_uppercase = obj = fl_add_checkbutton(FL_PUSH_BUTTON, 805, 330, 30, 30, idex(_(dummy))); + fl_set_button_shortcut(obj, scex(_(dummy)), 1); + } + fl_set_object_lsize(obj, FL_NORMAL_SIZE); + fl_set_object_lalign(obj, FL_ALIGN_LEFT); + fl_set_object_callback(obj, C_FormBaseInputCB, 0); { char const * const dummy = N_("Text before|#T"); - fdui->input_before = obj = fl_add_input(FL_NORMAL_INPUT, 100, 680, 250, 30, idex(_(dummy))); + fdui->input_before = obj = fl_add_input(FL_NORMAL_INPUT, 530, 375, 250, 30, idex(_(dummy))); fl_set_button_shortcut(obj, scex(_(dummy)), 1); } fl_set_object_gravity(obj, FL_SouthWest, FL_SouthEast); @@ -110,7 +128,7 @@ FD_form_citation * FormCitation::build_citation() fl_set_object_callback(obj, C_FormBaseInputCB, 0); { char const * const dummy = N_("Text after|#e"); - fdui->input_after = obj = fl_add_input(FL_NORMAL_INPUT, 100, 730, 250, 30, idex(_(dummy))); + fdui->input_after = obj = fl_add_input(FL_NORMAL_INPUT, 530, 410, 250, 30, idex(_(dummy))); fl_set_button_shortcut(obj, scex(_(dummy)), 1); } fl_set_object_gravity(obj, FL_SouthWest, FL_SouthEast); @@ -118,24 +136,24 @@ FD_form_citation * FormCitation::build_citation() fl_set_object_callback(obj, C_FormBaseInputCB, 0); { char const * const dummy = N_("Restore|#R"); - fdui->button_restore = obj = fl_add_button(FL_NORMAL_BUTTON, 10, 790, 90, 30, idex(_(dummy))); + fdui->button_restore = obj = fl_add_button(FL_NORMAL_BUTTON, 440, 460, 90, 30, idex(_(dummy))); fl_set_button_shortcut(obj, scex(_(dummy)), 1); } fl_set_object_gravity(obj, FL_SouthWest, FL_SouthWest); fl_set_object_callback(obj, C_FormBaseRestoreCB, 0); - fdui->button_ok = obj = fl_add_button(FL_RETURN_BUTTON, 130, 790, 90, 30, _("OK")); + fdui->button_ok = obj = fl_add_button(FL_RETURN_BUTTON, 560, 460, 90, 30, _("OK")); fl_set_object_gravity(obj, FL_SouthEast, FL_SouthEast); fl_set_object_callback(obj, C_FormBaseOKCB, 0); { char const * const dummy = N_("Apply|#A"); - fdui->button_apply = obj = fl_add_button(FL_NORMAL_BUTTON, 230, 790, 90, 30, idex(_(dummy))); + fdui->button_apply = obj = fl_add_button(FL_NORMAL_BUTTON, 660, 460, 90, 30, idex(_(dummy))); fl_set_button_shortcut(obj, scex(_(dummy)), 1); } fl_set_object_gravity(obj, FL_SouthEast, FL_SouthEast); fl_set_object_callback(obj, C_FormBaseApplyCB, 0); { char const * const dummy = N_("Cancel|^["); - fdui->button_cancel = obj = fl_add_button(FL_NORMAL_BUTTON, 330, 790, 90, 30, idex(_(dummy))); + fdui->button_cancel = obj = fl_add_button(FL_NORMAL_BUTTON, 760, 460, 90, 30, idex(_(dummy))); fl_set_button_shortcut(obj, scex(_(dummy)), 1); } fl_set_object_gravity(obj, FL_SouthEast, FL_SouthEast); diff --git a/src/frontends/xforms/form_citation.h b/src/frontends/xforms/form_citation.h index c168b10351..49c2f8e2e3 100644 --- a/src/frontends/xforms/form_citation.h +++ b/src/frontends/xforms/form_citation.h @@ -32,6 +32,8 @@ struct FD_form_citation { FL_OBJECT *button_previous; FL_OBJECT *button_next; FL_OBJECT *choice_style; + FL_OBJECT *button_full_author_list; + FL_OBJECT *button_force_uppercase; FL_OBJECT *input_before; FL_OBJECT *input_after; FL_OBJECT *button_restore; diff --git a/src/frontends/xforms/form_document.C b/src/frontends/xforms/form_document.C index 5446488672..8a52aee6b0 100644 --- a/src/frontends/xforms/form_document.C +++ b/src/frontends/xforms/form_document.C @@ -457,22 +457,22 @@ FD_form_doc_options * FormDocument::build_doc_options() obj = fl_add_box(FL_FLAT_BOX, 0, 0, 440, 345, ""); { char const * const dummy = N_("Float Placement:|#L"); - fdui->input_float_placement = obj = fl_add_input(FL_NORMAL_INPUT, 155, 60, 120, 30, idex(_(dummy))); + fdui->input_float_placement = obj = fl_add_input(FL_NORMAL_INPUT, 220, 45, 120, 30, idex(_(dummy))); fl_set_button_shortcut(obj, scex(_(dummy)), 1); } fl_set_object_lsize(obj, FL_NORMAL_SIZE); fl_set_object_callback(obj, C_FormBaseDeprecatedInputCB, INPUT); - fdui->slider_secnumdepth = obj = fl_add_counter(FL_SIMPLE_COUNTER, 155, 110, 80, 30, _("Section number depth")); + fdui->slider_secnumdepth = obj = fl_add_counter(FL_SIMPLE_COUNTER, 220, 85, 80, 30, _("Section number depth")); fl_set_object_lsize(obj, FL_NORMAL_SIZE); fl_set_object_lalign(obj, FL_ALIGN_LEFT); fl_set_object_callback(obj, C_FormBaseDeprecatedInputCB, INPUT); - fdui->slider_tocdepth = obj = fl_add_counter(FL_SIMPLE_COUNTER, 155, 150, 80, 30, _("Table of contents depth")); + fdui->slider_tocdepth = obj = fl_add_counter(FL_SIMPLE_COUNTER, 220, 125, 80, 30, _("Table of contents depth")); fl_set_object_lsize(obj, FL_NORMAL_SIZE); fl_set_object_lalign(obj, FL_ALIGN_LEFT); fl_set_object_callback(obj, C_FormBaseDeprecatedInputCB, INPUT); { - char const * const dummy = N_("PS Driver:|#S"); - fdui->choice_postscript_driver = obj = fl_add_choice(FL_NORMAL_CHOICE, 155, 205, 190, 30, idex(_(dummy))); + char const * const dummy = N_("PS Driver|#S"); + fdui->choice_postscript_driver = obj = fl_add_choice(FL_NORMAL_CHOICE, 220, 165, 190, 30, idex(_(dummy))); fl_set_button_shortcut(obj, scex(_(dummy)), 1); } fl_set_object_boxtype(obj, FL_FRAME_BOX); @@ -480,11 +480,28 @@ FD_form_doc_options * FormDocument::build_doc_options() fl_set_object_callback(obj, C_FormBaseDeprecatedInputCB, INPUT); { char const * const dummy = N_("Use AMS Math|#M"); - fdui->check_use_amsmath = obj = fl_add_checkbutton(FL_PUSH_BUTTON, 140, 250, 200, 30, idex(_(dummy))); + fdui->check_use_amsmath = obj = fl_add_checkbutton(FL_PUSH_BUTTON, 220, 205, 35, 30, idex(_(dummy))); fl_set_button_shortcut(obj, scex(_(dummy)), 1); } fl_set_object_lsize(obj, FL_NORMAL_SIZE); + fl_set_object_lalign(obj, FL_ALIGN_LEFT); + fl_set_object_callback(obj, C_FormBaseDeprecatedInputCB, INPUT); + { + char const * const dummy = N_("Use Natbib|#N"); + fdui->check_use_natbib = obj = fl_add_checkbutton(FL_PUSH_BUTTON, 220, 245, 35, 30, idex(_(dummy))); + fl_set_button_shortcut(obj, scex(_(dummy)), 1); + } + fl_set_object_lsize(obj, FL_NORMAL_SIZE); + fl_set_object_lalign(obj, FL_ALIGN_LEFT); fl_set_object_callback(obj, C_FormBaseDeprecatedInputCB, INPUT); + { + char const * const dummy = N_("Citation style|#C"); + fdui->choice_citation_format = obj = fl_add_choice(FL_NORMAL_CHOICE, 220, 285, 190, 30, idex(_(dummy))); + fl_set_button_shortcut(obj, scex(_(dummy)), 1); + } + fl_set_object_boxtype(obj, FL_FRAME_BOX); + fl_set_object_lsize(obj, FL_NORMAL_SIZE); + fl_set_object_callback(obj, C_FormBaseDeprecatedInputCB, 0); fl_end_form(); fdui->form->fdui = fdui; diff --git a/src/frontends/xforms/form_document.h b/src/frontends/xforms/form_document.h index 96dcfead40..b87f60ff1a 100644 --- a/src/frontends/xforms/form_document.h +++ b/src/frontends/xforms/form_document.h @@ -96,6 +96,8 @@ struct FD_form_doc_options { FL_OBJECT *slider_tocdepth; FL_OBJECT *choice_postscript_driver; FL_OBJECT *check_use_amsmath; + FL_OBJECT *check_use_natbib; + FL_OBJECT *choice_citation_format; }; struct FD_form_doc_bullet { ~FD_form_doc_bullet(); diff --git a/src/frontends/xforms/forms/form_citation.fd b/src/frontends/xforms/forms/form_citation.fd index d765b77b4d..cfdb1aa3f5 100644 --- a/src/frontends/xforms/forms/form_citation.fd +++ b/src/frontends/xforms/forms/form_citation.fd @@ -8,14 +8,14 @@ Unit of measure: FL_COORD_PIXEL =============== FORM =============== Name: form_citation -Width: 430 -Height: 830 -Number of Objects: 21 +Width: 860 +Height: 510 +Number of Objects: 24 -------------------- class: FL_BOX type: UP_BOX -box: 0 0 430 830 +box: 0 0 860 510 boxtype: FL_UP_BOX colors: FL_COL1 FL_COL1 alignment: FL_ALIGN_CENTER @@ -33,7 +33,7 @@ argument: -------------------- class: FL_BROWSER type: HOLD_BROWSER -box: 10 30 180 300 +box: 10 30 180 460 boxtype: FL_DOWN_BOX colors: FL_COL1 FL_YELLOW alignment: FL_ALIGN_TOP_LEFT @@ -51,7 +51,7 @@ argument: 0 -------------------- class: FL_BROWSER type: HOLD_BROWSER -box: 240 30 180 300 +box: 240 30 180 460 boxtype: FL_DOWN_BOX colors: FL_COL1 FL_YELLOW alignment: FL_ALIGN_TOP_LEFT @@ -141,7 +141,7 @@ argument: 0 -------------------- class: FL_BROWSER type: NORMAL_BROWSER -box: 10 360 410 95 +box: 440 30 410 95 boxtype: FL_DOWN_BOX colors: FL_COL1 FL_YELLOW alignment: FL_ALIGN_TOP_LEFT @@ -159,12 +159,12 @@ argument: -------------------- class: FL_LABELFRAME type: ENGRAVED_FRAME -box: 10 475 410 125 +box: 440 145 410 125 boxtype: FL_NO_BOX colors: FL_BLACK FL_COL1 alignment: FL_ALIGN_TOP_LEFT -style: FL_NORMAL_STYLE -size: FL_DEFAULT_SIZE +style: FL_BOLD_STYLE +size: FL_NORMAL_SIZE lcol: FL_BLACK label: Search shortcut: @@ -177,7 +177,7 @@ argument: -------------------- class: FL_INPUT type: NORMAL_INPUT -box: 25 490 380 30 +box: 455 160 380 30 boxtype: FL_DOWN_BOX colors: FL_COL1 FL_MCOL alignment: FL_ALIGN_TOP @@ -195,7 +195,7 @@ argument: -------------------- class: FL_CHECKBUTTON type: PUSH_BUTTON -box: 25 525 30 30 +box: 455 195 30 30 boxtype: FL_NO_BOX colors: FL_COL1 FL_YELLOW alignment: FL_ALIGN_CENTER @@ -207,13 +207,13 @@ shortcut: resize: FL_RESIZE_ALL gravity: FL_SouthWest FL_SouthWest name: button_search_type -callback: -argument: +callback: +argument: -------------------- class: FL_CHECKBUTTON type: PUSH_BUTTON -box: 25 560 30 30 +box: 455 230 30 30 boxtype: FL_NO_BOX colors: FL_COL1 FL_YELLOW alignment: FL_ALIGN_CENTER @@ -231,7 +231,7 @@ argument: -------------------- class: FL_BUTTON type: NORMAL_BUTTON -box: 315 525 90 30 +box: 745 195 90 30 boxtype: FL_UP_BOX colors: FL_COL1 FL_COL1 alignment: FL_ALIGN_CENTER @@ -249,7 +249,7 @@ argument: 0 -------------------- class: FL_BUTTON type: NORMAL_BUTTON -box: 315 560 90 30 +box: 745 230 90 30 boxtype: FL_UP_BOX colors: FL_COL1 FL_COL1 alignment: FL_ALIGN_CENTER @@ -264,17 +264,35 @@ name: button_next callback: C_FormBaseInputCB argument: 0 +-------------------- +class: FL_LABELFRAME +type: ENGRAVED_FRAME +box: 440 285 410 80 +boxtype: FL_NO_BOX +colors: FL_BLACK FL_COL1 +alignment: FL_ALIGN_TOP_LEFT +style: FL_BOLD_STYLE +size: FL_NORMAL_SIZE +lcol: FL_BLACK +label: Citation style +shortcut: frame_style +resize: FL_RESIZE_ALL +gravity: FL_NoGravity FL_NoGravity +name: +callback: +argument: + -------------------- class: FL_CHOICE type: NORMAL_CHOICE -box: 160 630 130 30 +box: 590 300 130 30 boxtype: FL_FRAME_BOX colors: FL_COL1 FL_BLACK alignment: FL_ALIGN_LEFT style: FL_NORMAL_STYLE size: FL_DEFAULT_SIZE lcol: FL_BLACK -label: Citation style|#s +label: shortcut: resize: FL_RESIZE_NONE gravity: FL_SouthWest FL_SouthEast @@ -282,10 +300,46 @@ name: choice_style callback: C_FormBaseInputCB argument: 0 +-------------------- +class: FL_CHECKBUTTON +type: PUSH_BUTTON +box: 580 330 30 30 +boxtype: FL_NO_BOX +colors: FL_COL1 FL_YELLOW +alignment: FL_ALIGN_LEFT +style: FL_NORMAL_STYLE +size: FL_NORMAL_SIZE +lcol: FL_BLACK +label: Full author list|#F +shortcut: +resize: FL_RESIZE_ALL +gravity: FL_NoGravity FL_NoGravity +name: button_full_author_list +callback: C_FormBaseInputCB +argument: 0 + +-------------------- +class: FL_CHECKBUTTON +type: PUSH_BUTTON +box: 805 330 30 30 +boxtype: FL_NO_BOX +colors: FL_COL1 FL_YELLOW +alignment: FL_ALIGN_LEFT +style: FL_NORMAL_STYLE +size: FL_NORMAL_SIZE +lcol: FL_BLACK +label: Force upper case|#u +shortcut: +resize: FL_RESIZE_ALL +gravity: FL_NoGravity FL_NoGravity +name: button_force_uppercase +callback: C_FormBaseInputCB +argument: 0 + -------------------- class: FL_INPUT type: NORMAL_INPUT -box: 100 680 250 30 +box: 530 375 250 30 boxtype: FL_DOWN_BOX colors: FL_COL1 FL_MCOL alignment: FL_ALIGN_LEFT @@ -303,7 +357,7 @@ argument: 0 -------------------- class: FL_INPUT type: NORMAL_INPUT -box: 100 730 250 30 +box: 530 410 250 30 boxtype: FL_DOWN_BOX colors: FL_COL1 FL_MCOL alignment: FL_ALIGN_LEFT @@ -321,7 +375,7 @@ argument: 0 -------------------- class: FL_BUTTON type: NORMAL_BUTTON -box: 10 790 90 30 +box: 440 460 90 30 boxtype: FL_UP_BOX colors: FL_COL1 FL_COL1 alignment: FL_ALIGN_CENTER @@ -339,7 +393,7 @@ argument: 0 -------------------- class: FL_BUTTON type: RETURN_BUTTON -box: 130 790 90 30 +box: 560 460 90 30 boxtype: FL_UP_BOX colors: FL_COL1 FL_COL1 alignment: FL_ALIGN_CENTER @@ -357,7 +411,7 @@ argument: 0 -------------------- class: FL_BUTTON type: NORMAL_BUTTON -box: 230 790 90 30 +box: 660 460 90 30 boxtype: FL_UP_BOX colors: FL_COL1 FL_COL1 alignment: FL_ALIGN_CENTER @@ -375,7 +429,7 @@ argument: 0 -------------------- class: FL_BUTTON type: NORMAL_BUTTON -box: 330 790 90 30 +box: 760 460 90 30 boxtype: FL_UP_BOX colors: FL_COL1 FL_COL1 alignment: FL_ALIGN_CENTER diff --git a/src/frontends/xforms/forms/form_document.fd b/src/frontends/xforms/forms/form_document.fd index 36671eab72..1b4007bca6 100644 --- a/src/frontends/xforms/forms/form_document.fd +++ b/src/frontends/xforms/forms/form_document.fd @@ -346,7 +346,7 @@ argument: -------------------- class: FL_BEGIN_GROUP type: 0 -box: 0 0 0 0 +box: 0 10 10 0 boxtype: FL_NO_BOX colors: FL_COL1 FL_MCOL alignment: FL_ALIGN_CENTER @@ -874,7 +874,7 @@ argument: INPUT -------------------- class: FL_BEGIN_GROUP type: 0 -box: 0 0 0 0 +box: 0 10 10 0 boxtype: FL_NO_BOX colors: FL_COL1 FL_MCOL alignment: FL_ALIGN_CENTER @@ -946,7 +946,7 @@ argument: -------------------- class: FL_BEGIN_GROUP type: 0 -box: 0 0 0 0 +box: 0 10 10 0 boxtype: FL_NO_BOX colors: FL_COL1 FL_MCOL alignment: FL_ALIGN_CENTER @@ -1018,7 +1018,7 @@ argument: -------------------- class: FL_BEGIN_GROUP type: 0 -box: 0 0 0 0 +box: 0 10 10 0 boxtype: FL_NO_BOX colors: FL_COL1 FL_MCOL alignment: FL_ALIGN_CENTER @@ -1187,7 +1187,7 @@ argument: INPUT -------------------- class: FL_BEGIN_GROUP type: 0 -box: 0 0 0 0 +box: 0 10 10 0 boxtype: FL_NO_BOX colors: FL_COL1 FL_MCOL alignment: FL_ALIGN_CENTER @@ -1278,7 +1278,7 @@ argument: INPUT Name: form_doc_options Width: 440 Height: 345 -Number of Objects: 6 +Number of Objects: 8 -------------------- class: FL_BOX @@ -1301,7 +1301,7 @@ argument: -------------------- class: FL_INPUT type: NORMAL_INPUT -box: 155 60 120 30 +box: 220 45 120 30 boxtype: FL_DOWN_BOX colors: FL_COL1 FL_MCOL alignment: FL_ALIGN_LEFT @@ -1319,7 +1319,7 @@ argument: INPUT -------------------- class: FL_COUNTER type: SIMPLE_COUNTER -box: 155 110 80 30 +box: 220 85 80 30 boxtype: FL_UP_BOX colors: FL_COL1 FL_BLUE alignment: FL_ALIGN_LEFT @@ -1337,7 +1337,7 @@ argument: INPUT -------------------- class: FL_COUNTER type: SIMPLE_COUNTER -box: 155 150 80 30 +box: 220 125 80 30 boxtype: FL_UP_BOX colors: FL_COL1 FL_BLUE alignment: FL_ALIGN_LEFT @@ -1355,14 +1355,14 @@ argument: INPUT -------------------- class: FL_CHOICE type: NORMAL_CHOICE -box: 155 205 190 30 +box: 220 165 190 30 boxtype: FL_FRAME_BOX colors: FL_COL1 FL_BLACK alignment: FL_ALIGN_LEFT style: FL_NORMAL_STYLE size: FL_NORMAL_SIZE lcol: FL_BLACK -label: PS Driver:|#S +label: PS Driver|#S shortcut: resize: FL_RESIZE_ALL gravity: FL_NoGravity FL_NoGravity @@ -1373,10 +1373,10 @@ argument: INPUT -------------------- class: FL_CHECKBUTTON type: PUSH_BUTTON -box: 140 250 200 30 +box: 220 205 35 30 boxtype: FL_NO_BOX colors: FL_COL1 FL_YELLOW -alignment: FL_ALIGN_CENTER +alignment: FL_ALIGN_LEFT style: FL_NORMAL_STYLE size: FL_NORMAL_SIZE lcol: FL_BLACK @@ -1388,6 +1388,42 @@ name: check_use_amsmath callback: C_FormBaseDeprecatedInputCB argument: INPUT +-------------------- +class: FL_CHECKBUTTON +type: PUSH_BUTTON +box: 220 245 35 30 +boxtype: FL_NO_BOX +colors: FL_COL1 FL_YELLOW +alignment: FL_ALIGN_LEFT +style: FL_NORMAL_STYLE +size: FL_NORMAL_SIZE +lcol: FL_BLACK +label: Use Natbib|#N +shortcut: +resize: FL_RESIZE_ALL +gravity: FL_NoGravity FL_NoGravity +name: check_use_natbib +callback: C_FormBaseDeprecatedInputCB +argument: INPUT + +-------------------- +class: FL_CHOICE +type: NORMAL_CHOICE +box: 220 285 190 30 +boxtype: FL_FRAME_BOX +colors: FL_COL1 FL_BLACK +alignment: FL_ALIGN_LEFT +style: FL_NORMAL_STYLE +size: FL_NORMAL_SIZE +lcol: FL_BLACK +label: Citation style|#C +shortcut: +resize: FL_RESIZE_ALL +gravity: FL_NoGravity FL_NoGravity +name: choice_citation_format +callback: C_FormBaseDeprecatedInputCB +argument: 0 + =============== FORM =============== Name: form_doc_bullet Width: 440 @@ -1430,6 +1466,7 @@ name: bmtable_bullet_panel callback: argument: file: /nfs/sinco/source/lyx/lyx-devel/lib/images/psnfss2.xpm + focus_file: fullpath: 1 -------------------- @@ -1489,7 +1526,7 @@ argument: INPUTBULLETLATEX -------------------- class: FL_BEGIN_GROUP type: 0 -box: 0 0 0 0 +box: 0 10 10 0 boxtype: FL_NO_BOX colors: FL_COL1 FL_MCOL alignment: FL_ALIGN_CENTER @@ -1616,7 +1653,7 @@ argument: -------------------- class: FL_BEGIN_GROUP type: 0 -box: 0 0 0 0 +box: 0 10 10 0 boxtype: FL_NO_BOX colors: FL_COL1 FL_MCOL alignment: FL_ALIGN_CENTER diff --git a/src/insets/ChangeLog b/src/insets/ChangeLog index f1652a9d95..233192c6e6 100644 --- a/src/insets/ChangeLog +++ b/src/insets/ChangeLog @@ -1,3 +1,8 @@ +2001-07-19 Angus Leeming + + * insetcite.[Ch] (latex, validate): new methods, required for natbib + support. + 2001-07-19 Dekel Tsur * figinset.C (RegisterFigure): Print debug message only when diff --git a/src/insets/insetcite.C b/src/insets/insetcite.C index 354cc56284..591e450bba 100644 --- a/src/insets/insetcite.C +++ b/src/insets/insetcite.C @@ -14,7 +14,9 @@ #endif #include "insetcite.h" +#include "buffer.h" #include "BufferView.h" +#include "LaTeXFeatures.h" #include "LyXView.h" #include "frontends/Dialogs.h" #include "support/lstrings.h" @@ -61,9 +63,37 @@ void InsetCitation::edit(BufferView * bv, int, int, unsigned int) bv->owner()->getDialogs()->showCitation(this); } - int InsetCitation::ascii(Buffer const *, std::ostream & os, int) const { os << "[" << getContents() << "]"; return 0; } + +// 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[]{} +int InsetCitation::latex(Buffer const * buffer, std::ostream & os, + bool /*fragile*/, bool/*fs*/) const +{ + os << "\\"; + if (buffer->params.use_natbib) + os << getCmdName(); + else + os << "cite"; + + if (!getOptions().empty()) + os << "[" << getOptions() << "]"; + + os << "{" << getContents() << "}"; + + return 0; +} + + +void InsetCitation::validate(LaTeXFeatures & features) const +{ + if (getCmdName() != "cite" && features.bufferParams().use_natbib) + features.natbib = true; +} + diff --git a/src/insets/insetcite.h b/src/insets/insetcite.h index 2ff0dfa753..58a413bafd 100644 --- a/src/insets/insetcite.h +++ b/src/insets/insetcite.h @@ -37,6 +37,10 @@ public: void edit(BufferView *, int, int, unsigned int); /// int ascii(Buffer const *, std::ostream &, int linelen) const; + /// + int latex(Buffer const *, std::ostream &, bool, bool) const; + /// + void validate(LaTeXFeatures &) const; }; #endif // INSET_CITE_H -- 2.39.5