]> git.lyx.org Git - lyx.git/blob - src/insets/InsetBibitem.cpp
Rename a couple routines in preparation for more.
[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 "Lexer.h"
27 #include "Paragraph.h"
28 #include "ParagraphList.h"
29 #include "TextClass.h"
30
31 #include "frontends/alert.h"
32
33 #include "support/convert.h"
34 #include "support/docstream.h"
35 #include "support/gettext.h"
36 #include "support/lstrings.h"
37
38 using namespace std;
39 using namespace lyx::support;
40
41 namespace lyx {
42
43
44 int InsetBibitem::key_counter = 0;
45 docstring const key_prefix = from_ascii("key-");
46
47
48 InsetBibitem::InsetBibitem(Buffer const & buf, InsetCommandParams const & p)
49         : InsetCommand(p, "bibitem")
50 {
51         Inset::setBuffer(const_cast<Buffer &>(buf));
52         buffer_->invalidateBibinfoCache();
53         if (getParam("key").empty())
54                 setParam("key", key_prefix + convert<docstring>(++key_counter));
55 }
56
57
58 InsetBibitem::~InsetBibitem()
59 {
60         if (isBufferValid())
61                 buffer_->invalidateBibinfoCache();
62 }
63
64
65 void InsetBibitem::initView()
66 {
67         updateCommand(getParam("key"));
68 }
69
70
71 void InsetBibitem::updateCommand(docstring const & new_key, bool)
72 {
73         docstring const old_key = getParam("key");
74         docstring key = new_key;
75
76         vector<docstring> bibkeys = buffer().masterBibInfo().getKeys();
77
78         int i = 1;
79
80         if (find(bibkeys.begin(), bibkeys.end(), key) != bibkeys.end()) {
81                 // generate unique label
82                 key = new_key + '-' + convert<docstring>(i);
83                 while (find(bibkeys.begin(), bibkeys.end(), key) != bibkeys.end()) {
84                         ++i;
85                         key = new_key + '-' + convert<docstring>(i);
86                 }
87                 frontend::Alert::warning(_("Keys must be unique!"),
88                         bformat(_("The key %1$s already exists,\n"
89                         "it will be changed to %2$s."), new_key, key));
90         }
91         setParam("key", key);
92
93         buffer().updateLabels();
94 }
95
96
97 ParamInfo const & InsetBibitem::findInfo(string const & /* cmdName */)
98 {
99         static ParamInfo param_info_;
100         if (param_info_.empty()) {
101                 param_info_.add("label", ParamInfo::LATEX_OPTIONAL);
102                 param_info_.add("key", ParamInfo::LATEX_REQUIRED);
103         }
104         return param_info_;
105 }
106
107
108 void InsetBibitem::doDispatch(Cursor & cur, FuncRequest & cmd)
109 {
110         switch (cmd.action) {
111
112         case LFUN_INSET_MODIFY: {
113                 InsetCommandParams p(BIBITEM_CODE);
114                 InsetCommand::string2params("bibitem", to_utf8(cmd.argument()), p);
115                 if (p.getCmdName().empty()) {
116                         cur.noUpdate();
117                         break;
118                 }
119                 docstring const & old_key = params()["key"];
120                 setParam("label", p["label"]);
121                 if (p["key"] != old_key) {
122                         updateCommand(p["key"]);
123                         cur.bv().buffer().changeRefsIfUnique(old_key,
124                                 params()["key"], CITE_CODE);
125                 }
126                 buffer_->invalidateBibinfoCache();
127                 break;
128         }
129
130         default:
131                 InsetCommand::doDispatch(cur, cmd);
132                 break;
133         }
134 }
135
136
137 void InsetBibitem::read(Lexer & lex)
138 {
139         InsetCommand::read(lex);
140
141         if (prefixIs(getParam("key"), key_prefix)) {
142                 int const key = convert<int>(getParam("key").substr(key_prefix.length()));
143                 key_counter = max(key_counter, key);
144         }
145 }
146
147
148 docstring InsetBibitem::bibLabel() const
149 {
150         docstring const & label = getParam("label");
151         return label.empty() ? autolabel_ : label;
152 }
153
154
155 docstring InsetBibitem::screenLabel() const
156 {
157         return getParam("key") + " [" + bibLabel() + ']';
158 }
159
160
161 int InsetBibitem::plaintext(odocstream & os, OutputParams const &) const
162 {
163         odocstringstream oss;
164         oss << '[' << bibLabel() << "] ";
165
166         docstring const str = oss.str();
167         os << str;
168
169         return str.size();
170 }
171
172
173 // ale070405
174 docstring bibitemWidest(Buffer const & buffer)
175 {
176         int w = 0;
177
178         InsetBibitem const * bitem = 0;
179
180         // FIXME: this font is used unitialized for now but should  be set to
181         // a proportional font. Here is what Georg Baum has to say about it:
182         /*
183         bibitemWidest() is supposed to find the bibitem with the widest label in the
184         output, because that is needed as an argument of the bibliography
185         environment to determine the correct indentation. To be 100% correct we
186         would need the metrics of the font that is used in the output, but usually
187         we don't have access to these.
188         In practice, any proportional font is probably good enough, since we don't
189         need to know the final with, we only need to know the which label is the
190         widest.
191         Unless there is an easy way to get the metrics of the output font I suggest
192         to use a hardcoded font like "Times" or so.
193
194         It is very important that the result of this function is the same both with
195         and without GUI. After thinking about this it is clear that no Font
196         metrics should be used here, since these come from the gui. If we can't
197         easily get the LaTeX font metrics we should make our own poor mans font
198         metrics replacement, e.g. by hardcoding the metrics of the standard TeX
199         font.
200         */
201
202         docstring lbl;
203
204         ParagraphList::const_iterator it = buffer.paragraphs().begin();
205         ParagraphList::const_iterator end = buffer.paragraphs().end();
206
207         for (; it != end; ++it) {
208                 if (it->insetList().empty())
209                         continue;
210                 Inset * inset = it->insetList().begin()->inset;
211                 if (inset->lyxCode() != BIBITEM_CODE)
212                         continue;
213
214                 bitem = static_cast<InsetBibitem const *>(inset);
215                 docstring const label = bitem->bibLabel();
216
217                 // FIXME: we can't be sure using the following that the GUI
218                 // version and the command-line version will give the same
219                 // result.
220                 //
221                 //int const wx = use_gui?
222                 //      theFontMetrics(font).width(label): label.size();
223                 //
224                 // So for now we just use the label size in order to be sure
225                 // that GUI and no-GUI gives the same bibitem (even if that is
226                 // potentially the wrong one.
227                 int const wx = label.size();
228
229                 if (wx > w) {
230                         w = wx;
231                         lbl = label;
232                 }
233         }
234
235         if (!lbl.empty())
236                 return lbl;
237
238         return from_ascii("99");
239 }
240
241
242 void InsetBibitem::fillWithBibKeys(BiblioInfo & keys, InsetIterator const & it) const
243 {
244         docstring const key = getParam("key");
245         BibTeXInfo keyvalmap(false);
246         keyvalmap[from_ascii("label")] = getParam("label");
247         DocIterator doc_it(it); 
248         doc_it.forwardPos();
249         keyvalmap[from_ascii("ref")] = doc_it.paragraph().asString();
250         keys[key] = keyvalmap;
251 }
252
253
254 /// Update the counters of this inset and of its contents
255 void InsetBibitem::updateLabels(ParIterator const &) 
256 {
257         Counters & counters = buffer().masterBuffer()->params().documentClass().counters();
258         docstring const bibitem = from_ascii("bibitem");
259         if (counters.hasCounter(bibitem) && getParam("label").empty()) {
260                 counters.step(bibitem);
261                 autolabel_ = counters.theCounter(bibitem);
262         } else {
263                 autolabel_ = from_ascii("??");
264         }
265 }
266
267
268 } // namespace lyx