]> git.lyx.org Git - lyx.git/blob - src/frontends/controllers/ControlCitation.C
Implementation of controller-view split for FormCharacter.
[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::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                 if (result.empty()) // not a BibTeX record
124                         result = it->second;
125         }
126
127         return result;
128 }
129
130
131 vector<string>::const_iterator
132 searchKeys(ControlCitation const & controller,
133            vector<string> const & keys,
134            string const & expr,
135            vector<string>::const_iterator start,
136            ControlCitation::Search type,
137            ControlCitation::Direction dir,
138            bool caseSensitive)
139 {
140         // Preliminary checks
141         if(start < keys.begin() || start >= keys.end())
142                 return keys.end();
143         
144         string search_expr = frontStrip(strip(expr));
145         if (search_expr.empty())
146                 return start;
147
148         if (type == ControlCitation::SIMPLE)
149                 return simpleSearch(controller, keys, search_expr, start, dir,
150                                     caseSensitive);
151
152         return regexSearch(controller, keys, search_expr, start, dir);
153 }
154
155
156 vector<string>::const_iterator
157 simpleSearch(ControlCitation const & controller,
158              vector<string> const & keys,
159              string const & expr,
160              vector<string>::const_iterator start,
161              ControlCitation::Direction dir,
162              bool caseSensitive)
163 {
164         vector<string> searchwords = getVectorFromString(expr, " ");
165
166         // Loop over all keys from start...
167         for (vector<string>::const_iterator it = start;
168              // End condition is direction-dependent.
169              (dir == ControlCitation::FORWARD) ?
170                      (it<keys.end()) : (it>=keys.begin());
171              // increment is direction-dependent.
172              (dir == ControlCitation::FORWARD) ?
173                      (++it) : (--it)) {
174
175                 string data = (*it);
176                 ControlCitation::InfoMap::const_iterator info =
177                         controller.bibkeysInfo().find(*it);
178                 if (info != controller.bibkeysInfo().end())
179                         data += " " + info->second;
180                 if (!caseSensitive)
181                         data = lowercase(data);
182
183                 bool found = true;
184
185                 // Loop over all search words...
186                 if (caseSensitive) {
187                         for (vector<string>::const_iterator sit=
188                                      searchwords.begin();
189                              sit<searchwords.end(); ++sit) {
190                                 if (data.find(*sit) == string::npos) {
191                                         found = false;
192                                         break;
193                                 }
194                         }
195                 } else {
196                         for (vector<string>::const_iterator sit=
197                                      searchwords.begin();
198                              sit<searchwords.end(); ++sit) {
199                                 if (data.find(lowercase(*sit)) ==
200                                     string::npos) {
201                                         found = false;
202                                         break;
203                                 }
204                         }
205                 }
206                 
207                 if (found) return it;
208         }
209
210         return keys.end();
211 }
212
213
214 vector<string>::const_iterator
215 regexSearch(ControlCitation const & controller,
216             vector<string> const & keys,
217             string const & expr,
218             vector<string>::const_iterator start,
219             ControlCitation::Direction dir)
220 {
221         LRegex reg(expr);
222
223         for (vector<string>::const_iterator it = start;
224              // End condition is direction-dependent.
225              (dir == ControlCitation::FORWARD) ?
226                      (it<keys.end()) : (it>=keys.begin());
227              // increment is direction-dependent.
228              (dir == ControlCitation::FORWARD) ?
229                      (++it) : (--it)) {
230
231                 string data = (*it);
232                 ControlCitation::InfoMap::const_iterator info =
233                         controller.bibkeysInfo().find(*it);
234                 if (info != controller.bibkeysInfo().end())
235                         data += " " + info->second;
236
237                 if (reg.exec(data).size() > 0)
238                         return it;
239         }
240
241         return keys.end();
242 }
243
244 string const parseBibTeX(string data, string const & findkey)
245 {
246         string keyvalue;
247         
248         for (string::iterator it=data.begin(); it<data.end(); ++it) {
249                 if ((*it) == '\n' || (*it) == '\t')
250                         (*it)= ' ';
251         }
252         
253         data = frontStrip(data);
254         while (!data.empty() && data[0] != '=' && 
255                (data.find(' ') != string::npos || data.find('=') != string::npos)) {
256
257                 string::size_type keypos = min(data.find(' '), data.find('='));
258                 string key = lowercase(data.substr(0, keypos));
259       
260                 data = data.substr(keypos, data.length()-1);
261                 data = frontStrip(strip(data));
262                 if (data.length() > 1 && data[0]=='=') {
263                         data = frontStrip(data.substr(1, data.length()-1));
264                         if (!data.empty()) {
265                                 keypos = 1;
266                                 string value;
267                                 char enclosing;
268
269                                 if (data[0]=='{') {
270                                         enclosing = '}';
271                                 } else if (data[0]=='"') {
272                                         enclosing = '"';
273                                 } else {
274                                         keypos=0;
275                                         enclosing=' ';
276                                 }
277
278                                 if (keypos &&
279                                     data.find(enclosing)!=string::npos &&
280                                     data.length()>1) {
281                                         string tmp = data.substr(keypos,
282                                                                  data.length()-1);
283                                         while (tmp.find('{') != string::npos &&
284                                                tmp.find('}') != string::npos &&
285                                                tmp.find('{') < tmp.find('}') &&
286                                                tmp.find('{') < tmp.find(enclosing)) {
287
288                                                 keypos += tmp.find('{')+1;
289                                                 tmp = data.substr(keypos,
290                                                                   data.length()-1);
291                                                 keypos += tmp.find('}')+1;
292                                                 tmp = data.substr(keypos,
293                                                                   data.length()-1);
294                                         }
295
296                                         if (tmp.find(enclosing)==string::npos)
297                                                 return keyvalue;
298                                         else {
299                                                 keypos += tmp.find(enclosing);
300                                                 tmp = data.substr(keypos,
301                                                                   data.length()-1);
302                                         }
303
304                                         value = data.substr(1, keypos-1);
305
306                                         if (keypos+1<data.length()-1)
307                                                 data = frontStrip(data.substr(keypos+1, data.length()-1));
308                                         else
309                                                 data = "";
310
311                                 } else if (!keypos &&
312                                            (data.find(' ') ||
313                                             data.find(','))) {
314                                         keypos = data.length()-1;
315                                         if (data.find(' ') != string::npos)
316                                                 keypos = data.find(' ');
317                                         if (data.find(',') != string::npos &&
318                                             keypos > data.find(','))
319                                                 keypos = data.find(',');
320
321                                         value = data.substr(0, keypos);
322                   
323                                         if (keypos+1<data.length()-1)
324                                                 data = frontStrip(data.substr(keypos+1, data.length()-1));
325                                         else
326                                                 data = "";
327                                 }
328                                 else
329                                         return keyvalue;
330
331                                 if (findkey == key) {
332                                         keyvalue = value;
333                                         return keyvalue;
334                                 } 
335
336                                 data = frontStrip(frontStrip(data,','));
337                         }
338                 }
339                 else return keyvalue;
340         }
341         return keyvalue;
342 }