]> git.lyx.org Git - lyx.git/blob - src/insets/InsetListings.cpp
30ba1a2a4ef6e2d05b8ce089a699e315f3f0d9e9
[lyx.git] / src / insets / InsetListings.cpp
1 /**
2  * \file InsetListings.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Bo Peng
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "InsetListings.h"
14
15 #include "Language.h"
16 #include "gettext.h"
17 #include "DispatchResult.h"
18 #include "FuncRequest.h"
19 #include "FuncStatus.h"
20 #include "Cursor.h"
21 #include "support/lstrings.h"
22
23 #include <sstream>
24
25 namespace lyx {
26
27 using support::token;
28
29 using std::auto_ptr;
30 using std::istringstream;
31 using std::ostream;
32 using std::ostringstream;
33 using std::string;
34
35
36 void InsetListings::init()
37 {
38         setButtonLabel();
39         // FIXME: define Color::listing?
40         Font font(Font::ALL_SANE);
41         font.decSize();
42         font.decSize();
43         font.setColor(Color::foreground);
44         setLabelFont(font);
45         // FIXME: english_language?
46         text_.current_font.setLanguage(english_language);
47         text_.real_current_font.setLanguage(english_language);
48         // FIXME: why I can not make text of source code black with the following two lines?
49         text_.current_font.setColor(Color::foreground);
50         text_.real_current_font.setColor(Color::foreground);
51 }
52
53
54 InsetListings::InsetListings(BufferParams const & bp, InsetListingsParams const & par)
55         : InsetERT(bp, par.status())
56 {
57         init();
58 }
59
60
61 InsetListings::InsetListings(InsetListings const & in)
62         : InsetERT(in)
63 {
64         init();
65 }
66
67
68 auto_ptr<Inset> InsetListings::doClone() const
69 {
70         return auto_ptr<Inset>(new InsetListings(*this));
71 }
72
73
74 InsetListings::~InsetListings()
75 {
76         InsetListingsMailer(*this).hideDialog();
77 }
78
79
80 bool InsetListings::display() const
81 {
82         return !params().isInline();
83 }
84
85
86 void InsetListings::write(Buffer const & buf, ostream & os) const
87 {
88         os << "listings" << "\n";
89         InsetListingsParams const & par = params();
90         // parameter string is encoded to be a valid lyx token.
91         string opt = par.encodedString();
92         if (!opt.empty())
93                 os << "lstparams \"" << opt << "\"\n";
94         if (par.isInline())
95                 os << "inline true\n";
96         else
97                 os << "inline false\n";
98         InsetCollapsable::write(buf, os);
99 }
100
101
102 void InsetListings::read(Buffer const & buf, Lexer & lex)
103 {
104         while (lex.isOK()) {
105                 lex.next();
106                 string const token = lex.getString();
107                 if (token == "lstparams") {
108                         lex.next();
109                         string const value = lex.getString();
110                         params().fromEncodedString(value);
111                 } else if (token == "inline") {
112                         lex.next();
113                         params().setInline(lex.getBool());
114                 } else {
115                         // no special option, push back 'status' etc
116                         lex.pushToken(token);
117                         break;
118                 }
119         }
120         InsetCollapsable::read(buf, lex);
121 }
122
123
124 docstring const InsetListings::editMessage() const
125 {
126         return _("Opened Listings Inset");
127 }
128
129
130 int InsetListings::latex(Buffer const &, odocstream & os,
131                     OutputParams const &) const
132 {
133         string param_string = params().encodedString();
134         // NOTE: I use {} to quote text, which is an experimental feature
135         // of the listings package (see page 25 of the manual)
136         int lines = 0;
137         bool lstinline = params().isInline();
138         if (lstinline) {
139                 if (param_string.empty())
140                         os << "\\lstinline{";
141                 else
142                         os << "\\lstinline[" << from_ascii(param_string) << "]{";
143         } else {
144                 if (param_string.empty())
145                         os << "\n\\begingroup\n\\inputencoding{latin1}\n\\begin{lstlisting}\n";
146                 else
147                         os << "\n\\begingroup\n\\inputencoding{latin1}\n\\begin{lstlisting}[" << from_ascii(param_string) << "]\n";
148                 lines += 4;
149         }
150         ParagraphList::const_iterator par = paragraphs().begin();
151         ParagraphList::const_iterator end = paragraphs().end();
152
153         while (par != end) {
154                 pos_type siz = par->size();
155                 for (pos_type i = 0; i < siz; ++i) {
156                         // ignore all struck out text
157                         if (par->isDeleted(i))
158                                 continue;
159                         os.put(par->getChar(i));
160                 }
161                 ++par;
162                 // for the inline case, if there are multiple paragraphs
163                 // they are simply joined. Otherwise, expect latex errors. 
164                 if (par != end && !lstinline) {
165                         os << "\n";
166                         ++lines;
167                 }
168         }
169         if (lstinline)
170                 os << "}";              
171         else {
172                 os << "\n\\end{lstlisting}\n\\endgroup\n";
173                 lines += 3;
174         }
175
176         return lines;
177 }
178
179
180 void InsetListings::doDispatch(Cursor & cur, FuncRequest & cmd)
181 {
182         switch (cmd.action) {
183
184         case LFUN_INSET_MODIFY: {
185                 InsetListingsMailer::string2params(to_utf8(cmd.argument()), params());
186                 break;
187         }
188         case LFUN_INSET_DIALOG_UPDATE:
189                 InsetListingsMailer(*this).updateDialog(&cur.bv());
190                 break;  
191         case LFUN_MOUSE_RELEASE: {
192                 if (cmd.button() == mouse_button::button3 && hitButton(cmd)) {
193                         InsetListingsMailer(*this).showDialog(&cur.bv());
194                         break;
195                 }
196                 InsetERT::doDispatch(cur, cmd);
197                 break;
198         }
199         default:
200                 InsetERT::doDispatch(cur, cmd);
201                 break;
202         }
203 }
204
205
206 bool InsetListings::getStatus(Cursor & cur, FuncRequest const & cmd,
207         FuncStatus & status) const
208 {
209         switch (cmd.action) {
210                 case LFUN_INSET_DIALOG_UPDATE:
211                         status.enabled(true);
212                         return true;
213                 default:
214                         return InsetERT::getStatus(cur, cmd, status);
215         }
216 }
217
218
219 void InsetListings::setButtonLabel()
220 {
221         // FIXME UNICODE
222         setLabel(isOpen() ?  _("Listings") : getNewLabel(_("Listings")));
223 }
224
225
226 void InsetListings::validate(LaTeXFeatures & features) const
227 {
228         features.require("listings");
229         InsetERT::validate(features);
230 }
231
232
233 bool InsetListings::showInsetDialog(BufferView * bv) const
234 {
235         InsetListingsMailer(const_cast<InsetListings &>(*this)).showDialog(bv);
236         return true;
237 }
238
239
240 void InsetListings::getDrawFont(Font & font) const
241 {
242         font = Font(Font::ALL_INHERIT, english_language);
243         font.setFamily(Font::TYPEWRITER_FAMILY);
244         font.setColor(Color::foreground);
245 }
246
247
248 string const InsetListingsMailer::name_("listings");
249
250 InsetListingsMailer::InsetListingsMailer(InsetListings & inset)
251         : inset_(inset)
252 {}
253
254
255 string const InsetListingsMailer::inset2string(Buffer const &) const
256 {
257         return params2string(inset_.params());
258 }
259
260
261 void InsetListingsMailer::string2params(string const & in,
262                                    InsetListingsParams & params)
263 {
264         params = InsetListingsParams();
265         if (in.empty())
266                 return;
267         istringstream data(in);
268         Lexer lex(0, 0);
269         lex.setStream(data);
270         // discard "listings", which is only used to determine inset
271         lex.next();
272         params.read(lex);
273 }
274
275
276 string const
277 InsetListingsMailer::params2string(InsetListingsParams const & params)
278 {
279         ostringstream data;
280         data << name_ << " ";
281         params.write(data);
282         return data.str();
283 }
284
285
286 } // namespace lyx