]> git.lyx.org Git - lyx.git/blob - src/insets/insetbibitem.C
Fix crash on LateX export.
[lyx.git] / src / insets / insetbibitem.C
1 /**
2  * \file insetbibitem.C
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 "BufferView.h"
17 #include "dispatchresult.h"
18 #include "funcrequest.h"
19 #include "lyxfont.h"
20 #include "lyxlex.h"
21 #include "paragraph.h"
22 #include "ParagraphList.h"
23
24 #include "frontends/FontMetrics.h"
25
26 #include "support/lstrings.h"
27 #include "support/std_ostream.h"
28 #include "support/convert.h"
29
30 using lyx::docstring;
31 using lyx::support::prefixIs;
32
33 using std::max;
34 using std::string;
35 using std::auto_ptr;
36 using std::ostream;
37
38 int InsetBibitem::key_counter = 0;
39 string const key_prefix = "key-";
40
41 namespace lyx {
42 extern bool use_gui;
43 }
44
45 InsetBibitem::InsetBibitem(InsetCommandParams const & p)
46         : InsetCommand(p, "bibitem"), counter(1)
47 {
48         if (getContents().empty())
49                 setContents(key_prefix + convert<string>(++key_counter));
50 }
51
52
53 auto_ptr<InsetBase> InsetBibitem::doClone() const
54 {
55         auto_ptr<InsetBibitem> b(new InsetBibitem(params()));
56         b->setCounter(counter);
57         return auto_ptr<InsetBase>(b);
58 }
59
60
61 void InsetBibitem::doDispatch(LCursor & cur, FuncRequest & cmd)
62 {
63         switch (cmd.action) {
64
65         case LFUN_INSET_MODIFY: {
66                 InsetCommandParams p;
67                 InsetCommandMailer::string2params("bibitem", lyx::to_utf8(cmd.argument()), p);
68                 if (p.getCmdName().empty()) {
69                         cur.noUpdate();
70                         break;
71                 }
72                 if (p.getContents() != params().getContents()) 
73                         cur.bv().buffer()->changeRefsIfUnique(params().getContents(),
74                                                        p.getContents(), InsetBase::CITE_CODE);
75                 setParams(p);
76         }
77
78         default:
79                 InsetCommand::doDispatch(cur, cmd);
80                 break;
81         }
82 }
83
84
85 void InsetBibitem::setCounter(int c)
86 {
87         counter = c;
88 }
89
90
91 // I'm sorry but this is still necessary because \bibitem is used also
92 // as a LyX 2.x command, and lyxlex is not enough smart to understand
93 // real LaTeX commands. Yes, that could be fixed, but would be a waste
94 // of time cause LyX3 won't use lyxlex anyway.  (ale)
95 void InsetBibitem::write(Buffer const &, std::ostream & os) const
96 {
97         os << "\n\\bibitem ";
98         if (!getOptions().empty())
99                 os << '[' << getOptions() << ']';
100         os << '{' << getContents() << "}\n";
101 }
102
103
104 // This is necessary here because this is written without begin_inset
105 // This should be changed!!! (Jug)
106 void InsetBibitem::read(Buffer const &, LyXLex & lex)
107 {
108         if (lex.eatLine())
109                 scanCommand(lex.getString());
110         else
111                 lex.printError("InsetCommand: Parse error: `$$Token'");
112
113         if (prefixIs(getContents(), key_prefix)) {
114                 int const key = convert<int>(getContents().substr(key_prefix.length()));
115                 key_counter = max(key_counter, key);
116         }
117 }
118
119
120 docstring const InsetBibitem::getBibLabel() const
121 {
122         // FIXME UNICODE
123         return getOptions().empty() ?
124                 convert<docstring>(counter) :
125                 lyx::from_utf8(getOptions());
126 }
127
128
129 docstring const InsetBibitem::getScreenLabel(Buffer const &) const
130 {
131         // FIXME UNICODE
132         return lyx::from_utf8(getContents()) + " [" + getBibLabel() + ']';
133 }
134
135
136 int InsetBibitem::plaintext(Buffer const &, lyx::odocstream & os,
137                             OutputParams const &) const
138 {
139         os << '[' << getCounter() << "] ";
140         return 0;
141 }
142
143
144 // ale070405
145 docstring const bibitemWidest(Buffer const & buffer)
146 {
147         int w = 0;
148         // Does look like a hack? It is! (but will change at 0.13)
149
150         InsetBibitem const * bitem = 0;
151         // FIXME: this font is used unitialized for now but should  be set to
152         // a proportional font. Here is what Georg has to say about it:
153         /*
154         bibitemWidest() is supposed to find the bibitem with the widest label in the 
155         output, because that is needed as an argument of the bibliography 
156         environment to dtermine the correct indentation. To be 100% correct we 
157         would need the metrics of the font that is used in the output, but usually 
158         we don't have access to these.
159         In practice, any proportional font is probably good enough, since we don't 
160         need to know the final with, we only need to know the which label is the 
161         widest.
162         Unless there is an easy way to get the metrics of the output font I suggest 
163         to use a hardcoded font like "Times" or so.
164
165         It is very important that the result of this function is the same both with 
166         and without GUI. After thinking about this it is clear that no LyXFont 
167         metrics should be used here, since these come from the gui. If we can't 
168         easily get the LaTeX font metrics we should make our own poor mans front 
169         metrics replacement, e.g. by hardcoding the metrics of the standard TeX 
170         font.
171         */
172         LyXFont font;
173
174         ParagraphList::const_iterator it = buffer.paragraphs().begin();
175         ParagraphList::const_iterator end = buffer.paragraphs().end();
176
177         for (; it != end; ++it) {
178                 if (it->bibitem()) {
179                         docstring const label = it->bibitem()->getBibLabel();
180             
181                         // FIXME 1: we can't be sure using the following that the GUI
182                         // version and the command-line version will give the same 
183                         // result.
184                         // FIXME 2: this use_gui test should be transfered to the frontend.
185                         int const wx = lyx::use_gui?
186                                 theFontMetrics(font).width(label): label.size();
187
188                         if (wx > w) {
189                                 w = wx;
190                                 bitem = it->bibitem();
191                         }
192                 }
193         }
194
195         if (bitem && !bitem->getBibLabel().empty())
196                 return bitem->getBibLabel();
197
198         return lyx::from_ascii("99");
199 }