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"
18 #include "buffer_funcs.h"
19 #include "BufferParams.h"
20 #include "BufferView.h"
22 #include "DispatchResult.h"
24 #include "FuncRequest.h"
25 #include "InsetIterator.h"
26 #include "InsetList.h"
29 #include "output_xhtml.h"
30 #include "OutputParams.h"
31 #include "Paragraph.h"
32 #include "ParagraphList.h"
33 #include "ParIterator.h"
34 #include "TextClass.h"
36 #include "frontends/alert.h"
38 #include "support/convert.h"
39 #include "support/debug.h"
40 #include "support/docstream.h"
41 #include "support/gettext.h"
42 #include "support/lstrings.h"
45 using namespace lyx::support;
50 int InsetBibitem::key_counter = 0;
51 docstring const key_prefix = from_ascii("key-");
54 InsetBibitem::InsetBibitem(Buffer * buf, InsetCommandParams const & p)
55 : InsetCommand(buf, p, "bibitem")
57 buffer_->invalidateBibinfoCache();
58 if (getParam("key").empty())
59 setParam("key", key_prefix + convert<docstring>(++key_counter));
63 InsetBibitem::~InsetBibitem()
66 buffer_->invalidateBibinfoCache();
70 void InsetBibitem::initView()
72 updateCommand(getParam("key"));
76 void InsetBibitem::updateCommand(docstring const & new_key, bool)
78 docstring const old_key = getParam("key");
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));
98 buffer().updateBuffer();
102 ParamInfo const & InsetBibitem::findInfo(string const & /* cmdName */)
104 static ParamInfo param_info_;
105 if (param_info_.empty()) {
106 param_info_.add("label", ParamInfo::LATEX_OPTIONAL,
107 ParamInfo::HANDLING_LATEXIFY);
108 param_info_.add("key", ParamInfo::LATEX_REQUIRED,
109 ParamInfo::HANDLING_ESCAPE);
115 void InsetBibitem::doDispatch(Cursor & cur, FuncRequest & cmd)
117 switch (cmd.action) {
119 case LFUN_INSET_MODIFY: {
120 InsetCommandParams p(BIBITEM_CODE);
121 InsetCommand::string2params("bibitem", to_utf8(cmd.argument()), p);
122 if (p.getCmdName().empty()) {
126 docstring const & old_key = params()["key"];
127 setParam("label", p["label"]);
128 if (p["key"] != old_key) {
129 updateCommand(p["key"]);
130 cur.bv().buffer().changeRefsIfUnique(old_key,
131 params()["key"], CITE_CODE);
133 buffer_->invalidateBibinfoCache();
138 InsetCommand::doDispatch(cur, cmd);
144 void InsetBibitem::read(Lexer & lex)
146 InsetCommand::read(lex);
148 if (prefixIs(getParam("key"), key_prefix)) {
149 int const key = convert<int>(getParam("key").substr(key_prefix.length()));
150 key_counter = max(key_counter, key);
155 docstring InsetBibitem::bibLabel() const
157 docstring const & label = getParam("label");
158 return label.empty() ? autolabel_ : label;
162 docstring InsetBibitem::screenLabel() const
164 return getParam("key") + " [" + bibLabel() + ']';
168 int InsetBibitem::plaintext(odocstream & os, OutputParams const &) const
170 odocstringstream oss;
171 oss << '[' << bibLabel() << "] ";
173 docstring const str = oss.str();
181 docstring bibitemWidest(Buffer const & buffer, OutputParams const & runparams)
185 InsetBibitem const * bitem = 0;
187 // FIXME: this font is used unitialized for now but should be set to
188 // a proportional font. Here is what Georg Baum has to say about it:
190 bibitemWidest() is supposed to find the bibitem with the widest label in the
191 output, because that is needed as an argument of the bibliography
192 environment to determine the correct indentation. To be 100% correct we
193 would need the metrics of the font that is used in the output, but usually
194 we don't have access to these.
195 In practice, any proportional font is probably good enough, since we don't
196 need to know the final with, we only need to know the which label is the
198 Unless there is an easy way to get the metrics of the output font I suggest
199 to use a hardcoded font like "Times" or so.
201 It is very important that the result of this function is the same both with
202 and without GUI. After thinking about this it is clear that no Font
203 metrics should be used here, since these come from the gui. If we can't
204 easily get the LaTeX font metrics we should make our own poor mans font
205 metrics replacement, e.g. by hardcoding the metrics of the standard TeX
211 ParagraphList::const_iterator it = buffer.paragraphs().begin();
212 ParagraphList::const_iterator end = buffer.paragraphs().end();
214 for (; it != end; ++it) {
215 if (it->insetList().empty())
217 Inset * inset = it->insetList().begin()->inset;
218 if (inset->lyxCode() != BIBITEM_CODE)
221 bitem = static_cast<InsetBibitem const *>(inset);
222 docstring const label = bitem->bibLabel();
224 // FIXME: we can't be sure using the following that the GUI
225 // version and the command-line version will give the same
228 //int const wx = use_gui?
229 // theFontMetrics(font).width(label): label.size();
231 // So for now we just use the label size in order to be sure
232 // that GUI and no-GUI gives the same bibitem (even if that is
233 // potentially the wrong one.
234 int const wx = label.size();
244 for (size_t n = 0; n < lbl.size(); ++n) {
246 latex_lbl += runparams.encoding->latexChar(lbl[n]);
247 } catch (EncodingException & /* e */) {
248 if (runparams.dryrun) {
249 latex_lbl += "<" + _("LyX Warning: ")
250 + _("uncodable character") + " '";
251 latex_lbl += docstring(1, lbl[n]);
259 return from_ascii("99");
263 void InsetBibitem::fillWithBibKeys(BiblioInfo & keys, InsetIterator const & it) const
265 docstring const key = getParam("key");
266 BibTeXInfo keyvalmap(false);
267 keyvalmap.label(bibLabel());
268 DocIterator doc_it(it);
270 keyvalmap[from_ascii("ref")] = doc_it.paragraph().asString();
271 keys[key] = keyvalmap;
275 // Update the counters of this inset and of its contents
276 void InsetBibitem::updateBuffer(ParIterator const & it, UpdateType utype)
278 BufferParams const & bp = buffer().masterBuffer()->params();
279 Counters & counters = bp.documentClass().counters();
280 docstring const bibitem = from_ascii("bibitem");
281 if (counters.hasCounter(bibitem) && getParam("label").empty()) {
282 counters.step(bibitem, utype);
283 string const & lang = it.paragraph().getParLanguage(bp)->code();
284 autolabel_ = counters.theCounter(bibitem, lang);
286 autolabel_ = from_ascii("??");
291 docstring InsetBibitem::xhtml(XHTMLStream & xs, OutputParams const &) const
294 // XHTML 1.1 doesn't have the "name" attribute for <a>, so we have to use
295 // the "id" atttribute to get the document to validate. Probably, we will
296 // need to use "name" anyway, eventually, because some browsers do not
297 // handle jumping to ids. If we don't do that, though, we can just put the
298 // id into the span tag.
299 string const attrs = "id='" + to_utf8(getParam("key")) + "'";
300 xs << html::CompTag("a", attrs);
301 xs << html::StartTag("span", "class='bibitemlabel'");
303 xs << html::EndTag("span");