]> git.lyx.org Git - lyx.git/blob - src/insets/InsetBibitem.cpp
Probably fix #10850 compiler warnings.
[lyx.git] / src / insets / InsetBibitem.cpp
1 /**
2  * \file InsetBibitem.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Alejandro Aguilar Sierra
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12 #include <algorithm>
13
14 #include "InsetBibitem.h"
15
16 #include "BiblioInfo.h"
17 #include "Buffer.h"
18 #include "Cursor.h"
19 #include "buffer_funcs.h"
20 #include "BufferParams.h"
21 #include "BufferView.h"
22 #include "Counters.h"
23 #include "DispatchResult.h"
24 #include "Encoding.h"
25 #include "FuncRequest.h"
26 #include "InsetIterator.h"
27 #include "InsetList.h"
28 #include "Language.h"
29 #include "Lexer.h"
30 #include "output_xhtml.h"
31 #include "OutputParams.h"
32 #include "Paragraph.h"
33 #include "ParagraphList.h"
34 #include "ParIterator.h"
35 #include "TextClass.h"
36
37 #include "frontends/alert.h"
38
39 #include "support/lassert.h"
40 #include "support/convert.h"
41 #include "support/debug.h"
42 #include "support/docstream.h"
43 #include "support/gettext.h"
44 #include "support/lstrings.h"
45 #include "support/mutex.h"
46
47 using namespace std;
48 using namespace lyx::support;
49
50 namespace lyx {
51
52
53 int InsetBibitem::key_counter = 0;
54 static Mutex counter_mutex;
55 docstring const key_prefix = from_ascii("key-");
56
57
58 InsetBibitem::InsetBibitem(Buffer * buf, InsetCommandParams const & p)
59         : InsetCommand(buf, p)
60 {
61         buffer().invalidateBibinfoCache();
62         if (getParam("key").empty()) {
63                 Mutex::Locker lock(&counter_mutex);
64                 setParam("key", key_prefix + convert<docstring>(++key_counter));
65         }
66 }
67
68
69 InsetBibitem::~InsetBibitem()
70 {
71         if (isBufferLoaded()) {
72                 /* We do not use buffer() because Coverity believes that this
73                  * may throw an exception. Actually this code path is not
74                  * taken when buffer_ == 0 */
75                 buffer_->invalidateBibinfoCache();
76         }
77 }
78
79
80 void InsetBibitem::initView()
81 {
82         updateCommand(getParam("key"));
83 }
84
85
86 void InsetBibitem::updateCommand(docstring const & new_key, bool)
87 {
88         docstring key = new_key;
89         vector<docstring> bibkeys = buffer().masterBibInfo().getKeys();
90
91         if (find(bibkeys.begin(), bibkeys.end(), key) != bibkeys.end()) {
92                 int i = 1;
93                 // generate unique label
94                 key = new_key + '-' + convert<docstring>(i);
95                 while (find(bibkeys.begin(), bibkeys.end(), key) != bibkeys.end()) {
96                         ++i;
97                         key = new_key + '-' + convert<docstring>(i);
98                 }
99                 frontend::Alert::warning(_("Keys must be unique!"),
100                         bformat(_("The key %1$s already exists,\n"
101                         "it will be changed to %2$s."), new_key, key));
102         }
103         setParam("key", key);
104         buffer().invalidateBibinfoCache();
105 }
106
107
108 ParamInfo const & InsetBibitem::findInfo(string const & /* cmdName */)
109 {
110         static ParamInfo param_info_;
111         if (param_info_.empty()) {
112                 param_info_.add("label", ParamInfo::LATEX_OPTIONAL,
113                                 ParamInfo::HANDLING_LATEXIFY);
114                 param_info_.add("key", ParamInfo::LATEX_REQUIRED,
115                                 ParamInfo::ParamHandling(ParamInfo::HANDLING_ESCAPE
116                                                          | ParamInfo::HANDLING_LTRIM));
117                 param_info_.add("literal", ParamInfo::LYX_INTERNAL);
118         }
119         return param_info_;
120 }
121
122
123 void InsetBibitem::doDispatch(Cursor & cur, FuncRequest & cmd)
124 {
125         switch (cmd.action()) {
126
127         case LFUN_INSET_MODIFY: {
128                 InsetCommandParams p(BIBITEM_CODE);
129                 InsetCommand::string2params(to_utf8(cmd.argument()), p);
130                 if (p.getCmdName().empty()) {
131                         cur.noScreenUpdate();
132                         break;
133                 }
134
135                 cur.recordUndo();
136
137                 docstring const & old_key = params()["key"];
138                 docstring const & old_label = params()["label"];
139                 docstring const & old_literal = params()["literal"];
140                 docstring label = p["label"];
141                 docstring literal = p["literal"];
142
143                 if (old_label != label) {
144                         p["label"] = label;
145                         cur.forceBufferUpdate();
146                         buffer().invalidateBibinfoCache();
147                 }
148                 setParam("label", p["label"]);
149
150                 if (old_literal != literal) {
151                         p["literal"] = literal;
152                         cur.forceBufferUpdate();
153                         buffer().invalidateBibinfoCache();
154                 }
155                 setParam("literal", p["literal"]);
156
157                 if (p["key"] != old_key) {
158                         updateCommand(p["key"]);
159                         cur.bv().buffer().changeRefsIfUnique(old_key, params()["key"]);
160                         cur.forceBufferUpdate();
161                         buffer().invalidateBibinfoCache();
162                 }
163                 break;
164         }
165
166         default:
167                 InsetCommand::doDispatch(cur, cmd);
168                 break;
169         }
170 }
171
172
173 void InsetBibitem::read(Lexer & lex)
174 {
175         InsetCommand::read(lex);
176
177         if (prefixIs(getParam("key"), key_prefix)) {
178                 int const key = convert<int>(getParam("key").substr(key_prefix.length()));
179                 Mutex::Locker lock(&counter_mutex);
180                 key_counter = max(key_counter, key);
181         }
182 }
183
184
185 docstring InsetBibitem::bibLabel() const
186 {
187         BufferParams const & bp = buffer().masterBuffer()->params();
188         if (bp.citeEngineType() == ENGINE_TYPE_NUMERICAL)
189                 return autolabel_;
190         docstring const & label = getParam("label");
191         return label.empty() ? autolabel_ : label;
192 }
193
194
195 docstring InsetBibitem::screenLabel() const
196 {
197         return getParam("key") + " [" + bibLabel() + ']';
198 }
199
200
201 int InsetBibitem::plaintext(odocstringstream & os,
202         OutputParams const &, size_t) const
203 {
204         odocstringstream oss;
205         oss << '[' << bibLabel() << "] ";
206
207         docstring const str = oss.str();
208         os << str;
209
210         return str.size();
211 }
212
213
214 // ale070405
215 docstring bibitemWidest(Buffer const & buffer, OutputParams const & runparams)
216 {
217         BufferParams const & bp = buffer.masterBuffer()->params();
218         if (bp.citeEngineType() == ENGINE_TYPE_NUMERICAL)
219                 return from_ascii("99");
220
221         int w = 0;
222
223         InsetBibitem const * bitem = 0;
224
225         // FIXME: this font is used unitialized for now but should  be set to
226         // a proportional font. Here is what Georg Baum has to say about it:
227         /*
228         bibitemWidest() is supposed to find the bibitem with the widest label in the
229         output, because that is needed as an argument of the bibliography
230         environment to determine the correct indentation. To be 100% correct we
231         would need the metrics of the font that is used in the output, but usually
232         we don't have access to these.
233         In practice, any proportional font is probably good enough, since we don't
234         need to know the final with, we only need to know the which label is the
235         widest.
236         Unless there is an easy way to get the metrics of the output font I suggest
237         to use a hardcoded font like "Times" or so.
238
239         It is very important that the result of this function is the same both with
240         and without GUI. After thinking about this it is clear that no Font
241         metrics should be used here, since these come from the gui. If we can't
242         easily get the LaTeX font metrics we should make our own poor mans font
243         metrics replacement, e.g. by hardcoding the metrics of the standard TeX
244         font.
245         */
246
247         docstring lbl;
248
249         ParagraphList::const_iterator it = buffer.paragraphs().begin();
250         ParagraphList::const_iterator end = buffer.paragraphs().end();
251
252         for (; it != end; ++it) {
253                 if (it->insetList().empty())
254                         continue;
255                 Inset * inset = it->insetList().begin()->inset;
256                 if (inset->lyxCode() != BIBITEM_CODE)
257                         continue;
258
259                 bitem = static_cast<InsetBibitem const *>(inset);
260                 docstring const label = bitem->bibLabel();
261
262                 // FIXME: we can't be sure using the following that the GUI
263                 // version and the command-line version will give the same
264                 // result.
265                 //
266                 //int const wx = use_gui?
267                 //      theFontMetrics(font).width(label): label.size();
268                 //
269                 // So for now we just use the label size in order to be sure
270                 // that GUI and no-GUI gives the same bibitem (even if that is
271                 // potentially the wrong one.
272                 int const wx = label.size();
273
274                 if (wx > w) {
275                         w = wx;
276                         lbl = label;
277                 }
278         }
279
280         if (!lbl.empty()) {
281                 InsetCommandParams p(BIBITEM_CODE);
282                 return p.prepareCommand(runparams, lbl, ParamInfo::HANDLING_LATEXIFY);
283         }
284
285         return from_ascii("99");
286 }
287
288
289 void InsetBibitem::collectBibKeys(InsetIterator const & it, FileNameList & /*checkedFiles*/) const
290 {
291         docstring const key = getParam("key");
292         docstring const label = getParam("label");
293         BibTeXInfo keyvalmap(false);
294         keyvalmap.key(key);
295         keyvalmap.label(label);
296
297         BufferParams const & bp = buffer().masterBuffer()->params();
298         Counters & counters = bp.documentClass().counters();
299         docstring const bibitem = from_ascii("bibitem");
300         if (bp.citeEngineType() == ENGINE_TYPE_NUMERICAL || getParam("label").empty()) {
301                 if (counters.hasCounter(bibitem))
302                         counters.step(bibitem, InternalUpdate);
303                 string const & lang = it.paragraph().getParLanguage(bp)->code();
304                 keyvalmap.setCiteNumber(counters.theCounter(bibitem, lang));
305         }
306
307         DocIterator doc_it(it);
308         doc_it.forwardPos();
309         keyvalmap[from_ascii("ref")] = doc_it.paragraph().asString(
310                 AS_STR_INSETS | AS_STR_SKIPDELETE);
311         buffer().addBibTeXInfo(key, keyvalmap);
312 }
313
314
315 // Update the counters of this inset and of its contents
316 void InsetBibitem::updateBuffer(ParIterator const & it, UpdateType utype)
317 {
318         BufferParams const & bp = buffer().masterBuffer()->params();
319         Counters & counters = bp.documentClass().counters();
320         docstring const bibitem = from_ascii("bibitem");
321         if (bp.citeEngineType() == ENGINE_TYPE_NUMERICAL || getParam("label").empty()) {
322                 if (counters.hasCounter(bibitem))
323                         counters.step(bibitem, utype);
324                 string const & lang = it.paragraph().getParLanguage(bp)->code();
325                 autolabel_ = counters.theCounter(bibitem, lang);
326         } else {
327                 autolabel_ = from_ascii("??");
328         }
329 }
330
331
332 docstring InsetBibitem::xhtml(XHTMLStream & xs, OutputParams const &) const
333 {
334         // FIXME XHTML
335         // XHTML 1.1 doesn't have the "name" attribute for <a>, so we have to use
336         // the "id" atttribute to get the document to validate. Probably, we will
337         // need to use "name" anyway, eventually, because some browsers do not
338         // handle jumping to ids. If we don't do that, though, we can just put the
339         // id into the span tag.
340         string const attrs =
341                 "id='LyXCite-" + to_utf8(html::cleanAttr(getParam("key"))) + "'";
342         xs << html::CompTag("a", attrs);
343         xs << html::StartTag("span", "class='bibitemlabel'");
344         xs << bibLabel();
345         xs << html::EndTag("span");
346         return docstring();
347 }
348
349
350 } // namespace lyx