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