]> git.lyx.org Git - features.git/blob - src/insets/InsetBibitem.cpp
Don't need this argument, since it was only ever called thus:
[features.git] / src / insets / InsetBibitem.cpp
1 /**
2  * \file InsetBibitem.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Alejandro Aguilar Sierra
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12 #include <algorithm>
13
14 #include "InsetBibitem.h"
15
16 #include "BiblioInfo.h"
17 #include "Buffer.h"
18 #include "buffer_funcs.h"
19 #include "BufferParams.h"
20 #include "BufferView.h"
21 #include "Counters.h"
22 #include "DispatchResult.h"
23 #include "Encoding.h"
24 #include "FuncRequest.h"
25 #include "InsetIterator.h"
26 #include "InsetList.h"
27 #include "Language.h" 
28 #include "Lexer.h"
29 #include "output_xhtml.h"
30 #include "OutputParams.h"
31 #include "Paragraph.h"
32 #include "ParagraphList.h"
33 #include "ParIterator.h"
34 #include "TextClass.h"
35
36 #include "frontends/alert.h"
37
38 #include "support/convert.h"
39 #include "support/debug.h"
40 #include "support/docstream.h"
41 #include "support/gettext.h"
42 #include "support/lstrings.h"
43
44 using namespace std;
45 using namespace lyx::support;
46
47 namespace lyx {
48
49
50 int InsetBibitem::key_counter = 0;
51 docstring const key_prefix = from_ascii("key-");
52
53
54 InsetBibitem::InsetBibitem(Buffer * buf, InsetCommandParams const & p)
55         : InsetCommand(buf, p, "bibitem")
56 {
57         buffer_->invalidateBibinfoCache();
58         if (getParam("key").empty())
59                 setParam("key", key_prefix + convert<docstring>(++key_counter));
60 }
61
62
63 InsetBibitem::~InsetBibitem()
64 {
65         if (isBufferLoaded())
66                 buffer_->invalidateBibinfoCache();
67 }
68
69
70 void InsetBibitem::initView()
71 {
72         updateCommand(getParam("key"));
73 }
74
75
76 void InsetBibitem::updateCommand(docstring const & new_key, bool)
77 {
78         docstring key = new_key;
79
80         vector<docstring> bibkeys = buffer().masterBibInfo().getKeys();
81
82         int i = 1;
83
84         if (find(bibkeys.begin(), bibkeys.end(), key) != bibkeys.end()) {
85                 // generate unique label
86                 key = new_key + '-' + convert<docstring>(i);
87                 while (find(bibkeys.begin(), bibkeys.end(), key) != bibkeys.end()) {
88                         ++i;
89                         key = new_key + '-' + convert<docstring>(i);
90                 }
91                 frontend::Alert::warning(_("Keys must be unique!"),
92                         bformat(_("The key %1$s already exists,\n"
93                         "it will be changed to %2$s."), new_key, key));
94         }
95         setParam("key", key);
96 }
97
98
99 ParamInfo const & InsetBibitem::findInfo(string const & /* cmdName */)
100 {
101         static ParamInfo param_info_;
102         if (param_info_.empty()) {
103                 param_info_.add("label", ParamInfo::LATEX_OPTIONAL,
104                                 ParamInfo::HANDLING_LATEXIFY);
105                 param_info_.add("key", ParamInfo::LATEX_REQUIRED,
106                                 ParamInfo::HANDLING_ESCAPE);
107         }
108         return param_info_;
109 }
110
111
112 void InsetBibitem::doDispatch(Cursor & cur, FuncRequest & cmd)
113 {
114         switch (cmd.action()) {
115
116         case LFUN_INSET_MODIFY: {
117                 InsetCommandParams p(BIBITEM_CODE);
118                 InsetCommand::string2params("bibitem", to_utf8(cmd.argument()), p);
119                 if (p.getCmdName().empty()) {
120                         cur.noScreenUpdate();
121                         break;
122                 }
123                 docstring const & old_key = params()["key"];
124                 setParam("label", p["label"]);
125                 if (p["key"] != old_key) {
126                         updateCommand(p["key"]);
127                         cur.bv().buffer().changeRefsIfUnique(old_key,
128                                 params()["key"], CITE_CODE);
129                         cur.forceBufferUpdate();
130                         buffer_->invalidateBibinfoCache();
131                 }
132                 break;
133         }
134
135         default:
136                 InsetCommand::doDispatch(cur, cmd);
137                 break;
138         }
139 }
140
141
142 void InsetBibitem::read(Lexer & lex)
143 {
144         InsetCommand::read(lex);
145
146         if (prefixIs(getParam("key"), key_prefix)) {
147                 int const key = convert<int>(getParam("key").substr(key_prefix.length()));
148                 key_counter = max(key_counter, key);
149         }
150 }
151
152
153 docstring InsetBibitem::bibLabel() const
154 {
155         docstring const & label = getParam("label");
156         return label.empty() ? autolabel_ : label;
157 }
158
159
160 docstring InsetBibitem::screenLabel() const
161 {
162         return getParam("key") + " [" + bibLabel() + ']';
163 }
164
165
166 int InsetBibitem::plaintext(odocstream & os, OutputParams const &) const
167 {
168         odocstringstream oss;
169         oss << '[' << bibLabel() << "] ";
170
171         docstring const str = oss.str();
172         os << str;
173
174         return str.size();
175 }
176
177
178 // ale070405
179 docstring bibitemWidest(Buffer const & buffer, OutputParams const & runparams)
180 {
181         int w = 0;
182
183         InsetBibitem const * bitem = 0;
184
185         // FIXME: this font is used unitialized for now but should  be set to
186         // a proportional font. Here is what Georg Baum has to say about it:
187         /*
188         bibitemWidest() is supposed to find the bibitem with the widest label in the
189         output, because that is needed as an argument of the bibliography
190         environment to determine the correct indentation. To be 100% correct we
191         would need the metrics of the font that is used in the output, but usually
192         we don't have access to these.
193         In practice, any proportional font is probably good enough, since we don't
194         need to know the final with, we only need to know the which label is the
195         widest.
196         Unless there is an easy way to get the metrics of the output font I suggest
197         to use a hardcoded font like "Times" or so.
198
199         It is very important that the result of this function is the same both with
200         and without GUI. After thinking about this it is clear that no Font
201         metrics should be used here, since these come from the gui. If we can't
202         easily get the LaTeX font metrics we should make our own poor mans font
203         metrics replacement, e.g. by hardcoding the metrics of the standard TeX
204         font.
205         */
206
207         docstring lbl;
208
209         ParagraphList::const_iterator it = buffer.paragraphs().begin();
210         ParagraphList::const_iterator end = buffer.paragraphs().end();
211
212         for (; it != end; ++it) {
213                 if (it->insetList().empty())
214                         continue;
215                 Inset * inset = it->insetList().begin()->inset;
216                 if (inset->lyxCode() != BIBITEM_CODE)
217                         continue;
218
219                 bitem = static_cast<InsetBibitem const *>(inset);
220                 docstring const label = bitem->bibLabel();
221
222                 // FIXME: we can't be sure using the following that the GUI
223                 // version and the command-line version will give the same
224                 // result.
225                 //
226                 //int const wx = use_gui?
227                 //      theFontMetrics(font).width(label): label.size();
228                 //
229                 // So for now we just use the label size in order to be sure
230                 // that GUI and no-GUI gives the same bibitem (even if that is
231                 // potentially the wrong one.
232                 int const wx = label.size();
233
234                 if (wx > w) {
235                         w = wx;
236                         lbl = label;
237                 }
238         }
239
240         if (!lbl.empty()) {
241                 docstring latex_lbl;
242                 for (size_t n = 0; n < lbl.size(); ++n) {
243                         try {
244                                 latex_lbl += runparams.encoding->latexChar(lbl[n]);
245                         } catch (EncodingException & /* e */) {
246                                 if (runparams.dryrun) {
247                                         latex_lbl += "<" + _("LyX Warning: ")
248                                                   + _("uncodable character") + " '";
249                                         latex_lbl += docstring(1, lbl[n]);
250                                         latex_lbl += "'>";
251                                 }
252                         }
253                 }
254                 return latex_lbl;
255         }
256
257         return from_ascii("99");
258 }
259
260
261 void InsetBibitem::fillWithBibKeys(BiblioInfo & keys) const
262 {
263         docstring const key = getParam("key");
264         // false means it's not BibTeX
265         BibTeXInfo keyvalmap(false);
266         keyvalmap.label(bibLabel());
267         // The indirection here is a little annoying, but
268         //      DocIterator(Buffer *, Inset *) 
269         // is private.
270         InsetBibitem & me = const_cast<InsetBibitem &>(*this);
271         InsetIterator it(me);
272         DocIterator doc_it(it); 
273         doc_it.forwardPos();
274         keyvalmap[from_ascii("ref")] = doc_it.paragraph().asString();
275         keys[key] = keyvalmap;
276 }
277
278
279 // Update the counters of this inset and of its contents
280 void InsetBibitem::updateBuffer(ParIterator const & it, UpdateType utype)
281 {
282         BufferParams const & bp = buffer().masterBuffer()->params();
283         Counters & counters = bp.documentClass().counters();
284         docstring const bibitem = from_ascii("bibitem");
285         if (counters.hasCounter(bibitem) && getParam("label").empty()) {
286                 counters.step(bibitem, utype);
287                 string const & lang = it.paragraph().getParLanguage(bp)->code();
288                 autolabel_ = counters.theCounter(bibitem, lang);
289         } else {
290                 autolabel_ = from_ascii("??");
291         }
292 }
293
294
295 docstring InsetBibitem::xhtml(XHTMLStream & xs, OutputParams const &) const
296 {
297         // FIXME XHTML
298         // XHTML 1.1 doesn't have the "name" attribute for <a>, so we have to use
299         // the "id" atttribute to get the document to validate. Probably, we will
300         // need to use "name" anyway, eventually, because some browsers do not
301         // handle jumping to ids. If we don't do that, though, we can just put the
302         // id into the span tag.
303         string const attrs = "id='" + to_utf8(getParam("key")) + "'";
304         xs << html::CompTag("a", attrs);
305         xs << html::StartTag("span", "class='bibitemlabel'");
306         xs << bibLabel();
307         xs << html::EndTag("span");
308         return docstring();
309 }
310
311
312 } // namespace lyx