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"
39 using namespace lyx::support;
44 int InsetBibitem::key_counter = 0;
45 docstring const key_prefix = from_ascii("key-");
48 InsetBibitem::InsetBibitem(Buffer const & buf, InsetCommandParams const & p)
49 : InsetCommand(p, "bibitem")
51 Inset::setBuffer(const_cast<Buffer &>(buf));
52 buffer_->invalidateBibinfoCache();
53 if (getParam("key").empty())
54 setParam("key", key_prefix + convert<docstring>(++key_counter));
58 InsetBibitem::~InsetBibitem()
61 buffer_->invalidateBibinfoCache();
65 void InsetBibitem::initView()
67 updateCommand(getParam("key"));
71 void InsetBibitem::updateCommand(docstring const & new_key, bool)
73 docstring const old_key = getParam("key");
74 docstring key = new_key;
76 vector<docstring> bibkeys = buffer().masterBibInfo().getKeys();
80 if (find(bibkeys.begin(), bibkeys.end(), key) != bibkeys.end()) {
81 // generate unique label
82 key = new_key + '-' + convert<docstring>(i);
83 while (find(bibkeys.begin(), bibkeys.end(), key) != bibkeys.end()) {
85 key = new_key + '-' + convert<docstring>(i);
87 frontend::Alert::warning(_("Keys must be unique!"),
88 bformat(_("The key %1$s already exists,\n"
89 "it will be changed to %2$s."), new_key, key));
93 lyx::updateLabels(buffer());
97 ParamInfo const & InsetBibitem::findInfo(string const & /* cmdName */)
99 static ParamInfo param_info_;
100 if (param_info_.empty()) {
101 param_info_.add("label", ParamInfo::LATEX_OPTIONAL);
102 param_info_.add("key", ParamInfo::LATEX_REQUIRED);
108 void InsetBibitem::doDispatch(Cursor & cur, FuncRequest & cmd)
110 switch (cmd.action) {
112 case LFUN_INSET_MODIFY: {
113 InsetCommandParams p(BIBITEM_CODE);
114 InsetCommand::string2params("bibitem", to_utf8(cmd.argument()), p);
115 if (p.getCmdName().empty()) {
119 docstring old_key = params()["key"];
120 setParam("label", p["label"]);
121 updateCommand(p["key"]);
122 if (params()["key"] != old_key)
123 cur.bv().buffer().changeRefsIfUnique(old_key,
124 params()["key"], CITE_CODE);
129 InsetCommand::doDispatch(cur, cmd);
135 void InsetBibitem::read(Lexer & lex)
137 InsetCommand::read(lex);
139 if (prefixIs(getParam("key"), key_prefix)) {
140 int const key = convert<int>(getParam("key").substr(key_prefix.length()));
141 key_counter = max(key_counter, key);
146 docstring InsetBibitem::bibLabel() const
148 docstring const & label = getParam("label");
149 return label.empty() ? autolabel_ : label;
153 docstring InsetBibitem::screenLabel() const
155 return getParam("key") + " [" + bibLabel() + ']';
159 int InsetBibitem::plaintext(odocstream & os, OutputParams const &) const
161 odocstringstream oss;
162 oss << '[' << bibLabel() << "] ";
164 docstring const str = oss.str();
172 docstring bibitemWidest(Buffer const & buffer)
176 InsetBibitem const * bitem = 0;
178 // FIXME: this font is used unitialized for now but should be set to
179 // a proportional font. Here is what Georg Baum has to say about it:
181 bibitemWidest() is supposed to find the bibitem with the widest label in the
182 output, because that is needed as an argument of the bibliography
183 environment to dtermine the correct indentation. To be 100% correct we
184 would need the metrics of the font that is used in the output, but usually
185 we don't have access to these.
186 In practice, any proportional font is probably good enough, since we don't
187 need to know the final with, we only need to know the which label is the
189 Unless there is an easy way to get the metrics of the output font I suggest
190 to use a hardcoded font like "Times" or so.
192 It is very important that the result of this function is the same both with
193 and without GUI. After thinking about this it is clear that no Font
194 metrics should be used here, since these come from the gui. If we can't
195 easily get the LaTeX font metrics we should make our own poor mans font
196 metrics replacement, e.g. by hardcoding the metrics of the standard TeX
200 ParagraphList::const_iterator it = buffer.paragraphs().begin();
201 ParagraphList::const_iterator end = buffer.paragraphs().end();
203 for (; it != end; ++it) {
204 if (it->insetList().empty())
206 Inset * inset = it->insetList().begin()->inset;
207 if (inset->lyxCode() != BIBITEM_CODE)
210 bitem = static_cast<InsetBibitem const *>(inset);
211 docstring const label = bitem->bibLabel();
213 // FIXME: we can't be sure using the following that the GUI
214 // version and the command-line version will give the same
217 //int const wx = use_gui?
218 // theFontMetrics(font).width(label): label.size();
220 // So for now we just use the label size in order to be sure
221 // that GUI and no-GUI gives the same bibitem (even if that is
222 // potentially the wrong one.
223 int const wx = label.size();
229 if (bitem && !bitem->bibLabel().empty())
230 return bitem->bibLabel();
232 return from_ascii("99");
236 void InsetBibitem::fillWithBibKeys(BiblioInfo & keys, InsetIterator const & it) const
238 docstring const key = getParam("key");
239 BibTeXInfo keyvalmap(false);
240 keyvalmap[from_ascii("label")] = getParam("label");
241 DocIterator doc_it(it);
243 keyvalmap[from_ascii("ref")] = doc_it.paragraph().asString();
244 keys[key] = keyvalmap;
248 /// Update the counters of this inset and of its contents
249 void InsetBibitem::updateLabels(ParIterator const &)
251 Counters & counters = buffer().params().documentClass().counters();
252 docstring const bibitem = from_ascii("bibitem");
253 if (counters.hasCounter(bibitem) && getParam("label").empty()) {
254 counters.step(bibitem);
255 autolabel_ = counters.theCounter(bibitem);
257 autolabel_ = from_ascii("??");