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