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, InsetIterator const & it) const
263 docstring const key = getParam("key");
264 BibTeXInfo keyvalmap(false);
265 keyvalmap.label(bibLabel());
266 DocIterator doc_it(it);
268 keyvalmap[from_ascii("ref")] = doc_it.paragraph().asString();
269 keys[key] = keyvalmap;
273 // Update the counters of this inset and of its contents
274 void InsetBibitem::updateBuffer(ParIterator const & it, UpdateType utype)
276 BufferParams const & bp = buffer().masterBuffer()->params();
277 Counters & counters = bp.documentClass().counters();
278 docstring const bibitem = from_ascii("bibitem");
279 if (counters.hasCounter(bibitem) && getParam("label").empty()) {
280 counters.step(bibitem, utype);
281 string const & lang = it.paragraph().getParLanguage(bp)->code();
282 autolabel_ = counters.theCounter(bibitem, lang);
284 autolabel_ = from_ascii("??");
289 docstring InsetBibitem::xhtml(XHTMLStream & xs, OutputParams const &) const
292 // XHTML 1.1 doesn't have the "name" attribute for <a>, so we have to use
293 // the "id" atttribute to get the document to validate. Probably, we will
294 // need to use "name" anyway, eventually, because some browsers do not
295 // handle jumping to ids. If we don't do that, though, we can just put the
296 // id into the span tag.
297 string const attrs = "id='" + to_utf8(getParam("key")) + "'";
298 xs << html::CompTag("a", attrs);
299 xs << html::StartTag("span", "class='bibitemlabel'");
301 xs << html::EndTag("span");