]> git.lyx.org Git - lyx.git/blob - src/insets/InsetBibitem.cpp
The last commit was, uhh, not what I intended.
[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         lyx::updateLabels(buffer());
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 dtermine 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         ParagraphList::const_iterator it = buffer.paragraphs().begin();
203         ParagraphList::const_iterator end = buffer.paragraphs().end();
204
205         for (; it != end; ++it) {
206                 if (it->insetList().empty())
207                         continue;
208                 Inset * inset = it->insetList().begin()->inset;
209                 if (inset->lyxCode() != BIBITEM_CODE)
210                         continue;
211
212                 bitem = static_cast<InsetBibitem const *>(inset);
213                 docstring const label = bitem->bibLabel();
214
215                 // FIXME: we can't be sure using the following that the GUI
216                 // version and the command-line version will give the same
217                 // result.
218                 //
219                 //int const wx = use_gui?
220                 //      theFontMetrics(font).width(label): label.size();
221                 //
222                 // So for now we just use the label size in order to be sure
223                 // that GUI and no-GUI gives the same bibitem (even if that is
224                 // potentially the wrong one.
225                 int const wx = label.size();
226
227                 if (wx > w)
228                         w = wx;
229         }
230
231         if (bitem && !bitem->bibLabel().empty())
232                 return bitem->bibLabel();
233
234         return from_ascii("99");
235 }
236
237
238 void InsetBibitem::fillWithBibKeys(BiblioInfo & keys, InsetIterator const & it) const
239 {
240         docstring const key = getParam("key");
241         BibTeXInfo keyvalmap(false);
242         keyvalmap[from_ascii("label")] = getParam("label");
243         DocIterator doc_it(it); 
244         doc_it.forwardPos();
245         keyvalmap[from_ascii("ref")] = doc_it.paragraph().asString();
246         keys[key] = keyvalmap;
247 }
248
249
250 /// Update the counters of this inset and of its contents
251 void InsetBibitem::updateLabels(ParIterator const &) 
252 {
253         Counters & counters = buffer().params().documentClass().counters();
254         docstring const bibitem = from_ascii("bibitem");
255         if (counters.hasCounter(bibitem) && getParam("label").empty()) {
256                 counters.step(bibitem);
257                 autolabel_ = counters.theCounter(bibitem);
258         } else {
259                 autolabel_ = from_ascii("??");
260         }
261 }
262
263
264 } // namespace lyx