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