2 * \file InsetBibitem.cpp
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Alejandro Aguilar Sierra
8 * Full author contact details are available in file CREDITS.
14 #include "InsetBibitem.h"
16 #include "BiblioInfo.h"
19 #include "buffer_funcs.h"
20 #include "BufferParams.h"
21 #include "BufferView.h"
23 #include "DispatchResult.h"
25 #include "FuncRequest.h"
26 #include "InsetIterator.h"
27 #include "InsetList.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"
37 #include "frontends/alert.h"
39 #include "support/convert.h"
40 #include "support/debug.h"
41 #include "support/docstream.h"
42 #include "support/gettext.h"
43 #include "support/lstrings.h"
46 using namespace lyx::support;
51 int InsetBibitem::key_counter = 0;
52 docstring const key_prefix = from_ascii("key-");
55 InsetBibitem::InsetBibitem(Buffer * buf, InsetCommandParams const & p)
56 : InsetCommand(buf, p)
58 buffer().invalidateBibinfoCache();
59 if (getParam("key").empty())
60 setParam("key", key_prefix + convert<docstring>(++key_counter));
64 InsetBibitem::~InsetBibitem()
67 buffer().invalidateBibinfoCache();
71 void InsetBibitem::initView()
73 updateCommand(getParam("key"));
77 void InsetBibitem::updateCommand(docstring const & new_key, bool)
79 docstring key = new_key;
81 vector<docstring> bibkeys = buffer().masterBibInfo().getKeys();
85 if (find(bibkeys.begin(), bibkeys.end(), key) != bibkeys.end()) {
86 // generate unique label
87 key = new_key + '-' + convert<docstring>(i);
88 while (find(bibkeys.begin(), bibkeys.end(), key) != bibkeys.end()) {
90 key = new_key + '-' + convert<docstring>(i);
92 frontend::Alert::warning(_("Keys must be unique!"),
93 bformat(_("The key %1$s already exists,\n"
94 "it will be changed to %2$s."), new_key, key));
97 buffer().invalidateBibinfoCache();
101 ParamInfo const & InsetBibitem::findInfo(string const & /* cmdName */)
103 static ParamInfo param_info_;
104 if (param_info_.empty()) {
105 param_info_.add("label", ParamInfo::LATEX_OPTIONAL,
106 ParamInfo::HANDLING_LATEXIFY);
107 param_info_.add("key", ParamInfo::LATEX_REQUIRED,
108 ParamInfo::HANDLING_ESCAPE);
114 void InsetBibitem::doDispatch(Cursor & cur, FuncRequest & cmd)
116 switch (cmd.action()) {
118 case LFUN_INSET_MODIFY: {
119 InsetCommandParams p(BIBITEM_CODE);
120 InsetCommand::string2params(to_utf8(cmd.argument()), p);
121 if (p.getCmdName().empty()) {
122 cur.noScreenUpdate();
128 docstring const & old_key = params()["key"];
129 docstring const & old_label = params()["label"];
130 docstring label = p["label"];
132 // definitions for escaping
134 static docstring const backslash = from_ascii("\\");
135 static docstring const lbrace = from_ascii("{");
136 static docstring const rbrace = from_ascii("}");
137 static char_type const chars_escape[6] = {
138 '&', '_', '$', '%', '#', '^'};
139 static char_type const brackets_escape[2] = {'[', ']'};
141 if (!label.empty()) {
142 // The characters in chars_name[] need to be changed to a command when
143 // they are in the name field.
144 for (int k = 0; k < 6; k++)
145 for (size_t i = 0, pos;
146 (pos = label.find(chars_escape[k], i)) != string::npos;
152 // only if not already escaped
153 if (label[previous] != '\\')
154 label.replace(pos, 1, backslash + chars_escape[k] + lbrace + rbrace);
156 // The characters '[' and ']' need to be put into braces
157 for (int k = 0; k < 2; k++)
158 for (size_t i = 0, pos;
159 (pos = label.find(brackets_escape[k], i)) != string::npos;
165 // only if not already escaped
166 if (label[previous] != '{')
167 label.replace(pos, 1, lbrace + brackets_escape[k] + rbrace);
171 if (old_label != label) {
173 cur.forceBufferUpdate();
174 buffer().invalidateBibinfoCache();
177 setParam("label", p["label"]);
178 if (p["key"] != old_key) {
179 updateCommand(p["key"]);
180 cur.bv().buffer().changeRefsIfUnique(old_key,
181 params()["key"], CITE_CODE);
182 cur.forceBufferUpdate();
183 buffer().invalidateBibinfoCache();
189 InsetCommand::doDispatch(cur, cmd);
195 void InsetBibitem::read(Lexer & lex)
197 InsetCommand::read(lex);
199 if (prefixIs(getParam("key"), key_prefix)) {
200 int const key = convert<int>(getParam("key").substr(key_prefix.length()));
201 key_counter = max(key_counter, key);
206 docstring InsetBibitem::bibLabel() const
208 docstring const & label = getParam("label");
209 return label.empty() ? autolabel_ : label;
213 docstring InsetBibitem::screenLabel() const
215 return getParam("key") + " [" + bibLabel() + ']';
219 int InsetBibitem::plaintext(odocstringstream & os,
220 OutputParams const &, int) const
222 odocstringstream oss;
223 oss << '[' << bibLabel() << "] ";
225 docstring const str = oss.str();
233 docstring bibitemWidest(Buffer const & buffer, OutputParams const & runparams)
237 InsetBibitem const * bitem = 0;
239 // FIXME: this font is used unitialized for now but should be set to
240 // a proportional font. Here is what Georg Baum has to say about it:
242 bibitemWidest() is supposed to find the bibitem with the widest label in the
243 output, because that is needed as an argument of the bibliography
244 environment to determine the correct indentation. To be 100% correct we
245 would need the metrics of the font that is used in the output, but usually
246 we don't have access to these.
247 In practice, any proportional font is probably good enough, since we don't
248 need to know the final with, we only need to know the which label is the
250 Unless there is an easy way to get the metrics of the output font I suggest
251 to use a hardcoded font like "Times" or so.
253 It is very important that the result of this function is the same both with
254 and without GUI. After thinking about this it is clear that no Font
255 metrics should be used here, since these come from the gui. If we can't
256 easily get the LaTeX font metrics we should make our own poor mans font
257 metrics replacement, e.g. by hardcoding the metrics of the standard TeX
263 ParagraphList::const_iterator it = buffer.paragraphs().begin();
264 ParagraphList::const_iterator end = buffer.paragraphs().end();
266 for (; it != end; ++it) {
267 if (it->insetList().empty())
269 Inset * inset = it->insetList().begin()->inset;
270 if (inset->lyxCode() != BIBITEM_CODE)
273 bitem = static_cast<InsetBibitem const *>(inset);
274 docstring const label = bitem->bibLabel();
276 // FIXME: we can't be sure using the following that the GUI
277 // version and the command-line version will give the same
280 //int const wx = use_gui?
281 // theFontMetrics(font).width(label): label.size();
283 // So for now we just use the label size in order to be sure
284 // that GUI and no-GUI gives the same bibitem (even if that is
285 // potentially the wrong one.
286 int const wx = label.size();
295 pair<docstring, docstring> latex_lbl =
296 runparams.encoding->latexString(lbl, runparams.dryrun);
297 return latex_lbl.first;
300 return from_ascii("99");
304 void InsetBibitem::collectBibKeys(InsetIterator const & it) const
306 docstring const key = getParam("key");
307 docstring const label = getParam("label");
308 BibTeXInfo keyvalmap(false);
310 keyvalmap.label(label);
311 DocIterator doc_it(it);
313 keyvalmap[from_ascii("ref")] = doc_it.paragraph().asString(
314 AS_STR_INSETS | AS_STR_SKIPDELETE);
315 buffer().addBibTeXInfo(key, keyvalmap);
319 // Update the counters of this inset and of its contents
320 void InsetBibitem::updateBuffer(ParIterator const & it, UpdateType utype)
322 BufferParams const & bp = buffer().masterBuffer()->params();
323 Counters & counters = bp.documentClass().counters();
324 docstring const bibitem = from_ascii("bibitem");
325 if (getParam("label").empty()) {
326 if (counters.hasCounter(bibitem))
327 counters.step(bibitem, utype);
328 string const & lang = it.paragraph().getParLanguage(bp)->code();
329 autolabel_ = counters.theCounter(bibitem, lang);
331 autolabel_ = from_ascii("??");
336 docstring InsetBibitem::xhtml(XHTMLStream & xs, OutputParams const &) const
339 // XHTML 1.1 doesn't have the "name" attribute for <a>, so we have to use
340 // the "id" atttribute to get the document to validate. Probably, we will
341 // need to use "name" anyway, eventually, because some browsers do not
342 // handle jumping to ids. If we don't do that, though, we can just put the
343 // id into the span tag.
345 "id='LyXCite-" + to_utf8(html::cleanAttr(getParam("key"))) + "'";
346 xs << html::CompTag("a", attrs);
347 xs << html::StartTag("span", "class='bibitemlabel'");
349 xs << html::EndTag("span");