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 "output_xhtml.h"
28 #include "Paragraph.h"
29 #include "ParagraphList.h"
30 #include "TextClass.h"
32 #include "frontends/alert.h"
34 #include "support/convert.h"
35 #include "support/docstream.h"
36 #include "support/gettext.h"
37 #include "support/lstrings.h"
40 using namespace lyx::support;
45 int InsetBibitem::key_counter = 0;
46 docstring const key_prefix = from_ascii("key-");
49 InsetBibitem::InsetBibitem(Buffer const & buf, InsetCommandParams const & p)
50 : InsetCommand(p, "bibitem")
52 Inset::setBuffer(const_cast<Buffer &>(buf));
53 buffer_->invalidateBibinfoCache();
54 if (getParam("key").empty())
55 setParam("key", key_prefix + convert<docstring>(++key_counter));
59 InsetBibitem::~InsetBibitem()
62 buffer_->invalidateBibinfoCache();
66 void InsetBibitem::initView()
68 updateCommand(getParam("key"));
72 void InsetBibitem::updateCommand(docstring const & new_key, bool)
74 docstring const old_key = getParam("key");
75 docstring key = new_key;
77 vector<docstring> bibkeys = buffer().masterBibInfo().getKeys();
81 if (find(bibkeys.begin(), bibkeys.end(), key) != bibkeys.end()) {
82 // generate unique label
83 key = new_key + '-' + convert<docstring>(i);
84 while (find(bibkeys.begin(), bibkeys.end(), key) != bibkeys.end()) {
86 key = new_key + '-' + convert<docstring>(i);
88 frontend::Alert::warning(_("Keys must be unique!"),
89 bformat(_("The key %1$s already exists,\n"
90 "it will be changed to %2$s."), new_key, key));
94 buffer().updateLabels();
98 ParamInfo const & InsetBibitem::findInfo(string const & /* cmdName */)
100 static ParamInfo param_info_;
101 if (param_info_.empty()) {
102 param_info_.add("label", ParamInfo::LATEX_OPTIONAL);
103 param_info_.add("key", ParamInfo::LATEX_REQUIRED);
109 void InsetBibitem::doDispatch(Cursor & cur, FuncRequest & cmd)
111 switch (cmd.action) {
113 case LFUN_INSET_MODIFY: {
114 InsetCommandParams p(BIBITEM_CODE);
115 InsetCommand::string2params("bibitem", to_utf8(cmd.argument()), p);
116 if (p.getCmdName().empty()) {
120 docstring const & old_key = params()["key"];
121 setParam("label", p["label"]);
122 if (p["key"] != old_key) {
123 updateCommand(p["key"]);
124 cur.bv().buffer().changeRefsIfUnique(old_key,
125 params()["key"], CITE_CODE);
127 buffer_->invalidateBibinfoCache();
132 InsetCommand::doDispatch(cur, cmd);
138 void InsetBibitem::read(Lexer & lex)
140 InsetCommand::read(lex);
142 if (prefixIs(getParam("key"), key_prefix)) {
143 int const key = convert<int>(getParam("key").substr(key_prefix.length()));
144 key_counter = max(key_counter, key);
149 docstring InsetBibitem::bibLabel() const
151 docstring const & label = getParam("label");
152 return label.empty() ? autolabel_ : label;
156 docstring InsetBibitem::screenLabel() const
158 return getParam("key") + " [" + bibLabel() + ']';
162 int InsetBibitem::plaintext(odocstream & os, OutputParams const &) const
164 odocstringstream oss;
165 oss << '[' << bibLabel() << "] ";
167 docstring const str = oss.str();
175 docstring bibitemWidest(Buffer const & buffer)
179 InsetBibitem const * bitem = 0;
181 // FIXME: this font is used unitialized for now but should be set to
182 // a proportional font. Here is what Georg Baum has to say about it:
184 bibitemWidest() is supposed to find the bibitem with the widest label in the
185 output, because that is needed as an argument of the bibliography
186 environment to determine the correct indentation. To be 100% correct we
187 would need the metrics of the font that is used in the output, but usually
188 we don't have access to these.
189 In practice, any proportional font is probably good enough, since we don't
190 need to know the final with, we only need to know the which label is the
192 Unless there is an easy way to get the metrics of the output font I suggest
193 to use a hardcoded font like "Times" or so.
195 It is very important that the result of this function is the same both with
196 and without GUI. After thinking about this it is clear that no Font
197 metrics should be used here, since these come from the gui. If we can't
198 easily get the LaTeX font metrics we should make our own poor mans font
199 metrics replacement, e.g. by hardcoding the metrics of the standard TeX
205 ParagraphList::const_iterator it = buffer.paragraphs().begin();
206 ParagraphList::const_iterator end = buffer.paragraphs().end();
208 for (; it != end; ++it) {
209 if (it->insetList().empty())
211 Inset * inset = it->insetList().begin()->inset;
212 if (inset->lyxCode() != BIBITEM_CODE)
215 bitem = static_cast<InsetBibitem const *>(inset);
216 docstring const label = bitem->bibLabel();
218 // FIXME: we can't be sure using the following that the GUI
219 // version and the command-line version will give the same
222 //int const wx = use_gui?
223 // theFontMetrics(font).width(label): label.size();
225 // So for now we just use the label size in order to be sure
226 // that GUI and no-GUI gives the same bibitem (even if that is
227 // potentially the wrong one.
228 int const wx = label.size();
239 return from_ascii("99");
243 void InsetBibitem::fillWithBibKeys(BiblioInfo & keys, InsetIterator const & it) const
245 docstring const key = getParam("key");
246 BibTeXInfo keyvalmap(false);
247 keyvalmap[from_ascii("label")] = getParam("label");
248 DocIterator doc_it(it);
250 keyvalmap[from_ascii("ref")] = doc_it.paragraph().asString();
251 keys[key] = keyvalmap;
255 // Update the counters of this inset and of its contents
256 void InsetBibitem::updateLabels(ParIterator const &)
258 Counters & counters = buffer().masterBuffer()->params().documentClass().counters();
259 docstring const bibitem = from_ascii("bibitem");
260 if (counters.hasCounter(bibitem) && getParam("label").empty()) {
261 counters.step(bibitem);
262 autolabel_ = counters.theCounter(bibitem);
264 autolabel_ = from_ascii("??");
269 int InsetBibitem::xhtml(odocstream & os, OutputParams const &) const
271 os << "<a name='" << html::htmlize(getParam("key")) << "'></a>";
272 os << "<span class='biblabel'>" << bibLabel() << "</span> ";