]> git.lyx.org Git - lyx.git/blob - src/frontends/controllers/ControlCitation.cpp
Rename .C ==> .cpp for files in src, part one
[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         vector<pair<string, docstring> > blist;
52         kernel().buffer().fillWithBibKeys(blist);
53         bibkeysInfo_.clear();
54         for (size_t i = 0; i < blist.size(); ++i)
55                 bibkeysInfo_[blist[i].first] = blist[i].second;
56
57         if (citeStyles_.empty())
58                 citeStyles_ = biblio::getCiteStyles(engine);
59         else {
60                 if ((use_styles && citeStyles_.size() == 1) ||
61                     (!use_styles && citeStyles_.size() != 1))
62                         citeStyles_ = biblio::getCiteStyles(engine);
63         }
64
65         return true;
66 }
67
68
69
70 void ControlCitation::clearParams()
71 {
72         ControlCommand::clearParams();
73         bibkeysInfo_.clear();
74 }
75
76
77 vector<string> const ControlCitation::availableKeys() const
78 {
79         return biblio::getKeys(bibkeysInfo_);
80 }
81
82
83 biblio::CiteEngine const ControlCitation::getEngine() const
84 {
85         return kernel().buffer().params().getEngine();
86 }
87
88
89 docstring const ControlCitation::getInfo(std::string const & key) const
90 {
91         if (bibkeysInfo_.empty())
92                 return docstring();
93
94         return biblio::getInfo(bibkeysInfo_, key);
95 }
96
97 namespace {
98
99
100 // Escape special chars.
101 // All characters are literals except: '.|*?+(){}[]^$\'
102 // These characters are literals when preceded by a "\", which is done here
103 // @todo: This function should be moved to support, and then the test in tests
104 //        should be moved there as well.
105 docstring const escape_special_chars(docstring const & expr)
106 {
107         // Search for all chars '.|*?+(){}[^$]\'
108         // Note that '[' and '\' must be escaped.
109         // This is a limitation of boost::regex, but all other chars in BREs
110         // are assumed literal.
111         boost::regex reg("[].|*?+(){}^$\\[\\\\]");
112
113         // $& is a perl-like expression that expands to all
114         // of the current match
115         // The '$' must be prefixed with the escape character '\' for
116         // boost to treat it as a literal.
117         // Thus, to prefix a matched expression with '\', we use:
118         // FIXME: UNICODE
119         return from_utf8(boost::regex_replace(to_utf8(expr), reg, "\\\\$&"));
120 }
121
122 } // namespace anon
123
124 vector<string> ControlCitation::searchKeys(
125         vector<string> const & keys_to_search,
126         docstring const & search_expression,
127         bool case_sensitive, bool regex)
128 {
129         vector<string> foundKeys;
130
131         docstring expr = support::trim(search_expression);
132         if (expr.empty())
133                 return foundKeys;
134
135         if (!regex)
136                 // We must escape special chars in the search_expr so that
137                 // it is treated as a simple string by boost::regex.
138                 expr = escape_special_chars(expr);
139
140         boost::regex reg_exp(to_utf8(expr), case_sensitive?
141                 boost::regex_constants::normal : boost::regex_constants::icase);
142
143         vector<string>::const_iterator it = keys_to_search.begin();
144         vector<string>::const_iterator end = keys_to_search.end();
145         for (; it != end; ++it ) {
146                 biblio::InfoMap::const_iterator info = bibkeysInfo_.find(*it);
147                 if (info == bibkeysInfo_.end())
148                         continue;
149
150                 string data = *it;
151                 // FIXME UNICODE
152                 data += ' ' + to_utf8(info->second);
153
154                 try {
155                         // Attempts to find a match for the current RE
156                         // somewhere in data.
157                         if (boost::regex_search(data, reg_exp))
158                                 foundKeys.push_back(*it);
159                 }
160                 catch (boost::regex_error &) {
161                         return vector<string>();
162                 }
163         }
164         return foundKeys;
165 }
166
167
168 vector<docstring> const ControlCitation::getCiteStrings(string const & key) const
169 {
170         biblio::CiteEngine const engine = kernel().buffer().params().getEngine();
171         vector<biblio::CiteStyle> const cs = biblio::getCiteStyles(engine);
172
173         if (engine == biblio::ENGINE_NATBIB_NUMERICAL)
174                 return biblio::getNumericalStrings(key, bibkeysInfo_, cs);
175         else
176                 return biblio::getAuthorYearStrings(key, bibkeysInfo_, cs);
177 }
178
179 } // namespace frontend
180 } // namespace lyx