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