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"
44 #include "support/mutex.h"
47 using namespace lyx::support;
52 int InsetBibitem::key_counter = 0;
53 static Mutex counter_mutex;
54 docstring const key_prefix = from_ascii("key-");
57 InsetBibitem::InsetBibitem(Buffer * buf, InsetCommandParams const & p)
58 : InsetCommand(buf, p)
60 buffer().invalidateBibinfoCache();
61 if (getParam("key").empty()) {
62 Mutex::Locker lock(&counter_mutex);
63 setParam("key", key_prefix + convert<docstring>(++key_counter));
68 InsetBibitem::~InsetBibitem()
71 buffer().invalidateBibinfoCache();
75 void InsetBibitem::initView()
77 updateCommand(getParam("key"));
81 void InsetBibitem::updateCommand(docstring const & new_key, bool)
83 docstring key = new_key;
84 vector<docstring> bibkeys = buffer().masterBibInfo().getKeys();
86 if (find(bibkeys.begin(), bibkeys.end(), key) != bibkeys.end()) {
88 // generate unique label
89 key = new_key + '-' + convert<docstring>(i);
90 while (find(bibkeys.begin(), bibkeys.end(), key) != bibkeys.end()) {
92 key = new_key + '-' + convert<docstring>(i);
94 frontend::Alert::warning(_("Keys must be unique!"),
95 bformat(_("The key %1$s already exists,\n"
96 "it will be changed to %2$s."), new_key, key));
99 buffer().invalidateBibinfoCache();
103 ParamInfo const & InsetBibitem::findInfo(string const & /* cmdName */)
105 static ParamInfo param_info_;
106 if (param_info_.empty()) {
107 param_info_.add("label", ParamInfo::LATEX_OPTIONAL,
108 ParamInfo::HANDLING_LATEXIFY);
109 param_info_.add("key", ParamInfo::LATEX_REQUIRED,
110 ParamInfo::HANDLING_ESCAPE);
111 param_info_.add("literal", ParamInfo::LYX_INTERNAL);
117 void InsetBibitem::doDispatch(Cursor & cur, FuncRequest & cmd)
119 switch (cmd.action()) {
121 case LFUN_INSET_MODIFY: {
122 InsetCommandParams p(BIBITEM_CODE);
123 InsetCommand::string2params(to_utf8(cmd.argument()), p);
124 if (p.getCmdName().empty()) {
125 cur.noScreenUpdate();
131 docstring const & old_key = params()["key"];
132 docstring const & old_label = params()["label"];
133 docstring const & old_literal = params()["literal"];
134 docstring label = p["label"];
135 docstring literal = p["literal"];
137 if (old_label != label) {
139 cur.forceBufferUpdate();
140 buffer().invalidateBibinfoCache();
142 setParam("label", p["label"]);
144 if (old_literal != literal) {
145 p["literal"] = literal;
146 cur.forceBufferUpdate();
147 buffer().invalidateBibinfoCache();
149 setParam("literal", p["literal"]);
151 if (p["key"] != old_key) {
152 updateCommand(p["key"]);
153 cur.bv().buffer().changeRefsIfUnique(old_key, params()["key"]);
154 cur.forceBufferUpdate();
155 buffer().invalidateBibinfoCache();
161 InsetCommand::doDispatch(cur, cmd);
167 void InsetBibitem::read(Lexer & lex)
169 InsetCommand::read(lex);
171 if (prefixIs(getParam("key"), key_prefix)) {
172 int const key = convert<int>(getParam("key").substr(key_prefix.length()));
173 Mutex::Locker lock(&counter_mutex);
174 key_counter = max(key_counter, key);
179 docstring InsetBibitem::bibLabel() const
181 BufferParams const & bp = buffer().masterBuffer()->params();
182 if (bp.citeEngineType() == ENGINE_TYPE_NUMERICAL)
184 docstring const & label = getParam("label");
185 return label.empty() ? autolabel_ : label;
189 docstring InsetBibitem::screenLabel() const
191 return getParam("key") + " [" + bibLabel() + ']';
195 int InsetBibitem::plaintext(odocstringstream & os,
196 OutputParams const &, size_t) const
198 odocstringstream oss;
199 oss << '[' << bibLabel() << "] ";
201 docstring const str = oss.str();
209 docstring bibitemWidest(Buffer const & buffer, OutputParams const & runparams)
211 BufferParams const & bp = buffer.masterBuffer()->params();
212 if (bp.citeEngineType() == ENGINE_TYPE_NUMERICAL)
213 return from_ascii("99");
217 InsetBibitem const * bitem = 0;
219 // FIXME: this font is used unitialized for now but should be set to
220 // a proportional font. Here is what Georg Baum has to say about it:
222 bibitemWidest() is supposed to find the bibitem with the widest label in the
223 output, because that is needed as an argument of the bibliography
224 environment to determine the correct indentation. To be 100% correct we
225 would need the metrics of the font that is used in the output, but usually
226 we don't have access to these.
227 In practice, any proportional font is probably good enough, since we don't
228 need to know the final with, we only need to know the which label is the
230 Unless there is an easy way to get the metrics of the output font I suggest
231 to use a hardcoded font like "Times" or so.
233 It is very important that the result of this function is the same both with
234 and without GUI. After thinking about this it is clear that no Font
235 metrics should be used here, since these come from the gui. If we can't
236 easily get the LaTeX font metrics we should make our own poor mans font
237 metrics replacement, e.g. by hardcoding the metrics of the standard TeX
243 ParagraphList::const_iterator it = buffer.paragraphs().begin();
244 ParagraphList::const_iterator end = buffer.paragraphs().end();
246 for (; it != end; ++it) {
247 if (it->insetList().empty())
249 Inset * inset = it->insetList().begin()->inset;
250 if (inset->lyxCode() != BIBITEM_CODE)
253 bitem = static_cast<InsetBibitem const *>(inset);
254 docstring const label = bitem->bibLabel();
256 // FIXME: we can't be sure using the following that the GUI
257 // version and the command-line version will give the same
260 //int const wx = use_gui?
261 // theFontMetrics(font).width(label): label.size();
263 // So for now we just use the label size in order to be sure
264 // that GUI and no-GUI gives the same bibitem (even if that is
265 // potentially the wrong one.
266 int const wx = label.size();
275 InsetCommandParams p(BIBITEM_CODE);
276 return p.prepareCommand(runparams, lbl, ParamInfo::HANDLING_LATEXIFY);
279 return from_ascii("99");
283 void InsetBibitem::collectBibKeys(InsetIterator const & it) const
285 docstring const key = getParam("key");
286 docstring const label = getParam("label");
287 BibTeXInfo keyvalmap(false);
289 keyvalmap.label(label);
291 BufferParams const & bp = buffer().masterBuffer()->params();
292 Counters & counters = bp.documentClass().counters();
293 docstring const bibitem = from_ascii("bibitem");
294 if (bp.citeEngineType() == ENGINE_TYPE_NUMERICAL || getParam("label").empty()) {
295 if (counters.hasCounter(bibitem))
296 counters.step(bibitem, InternalUpdate);
297 string const & lang = it.paragraph().getParLanguage(bp)->code();
298 keyvalmap.setCiteNumber(counters.theCounter(bibitem, lang));
301 DocIterator doc_it(it);
303 keyvalmap[from_ascii("ref")] = doc_it.paragraph().asString(
304 AS_STR_INSETS | AS_STR_SKIPDELETE);
305 buffer().addBibTeXInfo(key, keyvalmap);
309 // Update the counters of this inset and of its contents
310 void InsetBibitem::updateBuffer(ParIterator const & it, UpdateType utype)
312 BufferParams const & bp = buffer().masterBuffer()->params();
313 Counters & counters = bp.documentClass().counters();
314 docstring const bibitem = from_ascii("bibitem");
315 if (bp.citeEngineType() == ENGINE_TYPE_NUMERICAL || getParam("label").empty()) {
316 if (counters.hasCounter(bibitem))
317 counters.step(bibitem, utype);
318 string const & lang = it.paragraph().getParLanguage(bp)->code();
319 autolabel_ = counters.theCounter(bibitem, lang);
321 autolabel_ = from_ascii("??");
326 docstring InsetBibitem::xhtml(XHTMLStream & xs, OutputParams const &) const
329 // XHTML 1.1 doesn't have the "name" attribute for <a>, so we have to use
330 // the "id" atttribute to get the document to validate. Probably, we will
331 // need to use "name" anyway, eventually, because some browsers do not
332 // handle jumping to ids. If we don't do that, though, we can just put the
333 // id into the span tag.
335 "id='LyXCite-" + to_utf8(html::cleanAttr(getParam("key"))) + "'";
336 xs << html::CompTag("a", attrs);
337 xs << html::StartTag("span", "class='bibitemlabel'");
339 xs << html::EndTag("span");