]> git.lyx.org Git - lyx.git/blob - src/insets/InsetBibitem.cpp
- InsetTabular.cpp: floats must not be inserted to tables, fixes #6844
[lyx.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, InsetIterator const & it) const
262 {
263         docstring const key = getParam("key");
264         BibTeXInfo keyvalmap(false);
265         keyvalmap.label(bibLabel());
266         DocIterator doc_it(it); 
267         doc_it.forwardPos();
268         keyvalmap[from_ascii("ref")] = doc_it.paragraph().asString();
269         keys[key] = keyvalmap;
270 }
271
272
273 // Update the counters of this inset and of its contents
274 void InsetBibitem::updateBuffer(ParIterator const & it, UpdateType utype)
275 {
276         BufferParams const & bp = buffer().masterBuffer()->params();
277         Counters & counters = bp.documentClass().counters();
278         docstring const bibitem = from_ascii("bibitem");
279         if (counters.hasCounter(bibitem) && getParam("label").empty()) {
280                 counters.step(bibitem, utype);
281                 string const & lang = it.paragraph().getParLanguage(bp)->code();
282                 autolabel_ = counters.theCounter(bibitem, lang);
283         } else {
284                 autolabel_ = from_ascii("??");
285         }
286 }
287
288
289 docstring InsetBibitem::xhtml(XHTMLStream & xs, OutputParams const &) const
290 {
291         // FIXME XHTML
292         // XHTML 1.1 doesn't have the "name" attribute for <a>, so we have to use
293         // the "id" atttribute to get the document to validate. Probably, we will
294         // need to use "name" anyway, eventually, because some browsers do not
295         // handle jumping to ids. If we don't do that, though, we can just put the
296         // id into the span tag.
297         string const attrs = "id='" + to_utf8(getParam("key")) + "'";
298         xs << html::CompTag("a", attrs);
299         xs << html::StartTag("span", "class='bibitemlabel'");
300         xs << bibLabel();
301         xs << html::EndTag("span");
302         return docstring();
303 }
304
305
306 } // namespace lyx