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 updateCommand(p["key"]);
122 if (params()["key"] != old_key)
123 cur.bv().buffer().changeRefsIfUnique(old_key,
124 params()["key"], CITE_CODE);
125 buffer_->invalidateBibinfoCache();
130 InsetCommand::doDispatch(cur, cmd);
136 void InsetBibitem::read(Lexer & lex)
138 InsetCommand::read(lex);
140 if (prefixIs(getParam("key"), key_prefix)) {
141 int const key = convert<int>(getParam("key").substr(key_prefix.length()));
142 key_counter = max(key_counter, key);
147 docstring InsetBibitem::bibLabel() const
149 docstring const & label = getParam("label");
150 return label.empty() ? autolabel_ : label;
154 docstring InsetBibitem::screenLabel() const
156 return getParam("key") + " [" + bibLabel() + ']';
160 int InsetBibitem::plaintext(odocstream & os, OutputParams const &) const
162 odocstringstream oss;
163 oss << '[' << bibLabel() << "] ";
165 docstring const str = oss.str();
173 docstring bibitemWidest(Buffer const & buffer)
177 InsetBibitem const * bitem = 0;
179 // FIXME: this font is used unitialized for now but should be set to
180 // a proportional font. Here is what Georg Baum has to say about it:
182 bibitemWidest() is supposed to find the bibitem with the widest label in the
183 output, because that is needed as an argument of the bibliography
184 environment to dtermine the correct indentation. To be 100% correct we
185 would need the metrics of the font that is used in the output, but usually
186 we don't have access to these.
187 In practice, any proportional font is probably good enough, since we don't
188 need to know the final with, we only need to know the which label is the
190 Unless there is an easy way to get the metrics of the output font I suggest
191 to use a hardcoded font like "Times" or so.
193 It is very important that the result of this function is the same both with
194 and without GUI. After thinking about this it is clear that no Font
195 metrics should be used here, since these come from the gui. If we can't
196 easily get the LaTeX font metrics we should make our own poor mans font
197 metrics replacement, e.g. by hardcoding the metrics of the standard TeX
201 ParagraphList::const_iterator it = buffer.paragraphs().begin();
202 ParagraphList::const_iterator end = buffer.paragraphs().end();
204 for (; it != end; ++it) {
205 if (it->insetList().empty())
207 Inset * inset = it->insetList().begin()->inset;
208 if (inset->lyxCode() != BIBITEM_CODE)
211 bitem = static_cast<InsetBibitem const *>(inset);
212 docstring const label = bitem->bibLabel();
214 // FIXME: we can't be sure using the following that the GUI
215 // version and the command-line version will give the same
218 //int const wx = use_gui?
219 // theFontMetrics(font).width(label): label.size();
221 // So for now we just use the label size in order to be sure
222 // that GUI and no-GUI gives the same bibitem (even if that is
223 // potentially the wrong one.
224 int const wx = label.size();
230 if (bitem && !bitem->bibLabel().empty())
231 return bitem->bibLabel();
233 return from_ascii("99");
237 void InsetBibitem::fillWithBibKeys(BiblioInfo & keys, InsetIterator const & it) const
239 docstring const key = getParam("key");
240 BibTeXInfo keyvalmap(false);
241 keyvalmap[from_ascii("label")] = getParam("label");
242 DocIterator doc_it(it);
244 keyvalmap[from_ascii("ref")] = doc_it.paragraph().asString();
245 keys[key] = keyvalmap;
249 /// Update the counters of this inset and of its contents
250 void InsetBibitem::updateLabels(ParIterator const &)
252 Counters & counters = buffer().params().documentClass().counters();
253 docstring const bibitem = from_ascii("bibitem");
254 if (counters.hasCounter(bibitem) && getParam("label").empty()) {
255 counters.step(bibitem);
256 autolabel_ = counters.theCounter(bibitem);
258 autolabel_ = from_ascii("??");