]> git.lyx.org Git - lyx.git/blob - src/frontends/controllers/ControlCitation.cpp
Simpler structure, 2-3s faster compiles. Not that it matters much...
[lyx.git] / src / frontends / controllers / ControlCitation.cpp
1 /**
2  * \file ControlCitation.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 Abdelrazak Younes
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #include "ControlCitation.h"
15
16 #include "Buffer.h"
17 #include "BufferParams.h"
18 #include "debug.h" // temporary
19
20 #include "support/lstrings.h"
21
22 #include <boost/regex.hpp>
23
24 #include <algorithm>
25
26 using std::string;
27 using std::vector;
28 using std::pair;
29
30 namespace lyx {
31 namespace frontend {
32
33 vector<biblio::CiteStyle> ControlCitation::citeStyles_;
34
35
36 ControlCitation::ControlCitation(Dialog & d)
37         : ControlCommand(d, "cite", "citation")
38 {}
39
40
41 bool ControlCitation::initialiseParams(string const & data)
42 {
43         if (!ControlCommand::initialiseParams(data))
44                 return false;
45
46         biblio::CiteEngine const engine = buffer().params().getEngine();
47
48         bool use_styles = engine != biblio::ENGINE_BASIC;
49
50         bibkeysInfo_.fillWithBibKeys(&buffer());
51         
52         if (citeStyles_.empty())
53                 citeStyles_ = biblio::getCiteStyles(engine);
54         else {
55                 if ((use_styles && citeStyles_.size() == 1) ||
56                     (!use_styles && citeStyles_.size() != 1))
57                         citeStyles_ = biblio::getCiteStyles(engine);
58         }
59
60         return true;
61 }
62
63
64
65 void ControlCitation::clearParams()
66 {
67         ControlCommand::clearParams();
68         bibkeysInfo_.clear();
69 }
70
71
72 vector<docstring> const ControlCitation::availableKeys() const
73 {
74         return bibkeysInfo_.getKeys();
75 }
76
77
78 vector<docstring> const ControlCitation::availableFields() const
79 {
80         return bibkeysInfo_.getFields();
81 }
82
83
84 vector<docstring> const ControlCitation::availableEntries() const
85 {
86         return bibkeysInfo_.getEntries();
87 }
88
89
90 void ControlCitation::filterByEntryType(
91         vector<docstring> & keyVector, docstring entryType) 
92 {
93         if (entryType.empty())
94                 return;
95         
96         vector<docstring>::iterator it = keyVector.begin();
97         vector<docstring>::iterator end = keyVector.end();
98         
99         vector<docstring> result;
100         for (; it != end; ++it) {
101                 docstring const key = *it;
102                 BiblioInfo::const_iterator cit = bibkeysInfo_.find(key);
103                 if (cit == bibkeysInfo_.end())
104                         continue;
105                 if (cit->second.entryType == entryType)
106                         result.push_back(key);
107         }
108         keyVector = result;
109 }
110
111
112 biblio::CiteEngine ControlCitation::getEngine() const
113 {
114         return buffer().params().getEngine();
115 }
116
117
118 docstring const ControlCitation::getInfo(docstring const & key) const
119 {
120         if (bibkeysInfo_.empty())
121                 return docstring();
122
123         return bibkeysInfo_.getInfo(key);
124 }
125
126 namespace {
127
128
129 // Escape special chars.
130 // All characters are literals except: '.|*?+(){}[]^$\'
131 // These characters are literals when preceded by a "\", which is done here
132 // @todo: This function should be moved to support, and then the test in tests
133 //        should be moved there as well.
134 docstring const escape_special_chars(docstring const & expr)
135 {
136         // Search for all chars '.|*?+(){}[^$]\'
137         // Note that '[' and '\' must be escaped.
138         // This is a limitation of boost::regex, but all other chars in BREs
139         // are assumed literal.
140         static const boost::regex reg("[].|*?+(){}^$\\[\\\\]");
141
142         // $& is a perl-like expression that expands to all
143         // of the current match
144         // The '$' must be prefixed with the escape character '\' for
145         // boost to treat it as a literal.
146         // Thus, to prefix a matched expression with '\', we use:
147         // FIXME: UNICODE
148         return from_utf8(boost::regex_replace(to_utf8(expr), reg, "\\\\$&"));
149 }
150
151 } // namespace anon
152
153 vector<docstring> ControlCitation::searchKeys(
154         vector<docstring> const & keys_to_search, bool only_keys,
155         docstring const & search_expression, docstring field,
156         bool case_sensitive, bool regex)
157 {
158         vector<docstring> foundKeys;
159
160         docstring expr = support::trim(search_expression);
161         if (expr.empty())
162                 return foundKeys;
163
164         if (!regex)
165                 // We must escape special chars in the search_expr so that
166                 // it is treated as a simple string by boost::regex.
167                 expr = escape_special_chars(expr);
168
169         boost::regex reg_exp(to_utf8(expr), case_sensitive ?
170                 boost::regex_constants::normal : boost::regex_constants::icase);
171
172         vector<docstring>::const_iterator it = keys_to_search.begin();
173         vector<docstring>::const_iterator end = keys_to_search.end();
174         for (; it != end; ++it ) {
175                 BiblioInfo::const_iterator info = bibkeysInfo_.find(*it);
176                 if (info == bibkeysInfo_.end())
177                         continue;
178                 
179                 BibTeXInfo const & kvm = info->second;
180                 string data;
181                 if (only_keys)
182                         data = to_utf8(*it);
183                 else if (field.empty())
184                         data = to_utf8(*it) + ' ' + to_utf8(kvm.allData);
185                 else if (kvm.hasField(field))
186                         data = to_utf8(kvm.getValueForField(field));
187                 
188                 if (data.empty())
189                         continue;
190
191                 try {
192                         if (boost::regex_search(data, reg_exp))
193                                 foundKeys.push_back(*it);
194                 }
195                 catch (boost::regex_error &) {
196                         return vector<docstring>();
197                 }
198         }
199         return foundKeys;
200 }
201
202
203 vector<docstring> const ControlCitation::getCiteStrings(docstring const & key) const
204 {
205         return bibkeysInfo_.getCiteStrings(key, buffer());
206 }
207
208 } // namespace frontend
209 } // namespace lyx