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));
99 ParamInfo const & InsetBibitem::findInfo(string const & /* cmdName */)
101 static ParamInfo param_info_;
102 if (param_info_.empty()) {
103 param_info_.add("label", ParamInfo::LATEX_OPTIONAL,
104 ParamInfo::HANDLING_LATEXIFY);
105 param_info_.add("key", ParamInfo::LATEX_REQUIRED,
106 ParamInfo::HANDLING_ESCAPE);
112 void InsetBibitem::doDispatch(Cursor & cur, FuncRequest & cmd)
114 switch (cmd.action()) {
116 case LFUN_INSET_MODIFY: {
117 InsetCommandParams p(BIBITEM_CODE);
118 InsetCommand::string2params("bibitem", to_utf8(cmd.argument()), p);
119 if (p.getCmdName().empty()) {
120 cur.noScreenUpdate();
123 docstring const & old_key = params()["key"];
124 setParam("label", p["label"]);
125 if (p["key"] != old_key) {
126 updateCommand(p["key"]);
127 cur.bv().buffer().changeRefsIfUnique(old_key,
128 params()["key"], CITE_CODE);
129 cur.forceBufferUpdate();
130 buffer_->invalidateBibinfoCache();
136 InsetCommand::doDispatch(cur, cmd);
142 void InsetBibitem::read(Lexer & lex)
144 InsetCommand::read(lex);
146 if (prefixIs(getParam("key"), key_prefix)) {
147 int const key = convert<int>(getParam("key").substr(key_prefix.length()));
148 key_counter = max(key_counter, key);
153 docstring InsetBibitem::bibLabel() const
155 docstring const & label = getParam("label");
156 return label.empty() ? autolabel_ : label;
160 docstring InsetBibitem::screenLabel() const
162 return getParam("key") + " [" + bibLabel() + ']';
166 int InsetBibitem::plaintext(odocstream & os, OutputParams const &) const
168 odocstringstream oss;
169 oss << '[' << bibLabel() << "] ";
171 docstring const str = oss.str();
179 docstring bibitemWidest(Buffer const & buffer, OutputParams const & runparams)
183 InsetBibitem const * bitem = 0;
185 // FIXME: this font is used unitialized for now but should be set to
186 // a proportional font. Here is what Georg Baum has to say about it:
188 bibitemWidest() is supposed to find the bibitem with the widest label in the
189 output, because that is needed as an argument of the bibliography
190 environment to determine the correct indentation. To be 100% correct we
191 would need the metrics of the font that is used in the output, but usually
192 we don't have access to these.
193 In practice, any proportional font is probably good enough, since we don't
194 need to know the final with, we only need to know the which label is the
196 Unless there is an easy way to get the metrics of the output font I suggest
197 to use a hardcoded font like "Times" or so.
199 It is very important that the result of this function is the same both with
200 and without GUI. After thinking about this it is clear that no Font
201 metrics should be used here, since these come from the gui. If we can't
202 easily get the LaTeX font metrics we should make our own poor mans font
203 metrics replacement, e.g. by hardcoding the metrics of the standard TeX
209 ParagraphList::const_iterator it = buffer.paragraphs().begin();
210 ParagraphList::const_iterator end = buffer.paragraphs().end();
212 for (; it != end; ++it) {
213 if (it->insetList().empty())
215 Inset * inset = it->insetList().begin()->inset;
216 if (inset->lyxCode() != BIBITEM_CODE)
219 bitem = static_cast<InsetBibitem const *>(inset);
220 docstring const label = bitem->bibLabel();
222 // FIXME: we can't be sure using the following that the GUI
223 // version and the command-line version will give the same
226 //int const wx = use_gui?
227 // theFontMetrics(font).width(label): label.size();
229 // So for now we just use the label size in order to be sure
230 // that GUI and no-GUI gives the same bibitem (even if that is
231 // potentially the wrong one.
232 int const wx = label.size();
242 for (size_t n = 0; n < lbl.size(); ++n) {
244 latex_lbl += runparams.encoding->latexChar(lbl[n]);
245 } catch (EncodingException & /* e */) {
246 if (runparams.dryrun) {
247 latex_lbl += "<" + _("LyX Warning: ")
248 + _("uncodable character") + " '";
249 latex_lbl += docstring(1, lbl[n]);
257 return from_ascii("99");
261 void InsetBibitem::fillWithBibKeys(BiblioInfo & keys) const
263 docstring const key = getParam("key");
264 // false means it's not BibTeX
265 BibTeXInfo keyvalmap(false);
266 keyvalmap.label(bibLabel());
267 // The indirection here is a little annoying, but
268 // DocIterator(Buffer *, Inset *)
270 InsetBibitem & me = const_cast<InsetBibitem &>(*this);
271 InsetIterator it(me);
272 DocIterator doc_it(it);
274 keyvalmap[from_ascii("ref")] = doc_it.paragraph().asString();
275 keys[key] = keyvalmap;
279 // Update the counters of this inset and of its contents
280 void InsetBibitem::updateBuffer(ParIterator const & it, UpdateType utype)
282 BufferParams const & bp = buffer().masterBuffer()->params();
283 Counters & counters = bp.documentClass().counters();
284 docstring const bibitem = from_ascii("bibitem");
285 if (counters.hasCounter(bibitem) && getParam("label").empty()) {
286 counters.step(bibitem, utype);
287 string const & lang = it.paragraph().getParLanguage(bp)->code();
288 autolabel_ = counters.theCounter(bibitem, lang);
290 autolabel_ = from_ascii("??");
295 docstring InsetBibitem::xhtml(XHTMLStream & xs, OutputParams const &) const
298 // XHTML 1.1 doesn't have the "name" attribute for <a>, so we have to use
299 // the "id" atttribute to get the document to validate. Probably, we will
300 // need to use "name" anyway, eventually, because some browsers do not
301 // handle jumping to ids. If we don't do that, though, we can just put the
302 // id into the span tag.
303 string const attrs = "id='" + to_utf8(getParam("key")) + "'";
304 xs << html::CompTag("a", attrs);
305 xs << html::StartTag("span", "class='bibitemlabel'");
307 xs << html::EndTag("span");