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