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"
28 #include "output_xhtml.h"
29 #include "Paragraph.h"
30 #include "ParagraphList.h"
31 #include "ParIterator.h"
32 #include "TextClass.h"
34 #include "frontends/alert.h"
36 #include "support/convert.h"
37 #include "support/docstream.h"
38 #include "support/gettext.h"
39 #include "support/lstrings.h"
42 using namespace lyx::support;
47 int InsetBibitem::key_counter = 0;
48 docstring const key_prefix = from_ascii("key-");
51 InsetBibitem::InsetBibitem(Buffer const & buf, InsetCommandParams const & p)
52 : InsetCommand(p, "bibitem")
54 Inset::setBuffer(const_cast<Buffer &>(buf));
55 buffer_->invalidateBibinfoCache();
56 if (getParam("key").empty())
57 setParam("key", key_prefix + convert<docstring>(++key_counter));
61 InsetBibitem::~InsetBibitem()
64 buffer_->invalidateBibinfoCache();
68 void InsetBibitem::initView()
70 updateCommand(getParam("key"));
74 void InsetBibitem::updateCommand(docstring const & new_key, bool)
76 docstring const old_key = getParam("key");
77 docstring key = new_key;
79 vector<docstring> bibkeys = buffer().masterBibInfo().getKeys();
83 if (find(bibkeys.begin(), bibkeys.end(), key) != bibkeys.end()) {
84 // generate unique label
85 key = new_key + '-' + convert<docstring>(i);
86 while (find(bibkeys.begin(), bibkeys.end(), key) != bibkeys.end()) {
88 key = new_key + '-' + convert<docstring>(i);
90 frontend::Alert::warning(_("Keys must be unique!"),
91 bformat(_("The key %1$s already exists,\n"
92 "it will be changed to %2$s."), new_key, key));
96 buffer().updateLabels();
100 ParamInfo const & InsetBibitem::findInfo(string const & /* cmdName */)
102 static ParamInfo param_info_;
103 if (param_info_.empty()) {
104 param_info_.add("label", ParamInfo::LATEX_OPTIONAL);
105 param_info_.add("key", ParamInfo::LATEX_REQUIRED);
111 void InsetBibitem::doDispatch(Cursor & cur, FuncRequest & cmd)
113 switch (cmd.action) {
115 case LFUN_INSET_MODIFY: {
116 InsetCommandParams p(BIBITEM_CODE);
117 InsetCommand::string2params("bibitem", to_utf8(cmd.argument()), p);
118 if (p.getCmdName().empty()) {
122 docstring const & old_key = params()["key"];
123 setParam("label", p["label"]);
124 if (p["key"] != old_key) {
125 updateCommand(p["key"]);
126 cur.bv().buffer().changeRefsIfUnique(old_key,
127 params()["key"], CITE_CODE);
129 buffer_->invalidateBibinfoCache();
134 InsetCommand::doDispatch(cur, cmd);
140 void InsetBibitem::read(Lexer & lex)
142 InsetCommand::read(lex);
144 if (prefixIs(getParam("key"), key_prefix)) {
145 int const key = convert<int>(getParam("key").substr(key_prefix.length()));
146 key_counter = max(key_counter, key);
151 docstring InsetBibitem::bibLabel() const
153 docstring const & label = getParam("label");
154 return label.empty() ? autolabel_ : label;
158 docstring InsetBibitem::screenLabel() const
160 return getParam("key") + " [" + bibLabel() + ']';
164 int InsetBibitem::plaintext(odocstream & os, OutputParams const &) const
166 odocstringstream oss;
167 oss << '[' << bibLabel() << "] ";
169 docstring const str = oss.str();
177 docstring bibitemWidest(Buffer const & buffer)
181 InsetBibitem const * bitem = 0;
183 // FIXME: this font is used unitialized for now but should be set to
184 // a proportional font. Here is what Georg Baum has to say about it:
186 bibitemWidest() is supposed to find the bibitem with the widest label in the
187 output, because that is needed as an argument of the bibliography
188 environment to determine the correct indentation. To be 100% correct we
189 would need the metrics of the font that is used in the output, but usually
190 we don't have access to these.
191 In practice, any proportional font is probably good enough, since we don't
192 need to know the final with, we only need to know the which label is the
194 Unless there is an easy way to get the metrics of the output font I suggest
195 to use a hardcoded font like "Times" or so.
197 It is very important that the result of this function is the same both with
198 and without GUI. After thinking about this it is clear that no Font
199 metrics should be used here, since these come from the gui. If we can't
200 easily get the LaTeX font metrics we should make our own poor mans font
201 metrics replacement, e.g. by hardcoding the metrics of the standard TeX
207 ParagraphList::const_iterator it = buffer.paragraphs().begin();
208 ParagraphList::const_iterator end = buffer.paragraphs().end();
210 for (; it != end; ++it) {
211 if (it->insetList().empty())
213 Inset * inset = it->insetList().begin()->inset;
214 if (inset->lyxCode() != BIBITEM_CODE)
217 bitem = static_cast<InsetBibitem const *>(inset);
218 docstring const label = bitem->bibLabel();
220 // FIXME: we can't be sure using the following that the GUI
221 // version and the command-line version will give the same
224 //int const wx = use_gui?
225 // theFontMetrics(font).width(label): label.size();
227 // So for now we just use the label size in order to be sure
228 // that GUI and no-GUI gives the same bibitem (even if that is
229 // potentially the wrong one.
230 int const wx = label.size();
241 return from_ascii("99");
245 void InsetBibitem::fillWithBibKeys(BiblioInfo & keys, InsetIterator const & it) const
247 docstring const key = getParam("key");
248 BibTeXInfo keyvalmap(false);
249 keyvalmap.label(bibLabel());
250 DocIterator doc_it(it);
252 keyvalmap[from_ascii("ref")] = doc_it.paragraph().asString();
253 keys[key] = keyvalmap;
257 // Update the counters of this inset and of its contents
258 void InsetBibitem::updateLabels(ParIterator const & it)
260 BufferParams const & bp = buffer().masterBuffer()->params();
261 Counters & counters = bp.documentClass().counters();
262 docstring const bibitem = from_ascii("bibitem");
263 if (counters.hasCounter(bibitem) && getParam("label").empty()) {
264 counters.step(bibitem);
265 string const & lang = it.paragraph().getParLanguage(bp)->code();
266 autolabel_ = counters.theCounter(bibitem, lang);
268 autolabel_ = from_ascii("??");
273 docstring InsetBibitem::xhtml(odocstream & os, OutputParams const &) const
275 os << "<a name='" << html::htmlize(getParam("key")) << "'></a>";
276 os << "<span class='biblabel'>" << bibLabel() << "</span> ";