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