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 key = new_key;
80 vector<docstring> bibkeys = buffer().masterBibInfo().getKeys();
84 if (find(bibkeys.begin(), bibkeys.end(), key) != bibkeys.end()) {
85 // generate unique label
86 key = new_key + '-' + convert<docstring>(i);
87 while (find(bibkeys.begin(), bibkeys.end(), key) != bibkeys.end()) {
89 key = new_key + '-' + convert<docstring>(i);
91 frontend::Alert::warning(_("Keys must be unique!"),
92 bformat(_("The key %1$s already exists,\n"
93 "it will be changed to %2$s."), new_key, key));
96 buffer().invalidateBibinfoCache();
100 ParamInfo const & InsetBibitem::findInfo(string const & /* cmdName */)
102 static ParamInfo param_info_;
103 if (param_info_.empty()) {
104 param_info_.add("label", ParamInfo::LATEX_OPTIONAL,
105 ParamInfo::HANDLING_LATEXIFY);
106 param_info_.add("key", ParamInfo::LATEX_REQUIRED,
107 ParamInfo::HANDLING_ESCAPE);
113 void InsetBibitem::doDispatch(Cursor & cur, FuncRequest & cmd)
115 switch (cmd.action()) {
117 case LFUN_INSET_MODIFY: {
118 InsetCommandParams p(BIBITEM_CODE);
119 InsetCommand::string2params("bibitem", to_utf8(cmd.argument()), p);
120 if (p.getCmdName().empty()) {
121 cur.noScreenUpdate();
124 docstring const & old_key = params()["key"];
125 setParam("label", p["label"]);
126 if (p["key"] != old_key) {
127 updateCommand(p["key"]);
128 cur.bv().buffer().changeRefsIfUnique(old_key,
129 params()["key"], CITE_CODE);
130 cur.forceBufferUpdate();
131 buffer().invalidateBibinfoCache();
137 InsetCommand::doDispatch(cur, cmd);
143 void InsetBibitem::read(Lexer & lex)
145 InsetCommand::read(lex);
147 if (prefixIs(getParam("key"), key_prefix)) {
148 int const key = convert<int>(getParam("key").substr(key_prefix.length()));
149 key_counter = max(key_counter, key);
154 docstring InsetBibitem::bibLabel() const
156 docstring const & label = getParam("label");
157 return label.empty() ? autolabel_ : label;
161 docstring InsetBibitem::screenLabel() const
163 return getParam("key") + " [" + bibLabel() + ']';
167 int InsetBibitem::plaintext(odocstream & os, OutputParams const &) const
169 odocstringstream oss;
170 oss << '[' << bibLabel() << "] ";
172 docstring const str = oss.str();
180 docstring bibitemWidest(Buffer const & buffer, OutputParams const & runparams)
184 InsetBibitem const * bitem = 0;
186 // FIXME: this font is used unitialized for now but should be set to
187 // a proportional font. Here is what Georg Baum has to say about it:
189 bibitemWidest() is supposed to find the bibitem with the widest label in the
190 output, because that is needed as an argument of the bibliography
191 environment to determine the correct indentation. To be 100% correct we
192 would need the metrics of the font that is used in the output, but usually
193 we don't have access to these.
194 In practice, any proportional font is probably good enough, since we don't
195 need to know the final with, we only need to know the which label is the
197 Unless there is an easy way to get the metrics of the output font I suggest
198 to use a hardcoded font like "Times" or so.
200 It is very important that the result of this function is the same both with
201 and without GUI. After thinking about this it is clear that no Font
202 metrics should be used here, since these come from the gui. If we can't
203 easily get the LaTeX font metrics we should make our own poor mans font
204 metrics replacement, e.g. by hardcoding the metrics of the standard TeX
210 ParagraphList::const_iterator it = buffer.paragraphs().begin();
211 ParagraphList::const_iterator end = buffer.paragraphs().end();
213 for (; it != end; ++it) {
214 if (it->insetList().empty())
216 Inset * inset = it->insetList().begin()->inset;
217 if (inset->lyxCode() != BIBITEM_CODE)
220 bitem = static_cast<InsetBibitem const *>(inset);
221 docstring const label = bitem->bibLabel();
223 // FIXME: we can't be sure using the following that the GUI
224 // version and the command-line version will give the same
227 //int const wx = use_gui?
228 // theFontMetrics(font).width(label): label.size();
230 // So for now we just use the label size in order to be sure
231 // that GUI and no-GUI gives the same bibitem (even if that is
232 // potentially the wrong one.
233 int const wx = label.size();
243 for (size_t n = 0; n < lbl.size(); ++n) {
245 latex_lbl += runparams.encoding->latexChar(lbl[n]);
246 } catch (EncodingException & /* e */) {
247 if (runparams.dryrun) {
248 latex_lbl += "<" + _("LyX Warning: ")
249 + _("uncodable character") + " '";
250 latex_lbl += docstring(1, lbl[n]);
258 return from_ascii("99");
262 void InsetBibitem::fillWithBibKeys(BiblioInfo & keys, InsetIterator const & it) const
264 docstring const key = getParam("key");
265 BibTeXInfo keyvalmap(false);
266 keyvalmap.label(bibLabel());
267 DocIterator doc_it(it);
269 keyvalmap[from_ascii("ref")] = doc_it.paragraph().asString();
270 keys[key] = keyvalmap;
274 // Update the counters of this inset and of its contents
275 void InsetBibitem::updateBuffer(ParIterator const & it, UpdateType utype)
277 BufferParams const & bp = buffer().masterBuffer()->params();
278 Counters & counters = bp.documentClass().counters();
279 docstring const bibitem = from_ascii("bibitem");
280 if (counters.hasCounter(bibitem) && getParam("label").empty()) {
281 counters.step(bibitem, utype);
282 string const & lang = it.paragraph().getParLanguage(bp)->code();
283 autolabel_ = counters.theCounter(bibitem, lang);
285 autolabel_ = from_ascii("??");
290 docstring InsetBibitem::xhtml(XHTMLStream & xs, OutputParams const &) const
293 // XHTML 1.1 doesn't have the "name" attribute for <a>, so we have to use
294 // the "id" atttribute to get the document to validate. Probably, we will
295 // need to use "name" anyway, eventually, because some browsers do not
296 // handle jumping to ids. If we don't do that, though, we can just put the
297 // id into the span tag.
298 string const attrs = "id='" + to_utf8(getParam("key")) + "'";
299 xs << html::CompTag("a", attrs);
300 xs << html::StartTag("span", "class='bibitemlabel'");
302 xs << html::EndTag("span");