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