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/convert.h"
34 #include "support/docstream.h"
35 #include "support/gettext.h"
36 #include "support/lstrings.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 if (params()["key"] != old_key) {
122 updateCommand(p["key"]);
123 cur.bv().buffer().changeRefsIfUnique(old_key,
124 params()["key"], CITE_CODE);
126 buffer_->invalidateBibinfoCache();
131 InsetCommand::doDispatch(cur, cmd);
137 void InsetBibitem::read(Lexer & lex)
139 InsetCommand::read(lex);
141 if (prefixIs(getParam("key"), key_prefix)) {
142 int const key = convert<int>(getParam("key").substr(key_prefix.length()));
143 key_counter = max(key_counter, key);
148 docstring InsetBibitem::bibLabel() const
150 docstring const & label = getParam("label");
151 return label.empty() ? autolabel_ : label;
155 docstring InsetBibitem::screenLabel() const
157 return getParam("key") + " [" + bibLabel() + ']';
161 int InsetBibitem::plaintext(odocstream & os, OutputParams const &) const
163 odocstringstream oss;
164 oss << '[' << bibLabel() << "] ";
166 docstring const str = oss.str();
174 docstring bibitemWidest(Buffer const & buffer)
178 InsetBibitem const * bitem = 0;
180 // FIXME: this font is used unitialized for now but should be set to
181 // a proportional font. Here is what Georg Baum has to say about it:
183 bibitemWidest() is supposed to find the bibitem with the widest label in the
184 output, because that is needed as an argument of the bibliography
185 environment to dtermine the correct indentation. To be 100% correct we
186 would need the metrics of the font that is used in the output, but usually
187 we don't have access to these.
188 In practice, any proportional font is probably good enough, since we don't
189 need to know the final with, we only need to know the which label is the
191 Unless there is an easy way to get the metrics of the output font I suggest
192 to use a hardcoded font like "Times" or so.
194 It is very important that the result of this function is the same both with
195 and without GUI. After thinking about this it is clear that no Font
196 metrics should be used here, since these come from the gui. If we can't
197 easily get the LaTeX font metrics we should make our own poor mans font
198 metrics replacement, e.g. by hardcoding the metrics of the standard TeX
202 ParagraphList::const_iterator it = buffer.paragraphs().begin();
203 ParagraphList::const_iterator end = buffer.paragraphs().end();
205 for (; it != end; ++it) {
206 if (it->insetList().empty())
208 Inset * inset = it->insetList().begin()->inset;
209 if (inset->lyxCode() != BIBITEM_CODE)
212 bitem = static_cast<InsetBibitem const *>(inset);
213 docstring const label = bitem->bibLabel();
215 // FIXME: we can't be sure using the following that the GUI
216 // version and the command-line version will give the same
219 //int const wx = use_gui?
220 // theFontMetrics(font).width(label): label.size();
222 // So for now we just use the label size in order to be sure
223 // that GUI and no-GUI gives the same bibitem (even if that is
224 // potentially the wrong one.
225 int const wx = label.size();
231 if (bitem && !bitem->bibLabel().empty())
232 return bitem->bibLabel();
234 return from_ascii("99");
238 void InsetBibitem::fillWithBibKeys(BiblioInfo & keys, InsetIterator const & it) const
240 docstring const key = getParam("key");
241 BibTeXInfo keyvalmap(false);
242 keyvalmap[from_ascii("label")] = getParam("label");
243 DocIterator doc_it(it);
245 keyvalmap[from_ascii("ref")] = doc_it.paragraph().asString();
246 keys[key] = keyvalmap;
250 /// Update the counters of this inset and of its contents
251 void InsetBibitem::updateLabels(ParIterator const &)
253 Counters & counters = buffer().params().documentClass().counters();
254 docstring const bibitem = from_ascii("bibitem");
255 if (counters.hasCounter(bibitem) && getParam("label").empty()) {
256 counters.step(bibitem);
257 autolabel_ = counters.theCounter(bibitem);
259 autolabel_ = from_ascii("??");