]> git.lyx.org Git - lyx.git/blob - src/insets/InsetBibitem.cpp
Pure HTML output for math macros.
[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         buffer().updateBuffer();
98 }
99
100
101 ParamInfo const & InsetBibitem::findInfo(string const & /* cmdName */)
102 {
103         static ParamInfo param_info_;
104         if (param_info_.empty()) {
105                 param_info_.add("label", ParamInfo::LATEX_OPTIONAL,
106                                 ParamInfo::HANDLING_LATEXIFY);
107                 param_info_.add("key", ParamInfo::LATEX_REQUIRED,
108                                 ParamInfo::HANDLING_ESCAPE);
109         }
110         return param_info_;
111 }
112
113
114 void InsetBibitem::doDispatch(Cursor & cur, FuncRequest & cmd)
115 {
116         switch (cmd.action) {
117
118         case LFUN_INSET_MODIFY: {
119                 InsetCommandParams p(BIBITEM_CODE);
120                 InsetCommand::string2params("bibitem", to_utf8(cmd.argument()), p);
121                 if (p.getCmdName().empty()) {
122                         cur.noUpdate();
123                         break;
124                 }
125                 docstring const & old_key = params()["key"];
126                 setParam("label", p["label"]);
127                 if (p["key"] != old_key) {
128                         updateCommand(p["key"]);
129                         cur.bv().buffer().changeRefsIfUnique(old_key,
130                                 params()["key"], CITE_CODE);
131                 }
132                 buffer_->invalidateBibinfoCache();
133                 break;
134         }
135
136         default:
137                 InsetCommand::doDispatch(cur, cmd);
138                 break;
139         }
140 }
141
142
143 void InsetBibitem::read(Lexer & lex)
144 {
145         InsetCommand::read(lex);
146
147         if (prefixIs(getParam("key"), key_prefix)) {
148                 int const key = convert<int>(getParam("key").substr(key_prefix.length()));
149                 key_counter = max(key_counter, key);
150         }
151 }
152
153
154 docstring InsetBibitem::bibLabel() const
155 {
156         docstring const & label = getParam("label");
157         return label.empty() ? autolabel_ : label;
158 }
159
160
161 docstring InsetBibitem::screenLabel() const
162 {
163         return getParam("key") + " [" + bibLabel() + ']';
164 }
165
166
167 int InsetBibitem::plaintext(odocstream & os, OutputParams const &) const
168 {
169         odocstringstream oss;
170         oss << '[' << bibLabel() << "] ";
171
172         docstring const str = oss.str();
173         os << str;
174
175         return str.size();
176 }
177
178
179 // ale070405
180 docstring bibitemWidest(Buffer const & buffer, OutputParams const & runparams)
181 {
182         int w = 0;
183
184         InsetBibitem const * bitem = 0;
185
186         // FIXME: this font is used unitialized for now but should  be set to
187         // a proportional font. Here is what Georg Baum has to say about it:
188         /*
189         bibitemWidest() is supposed to find the bibitem with the widest label in the
190         output, because that is needed as an argument of the bibliography
191         environment to determine the correct indentation. To be 100% correct we
192         would need the metrics of the font that is used in the output, but usually
193         we don't have access to these.
194         In practice, any proportional font is probably good enough, since we don't
195         need to know the final with, we only need to know the which label is the
196         widest.
197         Unless there is an easy way to get the metrics of the output font I suggest
198         to use a hardcoded font like "Times" or so.
199
200         It is very important that the result of this function is the same both with
201         and without GUI. After thinking about this it is clear that no Font
202         metrics should be used here, since these come from the gui. If we can't
203         easily get the LaTeX font metrics we should make our own poor mans font
204         metrics replacement, e.g. by hardcoding the metrics of the standard TeX
205         font.
206         */
207
208         docstring lbl;
209
210         ParagraphList::const_iterator it = buffer.paragraphs().begin();
211         ParagraphList::const_iterator end = buffer.paragraphs().end();
212
213         for (; it != end; ++it) {
214                 if (it->insetList().empty())
215                         continue;
216                 Inset * inset = it->insetList().begin()->inset;
217                 if (inset->lyxCode() != BIBITEM_CODE)
218                         continue;
219
220                 bitem = static_cast<InsetBibitem const *>(inset);
221                 docstring const label = bitem->bibLabel();
222
223                 // FIXME: we can't be sure using the following that the GUI
224                 // version and the command-line version will give the same
225                 // result.
226                 //
227                 //int const wx = use_gui?
228                 //      theFontMetrics(font).width(label): label.size();
229                 //
230                 // So for now we just use the label size in order to be sure
231                 // that GUI and no-GUI gives the same bibitem (even if that is
232                 // potentially the wrong one.
233                 int const wx = label.size();
234
235                 if (wx > w) {
236                         w = wx;
237                         lbl = label;
238                 }
239         }
240
241         if (!lbl.empty()) {
242                 docstring latex_lbl;
243                 for (size_t n = 0; n < lbl.size(); ++n) {
244                         try {
245                                 latex_lbl += runparams.encoding->latexChar(lbl[n]);
246                         } catch (EncodingException & /* e */) {
247                                 if (runparams.dryrun) {
248                                         latex_lbl += "<" + _("LyX Warning: ")
249                                                   + _("uncodable character") + " '";
250                                         latex_lbl += docstring(1, lbl[n]);
251                                         latex_lbl += "'>";
252                                 }
253                         }
254                 }
255                 return latex_lbl;
256         }
257
258         return from_ascii("99");
259 }
260
261
262 void InsetBibitem::fillWithBibKeys(BiblioInfo & keys, InsetIterator const & it) const
263 {
264         docstring const key = getParam("key");
265         BibTeXInfo keyvalmap(false);
266         keyvalmap.label(bibLabel());
267         DocIterator doc_it(it); 
268         doc_it.forwardPos();
269         keyvalmap[from_ascii("ref")] = doc_it.paragraph().asString();
270         keys[key] = keyvalmap;
271 }
272
273
274 // Update the counters of this inset and of its contents
275 void InsetBibitem::updateBuffer(ParIterator const & it, UpdateType utype)
276 {
277         BufferParams const & bp = buffer().masterBuffer()->params();
278         Counters & counters = bp.documentClass().counters();
279         docstring const bibitem = from_ascii("bibitem");
280         if (counters.hasCounter(bibitem) && getParam("label").empty()) {
281                 counters.step(bibitem, utype);
282                 string const & lang = it.paragraph().getParLanguage(bp)->code();
283                 autolabel_ = counters.theCounter(bibitem, lang);
284         } else {
285                 autolabel_ = from_ascii("??");
286         }
287 }
288
289
290 docstring InsetBibitem::xhtml(XHTMLStream & xs, OutputParams const &) const
291 {
292         // FIXME XHTML
293         // XHTML 1.1 doesn't have the "name" attribute for <a>, so we have to use
294         // the "id" atttribute to get the document to validate. Probably, we will
295         // need to use "name" anyway, eventually, because some browsers do not
296         // handle jumping to ids. If we don't do that, though, we can just put the
297         // id into the span tag.
298         string const attrs = "id='" + to_utf8(getParam("key")) + "'";
299         xs << html::CompTag("a", attrs);
300         xs << html::StartTag("span", "class='bibitemlabel'");
301         xs << bibLabel();
302         xs << html::EndTag("span");
303         return docstring();
304 }
305
306
307 } // namespace lyx