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