]> git.lyx.org Git - lyx.git/blob - src/insets/InsetBibitem.cpp
2eec3310e38ffa740af5ba7375c1ef9bd8c7cb3e
[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/lstrings.h"
34 #include "support/docstream.h"
35 #include "support/gettext.h"
36 #include "support/convert.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 (buffer_)
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 old_key = params()["key"];
120                 setParam("label", p["label"]);
121                 updateCommand(p["key"]);
122                 if (params()["key"] != old_key)
123                         cur.bv().buffer().changeRefsIfUnique(old_key,
124                                 params()["key"], CITE_CODE);
125                 break;
126         }
127
128         default:
129                 InsetCommand::doDispatch(cur, cmd);
130                 break;
131         }
132 }
133
134
135 void InsetBibitem::read(Lexer & lex)
136 {
137         InsetCommand::read(lex);
138
139         if (prefixIs(getParam("key"), key_prefix)) {
140                 int const key = convert<int>(getParam("key").substr(key_prefix.length()));
141                 key_counter = max(key_counter, key);
142         }
143 }
144
145
146 docstring InsetBibitem::bibLabel() const
147 {
148         docstring const & label = getParam("label");
149         return label.empty() ? autolabel_ : label;
150 }
151
152
153 docstring InsetBibitem::screenLabel() const
154 {
155         return getParam("key") + " [" + bibLabel() + ']';
156 }
157
158
159 int InsetBibitem::plaintext(odocstream & os, OutputParams const &) const
160 {
161         odocstringstream oss;
162         oss << '[' << bibLabel() << "] ";
163
164         docstring const str = oss.str();
165         os << str;
166
167         return str.size();
168 }
169
170
171 // ale070405
172 docstring bibitemWidest(Buffer const & buffer)
173 {
174         int w = 0;
175
176         InsetBibitem const * bitem = 0;
177
178         // FIXME: this font is used unitialized for now but should  be set to
179         // a proportional font. Here is what Georg Baum has to say about it:
180         /*
181         bibitemWidest() is supposed to find the bibitem with the widest label in the
182         output, because that is needed as an argument of the bibliography
183         environment to dtermine the correct indentation. To be 100% correct we
184         would need the metrics of the font that is used in the output, but usually
185         we don't have access to these.
186         In practice, any proportional font is probably good enough, since we don't
187         need to know the final with, we only need to know the which label is the
188         widest.
189         Unless there is an easy way to get the metrics of the output font I suggest
190         to use a hardcoded font like "Times" or so.
191
192         It is very important that the result of this function is the same both with
193         and without GUI. After thinking about this it is clear that no Font
194         metrics should be used here, since these come from the gui. If we can't
195         easily get the LaTeX font metrics we should make our own poor mans font
196         metrics replacement, e.g. by hardcoding the metrics of the standard TeX
197         font.
198         */
199
200         ParagraphList::const_iterator it = buffer.paragraphs().begin();
201         ParagraphList::const_iterator end = buffer.paragraphs().end();
202
203         for (; it != end; ++it) {
204                 if (it->insetList().empty())
205                         continue;
206                 Inset * inset = it->insetList().begin()->inset;
207                 if (inset->lyxCode() != BIBITEM_CODE)
208                         continue;
209
210                 bitem = static_cast<InsetBibitem const *>(inset);
211                 docstring const label = bitem->bibLabel();
212
213                 // FIXME: we can't be sure using the following that the GUI
214                 // version and the command-line version will give the same
215                 // result.
216                 //
217                 //int const wx = use_gui?
218                 //      theFontMetrics(font).width(label): label.size();
219                 //
220                 // So for now we just use the label size in order to be sure
221                 // that GUI and no-GUI gives the same bibitem (even if that is
222                 // potentially the wrong one.
223                 int const wx = label.size();
224
225                 if (wx > w)
226                         w = wx;
227         }
228
229         if (bitem && !bitem->bibLabel().empty())
230                 return bitem->bibLabel();
231
232         return from_ascii("99");
233 }
234
235
236 void InsetBibitem::fillWithBibKeys(BiblioInfo & keys, InsetIterator const & it) const
237 {
238         docstring const key = getParam("key");
239         BibTeXInfo keyvalmap(false);
240         keyvalmap[from_ascii("label")] = getParam("label");
241         DocIterator doc_it(it); 
242         doc_it.forwardPos();
243         keyvalmap[from_ascii("ref")] = doc_it.paragraph().asString();
244         keys[key] = keyvalmap;
245 }
246
247
248 /// Update the counters of this inset and of its contents
249 void InsetBibitem::updateLabels(ParIterator const &) 
250 {
251         Counters & counters = buffer().params().documentClass().counters();
252         docstring const bibitem = from_ascii("bibitem");
253         if (counters.hasCounter(bibitem) && getParam("label").empty()) {
254                 counters.step(bibitem);
255                 autolabel_ = counters.theCounter(bibitem);
256         } else {
257                 autolabel_ = from_ascii("??");
258         }
259 }
260
261
262 } // namespace lyx