]> git.lyx.org Git - lyx.git/blob - src/BiblioInfo.cpp
EmbeddedObjects.lyx, Math.lyx, UserGuide.lyx: Spanish translation updates by Ignacio
[lyx.git] / src / BiblioInfo.cpp
1 /**
2  * \file BiblioInfo.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Angus Leeming
7  * \author Herbert Voß
8  * \author Richard Heck
9  *
10  * Full author contact details are available in file CREDITS.
11  */
12
13 #include <config.h>
14
15 #include "BiblioInfo.h"
16 #include "Buffer.h"
17 #include "BufferParams.h"
18 #include "buffer_funcs.h"
19 #include "InsetIterator.h"
20 #include "Paragraph.h"
21
22 #include "insets/Inset.h"
23 #include "insets/InsetBibitem.h"
24 #include "insets/InsetBibtex.h"
25 #include "insets/InsetInclude.h"
26
27 #include "support/docstream.h"
28 #include "support/gettext.h"
29 #include "support/lassert.h"
30 #include "support/lstrings.h"
31
32 #include "boost/regex.hpp"
33
34 using namespace std;
35 using namespace lyx::support;
36
37
38 namespace lyx {
39
40 //////////////////////////////////////////////////////////////////////
41 //
42 // BibTeXInfo
43 //
44 //////////////////////////////////////////////////////////////////////
45
46 BibTeXInfo::BibTeXInfo(docstring const & key, docstring const & type)
47         : is_bibtex_(true), bib_key_(key), entry_type_(type)
48 {}
49
50
51 bool BibTeXInfo::hasField(docstring const & field) const
52 {
53         return count(field) == 1;
54 }
55
56
57 docstring const & BibTeXInfo::operator[](docstring const & field) const
58 {
59         BibTeXInfo::const_iterator it = find(field);
60         if (it != end())
61                 return it->second;
62         static docstring const empty_value = docstring();
63         return empty_value;
64 }
65         
66         
67 docstring const & BibTeXInfo::operator[](string const & field) const
68 {
69         return operator[](from_ascii(field));
70 }
71
72
73 docstring familyName(docstring const & name)
74 {
75         if (name.empty())
76                 return docstring();
77
78         // Very simple parser
79         docstring fname = name;
80
81         // possible authorname combinations are:
82         // "Surname, FirstName"
83         // "Surname, F."
84         // "FirstName Surname"
85         // "F. Surname"
86         docstring::size_type idx = fname.find(',');
87         if (idx != docstring::npos)
88                 return ltrim(fname.substr(0, idx));
89         idx = fname.rfind('.');
90         if (idx != docstring::npos && idx + 1 < fname.size())
91                 fname = ltrim(fname.substr(idx + 1));
92         // test if we have a LaTeX Space in front
93         if (fname[0] == '\\')
94                 return fname.substr(2);
95         return rtrim(fname);
96 }
97
98 docstring const BibTeXInfo::getAbbreviatedAuthor() const
99 {
100         if (!is_bibtex_) {
101                 docstring const opt = trim(operator[]("label"));
102                 if (opt.empty())
103                         return docstring();
104
105                 docstring authors;
106                 split(opt, authors, '(');
107                 return authors;
108         }
109
110         docstring author = operator[]("author");
111         if (author.empty()) {
112                 author = operator[]("editor");
113                 if (author.empty())
114                         return bib_key_;
115         }
116
117         // OK, we've got some names. Let's format them.
118         // Try to split the author list on " and "
119         vector<docstring> const authors =
120                 getVectorFromString(author, from_ascii(" and "));
121
122         if (authors.size() == 2)
123                 return bformat(_("%1$s and %2$s"),
124                         familyName(authors[0]), familyName(authors[1]));
125
126         if (authors.size() > 2)
127                 return bformat(_("%1$s et al."), familyName(authors[0]));
128
129         return familyName(authors[0]);
130 }
131
132
133 docstring const BibTeXInfo::getYear() const
134 {
135         if (!is_bibtex_) {
136                 docstring const opt = trim(operator[]("label"));
137                 if (opt.empty())
138                         return docstring();
139
140                 docstring authors;
141                 docstring const tmp = split(opt, authors, '(');
142                 docstring year;
143                 split(tmp, year, ')');
144                 return year;
145         }
146
147         docstring year = operator[]("year");
148         if (year.empty())
149                 year = _("No year");
150         return year;
151 }
152
153
154 docstring const BibTeXInfo::getInfo() const
155 {
156         if (!is_bibtex_) {
157                 BibTeXInfo::const_iterator it = find(from_ascii("ref"));
158                 return it->second;
159         }
160  
161         // FIXME
162         // This could be made a lot better using the entryType
163         // field to customize the output based upon entry type.
164         
165         // Search for all possible "required" fields
166         docstring author = operator[]("author");
167         if (author.empty())
168                 author = operator[]("editor");
169  
170         docstring year   = operator[]("year");
171         docstring title  = operator[]("title");
172         docstring docLoc = operator[]("pages");
173         if (docLoc.empty()) {
174                 docLoc = operator[]("chapter");
175                 if (!docLoc.empty())
176                         docLoc = from_ascii("Ch. ") + docLoc;
177         }       else {
178                 docLoc = from_ascii("pp. ") + docLoc;
179         }
180
181         docstring media = operator[]("journal");
182         if (media.empty()) {
183                 media = operator[]("publisher");
184                 if (media.empty()) {
185                         media = operator[]("school");
186                         if (media.empty())
187                                 media = operator[]("institution");
188                 }
189         }
190         docstring volume = operator[]("volume");
191
192         odocstringstream result;
193         if (!author.empty())
194                 result << author << ", ";
195         if (!title.empty())
196                 result << title;
197         if (!media.empty())
198                 result << ", " << media;
199         if (!year.empty())
200                 result << ", " << year;
201         if (!docLoc.empty())
202                 result << ", " << docLoc;
203
204         docstring const result_str = rtrim(result.str());
205         if (!result_str.empty())
206                 return result_str;
207
208         // This should never happen (or at least be very unusual!)
209         return docstring();
210 }
211
212
213 //////////////////////////////////////////////////////////////////////
214 //
215 // BiblioInfo
216 //
217 //////////////////////////////////////////////////////////////////////
218
219 namespace {
220 // A functor for use with sort, leading to case insensitive sorting
221         class compareNoCase: public binary_function<docstring, docstring, bool>
222         {
223                 public:
224                         bool operator()(docstring const & s1, docstring const & s2) const {
225                                 return compare_no_case(s1, s2) < 0;
226                         }
227         };
228 } // namespace anon
229
230
231 vector<docstring> const BiblioInfo::getKeys() const
232 {
233         vector<docstring> bibkeys;
234         BiblioInfo::const_iterator it  = begin();
235         for (; it != end(); ++it)
236                 bibkeys.push_back(it->first);
237         sort(bibkeys.begin(), bibkeys.end(), compareNoCase());
238         return bibkeys;
239 }
240
241
242 vector<docstring> const BiblioInfo::getFields() const
243 {
244         vector<docstring> bibfields;
245         set<docstring>::const_iterator it = field_names_.begin();
246         set<docstring>::const_iterator end = field_names_.end();
247         for (; it != end; ++it)
248                 bibfields.push_back(*it);
249         sort(bibfields.begin(), bibfields.end());
250         return bibfields;
251 }
252
253
254 vector<docstring> const BiblioInfo::getEntries() const
255 {
256         vector<docstring> bibentries;
257         set<docstring>::const_iterator it = entry_types_.begin();
258         set<docstring>::const_iterator end = entry_types_.end();
259         for (; it != end; ++it)
260                 bibentries.push_back(*it);
261         sort(bibentries.begin(), bibentries.end());
262         return bibentries;
263 }
264
265
266 docstring const BiblioInfo::getAbbreviatedAuthor(docstring const & key) const
267 {
268         BiblioInfo::const_iterator it = find(key);
269         if (it == end())
270                 return docstring();
271         BibTeXInfo const & data = it->second;
272         return data.getAbbreviatedAuthor();
273 }
274
275
276 docstring const BiblioInfo::getYear(docstring const & key) const
277 {
278         BiblioInfo::const_iterator it = find(key);
279         if (it == end())
280                 return docstring();
281         BibTeXInfo const & data = it->second;
282         return data.getYear();
283 }
284
285
286 docstring const BiblioInfo::getInfo(docstring const & key) const
287 {
288         BiblioInfo::const_iterator it = find(key);
289         if (it == end())
290                 return docstring();
291         BibTeXInfo const & data = it->second;
292         return data.getInfo();
293 }
294
295
296 vector<docstring> const BiblioInfo::getCiteStrings(
297         docstring const & key, Buffer const & buf) const
298 {
299         CiteEngine const engine = buf.params().citeEngine();
300         if (engine == ENGINE_BASIC || engine == ENGINE_NATBIB_NUMERICAL)
301                 return getNumericalStrings(key, buf);
302         else
303                 return getAuthorYearStrings(key, buf);
304 }
305
306
307 vector<docstring> const BiblioInfo::getNumericalStrings(
308         docstring const & key, Buffer const & buf) const
309 {
310         if (empty())
311                 return vector<docstring>();
312
313         docstring const author = getAbbreviatedAuthor(key);
314         docstring const year   = getYear(key);
315         if (author.empty() || year.empty())
316                 return vector<docstring>();
317
318         vector<CiteStyle> const & styles = citeStyles(buf.params().citeEngine());
319         
320         vector<docstring> vec(styles.size());
321         for (size_t i = 0; i != vec.size(); ++i) {
322                 docstring str;
323
324                 switch (styles[i]) {
325                         case CITE:
326                         case CITEP:
327                                 str = from_ascii("[#ID]");
328                                 break;
329
330                         case NOCITE:
331                                 str = _("Add to bibliography only.");
332                                 break;
333
334                         case CITET:
335                                 str = author + " [#ID]";
336                                 break;
337
338                         case CITEALT:
339                                 str = author + " #ID";
340                                 break;
341
342                         case CITEALP:
343                                 str = from_ascii("#ID");
344                                 break;
345
346                         case CITEAUTHOR:
347                                 str = author;
348                                 break;
349
350                         case CITEYEAR:
351                                 str = year;
352                                 break;
353
354                         case CITEYEARPAR:
355                                 str = '(' + year + ')';
356                                 break;
357                 }
358
359                 vec[i] = str;
360         }
361
362         return vec;
363 }
364
365
366 vector<docstring> const BiblioInfo::getAuthorYearStrings(
367         docstring const & key, Buffer const & buf) const
368 {
369         if (empty())
370                 return vector<docstring>();
371
372         docstring const author = getAbbreviatedAuthor(key);
373         docstring const year   = getYear(key);
374         if (author.empty() || year.empty())
375                 return vector<docstring>();
376
377         vector<CiteStyle> const & styles = citeStyles(buf.params().citeEngine());
378         
379         vector<docstring> vec(styles.size());
380         for (size_t i = 0; i != vec.size(); ++i) {
381                 docstring str;
382
383                 switch (styles[i]) {
384                         case CITE:
385                 // jurabib only: Author/Annotator
386                 // (i.e. the "before" field, 2nd opt arg)
387                                 str = author + "/<" + _("before") + '>';
388                                 break;
389
390                         case NOCITE:
391                                 str = _("Add to bibliography only.");
392                                 break;
393
394                         case CITET:
395                                 str = author + " (" + year + ')';
396                                 break;
397
398                         case CITEP:
399                                 str = '(' + author + ", " + year + ')';
400                                 break;
401
402                         case CITEALT:
403                                 str = author + ' ' + year ;
404                                 break;
405
406                         case CITEALP:
407                                 str = author + ", " + year ;
408                                 break;
409
410                         case CITEAUTHOR:
411                                 str = author;
412                                 break;
413
414                         case CITEYEAR:
415                                 str = year;
416                                 break;
417
418                         case CITEYEARPAR:
419                                 str = '(' + year + ')';
420                                 break;
421                 }
422                 vec[i] = str;
423         }
424         return vec;
425 }
426
427
428 void BiblioInfo::mergeBiblioInfo(BiblioInfo const & info)
429 {
430         bimap_.insert(info.begin(), info.end());
431 }
432
433
434 //////////////////////////////////////////////////////////////////////
435 //
436 // CitationStyle
437 //
438 //////////////////////////////////////////////////////////////////////
439
440 namespace {
441
442
443 char const * const citeCommands[] = {
444         "cite", "citet", "citep", "citealt", "citealp",
445         "citeauthor", "citeyear", "citeyearpar", "nocite" };
446
447 unsigned int const nCiteCommands =
448                 sizeof(citeCommands) / sizeof(char *);
449
450 CiteStyle const citeStylesArray[] = {
451         CITE, CITET, CITEP, CITEALT, CITEALP, 
452         CITEAUTHOR, CITEYEAR, CITEYEARPAR, NOCITE };
453
454 unsigned int const nCiteStyles =
455                 sizeof(citeStylesArray) / sizeof(CiteStyle);
456
457 CiteStyle const citeStylesFull[] = {
458         CITET, CITEP, CITEALT, CITEALP, CITEAUTHOR };
459
460 unsigned int const nCiteStylesFull =
461                 sizeof(citeStylesFull) / sizeof(CiteStyle);
462
463 CiteStyle const citeStylesUCase[] = {
464         CITET, CITEP, CITEALT, CITEALP, CITEAUTHOR };
465
466 unsigned int const nCiteStylesUCase =
467         sizeof(citeStylesUCase) / sizeof(CiteStyle);
468
469 } // namespace anon
470
471
472 CitationStyle citationStyleFromString(string const & command)
473 {
474         CitationStyle s;
475         if (command.empty())
476                 return s;
477
478         string cmd = command;
479         if (cmd[0] == 'C') {
480                 s.forceUpperCase = true;
481                 cmd[0] = 'c';
482         }
483
484         size_t const n = cmd.size() - 1;
485         if (cmd != "cite" && cmd[n] == '*') {
486                 s.full = true;
487                 cmd = cmd.substr(0, n);
488         }
489
490         char const * const * const last = citeCommands + nCiteCommands;
491         char const * const * const ptr = find(citeCommands, last, cmd);
492
493         if (ptr != last) {
494                 size_t idx = ptr - citeCommands;
495                 s.style = citeStylesArray[idx];
496         }
497         return s;
498 }
499
500
501 string citationStyleToString(const CitationStyle & s)
502 {
503         string cite = citeCommands[s.style];
504         if (s.full) {
505                 CiteStyle const * last = citeStylesFull + nCiteStylesFull;
506                 if (find(citeStylesFull, last, s.style) != last)
507                         cite += '*';
508         }
509
510         if (s.forceUpperCase) {
511                 CiteStyle const * last = citeStylesUCase + nCiteStylesUCase;
512                 if (find(citeStylesUCase, last, s.style) != last)
513                         cite[0] = 'C';
514         }
515
516         return cite;
517 }
518
519 vector<CiteStyle> citeStyles(CiteEngine engine)
520 {
521         unsigned int nStyles = 0;
522         unsigned int start = 0;
523
524         switch (engine) {
525                 case ENGINE_BASIC:
526                         nStyles = 2;
527                         start = 0;
528                         break;
529                 case ENGINE_NATBIB_AUTHORYEAR:
530                 case ENGINE_NATBIB_NUMERICAL:
531                         nStyles = nCiteStyles - 1;
532                         start = 1;
533                         break;
534                 case ENGINE_JURABIB:
535                         nStyles = nCiteStyles;
536                         start = 0;
537                         break;
538         }
539
540         vector<CiteStyle> styles(nStyles);
541         size_t i = 0;
542         int j = start;
543         for (; i != styles.size(); ++i, ++j)
544                 styles[i] = citeStylesArray[j];
545
546         return styles;
547 }
548
549 } // namespace lyx
550