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"
27 #include "Paragraph.h"
28 #include "ParagraphList.h"
29 #include "TextClass.h"
31 #include "frontends/alert.h"
33 #include "support/lstrings.h"
34 #include "support/docstream.h"
35 #include "support/gettext.h"
36 #include "support/convert.h"
41 using namespace lyx::support;
46 int InsetBibitem::key_counter = 0;
47 docstring const key_prefix = from_ascii("key-");
50 InsetBibitem::InsetBibitem(InsetCommandParams const & p)
51 : InsetCommand(p, "bibitem")
53 if (getParam("key").empty())
54 setParam("key", key_prefix + convert<docstring>(++key_counter));
58 void InsetBibitem::initView()
60 updateCommand(getParam("key"));
64 void InsetBibitem::updateCommand(docstring const & new_key, bool)
66 docstring const old_key = getParam("key");
67 docstring key = new_key;
70 keys.fillWithBibKeys(&buffer());
71 vector<docstring> bibkeys = keys.getKeys();
75 if (find(bibkeys.begin(), bibkeys.end(), key) != bibkeys.end()) {
76 // generate unique label
77 key = new_key + '-' + convert<docstring>(i);
78 while (find(bibkeys.begin(), bibkeys.end(), key) != bibkeys.end()) {
80 key = new_key + '-' + convert<docstring>(i);
82 frontend::Alert::warning(_("Keys must be unique!"),
83 bformat(_("The key %1$s already exists,\n"
84 "it will be changed to %2$s."), new_key, key));
88 lyx::updateLabels(buffer());
92 ParamInfo const & InsetBibitem::findInfo(string const & /* cmdName */)
94 static ParamInfo param_info_;
95 if (param_info_.empty()) {
96 param_info_.add("label", ParamInfo::LATEX_OPTIONAL);
97 param_info_.add("key", ParamInfo::LATEX_REQUIRED);
103 void InsetBibitem::doDispatch(Cursor & cur, FuncRequest & cmd)
105 switch (cmd.action) {
107 case LFUN_INSET_MODIFY: {
108 InsetCommandParams p(BIBITEM_CODE);
109 InsetCommandMailer::string2params("bibitem", to_utf8(cmd.argument()), p);
110 if (p.getCmdName().empty()) {
114 docstring old_key = params()["key"];
115 setParam("label", p["label"]);
116 updateCommand(p["key"]);
117 if (params()["key"] != old_key)
118 cur.bv().buffer().changeRefsIfUnique(old_key,
119 params()["key"], CITE_CODE);
124 InsetCommand::doDispatch(cur, cmd);
130 void InsetBibitem::read(Lexer & lex)
132 InsetCommand::read(lex);
134 if (prefixIs(getParam("key"), key_prefix)) {
135 int const key = convert<int>(getParam("key").substr(key_prefix.length()));
136 key_counter = max(key_counter, key);
141 docstring InsetBibitem::bibLabel() const
143 docstring const & label = getParam("label");
144 return label.empty() ? autolabel_ : label;
148 docstring InsetBibitem::screenLabel() const
150 return getParam("key") + " [" + bibLabel() + ']';
154 int InsetBibitem::plaintext(odocstream & os, OutputParams const &) const
156 odocstringstream oss;
157 oss << '[' << bibLabel() << "] ";
159 docstring const str = oss.str();
167 docstring const bibitemWidest(Buffer const & buffer)
171 InsetBibitem const * bitem = 0;
173 // FIXME: this font is used unitialized for now but should be set to
174 // a proportional font. Here is what Georg Baum has to say about it:
176 bibitemWidest() is supposed to find the bibitem with the widest label in the
177 output, because that is needed as an argument of the bibliography
178 environment to dtermine the correct indentation. To be 100% correct we
179 would need the metrics of the font that is used in the output, but usually
180 we don't have access to these.
181 In practice, any proportional font is probably good enough, since we don't
182 need to know the final with, we only need to know the which label is the
184 Unless there is an easy way to get the metrics of the output font I suggest
185 to use a hardcoded font like "Times" or so.
187 It is very important that the result of this function is the same both with
188 and without GUI. After thinking about this it is clear that no Font
189 metrics should be used here, since these come from the gui. If we can't
190 easily get the LaTeX font metrics we should make our own poor mans font
191 metrics replacement, e.g. by hardcoding the metrics of the standard TeX
195 ParagraphList::const_iterator it = buffer.paragraphs().begin();
196 ParagraphList::const_iterator end = buffer.paragraphs().end();
198 for (; it != end; ++it) {
199 if (it->insetList().empty())
201 Inset * inset = it->insetList().begin()->inset;
202 if (inset->lyxCode() != BIBITEM_CODE)
205 bitem = static_cast<InsetBibitem const *>(inset);
206 docstring const label = bitem->bibLabel();
208 // FIXME: we can't be sure using the following that the GUI
209 // version and the command-line version will give the same
212 //int const wx = use_gui?
213 // theFontMetrics(font).width(label): label.size();
215 // So for now we just use the label size in order to be sure
216 // that GUI and no-GUI gives the same bibitem (even if that is
217 // potentially the wrong one.
218 int const wx = label.size();
224 if (bitem && !bitem->bibLabel().empty())
225 return bitem->bibLabel();
227 return from_ascii("99");
231 void InsetBibitem::fillWithBibKeys(BiblioInfo & keys, InsetIterator const & it) const
233 docstring const key = getParam("key");
234 BibTeXInfo keyvalmap(false);
235 keyvalmap[from_ascii("label")] = getParam("label");
236 DocIterator doc_it(it);
238 keyvalmap[from_ascii("ref")] = doc_it.paragraph().asString(false);
239 keys[key] = keyvalmap;
243 /// Update the counters of this inset and of its contents
244 void InsetBibitem::updateLabels(ParIterator const &)
246 Counters & counters = buffer().params().documentClass().counters();
247 docstring const bibitem = from_ascii("bibitem");
248 if (counters.hasCounter(bibitem) && getParam("label").empty()) {
249 counters.step(bibitem);
250 autolabel_ = counters.theCounter(bibitem);
252 autolabel_ = from_ascii("??");