]> git.lyx.org Git - lyx.git/blob - src/frontends/controllers/ControlCitation.C
Merging BRANCH_MVC back into HEAD.
[lyx.git] / src / frontends / controllers / ControlCitation.C
1 // -*- C++ -*-
2 /* This file is part of
3  * ====================================================== 
4  *
5  *           LyX, The Document Processor
6  *
7  *           Copyright 2000 The LyX Team.
8  *
9  * ======================================================
10  *
11  * \file ControlCitation.C
12  * \author Angus Leeming <a.leeming@ic.ac.uk>
13  */
14
15 #include <algorithm>
16
17 #ifdef __GNUG__
18 #pragma implementation
19 #endif
20
21 #include <config.h>
22
23 #include "ControlCitation.h"
24 #include "buffer.h"
25 #include "ButtonController.h"
26 #include "Dialogs.h"
27 #include "LyXView.h"
28 #include "ViewBase.h"
29 #include "support/lstrings.h"
30 #include "support/LRegex.h"
31
32 using std::find;
33 using std::min;
34 using std::pair;
35 using std::vector;
36 using std::sort;
37         
38 ControlCitation::ControlCitation(LyXView & lv, Dialogs & d)
39         : ControlCommand(lv, d, LFUN_CITATION_INSERT)
40 {
41         // These are permanent connections so we won't bother
42         // storing a copy because we won't be disconnecting.
43         d_.showCitation.connect(slot(this, &ControlCitation::showInset));
44         d_.createCitation.connect(slot(this, &ControlCitation::createInset));
45 }
46
47
48 void ControlCitation::hide()
49 {
50         bibkeysInfo_.clear();
51         ControlCommand::hide(); 
52 }
53
54
55 // A functor for use with std::sort, leading to case insensitive sorting
56 struct compareNoCase: public std::binary_function<string, string, bool> 
57 {
58         bool operator()(string const & s1, string const & s2) const {
59                 return compare_no_case(s1, s2) < 0;
60         }
61 };
62
63
64 vector<string> const ControlCitation::getBibkeys()
65 {
66         vector<string> bibkeys;
67         bibkeysInfo_.clear();
68
69         vector<pair<string,string> > blist = lv_.buffer()->getBibkeyList();
70
71         for (vector<pair<string,string> >::size_type i=0; i<blist.size(); ++i) {
72                 bibkeys.push_back(blist[i].first);
73                 bibkeysInfo_.insert(InfoMapValue(blist[i].first,
74                                                  blist[i].second));
75         }
76
77         sort(bibkeys.begin(), bibkeys.end(), compareNoCase());
78         return bibkeys;
79 }
80
81
82 string const ControlCitation::getBibkeyInfo(string const & key)
83 {
84         string result;
85
86         if (bibkeysInfo_.empty()) getBibkeys();
87
88         InfoMap::const_iterator it = bibkeysInfo_.find(key);
89         if (it != bibkeysInfo_.end()) {
90                 // Search for all possible "required" keys
91                 string author = parseBibTeX((*it).second, "author");
92                 if (author.empty())
93                         author = parseBibTeX((*it).second, "editor");
94
95                 string year       = parseBibTeX((*it).second, "year");
96                 string title      = parseBibTeX((*it).second, "title");
97                 string booktitle  = parseBibTeX((*it).second, "booktitle");
98                 string chapter    = parseBibTeX((*it).second, "chapter");
99                 string pages      = parseBibTeX((*it).second, "pages");
100
101                 string media      = parseBibTeX((*it).second, "journal");
102                 if (media.empty())
103                         media = parseBibTeX((*it).second, "publisher");
104                 if (media.empty())
105                         media = parseBibTeX((*it).second, "school");
106                 if (media.empty())
107                         media = parseBibTeX((*it).second, "institution");
108
109                 result = author;
110                 if (!year.empty())
111                         result += ", " + year;
112                 if (!title.empty())
113                         result += ", " + title;
114                 if (!booktitle.empty())
115                         result += ", in " + booktitle;
116                 if (!chapter.empty())
117                         result += ", Ch. " + chapter;
118                 if (!media.empty())
119                         result += ", " + media;
120                 if (!pages.empty())
121                         result += ", pp. " + pages;
122         }
123
124         return result;
125 }
126
127
128 vector<string>::const_iterator
129 searchKeys(ControlCitation const & controller,
130            vector<string> const & keys,
131            string const & expr,
132            vector<string>::const_iterator start,
133            ControlCitation::Search type,
134            ControlCitation::Direction dir,
135            bool caseSensitive)
136 {
137         // Preliminary checks
138         if(start < keys.begin() || start >= keys.end())
139                 return keys.end();
140         
141         string search_expr = frontStrip(strip(expr));
142         if (search_expr.empty())
143                 return start;
144
145         if (type == ControlCitation::SIMPLE)
146                 return simpleSearch(controller, keys, search_expr, start, dir,
147                                     caseSensitive);
148
149         return regexSearch(controller, keys, search_expr, start, dir);
150 }
151
152
153 vector<string>::const_iterator
154 simpleSearch(ControlCitation const & controller,
155              vector<string> const & keys,
156              string const & expr,
157              vector<string>::const_iterator start,
158              ControlCitation::Direction dir,
159              bool caseSensitive)
160 {
161         vector<string> searchwords = getVectorFromString(expr, ' ');
162
163         // Loop over all keys from start...
164         for (vector<string>::const_iterator it = start;
165              // End condition is direction-dependent.
166              (dir == ControlCitation::FORWARD) ?
167                      (it<keys.end()) : (it>=keys.begin());
168              // increment is direction-dependent.
169              (dir == ControlCitation::FORWARD) ?
170                      (++it) : (--it)) {
171
172                 string data = (*it);
173                 ControlCitation::InfoMap::const_iterator info =
174                         controller.bibkeysInfo().find(*it);
175                 if (info != controller.bibkeysInfo().end())
176                         data += " " + info->second;
177                 if (!caseSensitive)
178                         data = lowercase(data);
179
180                 bool found = true;
181
182                 // Loop over all search words...
183                 if (caseSensitive) {
184                         for (vector<string>::const_iterator sit=
185                                      searchwords.begin();
186                              sit<searchwords.end(); ++sit) {
187                                 if (data.find(*sit) == string::npos) {
188                                         found = false;
189                                         break;
190                                 }
191                         }
192                 } else {
193                         for (vector<string>::const_iterator sit=
194                                      searchwords.begin();
195                              sit<searchwords.end(); ++sit) {
196                                 if (data.find(lowercase(*sit)) ==
197                                     string::npos) {
198                                         found = false;
199                                         break;
200                                 }
201                         }
202                 }
203                 
204                 if (found) return it;
205         }
206
207         return keys.end();
208 }
209
210
211 vector<string>::const_iterator
212 regexSearch(ControlCitation const & controller,
213             vector<string> const & keys,
214             string const & expr,
215             vector<string>::const_iterator start,
216             ControlCitation::Direction dir)
217 {
218         LRegex reg(expr);
219
220         for (vector<string>::const_iterator it = start;
221              // End condition is direction-dependent.
222              (dir == ControlCitation::FORWARD) ?
223                      (it<keys.end()) : (it>=keys.begin());
224              // increment is direction-dependent.
225              (dir == ControlCitation::FORWARD) ?
226                      (++it) : (--it)) {
227
228                 string data = (*it);
229                 ControlCitation::InfoMap::const_iterator info =
230                         controller.bibkeysInfo().find(*it);
231                 if (info != controller.bibkeysInfo().end())
232                         data += " " + info->second;
233
234                 if (reg.exec(data).size() > 0)
235                         return it;
236         }
237
238         return keys.end();
239 }
240
241 string const getStringFromVector(vector<string> const & vec, char delim)
242 {
243         string str;
244         for (vector<string>::size_type i=0; i<vec.size(); ++i) {
245                 if (i > 0) str += tostr(delim) + " ";
246                 str += vec[i];
247         }
248         return str;
249 }
250
251 vector<string> const getVectorFromString(string const & str, char delim)
252 {
253         vector<string> vec;
254         string keys(str);
255         string tmp;
256         keys = frontStrip(split(keys, tmp, delim));
257         while (!tmp.empty()) {
258                 vec.push_back(tmp);
259                 keys = frontStrip(split(keys, tmp, delim));
260         }
261         return vec;
262 }
263
264 string const parseBibTeX(string data, string const & findkey)
265 {
266         string keyvalue;
267         
268         for (string::iterator it=data.begin(); it<data.end(); ++it) {
269                 if ((*it) == '\n' || (*it) == '\t')
270                         (*it)= ' ';
271         }
272         
273         data = frontStrip(data);
274         while (!data.empty() && data[0] != '=' && 
275                (data.find(' ') != string::npos || data.find('=') != string::npos)) {
276
277                 string::size_type keypos = min(data.find(' '), data.find('='));
278                 string key = lowercase(data.substr(0, keypos));
279       
280                 data = data.substr(keypos, data.length()-1);
281                 data = frontStrip(strip(data));
282                 if (data.length() > 1 && data[0]=='=') {
283                         data = frontStrip(data.substr(1, data.length()-1));
284                         if (!data.empty()) {
285                                 keypos = 1;
286                                 string value;
287                                 char enclosing;
288
289                                 if (data[0]=='{') {
290                                         enclosing = '}';
291                                 } else if (data[0]=='"') {
292                                         enclosing = '"';
293                                 } else {
294                                         keypos=0;
295                                         enclosing=' ';
296                                 }
297
298                                 if (keypos &&
299                                     data.find(enclosing)!=string::npos &&
300                                     data.length()>1) {
301                                         string tmp = data.substr(keypos,
302                                                                  data.length()-1);
303                                         while (tmp.find('{') != string::npos &&
304                                                tmp.find('}') != string::npos &&
305                                                tmp.find('{') < tmp.find('}') &&
306                                                tmp.find('{') < tmp.find(enclosing)) {
307
308                                                 keypos += tmp.find('{')+1;
309                                                 tmp = data.substr(keypos,
310                                                                   data.length()-1);
311                                                 keypos += tmp.find('}')+1;
312                                                 tmp = data.substr(keypos,
313                                                                   data.length()-1);
314                                         }
315
316                                         if (tmp.find(enclosing)==string::npos)
317                                                 return keyvalue;
318                                         else {
319                                                 keypos += tmp.find(enclosing);
320                                                 tmp = data.substr(keypos,
321                                                                   data.length()-1);
322                                         }
323
324                                         value = data.substr(1, keypos-1);
325
326                                         if (keypos+1<data.length()-1)
327                                                 data = frontStrip(data.substr(keypos+1, data.length()-1));
328                                         else
329                                                 data = "";
330
331                                 } else if (!keypos &&
332                                            (data.find(' ') ||
333                                             data.find(','))) {
334                                         keypos = data.length()-1;
335                                         if (data.find(' ') != string::npos)
336                                                 keypos = data.find(' ');
337                                         if (data.find(',') != string::npos &&
338                                             keypos > data.find(','))
339                                                 keypos = data.find(',');
340
341                                         value = data.substr(0, keypos);
342                   
343                                         if (keypos+1<data.length()-1)
344                                                 data = frontStrip(data.substr(keypos+1, data.length()-1));
345                                         else
346                                                 data = "";
347                                 }
348                                 else
349                                         return keyvalue;
350
351                                 if (findkey == key) {
352                                         keyvalue = value;
353                                         return keyvalue;
354                                 } 
355
356                                 data = frontStrip(frontStrip(data,','));
357                         }
358                 }
359                 else return keyvalue;
360         }
361         return keyvalue;
362 }