]> git.lyx.org Git - features.git/commitdiff
Move the lyx::biblio namespace into src/. Also make changes to how the BibTeX
authorRichard Heck <rgheck@comcast.net>
Tue, 14 Aug 2007 16:50:51 +0000 (16:50 +0000)
committerRichard Heck <rgheck@comcast.net>
Tue, 14 Aug 2007 16:50:51 +0000 (16:50 +0000)
information is acquired. This involves (i) moving the bulk of fillWithBibKeys()
into Biblio.cpp, (ii) introducing a virtual method Inset::fillWithBibKeys() that,
by default, does nothing, and (iii) over-riding this method in the insets that do
need to do something.

This is all preparatory for a more substantial re-working of the BibTex code,
which should follow shortly.

git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@19565 a592a061-630c-0410-9148-cb99ea01b6c8

18 files changed:
development/scons/scons_manifest.py
po/POTFILES.in
src/Biblio.cpp [new file with mode: 0644]
src/Biblio.h [new file with mode: 0644]
src/Buffer.cpp
src/BufferParams.h
src/Makefile.am
src/frontends/controllers/ControlCitation.h
src/frontends/controllers/frontend_helpers.cpp
src/frontends/controllers/frontend_helpers.h
src/insets/Inset.h
src/insets/InsetBibitem.cpp
src/insets/InsetBibitem.h
src/insets/InsetBibtex.cpp
src/insets/InsetBibtex.h
src/insets/InsetCitation.h
src/insets/InsetInclude.cpp
src/insets/InsetInclude.h

index ebde867e5059be782ac2db5ee499a3c5f1913538..b45ac7ef616b9f69e31c0209efedb196815ec98b 100644 (file)
@@ -33,6 +33,7 @@ TOP_extra_files = Split('''
 src_header_files = Split('''
     ASpell_local.h
     Author.h
+    Biblio.h
     Bidi.h
     Box.h
     BranchList.h
@@ -143,6 +144,7 @@ src_header_files = Split('''
 
 src_pre_files = Split('''
     Author.cpp
+    Biblio.cpp
     Bidi.cpp
     BranchList.cpp
     Buffer.cpp
index 8596c0990672411cd5b0efe8b0763e76538038ec..df3ec42c3240447e19632408bd6a4c57f310ca6e 100644 (file)
@@ -1,3 +1,4 @@
+src/Biblio.cpp
 src/Buffer.cpp
 src/BufferList.cpp
 src/BufferParams.cpp
diff --git a/src/Biblio.cpp b/src/Biblio.cpp
new file mode 100644 (file)
index 0000000..8c48332
--- /dev/null
@@ -0,0 +1,849 @@
+/**
+ * \file Biblio.cpp
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author Angus Leeming
+ * \author Herbert Voß
+ * \author Richard Heck (re-write of BibTeX representation)
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+#include "Biblio.h"
+
+#include "gettext.h"
+#include "InsetIterator.h"
+#include "Paragraph.h"
+
+#include "insets/Inset.h"
+#include "insets/InsetBibitem.h"
+#include "insets/InsetBibtex.h"
+#include "insets/InsetInclude.h"
+
+#include "support/lstrings.h"
+
+using std::string;
+using std::vector;
+using std::pair;
+using std::endl;
+
+namespace lyx {
+using support::ascii_lowercase;
+using support::bformat;
+using support::compare_ascii_no_case;
+using support::contains;
+using support::getVectorFromString;
+using support::ltrim;
+using support::prefixIs;
+using support::rtrim;
+using support::split;
+using support::subst;
+using support::token;
+using support::trim;
+
+namespace biblio {
+
+namespace {
+
+       vector<string> const init_possible_cite_commands()
+       {
+               char const * const pos[] = {
+                       "cite", "citet", "citep", "citealt", "citealp",
+                       "citeauthor", "citeyear", "citeyearpar",
+                       "citet*", "citep*", "citealt*", "citealp*", "citeauthor*",
+                       "Citet",  "Citep",  "Citealt",  "Citealp",  "Citeauthor",
+                       "Citet*", "Citep*", "Citealt*", "Citealp*", "Citeauthor*",
+                       "fullcite",
+                       "footcite", "footcitet", "footcitep", "footcitealt",
+                       "footcitealp", "footciteauthor", "footciteyear", "footciteyearpar",
+                       "citefield", "citetitle", "cite*"
+               };
+               size_t const size_pos = sizeof(pos) / sizeof(pos[0]);
+
+               return vector<string>(pos, pos + size_pos);
+       }
+
+
+       vector<string> const & possible_cite_commands()
+       {
+               static vector<string> const pos = init_possible_cite_commands();
+               return pos;
+       }
+
+
+       bool is_possible_cite_command(string const & input)
+       {
+               vector<string> const & possibles = possible_cite_commands();
+               vector<string>::const_iterator const end = possibles.end();
+               return std::find(possibles.begin(), end, input) != end;
+       }
+
+
+       string const default_cite_command(CiteEngine engine)
+       {
+               string str;
+               switch (engine) {
+                       case ENGINE_BASIC:
+                               str = "cite";
+                               break;
+                       case ENGINE_NATBIB_AUTHORYEAR:
+                               str = "citet";
+                               break;
+                       case ENGINE_NATBIB_NUMERICAL:
+                               str = "citep";
+                               break;
+                       case ENGINE_JURABIB:
+                               str = "cite";
+                               break;
+               }
+               return str;
+       }
+
+
+} // namespace anon
+
+
+const docstring TheBibliographyRef(from_ascii("TheBibliographyRef"));
+
+string const asValidLatexCommand(string const & input,
+                                 CiteEngine const engine)
+{
+       string const default_str = default_cite_command(engine);
+       if (!is_possible_cite_command(input))
+               return default_str;
+
+       string output;
+       switch (engine) {
+               case ENGINE_BASIC:
+                       output = default_str;
+                       break;
+
+               case ENGINE_NATBIB_AUTHORYEAR:
+               case ENGINE_NATBIB_NUMERICAL:
+                       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);
+
+                               break;
+                       }
+       }
+
+       return output;
+}
+
+
+docstring const familyName(docstring const & name)
+{
+       if (name.empty())
+               return docstring();
+
+// Very simple parser
+       docstring fname = name;
+
+// possible authorname combinations are:
+// "Surname, FirstName"
+// "Surname, F."
+// "FirstName Surname"
+// "F. Surname"
+       docstring::size_type idx = fname.find(',');
+       if (idx != docstring::npos)
+               return ltrim(fname.substr(0, idx));
+       idx = fname.rfind('.');
+       if (idx != docstring::npos && idx + 1 < fname.size())
+               fname = ltrim(fname.substr(idx + 1));
+// test if we have a LaTeX Space in front
+       if (fname[0] == '\\')
+               return fname.substr(2);
+
+       return rtrim(fname);
+}
+
+
+docstring const getAbbreviatedAuthor(InfoMap const & map, string const & key)
+{
+       BOOST_ASSERT(!map.empty());
+
+       InfoMap::const_iterator it = map.find(key);
+       if (it == map.end())
+               return docstring();
+       docstring const & data = it->second;
+
+// Is the entry a BibTeX one or one from lyx-layout "bibliography"?
+       docstring::size_type const pos = data.find(TheBibliographyRef);
+       if (pos != docstring::npos) {
+               if (pos <= 2) {
+                       return docstring();
+               }
+
+               docstring const opt = trim(data.substr(0, pos - 1));
+               if (opt.empty())
+                       return docstring();
+
+               docstring authors;
+               split(opt, authors, '(');
+               return authors;
+       }
+
+       docstring author = parseBibTeX(data, "author");
+
+       if (author.empty())
+               author = parseBibTeX(data, "editor");
+
+       if (author.empty()) {
+               author = parseBibTeX(data, "key");
+               if (author.empty())
+               // FIXME UNICODE
+                       return from_utf8(key);
+               return author;
+       }
+
+       vector<docstring> const authors = getVectorFromString(author, from_ascii(" and "));
+       if (authors.empty())
+               return author;
+
+       if (authors.size() == 2)
+               return bformat(_("%1$s and %2$s"),
+                                                                       familyName(authors[0]), familyName(authors[1]));
+
+       if (authors.size() > 2)
+               return bformat(_("%1$s et al."), familyName(authors[0]));
+
+       return familyName(authors[0]);
+}
+
+
+docstring const getYear(InfoMap const & map, string const & key)
+{
+       BOOST_ASSERT(!map.empty());
+
+       InfoMap::const_iterator it = map.find(key);
+       if (it == map.end())
+               return docstring();
+       docstring const & data = it->second;
+
+// Is the entry a BibTeX one or one from lyx-layout "bibliography"?
+       docstring::size_type const pos = data.find(TheBibliographyRef);
+       if (pos != docstring::npos) {
+               if (pos <= 2) {
+                       return docstring();
+               }
+
+               docstring const opt =
+                                       trim(data.substr(0, pos - 1));
+               if (opt.empty())
+                       return docstring();
+
+               docstring authors;
+               docstring const tmp = split(opt, authors, '(');
+               docstring year;
+               split(tmp, year, ')');
+               return year;
+
+       }
+
+       docstring year = parseBibTeX(data, "year");
+       if (year.empty())
+               year = _("No year");
+
+       return year;
+}
+
+
+namespace {
+// A functor for use with std::sort, leading to case insensitive sorting
+class compareNoCase: public std::binary_function<string, string, bool>
+{
+       public:
+               bool operator()(string const & s1, string const & s2) const {
+                       return compare_ascii_no_case(s1, s2) < 0;
+               }
+};
+} // namespace anon
+
+
+vector<string> const getKeys(InfoMap const & map)
+{
+       vector<string> bibkeys;
+       InfoMap::const_iterator it  = map.begin();
+       InfoMap::const_iterator end = map.end();
+       for (; it != end; ++it) {
+               bibkeys.push_back(it->first);
+       }
+
+       std::sort(bibkeys.begin(), bibkeys.end(), compareNoCase());
+       return bibkeys;
+}
+
+
+docstring const getInfo(InfoMap const & map, string const & key)
+{
+       BOOST_ASSERT(!map.empty());
+
+       InfoMap::const_iterator it = map.find(key);
+       if (it == map.end())
+               return docstring();
+       docstring const & data = it->second;
+
+// is the entry a BibTeX one or one from lyx-layout "bibliography"?
+       docstring::size_type const pos = data.find(TheBibliographyRef);
+       if (pos != docstring::npos) {
+               docstring::size_type const pos2 = pos + TheBibliographyRef.size();
+               docstring const info = trim(data.substr(pos2));
+               return info;
+       }
+
+// Search for all possible "required" keys
+       docstring author = parseBibTeX(data, "author");
+       if (author.empty())
+               author = parseBibTeX(data, "editor");
+
+       docstring year      = parseBibTeX(data, "year");
+       docstring title     = parseBibTeX(data, "title");
+       docstring booktitle = parseBibTeX(data, "booktitle");
+       docstring chapter   = parseBibTeX(data, "chapter");
+       docstring number    = parseBibTeX(data, "number");
+       docstring volume    = parseBibTeX(data, "volume");
+       docstring pages     = parseBibTeX(data, "pages");
+       docstring annote    = parseBibTeX(data, "annote");
+       docstring media     = parseBibTeX(data, "journal");
+       if (media.empty())
+               media = parseBibTeX(data, "publisher");
+       if (media.empty())
+               media = parseBibTeX(data, "school");
+       if (media.empty())
+               media = parseBibTeX(data, "institution");
+
+       odocstringstream result;
+       if (!author.empty())
+               result << author << ", ";
+       if (!title.empty())
+               result << title;
+       if (!booktitle.empty())
+               result << ", in " << booktitle;
+       if (!chapter.empty())
+               result << ", Ch. " << chapter;
+       if (!media.empty())
+               result << ", " << media;
+       if (!volume.empty())
+               result << ", vol. " << volume;
+       if (!number.empty())
+               result << ", no. " << number;
+       if (!pages.empty())
+               result << ", pp. " << pages;
+       if (!year.empty())
+               result << ", " << year;
+       if (!annote.empty())
+               result << "\n\n" << annote;
+
+       docstring const result_str = rtrim(result.str());
+       if (!result_str.empty())
+               return result_str;
+
+// This should never happen (or at least be very unusual!)
+       return data;
+}
+
+
+namespace {
+
+// Escape special chars.
+// All characters are literals except: '.|*?+(){}[]^$\'
+// These characters are literals when preceded by a "\", which is done here
+// @todo: This function should be moved to support, and then the test in tests
+//        should be moved there as well.
+string const escape_special_chars(string const & expr)
+{
+       // Search for all chars '.|*?+(){}[^$]\'
+       // Note that '[' and '\' must be escaped.
+       // This is a limitation of boost::regex, but all other chars in BREs
+       // are assumed literal.
+               boost::regex reg("[].|*?+(){}^$\\[\\\\]");
+
+       // $& is a perl-like expression that expands to all
+       // of the current match
+       // The '$' must be prefixed with the escape character '\' for
+       // boost to treat it as a literal.
+       // Thus, to prefix a matched expression with '\', we use:
+               return boost::regex_replace(expr, reg, "\\\\$&");
+}
+
+
+// A functor for use with std::find_if, used to ascertain whether a
+// data entry matches the required regex_
+// @throws: boost::regex_error if the supplied regex pattern is not valid
+// @todo: This function should be moved to support.
+class RegexMatch : public std::unary_function<string, bool>
+{
+       public:
+// re and icase are used to construct an instance of boost::RegEx.
+// if icase is true, then matching is insensitive to case
+               RegexMatch(InfoMap const & m, string const & re, bool icase)
+               : map_(m), regex_(re, icase) {}
+
+               bool operator()(string const & key) const {
+// the data searched is the key + its associated BibTeX/biblio
+// fields
+                       string data = key;
+                       InfoMap::const_iterator info = map_.find(key);
+                       if (info != map_.end())
+       // FIXME UNICODE
+                               data += ' ' + to_utf8(info->second);
+
+// Attempts to find a match for the current RE
+// somewhere in data.
+                       return boost::regex_search(data, regex_);
+               }
+       private:
+               InfoMap const map_;
+               mutable boost::regex regex_;
+};
+
+} // namespace anon
+
+
+vector<string>::const_iterator searchKeys(InfoMap const & theMap,
+               vector<string> const & keys,
+               string const & search_expr,
+               vector<string>::const_iterator start,
+               Search type,
+               Direction dir,
+       bool caseSensitive)
+{
+       // Preliminary checks
+       if (start < keys.begin() || start >= keys.end())
+               return keys.end();
+
+       string expr = trim(search_expr);
+       if (expr.empty())
+               return keys.end();
+
+       if (type == SIMPLE)
+       // We must escape special chars in the search_expr so that
+       // it is treated as a simple string by boost::regex.
+       expr = escape_special_chars(expr);
+
+       try {
+               // Build the functor that will be passed to find_if.
+               RegexMatch const match(theMap, expr, !caseSensitive);
+
+               // Search the vector of 'keys' from 'start' for one
+               // that matches the predicate 'match'. Searching can
+               // be forward or backward from start.
+               if (dir == FORWARD)
+                       return std::find_if(start, keys.end(), match);
+
+               vector<string>::const_reverse_iterator rit(start);
+               vector<string>::const_reverse_iterator rend = keys.rend();
+               rit = std::find_if(rit, rend, match);
+
+               if (rit == rend)
+                       return keys.end();
+               // This is correct and always safe.
+               // (See Meyer's Effective STL, Item 28.)
+               return (++rit).base();
+       }
+       catch (boost::regex_error &) {
+               return keys.end();
+       }
+}
+
+
+docstring const parseBibTeX(docstring data, string const & findkey)
+{
+       // at first we delete all characters right of '%' and
+       // replace tabs through a space and remove leading spaces
+       // we read the data line by line so that the \n are
+       // ignored, too.
+       docstring data_;
+       int Entries = 0;
+       docstring dummy = token(data,'\n', Entries);
+       while (!dummy.empty()) {
+               // no tabs
+               dummy = subst(dummy, '\t', ' ');
+               // no leading spaces
+               dummy = ltrim(dummy);
+               // ignore lines with a beginning '%' or ignore all right of %
+               docstring::size_type const idx =
+                                       dummy.empty() ? docstring::npos : dummy.find('%');
+               if (idx != docstring::npos)
+                       // Check if this is really a comment or just "\%"
+                       if (idx == 0 || dummy[idx - 1] != '\\')
+                               dummy.erase(idx, docstring::npos);
+                       else
+                               //  This is "\%", so just erase the '\'
+                               dummy.erase(idx - 1, 1);
+               // do we have a new token or a new line of
+               // the same one? In the first case we ignore
+               // the \n and in the second we replace it
+               // with a space
+               if (!dummy.empty()) {
+                       if (!contains(dummy, '='))
+                               data_ += ' ' + dummy;
+                       else
+                               data_ += dummy;
+               }
+               dummy = token(data, '\n', ++Entries);
+       } //end while
+
+       // replace double commas with "" for easy scanning
+       data = subst(data_, from_ascii(",,"), from_ascii("\"\""));
+
+       // unlikely!
+       if (data.empty())
+               return docstring();
+
+       // now get only the important line of the bibtex entry.
+       // all entries are devided by ',' except the last one.
+       data += ',';
+       // now we have same behaviour for all entries because the last one
+       // is "blah ... }"
+       Entries = 0;
+       bool found = false;
+       // parsing of title and booktitle is different from the
+       // others, because booktitle contains title
+       do {
+               dummy = token(data, ',', Entries++);
+               if (!dummy.empty()) {
+                       found = contains(ascii_lowercase(dummy), from_ascii(findkey));
+                       if (findkey == "title" &&
+                                                               contains(ascii_lowercase(dummy), from_ascii("booktitle")))
+                               found = false;
+               }
+       } while (!found && !dummy.empty());
+       if (dummy.empty())
+               // no such keyword
+               return docstring();
+
+       // we are not sure, if we get all, because "key= "blah, blah" is
+       // allowed.
+       // Therefore we read all until the next "=" character, which follows a
+       // new keyword
+       docstring keyvalue = dummy;
+       dummy = token(data, ',', Entries++);
+       while (!contains(dummy, '=') && !dummy.empty()) {
+               keyvalue += ',' + dummy;
+               dummy = token(data, ',', Entries++);
+       }
+
+       // replace double "" with originals ,, (two commas)
+       // leaving us with the all-important line
+       data = subst(keyvalue, from_ascii("\"\""), from_ascii(",,"));
+
+       // Clean-up.
+       // 1. Spaces
+       data = rtrim(data);
+       // 2. if there is no opening '{' then a closing '{' is probably cruft.
+       if (!contains(data, '{'))
+               data = rtrim(data, "}");
+       // happens, when last keyword
+               docstring::size_type const idx =
+                       !data.empty() ? data.find('=') : docstring::npos;
+
+               if (idx == docstring::npos)
+                       return docstring();
+
+               data = trim(data.substr(idx));
+
+       // a valid entry?
+       if (data.length() < 2 || data[0] != '=')
+               return docstring();
+       else {
+               // delete '=' and the following spaces
+               data = ltrim(data, " =");
+               if (data.length() < 2) {
+                       // not long enough to find delimiters
+                       return data;
+               } else {
+                       docstring::size_type keypos = 1;
+                       char_type enclosing;
+                       if (data[0] == '{') {
+                               enclosing = '}';
+                       } else if (data[0] == '"') {
+                               enclosing = '"';
+                       } else {
+                               // no {} and no "", pure data but with a
+                               // possible ',' at the end
+                               return rtrim(data, ",");
+                       }
+                       docstring tmp = data.substr(keypos);
+                       while (tmp.find('{') != docstring::npos &&
+                                       tmp.find('}') != docstring::npos &&
+                                       tmp.find('{') < tmp.find('}') &&
+                                       tmp.find('{') < tmp.find(enclosing)) {
+                               keypos += tmp.find('{') + 1;
+                               tmp = data.substr(keypos);
+                               keypos += tmp.find('}') + 1;
+                               tmp = data.substr(keypos);
+                       }
+                       if (tmp.find(enclosing) == docstring::npos)
+                               return data;
+                       else {
+                               keypos += tmp.find(enclosing);
+                               return data.substr(1, keypos - 1);
+                       }
+               }
+       }
+}
+
+
+namespace {
+
+
+char const * const citeCommands[] = {
+       "cite", "citet", "citep", "citealt", "citealp", "citeauthor",
+       "citeyear", "citeyearpar" };
+
+unsigned int const nCiteCommands =
+               sizeof(citeCommands) / sizeof(char *);
+
+CiteStyle const citeStyles[] = {
+       CITE, CITET, CITEP, CITEALT, CITEALP,
+CITEAUTHOR, CITEYEAR, CITEYEARPAR };
+
+unsigned int const nCiteStyles =
+               sizeof(citeStyles) / 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::CitationStyle(string const & command)
+       : style(CITE), full(false), forceUCase(false)
+{
+       if (command.empty())
+               return;
+
+       string cmd = command;
+       if (cmd[0] == 'C') {
+               forceUCase = true;
+               cmd[0] = 'c';
+       }
+
+       string::size_type const n = cmd.size() - 1;
+       if (cmd != "cite" && cmd[n] == '*') {
+               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;
+               style = citeStyles[idx];
+       }
+}
+
+
+string const CitationStyle::asLatexStr() const
+{
+       string cite = citeCommands[style];
+       if (full) {
+               CiteStyle const * last = citeStylesFull + nCiteStylesFull;
+               if (std::find(citeStylesFull, last, style) != last)
+                       cite += '*';
+       }
+
+       if (forceUCase) {
+               CiteStyle const * last = citeStylesUCase + nCiteStylesUCase;
+               if (std::find(citeStylesUCase, last, style) != last)
+                       cite[0] = 'C';
+       }
+
+       return cite;
+}
+
+
+vector<CiteStyle> const getCiteStyles(CiteEngine const engine)
+{
+       unsigned int nStyles = 0;
+       unsigned int start = 0;
+
+       switch (engine) {
+               case ENGINE_BASIC:
+                       nStyles = 1;
+                       start = 0;
+                       break;
+               case ENGINE_NATBIB_AUTHORYEAR:
+               case ENGINE_NATBIB_NUMERICAL:
+                       nStyles = nCiteStyles - 1;
+                       start = 1;
+                       break;
+               case ENGINE_JURABIB:
+                       nStyles = nCiteStyles;
+                       start = 0;
+                       break;
+       }
+
+       typedef vector<CiteStyle> cite_vec;
+
+       cite_vec styles(nStyles);
+       cite_vec::size_type i = 0;
+       int j = start;
+       for (; i != styles.size(); ++i, ++j)
+               styles[i] = citeStyles[j];
+
+       return styles;
+}
+
+
+vector<docstring> const
+       getNumericalStrings(string const & key,
+       InfoMap const & map, vector<CiteStyle> const & styles)
+{
+       if (map.empty())
+               return vector<docstring>();
+
+       docstring const author = getAbbreviatedAuthor(map, key);
+       docstring const year   = getYear(map, key);
+       if (author.empty() || year.empty())
+               return vector<docstring>();
+
+       vector<docstring> vec(styles.size());
+       for (vector<docstring>::size_type i = 0; i != vec.size(); ++i) {
+               docstring str;
+
+               switch (styles[i]) {
+                       case CITE:
+                       case CITEP:
+                               str = from_ascii("[#ID]");
+                               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;
+       }
+
+       return vec;
+}
+
+
+vector<docstring> const
+               getAuthorYearStrings(string const & key,
+                       InfoMap const & map, vector<CiteStyle> const & styles)
+{
+       if (map.empty())
+               return vector<docstring>();
+
+       docstring const author = getAbbreviatedAuthor(map, key);
+       docstring const year   = getYear(map, key);
+       if (author.empty() || year.empty())
+               return vector<docstring>();
+
+       vector<docstring> vec(styles.size());
+       for (vector<docstring>::size_type 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 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 fillWithBibKeys(Buffer const * const buf, 
+                     vector<pair<string, docstring> > & keys)
+{      
+       /// if this is a child document and the parent is already loaded
+       /// use the parent's list instead  [ale990412]
+       Buffer const * const tmp = buf->getMasterBuffer();
+       BOOST_ASSERT(tmp);
+       if (tmp != buf) {
+               fillWithBibKeys(tmp, keys);
+               return;
+       }
+
+       for (InsetIterator it = inset_iterator_begin(buf->inset()); it; ++it)
+                       it->fillWithBibKeys(*buf, keys, it);
+}
+} // namespace biblio
+} // namespace lyx
+
diff --git a/src/Biblio.h b/src/Biblio.h
new file mode 100644 (file)
index 0000000..a6fe6c6
--- /dev/null
@@ -0,0 +1,175 @@
+// -*- C++ -*-
+/**
+ * \file Biblio.h
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author Angus Leeming
+ * \author Herbert Voß
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+#ifndef BIBLIO_H
+#define BIBLIO_H
+
+#include "Buffer.h"
+#include "support/docstring.h"
+
+#include <vector>
+
+namespace lyx {
+       
+namespace biblio {
+       
+       extern const docstring TheBibliographyRef;
+
+       enum CiteEngine {
+               ENGINE_BASIC,
+               ENGINE_NATBIB_AUTHORYEAR,
+               ENGINE_NATBIB_NUMERICAL,
+               ENGINE_JURABIB
+       };
+
+
+       enum CiteStyle {
+               CITE,
+               CITET,
+               CITEP,
+               CITEALT,
+               CITEALP,
+               CITEAUTHOR,
+               CITEYEAR,
+               CITEYEARPAR
+       };
+
+
+       enum Search {
+               SIMPLE,
+               REGEX
+       };
+
+
+       enum Direction {
+               FORWARD,
+               BACKWARD
+       };
+
+
+/** Fills keys with BibTeX information derived from the various
+ *  in this document or its master document.
+ */
+       void fillWithBibKeys(Buffer const * const buf, 
+               std::vector<std::pair<std::string, docstring> > & keys);
+
+/** Each citation engine recognizes only a subset of all possible
+       *  citation commands. Given a latex command \c input, this function
+       *  returns an appropriate command, valid for \c engine.
+ */
+       std::string const asValidLatexCommand(std::string const & input,
+                                             CiteEngine const engine);
+
+/// First entry is the bibliography key, second the data
+       typedef std::map<std::string, docstring> InfoMap;
+
+/// Returns a vector of bibliography keys
+       std::vector<std::string> const getKeys(InfoMap const &);
+
+/** Returns the BibTeX data associated with a given key.
+       Empty if no info exists. */
+       docstring const getInfo(InfoMap const &, std::string const & key);
+
+/// return the year from the bibtex data record
+       docstring const getYear(InfoMap const & map, std::string const & key);
+
+/// return the short form of an authorlist
+       docstring const getAbbreviatedAuthor(InfoMap const & map, std::string const & key);
+
+// return only the family name
+       docstring const familyName(docstring const & name);
+
+/** Search a BibTeX info field for the given key and return the
+       associated field. */
+       docstring const parseBibTeX(docstring data, std::string const & findkey);
+
+/** Returns an iterator to the first key that meets the search
+       criterion, or end() if unsuccessful.
+
+    User supplies :
+       the InfoMap of bibkeys info,
+       the vector of keys to be searched,
+       the search criterion,
+       an iterator defining the starting point of the search,
+       an enum defining a Simple or Regex search,
+       an enum defining the search direction.
+ */
+
+       std::vector<std::string>::const_iterator
+                       searchKeys(InfoMap const & map,
+                                  std::vector<std::string> const & keys_to_search,
+                                  docstring const & search_expression,
+                                  std::vector<std::string>::const_iterator start,
+        Search,
+       Direction,
+ bool caseSensitive=false);
+
+
+       class CitationStyle {
+               public:
+                       ///
+                       CitationStyle(CiteStyle s = CITE, bool f = false, bool force = false)
+                       : style(s), full(f), forceUCase(force) {}
+                       /// \param latex_str a LaTeX command, "cite", "Citep*", etc
+                       CitationStyle(std::string const & latex_str);
+                       ///
+                       std::string const asLatexStr() const;
+                       ///
+                       CiteStyle style;
+                       ///
+                       bool full;
+                       ///
+                       bool forceUCase;
+       };
+
+
+/// Returns a vector of available Citation styles.
+       std::vector<CiteStyle> const getCiteStyles(CiteEngine const );
+
+/**
+       "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<docstring> const
+                       getNumericalStrings(std::string const & key,
+                                           InfoMap const & map,
+                                           std::vector<CiteStyle> 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<docstring> const
+                       getAuthorYearStrings(std::string const & key,
+                                            InfoMap const & map,
+                                            std::vector<CiteStyle> const & styles);
+
+} // namespace biblio
+} // namespace lyx
+#endif
index 987605cb695ffd47f5252b3e8206ce55e30ec7c3..18ce36f4d3899ba1780658eebe27f970b943dd24 100644 (file)
@@ -1354,36 +1354,7 @@ void Buffer::getLabelList(vector<docstring> & list) const
 void Buffer::fillWithBibKeys(vector<pair<string, docstring> > & keys)
        const
 {
-       /// if this is a child document and the parent is already loaded
-       /// use the parent's list instead  [ale990412]
-       Buffer const * tmp = getMasterBuffer();
-       BOOST_ASSERT(tmp);
-       if (tmp != this) {
-               tmp->fillWithBibKeys(keys);
-               return;
-       }
-
-       for (InsetIterator it = inset_iterator_begin(inset()); it; ++it) {
-               if (it->lyxCode() == Inset::BIBTEX_CODE) {
-                       InsetBibtex const & inset =
-                               static_cast<InsetBibtex const &>(*it);
-                       inset.fillWithBibKeys(*this, keys);
-               } else if (it->lyxCode() == Inset::INCLUDE_CODE) {
-                       InsetInclude const & inset =
-                               static_cast<InsetInclude const &>(*it);
-                       inset.fillWithBibKeys(*this, keys);
-               } else if (it->lyxCode() == Inset::BIBITEM_CODE) {
-                       InsetBibitem const & inset =
-                               static_cast<InsetBibitem const &>(*it);
-                       // FIXME UNICODE
-                       string const key = to_utf8(inset.getParam("key"));
-                       docstring const label = inset.getParam("label");
-                       DocIterator doc_it(it); doc_it.forwardPos();
-                       docstring const ref = doc_it.paragraph().asString(*this, false);
-                       docstring const info = label + "TheBibliographyRef" + ref;
-                       keys.push_back(pair<string, docstring>(key, info));
-               }
-       }
+       biblio::fillWithBibKeys(this, keys);
 }
 
 
index 9b9136ff0e4c99bd43901734464514dbfc68fe14..d0de105f03259e52c20580f96f7f39454ffa9225 100644 (file)
@@ -15,6 +15,7 @@
 #ifndef BUFFERPARAMS_H
 #define BUFFERPARAMS_H
 
+#include "Biblio.h"
 #include "TextClass.h"
 #include "paper.h"
 
index c275a12eb9629e9a84d7ce1ca63eb004cec33cd4..4be7c7b9c07456e98af923bb6da50fa252d0b6d0 100644 (file)
@@ -83,6 +83,8 @@ endif
 liblyxcore_la_SOURCES = \
        Author.cpp \
        Author.h \
+       Biblio.h \
+       Biblio.cpp \
        Bidi.cpp \
        Bidi.h \
        boost.cpp \
index 652094e3c2e48d14cbce26f9331b013dee8d3dc2..4bf16fde4e456942b936b4ddbeeca928115e0cb8 100644 (file)
@@ -13,9 +13,8 @@
 #ifndef CONTROLCITATION_H
 #define CONTROLCITATION_H
 
-
+#include "Biblio.h"
 #include "ControlCommand.h"
-#include "frontend_helpers.h"
 
 namespace lyx {
 namespace frontend {
index 25c1434641dfdca00f8c7db0d8e28c8a1a007a13..1d383c5b419e1cf4de70e8e5aa04e992659ab134 100644 (file)
@@ -48,815 +48,6 @@ using std::endl;
 
 namespace lyx {
 
-using support::ascii_lowercase;
-using support::bformat;
-using support::compare_ascii_no_case;
-using support::contains;
-using support::getVectorFromString;
-using support::ltrim;
-using support::prefixIs;
-using support::rtrim;
-using support::split;
-using support::subst;
-using support::token;
-using support::trim;
-
-namespace biblio {
-
-namespace {
-
-vector<string> const init_possible_cite_commands()
-{
-       char const * const pos[] = {
-               "cite",
-               "citet", "citep", "citealt", "citealp",
-               "citeauthor", "citeyear", "citeyearpar",
-               "citet*", "citep*", "citealt*", "citealp*", "citeauthor*",
-               "Citet",  "Citep",  "Citealt",  "Citealp",  "Citeauthor",
-               "Citet*", "Citep*", "Citealt*", "Citealp*", "Citeauthor*",
-               "fullcite",
-               "footcite", "footcitet", "footcitep", "footcitealt",
-               "footcitealp", "footciteauthor", "footciteyear",
-               "footciteyearpar",
-               "citefield",
-               "citetitle",
-               "cite*"
-       };
-       size_t const size_pos = sizeof(pos) / sizeof(pos[0]);
-
-       return vector<string>(pos, pos + size_pos);
-}
-
-
-vector<string> const & possible_cite_commands()
-{
-       static vector<string> const pos = init_possible_cite_commands();
-       return pos;
-}
-
-
-bool is_possible_cite_command(string const & input)
-{
-       vector<string> const & possibles = possible_cite_commands();
-       vector<string>::const_iterator const end = possibles.end();
-       return std::find(possibles.begin(), end, input) != end;
-}
-
-
-string const default_cite_command(CiteEngine engine)
-{
-       string str;
-       switch (engine) {
-       case ENGINE_BASIC:
-               str = "cite";
-               break;
-       case ENGINE_NATBIB_AUTHORYEAR:
-               str = "citet";
-               break;
-       case ENGINE_NATBIB_NUMERICAL:
-               str = "citep";
-               break;
-       case ENGINE_JURABIB:
-               str = "cite";
-               break;
-       }
-       return str;
-}
-
-
-static const docstring TheBibliographyRef(from_ascii("TheBibliographyRef"));
-
-} // namespace anon
-
-
-string const asValidLatexCommand(string const & input,
-                                CiteEngine const engine)
-{
-       string const default_str = default_cite_command(engine);
-       if (!is_possible_cite_command(input))
-               return default_str;
-
-       string output;
-       switch (engine) {
-       case ENGINE_BASIC:
-               output = default_str;
-               break;
-
-       case ENGINE_NATBIB_AUTHORYEAR:
-       case ENGINE_NATBIB_NUMERICAL:
-               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);
-
-               break;
-       }
-       }
-
-       return output;
-}
-
-
-docstring const familyName(docstring const & name)
-{
-       if (name.empty())
-               return docstring();
-
-       // Very simple parser
-       docstring fname = name;
-
-       // possible authorname combinations are:
-       // "Surname, FirstName"
-       // "Surname, F."
-       // "FirstName Surname"
-       // "F. Surname"
-       docstring::size_type idx = fname.find(',');
-       if (idx != docstring::npos)
-               return ltrim(fname.substr(0, idx));
-       idx = fname.rfind('.');
-       if (idx != docstring::npos && idx + 1 < fname.size())
-               fname = ltrim(fname.substr(idx + 1));
-       // test if we have a LaTeX Space in front
-       if (fname[0] == '\\')
-               return fname.substr(2);
-
-       return rtrim(fname);
-}
-
-
-docstring const getAbbreviatedAuthor(InfoMap const & map, string const & key)
-{
-       BOOST_ASSERT(!map.empty());
-
-       InfoMap::const_iterator it = map.find(key);
-       if (it == map.end())
-               return docstring();
-       docstring const & data = it->second;
-
-       // Is the entry a BibTeX one or one from lyx-layout "bibliography"?
-       docstring::size_type const pos = data.find(TheBibliographyRef);
-       if (pos != docstring::npos) {
-               if (pos <= 2) {
-                       return docstring();
-               }
-
-               docstring const opt = trim(data.substr(0, pos - 1));
-               if (opt.empty())
-                       return docstring();
-
-               docstring authors;
-               split(opt, authors, '(');
-               return authors;
-       }
-
-       docstring author = parseBibTeX(data, "author");
-
-       if (author.empty())
-               author = parseBibTeX(data, "editor");
-
-       if (author.empty()) {
-               author = parseBibTeX(data, "key");
-               if (author.empty())
-                       // FIXME UNICODE
-                       return from_utf8(key);
-               return author;
-       }
-
-       vector<docstring> const authors = getVectorFromString(author, from_ascii(" and "));
-       if (authors.empty())
-               return author;
-
-       if (authors.size() == 2)
-               return bformat(_("%1$s and %2$s"),
-                       familyName(authors[0]), familyName(authors[1]));
-
-       if (authors.size() > 2)
-               return bformat(_("%1$s et al."), familyName(authors[0]));
-
-       return familyName(authors[0]);
-}
-
-
-docstring const getYear(InfoMap const & map, string const & key)
-{
-       BOOST_ASSERT(!map.empty());
-
-       InfoMap::const_iterator it = map.find(key);
-       if (it == map.end())
-               return docstring();
-       docstring const & data = it->second;
-
-       // Is the entry a BibTeX one or one from lyx-layout "bibliography"?
-       docstring::size_type const pos = data.find(TheBibliographyRef);
-       if (pos != docstring::npos) {
-               if (pos <= 2) {
-                       return docstring();
-               }
-
-               docstring const opt =
-                       trim(data.substr(0, pos - 1));
-               if (opt.empty())
-                       return docstring();
-
-               docstring authors;
-               docstring const tmp = split(opt, authors, '(');
-               docstring year;
-               split(tmp, year, ')');
-               return year;
-
-       }
-
-       docstring year = parseBibTeX(data, "year");
-       if (year.empty())
-               year = _("No year");
-
-       return year;
-}
-
-
-namespace {
-
-// A functor for use with std::sort, leading to case insensitive sorting
-class compareNoCase: public std::binary_function<string, string, bool>
-{
-public:
-       bool operator()(string const & s1, string const & s2) const {
-               return compare_ascii_no_case(s1, s2) < 0;
-       }
-};
-
-} // namespace anon
-
-
-vector<string> const getKeys(InfoMap const & map)
-{
-       vector<string> bibkeys;
-       InfoMap::const_iterator it  = map.begin();
-       InfoMap::const_iterator end = map.end();
-       for (; it != end; ++it) {
-               bibkeys.push_back(it->first);
-       }
-
-       std::sort(bibkeys.begin(), bibkeys.end(), compareNoCase());
-       return bibkeys;
-}
-
-
-docstring const getInfo(InfoMap const & map, string const & key)
-{
-       BOOST_ASSERT(!map.empty());
-
-       InfoMap::const_iterator it = map.find(key);
-       if (it == map.end())
-               return docstring();
-       docstring const & data = it->second;
-
-       // is the entry a BibTeX one or one from lyx-layout "bibliography"?
-       docstring::size_type const pos = data.find(TheBibliographyRef);
-       if (pos != docstring::npos) {
-               docstring::size_type const pos2 = pos + TheBibliographyRef.size();
-               docstring const info = trim(data.substr(pos2));
-               return info;
-       }
-
-       // Search for all possible "required" keys
-       docstring author = parseBibTeX(data, "author");
-       if (author.empty())
-               author = parseBibTeX(data, "editor");
-
-       docstring year      = parseBibTeX(data, "year");
-       docstring title     = parseBibTeX(data, "title");
-       docstring booktitle = parseBibTeX(data, "booktitle");
-       docstring chapter   = parseBibTeX(data, "chapter");
-       docstring number    = parseBibTeX(data, "number");
-       docstring volume    = parseBibTeX(data, "volume");
-       docstring pages     = parseBibTeX(data, "pages");
-       docstring annote    = parseBibTeX(data, "annote");
-       docstring media     = parseBibTeX(data, "journal");
-       if (media.empty())
-               media = parseBibTeX(data, "publisher");
-       if (media.empty())
-               media = parseBibTeX(data, "school");
-       if (media.empty())
-               media = parseBibTeX(data, "institution");
-
-       odocstringstream result;
-       if (!author.empty())
-               result << author << ", ";
-       if (!title.empty())
-               result << title;
-       if (!booktitle.empty())
-               result << ", in " << booktitle;
-       if (!chapter.empty())
-               result << ", Ch. " << chapter;
-       if (!media.empty())
-               result << ", " << media;
-       if (!volume.empty())
-               result << ", vol. " << volume;
-       if (!number.empty())
-               result << ", no. " << number;
-       if (!pages.empty())
-               result << ", pp. " << pages;
-       if (!year.empty())
-               result << ", " << year;
-       if (!annote.empty())
-               result << "\n\n" << annote;
-
-       docstring const result_str = rtrim(result.str());
-       if (!result_str.empty())
-               return result_str;
-
-       // This should never happen (or at least be very unusual!)
-       return data;
-}
-
-
-namespace {
-
-// Escape special chars.
-// All characters are literals except: '.|*?+(){}[]^$\'
-// These characters are literals when preceded by a "\", which is done here
-// @todo: This function should be moved to support, and then the test in tests
-//        should be moved there as well.
-string const escape_special_chars(string const & expr)
-{
-       // Search for all chars '.|*?+(){}[^$]\'
-       // Note that '[' and '\' must be escaped.
-       // This is a limitation of boost::regex, but all other chars in BREs
-       // are assumed literal.
-       boost::regex reg("[].|*?+(){}^$\\[\\\\]");
-
-       // $& is a perl-like expression that expands to all
-       // of the current match
-       // The '$' must be prefixed with the escape character '\' for
-       // boost to treat it as a literal.
-       // Thus, to prefix a matched expression with '\', we use:
-       return boost::regex_replace(expr, reg, "\\\\$&");
-}
-
-
-// A functor for use with std::find_if, used to ascertain whether a
-// data entry matches the required regex_
-// @throws: boost::regex_error if the supplied regex pattern is not valid
-// @todo: This function should be moved to support.
-class RegexMatch : public std::unary_function<string, bool>
-{
-public:
-       // re and icase are used to construct an instance of boost::RegEx.
-       // if icase is true, then matching is insensitive to case
-       RegexMatch(InfoMap const & m, string const & re, bool icase)
-               : map_(m), regex_(re, icase) {}
-
-       bool operator()(string const & key) const {
-               // the data searched is the key + its associated BibTeX/biblio
-               // fields
-               string data = key;
-               InfoMap::const_iterator info = map_.find(key);
-               if (info != map_.end())
-                       // FIXME UNICODE
-                       data += ' ' + to_utf8(info->second);
-
-               // Attempts to find a match for the current RE
-               // somewhere in data.
-               return boost::regex_search(data, regex_);
-       }
-private:
-       InfoMap const map_;
-       mutable boost::regex regex_;
-};
-
-} // namespace anon
-
-
-vector<string>::const_iterator
-searchKeys(InfoMap const & theMap,
-          vector<string> const & keys,
-          string const & search_expr,
-          vector<string>::const_iterator start,
-          Search type,
-          Direction dir,
-          bool caseSensitive)
-{
-       // Preliminary checks
-       if (start < keys.begin() || start >= keys.end())
-               return keys.end();
-
-       string expr = trim(search_expr);
-       if (expr.empty())
-               return keys.end();
-
-       if (type == SIMPLE)
-               // We must escape special chars in the search_expr so that
-               // it is treated as a simple string by boost::regex.
-               expr = escape_special_chars(expr);
-
-       try {
-               // Build the functor that will be passed to find_if.
-               RegexMatch const match(theMap, expr, !caseSensitive);
-
-               // Search the vector of 'keys' from 'start' for one
-               // that matches the predicate 'match'. Searching can
-               // be forward or backward from start.
-               if (dir == FORWARD)
-                       return std::find_if(start, keys.end(), match);
-
-               vector<string>::const_reverse_iterator rit(start);
-               vector<string>::const_reverse_iterator rend = keys.rend();
-               rit = std::find_if(rit, rend, match);
-
-               if (rit == rend)
-                       return keys.end();
-               // This is correct and always safe.
-               // (See Meyer's Effective STL, Item 28.)
-               return (++rit).base();
-       }
-       catch (boost::regex_error &) {
-               return keys.end();
-       }
-}
-
-
-docstring const parseBibTeX(docstring data, string const & findkey)
-{
-       // at first we delete all characters right of '%' and
-       // replace tabs through a space and remove leading spaces
-       // we read the data line by line so that the \n are
-       // ignored, too.
-       docstring data_;
-       int Entries = 0;
-       docstring dummy = token(data,'\n', Entries);
-       while (!dummy.empty()) {
-               // no tabs
-               dummy = subst(dummy, '\t', ' ');
-               // no leading spaces
-               dummy = ltrim(dummy);
-               // ignore lines with a beginning '%' or ignore all right of %
-               docstring::size_type const idx =
-                       dummy.empty() ? docstring::npos : dummy.find('%');
-               if (idx != docstring::npos)
-                       // Check if this is really a comment or just "\%"
-                       if (idx == 0 || dummy[idx - 1] != '\\')
-                               dummy.erase(idx, docstring::npos);
-                       else
-                               //  This is "\%", so just erase the '\'
-                               dummy.erase(idx - 1, 1);
-               // do we have a new token or a new line of
-               // the same one? In the first case we ignore
-               // the \n and in the second we replace it
-               // with a space
-               if (!dummy.empty()) {
-                       if (!contains(dummy, '='))
-                               data_ += ' ' + dummy;
-                       else
-                               data_ += dummy;
-               }
-               dummy = token(data, '\n', ++Entries);
-       }
-
-       // replace double commas with "" for easy scanning
-       data = subst(data_, from_ascii(",,"), from_ascii("\"\""));
-
-       // unlikely!
-       if (data.empty())
-               return docstring();
-
-       // now get only the important line of the bibtex entry.
-       // all entries are devided by ',' except the last one.
-       data += ',';
-       // now we have same behaviour for all entries because the last one
-       // is "blah ... }"
-       Entries = 0;
-       bool found = false;
-       // parsing of title and booktitle is different from the
-       // others, because booktitle contains title
-       do {
-               dummy = token(data, ',', Entries++);
-               if (!dummy.empty()) {
-                       found = contains(ascii_lowercase(dummy), from_ascii(findkey));
-                       if (findkey == "title" &&
-                           contains(ascii_lowercase(dummy), from_ascii("booktitle")))
-                               found = false;
-               }
-       } while (!found && !dummy.empty());
-       if (dummy.empty())
-               // no such keyword
-               return docstring();
-
-       // we are not sure, if we get all, because "key= "blah, blah" is
-       // allowed.
-       // Therefore we read all until the next "=" character, which follows a
-       // new keyword
-       docstring keyvalue = dummy;
-       dummy = token(data, ',', Entries++);
-       while (!contains(dummy, '=') && !dummy.empty()) {
-               keyvalue += ',' + dummy;
-               dummy = token(data, ',', Entries++);
-       }
-
-       // replace double "" with originals ,, (two commas)
-       // leaving us with the all-important line
-       data = subst(keyvalue, from_ascii("\"\""), from_ascii(",,"));
-
-       // Clean-up.
-       // 1. Spaces
-       data = rtrim(data);
-       // 2. if there is no opening '{' then a closing '{' is probably cruft.
-       if (!contains(data, '{'))
-               data = rtrim(data, "}");
-       // happens, when last keyword
-       docstring::size_type const idx =
-               !data.empty() ? data.find('=') : docstring::npos;
-
-       if (idx == docstring::npos)
-               return docstring();
-
-       data = trim(data.substr(idx));
-
-       // a valid entry?
-       if (data.length() < 2 || data[0] != '=')
-               return docstring();
-       else {
-               // delete '=' and the following spaces
-               data = ltrim(data, " =");
-               if (data.length() < 2) {
-                       // not long enough to find delimiters
-                       return data;
-               } else {
-                       docstring::size_type keypos = 1;
-                       char_type enclosing;
-                       if (data[0] == '{') {
-                               enclosing = '}';
-                       } else if (data[0] == '"') {
-                               enclosing = '"';
-                       } else {
-                               // no {} and no "", pure data but with a
-                               // possible ',' at the end
-                               return rtrim(data, ",");
-                       }
-                       docstring tmp = data.substr(keypos);
-                       while (tmp.find('{') != docstring::npos &&
-                              tmp.find('}') != docstring::npos &&
-                              tmp.find('{') < tmp.find('}') &&
-                              tmp.find('{') < tmp.find(enclosing)) {
-
-                               keypos += tmp.find('{') + 1;
-                               tmp = data.substr(keypos);
-                               keypos += tmp.find('}') + 1;
-                               tmp = data.substr(keypos);
-                       }
-                       if (tmp.find(enclosing) == docstring::npos)
-                               return data;
-                       else {
-                               keypos += tmp.find(enclosing);
-                               return data.substr(1, keypos - 1);
-                       }
-               }
-       }
-}
-
-
-namespace {
-
-
-char const * const citeCommands[] = {
-       "cite", "citet", "citep", "citealt", "citealp", "citeauthor",
-       "citeyear", "citeyearpar" };
-
-unsigned int const nCiteCommands =
-       sizeof(citeCommands) / sizeof(char *);
-
-CiteStyle const citeStyles[] = {
-       CITE, CITET, CITEP, CITEALT, CITEALP,
-       CITEAUTHOR, CITEYEAR, CITEYEARPAR };
-
-unsigned int const nCiteStyles =
-       sizeof(citeStyles) / 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::CitationStyle(string const & command)
-       : style(CITE), full(false), forceUCase(false)
-{
-       if (command.empty())
-               return;
-
-       string cmd = command;
-       if (cmd[0] == 'C') {
-               forceUCase = true;
-               cmd[0] = 'c';
-       }
-
-       string::size_type const n = cmd.size() - 1;
-       if (cmd != "cite" && cmd[n] == '*') {
-               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;
-               style = citeStyles[idx];
-       }
-}
-
-
-string const CitationStyle::asLatexStr() const
-{
-       string cite = citeCommands[style];
-       if (full) {
-               CiteStyle const * last = citeStylesFull + nCiteStylesFull;
-               if (std::find(citeStylesFull, last, style) != last)
-                       cite += '*';
-       }
-
-       if (forceUCase) {
-               CiteStyle const * last = citeStylesUCase + nCiteStylesUCase;
-               if (std::find(citeStylesUCase, last, style) != last)
-                       cite[0] = 'C';
-       }
-
-       return cite;
-}
-
-
-vector<CiteStyle> const getCiteStyles(CiteEngine const engine)
-{
-       unsigned int nStyles = 0;
-       unsigned int start = 0;
-
-       switch (engine) {
-       case ENGINE_BASIC:
-               nStyles = 1;
-               start = 0;
-               break;
-       case ENGINE_NATBIB_AUTHORYEAR:
-       case ENGINE_NATBIB_NUMERICAL:
-               nStyles = nCiteStyles - 1;
-               start = 1;
-               break;
-       case ENGINE_JURABIB:
-               nStyles = nCiteStyles;
-               start = 0;
-               break;
-       }
-
-       typedef vector<CiteStyle> cite_vec;
-
-       cite_vec styles(nStyles);
-       cite_vec::size_type i = 0;
-       int j = start;
-       for (; i != styles.size(); ++i, ++j)
-               styles[i] = citeStyles[j];
-
-       return styles;
-}
-
-
-vector<docstring> const
-getNumericalStrings(string const & key,
-                   InfoMap const & map, vector<CiteStyle> const & styles)
-{
-       if (map.empty())
-               return vector<docstring>();
-
-       docstring const author = getAbbreviatedAuthor(map, key);
-       docstring const year   = getYear(map, key);
-       if (author.empty() || year.empty())
-               return vector<docstring>();
-
-       vector<docstring> vec(styles.size());
-       for (vector<docstring>::size_type i = 0; i != vec.size(); ++i) {
-               docstring str;
-
-               switch (styles[i]) {
-               case CITE:
-               case CITEP:
-                       str = from_ascii("[#ID]");
-                       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;
-       }
-
-       return vec;
-}
-
-
-vector<docstring> const
-getAuthorYearStrings(string const & key,
-                   InfoMap const & map, vector<CiteStyle> const & styles)
-{
-       if (map.empty())
-               return vector<docstring>();
-
-       docstring const author = getAbbreviatedAuthor(map, key);
-       docstring const year   = getYear(map, key);
-       if (author.empty() || year.empty())
-               return vector<docstring>();
-
-       vector<docstring> vec(styles.size());
-       for (vector<docstring>::size_type 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 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;
-}
-
-} // namespace biblio
-
 namespace frontend {
 
 vector<FamilyPair> const getFamilyData()
index 2d71a2668bf6da54b5b56b10a9e31b01a119804b..896c65b46e5a0e06f001007cb09808c5a90a1d4d 100644 (file)
 
 class Buffer;
 
-/** Functions of use to citation and bibtex GUI controllers and views */
-namespace lyx {
-namespace biblio {
-
-enum CiteEngine {
-       ENGINE_BASIC,
-       ENGINE_NATBIB_AUTHORYEAR,
-       ENGINE_NATBIB_NUMERICAL,
-       ENGINE_JURABIB
-};
-
-
-enum CiteStyle {
-       CITE,
-       CITET,
-       CITEP,
-       CITEALT,
-       CITEALP,
-       CITEAUTHOR,
-       CITEYEAR,
-       CITEYEARPAR
-};
-
-
-enum Search {
-       SIMPLE,
-       REGEX
-};
-
-
-enum Direction {
-       FORWARD,
-       BACKWARD
-};
-
-
-/** Each citation engine recognizes only a subset of all possible
- *  citation commands. Given a latex command \c input, this function
- *  returns an appropriate command, valid for \c engine.
- */
-std::string const asValidLatexCommand(std::string const & input,
-                                     CiteEngine const engine);
-
-/// First entry is the bibliography key, second the data
-typedef std::map<std::string, docstring> InfoMap;
-
-/// Returns a vector of bibliography keys
-std::vector<std::string> const getKeys(InfoMap const &);
-
-/** Returns the BibTeX data associated with a given key.
-    Empty if no info exists. */
-docstring const getInfo(InfoMap const &, std::string const & key);
-
-/// return the year from the bibtex data record
-docstring const getYear(InfoMap const & map, std::string const & key);
-
-/// return the short form of an authorlist
-docstring const getAbbreviatedAuthor(InfoMap const & map, std::string const & key);
-
-// return only the family name
-docstring const familyName(docstring const & name);
-
-/** Search a BibTeX info field for the given key and return the
-    associated field. */
-docstring const parseBibTeX(docstring data, std::string const & findkey);
-
-/** Returns an iterator to the first key that meets the search
-    criterion, or end() if unsuccessful.
-
-    User supplies :
-    the InfoMap of bibkeys info,
-    the vector of keys to be searched,
-    the search criterion,
-    an iterator defining the starting point of the search,
-    an enum defining a Simple or Regex search,
-    an enum defining the search direction.
-*/
-
-std::vector<std::string>::const_iterator
-searchKeys(InfoMap const & map,
-          std::vector<std::string> const & keys_to_search,
-          docstring const & search_expression,
-          std::vector<std::string>::const_iterator start,
-          Search,
-          Direction,
-          bool caseSensitive=false);
-
-
-class CitationStyle {
-public:
-       ///
-       CitationStyle(CiteStyle s = CITE, bool f = false, bool force = false)
-               : style(s), full(f), forceUCase(force) {}
-       /// \param latex_str a LaTeX command, "cite", "Citep*", etc
-       CitationStyle(std::string const & latex_str);
-       ///
-       std::string const asLatexStr() const;
-       ///
-       CiteStyle style;
-       ///
-       bool full;
-       ///
-       bool forceUCase;
-};
-
-
-/// Returns a vector of available Citation styles.
-std::vector<CiteStyle> const getCiteStyles(CiteEngine const );
-
-/**
-   "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<docstring> const
-getNumericalStrings(std::string const & key,
-                   InfoMap const & map,
-                   std::vector<CiteStyle> 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<docstring> const
-getAuthorYearStrings(std::string const & key,
-                    InfoMap const & map,
-                    std::vector<CiteStyle> const & styles);
-
-} // namespace biblio
-} // namespace lyx
-
-
 class Color_color;
 
-
 /** Functions of use to the character GUI controller and view */
 namespace lyx {
 namespace frontend {
index 614342084d455bdfabdafc4ba5f8dd81c9378292..bae6669ee6a44406e3371ebc90471bde1195d4c6 100644 (file)
@@ -31,6 +31,7 @@ class BufferView;
 class ParIterator;
 class ParConstIterator;
 class CursorSlice;
+class InsetIterator;
 class FuncRequest;
 class FuncStatus;
 class InsetLayout;
@@ -437,9 +438,14 @@ public:
        /// Add an entry to the TocList
        /// pit is the ParConstIterator of the paragraph containing the inset
        virtual void addToToc(TocList &, Buffer const &, ParConstIterator const &) const {}
-       // Update the counters of this inset and of its contents
+       /// Fill keys with BibTeX information
+       virtual void fillWithBibKeys(Buffer const &,
+               std::vector<std::pair<std::string, docstring> > &,
+               InsetIterator const &) const { return; }
+       /// Update the counters of this inset and of its contents
        virtual void updateLabels(Buffer const &, ParIterator const &) {}
 
+
 public:
        /// returns LyX code associated with the inset. Used for TOC, ...)
        virtual Code lyxCode() const { return NO_CODE; }
index b315608498b858b20eff3e62bd456e021285c195..166bcdd5a84c27d0e0ab0c9e1887b0198b958673 100644 (file)
 
 #include "InsetBibitem.h"
 
+#include "Biblio.h"
 #include "Buffer.h"
 #include "BufferView.h"
 #include "DispatchResult.h"
 #include "FuncRequest.h"
 #include "Font.h"
+#include "InsetIterator.h"
 #include "Lexer.h"
 #include "Paragraph.h"
 #include "ParagraphList.h"
@@ -184,4 +186,17 @@ docstring const bibitemWidest(Buffer const & buffer)
 }
 
 
+void InsetBibitem::fillWithBibKeys(Buffer const & buf,
+       std::vector<std::pair<std::string, docstring> > & keys,
+       InsetIterator const & it) const
+{
+       string const key = to_utf8(getParam("key"));
+       docstring const label = getParam("label");
+       DocIterator doc_it(it); 
+       doc_it.forwardPos();
+       docstring const ref = doc_it.paragraph().asString(buf, false);
+       docstring const info = label + biblio::TheBibliographyRef + ref;
+       keys.push_back(std::pair<string, docstring>(key, info));
+}
+
 } // namespace lyx
index 6dfaf2cc2225fd3cf714da33d25925a62dd9b4cf..98db70e68d569f40858c8a47308ed1c4bdc03792 100644 (file)
@@ -43,6 +43,11 @@ public:
        docstring const getBibLabel() const;
        ///
        int plaintext(Buffer const &, odocstream &, OutputParams const &) const;
+       ///
+       virtual void fillWithBibKeys(Buffer const &,
+               std::vector<std::pair<std::string, docstring> > &,
+               InsetIterator const &) const;
+
 protected:
        ///
        virtual void doDispatch(Cursor & cur, FuncRequest & cmd);
index f8ea110504eb3d789d97d6d65e91d32cbef861c7..7ba0a2814b59b45d475ff0ffffd0850776f514f7 100644 (file)
@@ -556,7 +556,8 @@ namespace {
 
 // This method returns a comma separated list of Bibtex entries
 void InsetBibtex::fillWithBibKeys(Buffer const & buffer,
-               std::vector<std::pair<string, docstring> > & keys) const
+               std::vector<std::pair<string, docstring> > & keys,
+               InsetIterator const & /*di*/) const
 {
        vector<FileName> const files = getFiles(buffer);
        for (vector<FileName>::const_iterator it = files.begin();
index 94f8836ec14dc64e0b817fb2e9196df154faa8a5..82defd4fd72c3380c178708ebdf43ad08afec513 100644 (file)
@@ -38,8 +38,9 @@ public:
        ///
        int latex(Buffer const &, odocstream &, OutputParams const &) const;
        ///
-       void fillWithBibKeys(Buffer const & buffer,
-               std::vector<std::pair<std::string, docstring> > & keys) const;
+       virtual void fillWithBibKeys(Buffer const &,
+               std::vector<std::pair<std::string, docstring> > &,
+               InsetIterator const &) const;
        ///
        std::vector<support::FileName> const getFiles(Buffer const &) const;
        ///
index e705fcb6bdd65dcb8706105442558c8fcd47498d..1d469c2e2ca50ea4ac0efa07f62783514c6d5777 100644 (file)
@@ -16,7 +16,7 @@
 
 #include "InsetCommand.h"
 
-#include "frontends/controllers/frontend_helpers.h"
+#include "Biblio.h"
 
 
 namespace lyx {
index ac0eb6b06a3ae9060f91905d044589253e1c578f..4b7ef4e055637a4c9494e73815b1889d1bdd93f2 100644 (file)
@@ -728,7 +728,8 @@ void InsetInclude::getLabelList(Buffer const & buffer,
 
 
 void InsetInclude::fillWithBibKeys(Buffer const & buffer,
-               std::vector<std::pair<string, docstring> > & keys) const
+               std::vector<std::pair<string, docstring> > & keys,
+               InsetIterator const & /*di*/) const
 {
        if (loadIfNeeded(buffer, params_)) {
                string const included_file = includedFilename(buffer, params_).absFilename();
index 4eb0409269e0a4ace1c26ff9876cd6071227083d..a89d4df765097bcb4d5020c1e5e3a80d67c81a01 100644 (file)
@@ -59,8 +59,9 @@ public:
         *  \param buffer the Buffer containing this inset.
         *  \param keys the list of bibkeys in the child buffer.
         */
-       void fillWithBibKeys(Buffer const & buffer,
-               std::vector<std::pair<std::string, docstring> > & keys) const;
+       virtual void fillWithBibKeys(Buffer const &,
+               std::vector<std::pair<std::string, docstring> > &,
+               InsetIterator const & /*di*/) const;
        /** Update the cache with all bibfiles in use of the child buffer
         *  (including bibfiles of grandchild documents).
         *  Does nothing if the child document is not loaded to prevent