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.
13 #include "InsetBibitem.h"
15 #include "BiblioInfo.h"
17 #include "buffer_funcs.h"
18 #include "BufferParams.h"
19 #include "BufferView.h"
21 #include "DispatchResult.h"
22 #include "FuncRequest.h"
23 #include "InsetIterator.h"
24 #include "InsetList.h"
26 #include "Paragraph.h"
27 #include "ParagraphList.h"
28 #include "TextClass.h"
30 #include "frontends/alert.h"
32 #include "support/lstrings.h"
33 #include "support/docstream.h"
34 #include "support/gettext.h"
35 #include "support/convert.h"
40 using namespace lyx::support;
45 int InsetBibitem::key_counter = 0;
46 docstring const key_prefix = from_ascii("key-");
49 InsetBibitem::InsetBibitem(InsetCommandParams const & p)
50 : InsetCommand(p, "bibitem")
52 if (getParam("key").empty())
53 setParam("key", key_prefix + convert<docstring>(++key_counter));
57 void InsetBibitem::initView()
59 updateCommand(getParam("key"));
63 void InsetBibitem::updateCommand(docstring const & new_key, bool)
65 docstring const old_key = getParam("key");
66 docstring key = new_key;
69 keys.fillWithBibKeys(&buffer());
70 vector<docstring> bibkeys = keys.getKeys();
74 if (find(bibkeys.begin(), bibkeys.end(), key) != bibkeys.end()) {
75 // generate unique label
76 key = new_key + '-' + convert<docstring>(i);
77 while (find(bibkeys.begin(), bibkeys.end(), key) != bibkeys.end()) {
79 key = new_key + '-' + convert<docstring>(i);
81 frontend::Alert::warning(_("Keys must be unique!"),
82 bformat(_("The key %1$s already exists,\n"
83 "it will be changed to %2$s."), new_key, key));
87 lyx::updateLabels(buffer());
91 ParamInfo const & InsetBibitem::findInfo(string const & /* cmdName */)
93 static ParamInfo param_info_;
94 if (param_info_.empty()) {
95 param_info_.add("label", ParamInfo::LATEX_OPTIONAL);
96 param_info_.add("key", ParamInfo::LATEX_REQUIRED);
102 void InsetBibitem::doDispatch(Cursor & cur, FuncRequest & cmd)
104 switch (cmd.action) {
106 case LFUN_INSET_MODIFY: {
107 InsetCommandParams p(BIBITEM_CODE);
108 InsetCommandMailer::string2params("bibitem", to_utf8(cmd.argument()), p);
109 if (p.getCmdName().empty()) {
113 docstring old_key = params()["key"];
114 setParam("label", p["label"]);
115 updateCommand(p["key"]);
116 if (params()["key"] != old_key)
117 cur.bv().buffer().changeRefsIfUnique(old_key,
118 params()["key"], CITE_CODE);
123 InsetCommand::doDispatch(cur, cmd);
129 void InsetBibitem::read(Lexer & lex)
131 InsetCommand::read(lex);
133 if (prefixIs(getParam("key"), key_prefix)) {
134 int const key = convert<int>(getParam("key").substr(key_prefix.length()));
135 key_counter = max(key_counter, key);
140 docstring InsetBibitem::bibLabel() const
142 docstring const & label = getParam("label");
143 return label.empty() ? autolabel_ : label;
147 docstring InsetBibitem::screenLabel() const
149 return getParam("key") + " [" + bibLabel() + ']';
153 int InsetBibitem::plaintext(odocstream & os, OutputParams const &) const
155 odocstringstream oss;
156 oss << '[' << bibLabel() << "] ";
158 docstring const str = oss.str();
166 docstring const bibitemWidest(Buffer const & buffer)
170 InsetBibitem const * bitem = 0;
172 // FIXME: this font is used unitialized for now but should be set to
173 // a proportional font. Here is what Georg Baum has to say about it:
175 bibitemWidest() is supposed to find the bibitem with the widest label in the
176 output, because that is needed as an argument of the bibliography
177 environment to dtermine the correct indentation. To be 100% correct we
178 would need the metrics of the font that is used in the output, but usually
179 we don't have access to these.
180 In practice, any proportional font is probably good enough, since we don't
181 need to know the final with, we only need to know the which label is the
183 Unless there is an easy way to get the metrics of the output font I suggest
184 to use a hardcoded font like "Times" or so.
186 It is very important that the result of this function is the same both with
187 and without GUI. After thinking about this it is clear that no Font
188 metrics should be used here, since these come from the gui. If we can't
189 easily get the LaTeX font metrics we should make our own poor mans font
190 metrics replacement, e.g. by hardcoding the metrics of the standard TeX
194 ParagraphList::const_iterator it = buffer.paragraphs().begin();
195 ParagraphList::const_iterator end = buffer.paragraphs().end();
197 for (; it != end; ++it) {
198 if (it->insetList().empty())
200 Inset * inset = it->insetList().begin()->inset;
201 if (inset->lyxCode() != BIBITEM_CODE)
204 bitem = static_cast<InsetBibitem const *>(inset);
205 docstring const label = bitem->bibLabel();
207 // FIXME: we can't be sure using the following that the GUI
208 // version and the command-line version will give the same
211 //int const wx = use_gui?
212 // theFontMetrics(font).width(label): label.size();
214 // So for now we just use the label size in order to be sure
215 // that GUI and no-GUI gives the same bibitem (even if that is
216 // potentially the wrong one.
217 int const wx = label.size();
223 if (bitem && !bitem->bibLabel().empty())
224 return bitem->bibLabel();
226 return from_ascii("99");
230 void InsetBibitem::fillWithBibKeys(BiblioInfo & keys, InsetIterator const & it) const
232 docstring const key = getParam("key");
233 BibTeXInfo keyvalmap(false);
234 keyvalmap[from_ascii("label")] = getParam("label");
235 DocIterator doc_it(it);
237 keyvalmap[from_ascii("ref")] = doc_it.paragraph().asString(false);
238 keys[key] = keyvalmap;
242 /// Update the counters of this inset and of its contents
243 void InsetBibitem::updateLabels(ParIterator const &)
245 Counters & counters = buffer().params().documentClass().counters();
246 docstring const bibitem = from_ascii("bibitem");
247 if (counters.hasCounter(bibitem) && getParam("label").empty()) {
248 counters.step(bibitem);
249 autolabel_ = counters.theCounter(bibitem);
251 autolabel_ = from_ascii("??");