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