]> git.lyx.org Git - lyx.git/blob - src/insets/InsetBibitem.cpp
Remove all BufferParam arguments in InsetXXX methods (since insets know about their...
[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 "FuncRequest.h"
24 #include "InsetIterator.h"
25 #include "InsetList.h"
26 #include "Language.h" 
27 #include "Lexer.h"
28 #include "output_xhtml.h"
29 #include "Paragraph.h"
30 #include "ParagraphList.h"
31 #include "ParIterator.h"
32 #include "TextClass.h"
33
34 #include "frontends/alert.h"
35
36 #include "support/convert.h"
37 #include "support/docstream.h"
38 #include "support/gettext.h"
39 #include "support/lstrings.h"
40
41 using namespace std;
42 using namespace lyx::support;
43
44 namespace lyx {
45
46
47 int InsetBibitem::key_counter = 0;
48 docstring const key_prefix = from_ascii("key-");
49
50
51 InsetBibitem::InsetBibitem(Buffer const & buf, InsetCommandParams const & p)
52         : InsetCommand(p, "bibitem")
53 {
54         Inset::setBuffer(const_cast<Buffer &>(buf));
55         buffer_->invalidateBibinfoCache();
56         if (getParam("key").empty())
57                 setParam("key", key_prefix + convert<docstring>(++key_counter));
58 }
59
60
61 InsetBibitem::~InsetBibitem()
62 {
63         if (isBufferValid())
64                 buffer_->invalidateBibinfoCache();
65 }
66
67
68 void InsetBibitem::initView()
69 {
70         updateCommand(getParam("key"));
71 }
72
73
74 void InsetBibitem::updateCommand(docstring const & new_key, bool)
75 {
76         docstring const old_key = getParam("key");
77         docstring key = new_key;
78
79         vector<docstring> bibkeys = buffer().masterBibInfo().getKeys();
80
81         int i = 1;
82
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()) {
87                         ++i;
88                         key = new_key + '-' + convert<docstring>(i);
89                 }
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));
93         }
94         setParam("key", key);
95
96         buffer().updateLabels();
97 }
98
99
100 ParamInfo const & InsetBibitem::findInfo(string const & /* cmdName */)
101 {
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);
106         }
107         return param_info_;
108 }
109
110
111 void InsetBibitem::doDispatch(Cursor & cur, FuncRequest & cmd)
112 {
113         switch (cmd.action) {
114
115         case LFUN_INSET_MODIFY: {
116                 InsetCommandParams p(BIBITEM_CODE);
117                 InsetCommand::string2params("bibitem", to_utf8(cmd.argument()), p);
118                 if (p.getCmdName().empty()) {
119                         cur.noUpdate();
120                         break;
121                 }
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);
128                 }
129                 buffer_->invalidateBibinfoCache();
130                 break;
131         }
132
133         default:
134                 InsetCommand::doDispatch(cur, cmd);
135                 break;
136         }
137 }
138
139
140 void InsetBibitem::read(Lexer & lex)
141 {
142         InsetCommand::read(lex);
143
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);
147         }
148 }
149
150
151 docstring InsetBibitem::bibLabel() const
152 {
153         docstring const & label = getParam("label");
154         return label.empty() ? autolabel_ : label;
155 }
156
157
158 docstring InsetBibitem::screenLabel() const
159 {
160         return getParam("key") + " [" + bibLabel() + ']';
161 }
162
163
164 int InsetBibitem::plaintext(odocstream & os, OutputParams const &) const
165 {
166         odocstringstream oss;
167         oss << '[' << bibLabel() << "] ";
168
169         docstring const str = oss.str();
170         os << str;
171
172         return str.size();
173 }
174
175
176 // ale070405
177 docstring bibitemWidest(Buffer const & buffer)
178 {
179         int w = 0;
180
181         InsetBibitem const * bitem = 0;
182
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:
185         /*
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
193         widest.
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.
196
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
202         font.
203         */
204
205         docstring lbl;
206
207         ParagraphList::const_iterator it = buffer.paragraphs().begin();
208         ParagraphList::const_iterator end = buffer.paragraphs().end();
209
210         for (; it != end; ++it) {
211                 if (it->insetList().empty())
212                         continue;
213                 Inset * inset = it->insetList().begin()->inset;
214                 if (inset->lyxCode() != BIBITEM_CODE)
215                         continue;
216
217                 bitem = static_cast<InsetBibitem const *>(inset);
218                 docstring const label = bitem->bibLabel();
219
220                 // FIXME: we can't be sure using the following that the GUI
221                 // version and the command-line version will give the same
222                 // result.
223                 //
224                 //int const wx = use_gui?
225                 //      theFontMetrics(font).width(label): label.size();
226                 //
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();
231
232                 if (wx > w) {
233                         w = wx;
234                         lbl = label;
235                 }
236         }
237
238         if (!lbl.empty())
239                 return lbl;
240
241         return from_ascii("99");
242 }
243
244
245 void InsetBibitem::fillWithBibKeys(BiblioInfo & keys, InsetIterator const & it) const
246 {
247         docstring const key = getParam("key");
248         BibTeXInfo keyvalmap(false);
249         keyvalmap.label(bibLabel());
250         DocIterator doc_it(it); 
251         doc_it.forwardPos();
252         keyvalmap[from_ascii("ref")] = doc_it.paragraph().asString();
253         keys[key] = keyvalmap;
254 }
255
256
257 // Update the counters of this inset and of its contents
258 void InsetBibitem::updateLabels(ParIterator const & it) 
259 {
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);
267         } else {
268                 autolabel_ = from_ascii("??");
269         }
270 }
271
272
273 docstring InsetBibitem::xhtml(odocstream & os, OutputParams const &) const
274 {
275         os << "<a name='" << html::htmlize(getParam("key")) << "'></a>";
276         os << "<span class='biblabel'>" << bibLabel() << "</span> "; 
277         return docstring();
278 }
279
280
281 } // namespace lyx