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"
23 #include "FuncRequest.h"
24 #include "InsetIterator.h"
25 #include "InsetList.h"
28 #include "output_xhtml.h"
29 #include "Paragraph.h"
30 #include "ParagraphList.h"
31 #include "ParIterator.h"
32 #include "TextClass.h"
34 #include "frontends/alert.h"
36 #include "support/convert.h"
37 #include "support/docstream.h"
38 #include "support/gettext.h"
39 #include "support/lstrings.h"
42 using namespace lyx::support;
47 int InsetBibitem::key_counter = 0;
48 docstring const key_prefix = from_ascii("key-");
51 InsetBibitem::InsetBibitem(Buffer * buf, InsetCommandParams const & p)
52 : InsetCommand(buf, p, "bibitem")
54 buffer_->invalidateBibinfoCache();
55 if (getParam("key").empty())
56 setParam("key", key_prefix + convert<docstring>(++key_counter));
60 InsetBibitem::~InsetBibitem()
63 buffer_->invalidateBibinfoCache();
67 void InsetBibitem::initView()
69 updateCommand(getParam("key"));
73 void InsetBibitem::updateCommand(docstring const & new_key, bool)
75 docstring const old_key = getParam("key");
76 docstring key = new_key;
78 vector<docstring> bibkeys = buffer().masterBibInfo().getKeys();
82 if (find(bibkeys.begin(), bibkeys.end(), key) != bibkeys.end()) {
83 // generate unique label
84 key = new_key + '-' + convert<docstring>(i);
85 while (find(bibkeys.begin(), bibkeys.end(), key) != bibkeys.end()) {
87 key = new_key + '-' + convert<docstring>(i);
89 frontend::Alert::warning(_("Keys must be unique!"),
90 bformat(_("The key %1$s already exists,\n"
91 "it will be changed to %2$s."), new_key, key));
95 buffer().updateLabels();
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 param_info_.add("key", ParamInfo::LATEX_REQUIRED);
110 void InsetBibitem::doDispatch(Cursor & cur, FuncRequest & cmd)
112 switch (cmd.action) {
114 case LFUN_INSET_MODIFY: {
115 InsetCommandParams p(BIBITEM_CODE);
116 InsetCommand::string2params("bibitem", to_utf8(cmd.argument()), p);
117 if (p.getCmdName().empty()) {
121 docstring const & old_key = params()["key"];
122 setParam("label", p["label"]);
123 if (p["key"] != old_key) {
124 updateCommand(p["key"]);
125 cur.bv().buffer().changeRefsIfUnique(old_key,
126 params()["key"], CITE_CODE);
128 buffer_->invalidateBibinfoCache();
133 InsetCommand::doDispatch(cur, cmd);
139 void InsetBibitem::read(Lexer & lex)
141 InsetCommand::read(lex);
143 if (prefixIs(getParam("key"), key_prefix)) {
144 int const key = convert<int>(getParam("key").substr(key_prefix.length()));
145 key_counter = max(key_counter, key);
150 docstring InsetBibitem::bibLabel() const
152 docstring const & label = getParam("label");
153 return label.empty() ? autolabel_ : label;
157 docstring InsetBibitem::screenLabel() const
159 return getParam("key") + " [" + bibLabel() + ']';
163 int InsetBibitem::plaintext(odocstream & os, OutputParams const &) const
165 odocstringstream oss;
166 oss << '[' << bibLabel() << "] ";
168 docstring const str = oss.str();
176 docstring bibitemWidest(Buffer const & buffer)
180 InsetBibitem const * bitem = 0;
182 // FIXME: this font is used unitialized for now but should be set to
183 // a proportional font. Here is what Georg Baum has to say about it:
185 bibitemWidest() is supposed to find the bibitem with the widest label in the
186 output, because that is needed as an argument of the bibliography
187 environment to determine the correct indentation. To be 100% correct we
188 would need the metrics of the font that is used in the output, but usually
189 we don't have access to these.
190 In practice, any proportional font is probably good enough, since we don't
191 need to know the final with, we only need to know the which label is the
193 Unless there is an easy way to get the metrics of the output font I suggest
194 to use a hardcoded font like "Times" or so.
196 It is very important that the result of this function is the same both with
197 and without GUI. After thinking about this it is clear that no Font
198 metrics should be used here, since these come from the gui. If we can't
199 easily get the LaTeX font metrics we should make our own poor mans font
200 metrics replacement, e.g. by hardcoding the metrics of the standard TeX
206 ParagraphList::const_iterator it = buffer.paragraphs().begin();
207 ParagraphList::const_iterator end = buffer.paragraphs().end();
209 for (; it != end; ++it) {
210 if (it->insetList().empty())
212 Inset * inset = it->insetList().begin()->inset;
213 if (inset->lyxCode() != BIBITEM_CODE)
216 bitem = static_cast<InsetBibitem const *>(inset);
217 docstring const label = bitem->bibLabel();
219 // FIXME: we can't be sure using the following that the GUI
220 // version and the command-line version will give the same
223 //int const wx = use_gui?
224 // theFontMetrics(font).width(label): label.size();
226 // So for now we just use the label size in order to be sure
227 // that GUI and no-GUI gives the same bibitem (even if that is
228 // potentially the wrong one.
229 int const wx = label.size();
240 return from_ascii("99");
244 void InsetBibitem::fillWithBibKeys(BiblioInfo & keys, InsetIterator const & it) const
246 docstring const key = getParam("key");
247 BibTeXInfo keyvalmap(false);
248 keyvalmap.label(bibLabel());
249 DocIterator doc_it(it);
251 keyvalmap[from_ascii("ref")] = doc_it.paragraph().asString();
252 keys[key] = keyvalmap;
256 // Update the counters of this inset and of its contents
257 void InsetBibitem::updateLabels(ParIterator const & it, UpdateType utype)
259 BufferParams const & bp = buffer().masterBuffer()->params();
260 Counters & counters = bp.documentClass().counters();
261 docstring const bibitem = from_ascii("bibitem");
262 if (counters.hasCounter(bibitem) && getParam("label").empty()) {
263 counters.step(bibitem, utype);
264 string const & lang = it.paragraph().getParLanguage(bp)->code();
265 autolabel_ = counters.theCounter(bibitem, lang);
267 autolabel_ = from_ascii("??");
272 docstring InsetBibitem::xhtml(XHTMLStream & xs, OutputParams const &) const
275 // XHTML 1.1 doesn't have the "name" attribute for <a>, so we have to use
276 // the "id" atttribute to get the document to validate. Probably, we will
277 // need to use "name" anyway, eventually, because some browsers do not
278 // handle jumping to ids. If we don't do that, though, we can just put the
279 // id into the span tag.
280 string const attrs = "id='" + to_utf8(getParam("key")) + "'";
281 xs << html::CompTag("a", attrs);
282 xs << html::StartTag("span", "class='bibitemlabel'");
284 xs << html::EndTag("span");