]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/GuiListings.cpp
d6894d0f62b8a690b930c681e85ffdfec08e5007
[lyx.git] / src / frontends / qt4 / GuiListings.cpp
1 /**
2  * \file GuiListings.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  * \author Jürgen Spitzmüller
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #include "GuiListings.h"
15
16 #include "qt_helpers.h"
17 #include "FuncRequest.h"
18 #include "insets/InsetListings.h"
19 #include "insets/InsetListingsParams.h"
20 #include "support/debug.h"
21
22 #include "support/gettext.h"
23 #include "support/lstrings.h"
24
25 #include <QLineEdit>
26 #include <QCloseEvent>
27 #include <QPushButton>
28 #include <QValidator>
29 #include <QRegExpValidator>
30
31 using namespace std;
32 using namespace lyx::support;
33
34 namespace lyx {
35 namespace frontend {
36
37
38 /////////////////////////////////////////////////////////////////////
39 //
40 // GuiListings
41 //
42 /////////////////////////////////////////////////////////////////////
43
44
45 char const * languages[] =
46 { "no language", "ABAP", "ACSL", "Ada", "ALGOL", "Assembler", "Awk", "bash", "Basic", "C",
47   "C++", "Caml", "Clean", "Cobol", "Comal 80", "command.com", "Comsol", "csh", "Delphi",
48   "Eiffel", "Elan", "erlang", "Euphoria", "Fortran", "Gnuplot", "Haskell", "HTML", "IDL", "inform",
49   "Java", "JVMIS", "ksh", "Lingo", "Lisp", "Logo", "make", "Mathematica", "Matlab", "Mercury",
50   "MetaPost", "Miranda", "ML", "Modula-2", "MuPAD", "NASTRAN", "Oberon-2", "OCL", "Octave",
51   "Oz", "Pascal", "Perl", "PHP", "PL/I", "Plasm", "PostScript", "POV", "Prolog", "Promela",
52   "PSTricks", "Python", "R", "Reduce", "Rexx", "RSL", "Ruby", "S", "SAS", "Scilab", "sh",
53   "SHELXL", "Simula", "tcl", "SPARQL", "SQL", "tcl", "TeX", "VBScript", "Verilog", "VHDL",
54   "VRML", "XML", "XSLT", "" };
55
56
57 char const * languages_gui[] =
58 { N_("No language"), "ABAP", "ACSL", "Ada", "ALGOL", "Assembler", "Awk", "bash", "Basic",
59   "C", "C++", "Caml", "Clean", "Cobol", "Comal 80", "command.com", "Comsol", "csh", "Delphi",
60   "Eiffel", "Elan", "Erlang", "Euphoria", "Fortran", "Gnuplot", "Haskell", "HTML", "IDL", "inform",
61   "Java", "JVMIS", "ksh", "Lingo", "Lisp", "Logo", "make", "Mathematica", "Matlab", "Mercury",
62   "MetaPost", "Miranda", "ML", "Modula-2", "MuPAD", "NASTRAN", "Oberon-2", "OCL", "Octave",
63   "Oz", "Pascal", "Perl", "PHP", "PL/I", "Plasm", "PostScript", "POV", "Prolog", "Promela",
64   "PSTricks", "Python", "R", "Reduce", "Rexx", "RSL", "Ruby", "S", "SAS", "Scilab", "sh",
65   "SHELXL", "Simula", "tcl", "SPARQL", "SQL", "tcl", "TeX", "VBScript", "Verilog", "VHDL",
66   "VRML", "XML", "XSLT", "" };
67
68
69 struct dialect_info {
70         /// the dialect
71         char const * dialect;
72         /// the associated language
73         char const * language;
74         /// representation of the dialect in the gui
75         char const * gui;
76         /// is this the default dialect?
77         bool is_default;
78 };
79
80
81 dialect_info const dialects[] = {
82         { "R/2 4.3", "ABAP", "R/2 4.3", false },
83         { "R/2 5.0", "ABAP", "R/2 5.0", false },
84         { "R/3 3.1", "ABAP", "R/3 3.1", false },
85         { "R/3 4.6C", "ABAP", "R/3 4.6C", false },
86         { "R/3 6.10", "ABAP", "R/3 6.10", true },
87         { "2005", "Ada", "2005", true },
88         { "83", "Ada", "83", false },
89         { "95", "Ada", "95", false },
90         { "60", "Algol", "60", false },
91         { "68", "Algol", "68", true },
92         { "Motorola68k", "Assembler", "Motorola 68xxx", false },
93         { "x86masm", "Assembler", "x86 (MASM)", false },
94         { "gnu", "Awk", "gnu", true },
95         { "POSIX", "Awk", "POSIX", false },
96         { "Visual", "Basic", "Visual", false },
97         { "ANSI", "C", "ANSI", true },
98         { "Handel", "C", "Handel", false },
99         { "Objective", "C", "Objective", false },
100         { "Sharp", "C", "Sharp", false },
101         { "ANSI", "C++", "ANSI", false },
102         { "GNU", "C++", "GNU", false },
103         { "ISO", "C++", "ISO", true },
104         { "Visual", "C++", "Visual", false },
105         { "light", "Caml", "light", true },
106         { "Objective", "Caml", "Objective", false },
107         { "1974", "Cobol", "1974", false },
108         { "1985", "Cobol", "1985", true },
109         { "ibm", "Cobol", "IBM", false },
110         { "WinXP", "command.com", "Windows XP", true },
111         { "77", "Fortran", "77", false },
112         { "90", "Fortran", "90", false },
113         { "95", "Fortran", "95", true },
114         { "CORBA", "IDL", "CORBA", false },
115         { "AspectJ", "Java", "Aspect J", false },
116         { "Auto", "Lisp", "Auto", false },
117         { "gnu", "make", "gnu", false },
118         { "1.0", "Mathematica", "1.0", false },
119         { "3.0", "Mathematica", "3.0", false },
120         { "5.2", "Mathematica", "5.2", true },
121         { "decorative", "OCL", "decorative", false },
122         { "OMG", "OCL", "OMG", true },
123         { "Borland6", "Pascal", "Borland 6", false },
124         { "Standard", "Pascal", "Standard", true },
125         { "XSC", "Pascal", "XSC", false },
126         { "PLUS", "S", "PLUS", false },
127         { "67", "Simula", "67", true },
128         { "CII", "Simula", "CII", false },
129         { "DEC", "Simula", "DEC", false },
130         { "IBM", "Simula", "IBM", false },
131         { "tk", "tcl", "tk", false },
132         { "AlLaTeX", "TeX", "AlLaTeX", false },
133         { "common", "TeX", "common", false },
134         { "LaTeX", "TeX", "LaTeX", false },
135         { "plain", "TeX", "plain", true },
136         { "primitive", "TeX", "primitive", false },
137         { "AMS", "VHDL", "AMS", false },
138         { "97", "VRML", "97", true }
139 };
140
141
142 size_t const nr_dialects = sizeof(dialects) / sizeof(dialect_info);
143
144
145 char const * font_sizes[] =
146 { "default", "tiny", "scriptsize", "footnotesize", "small", "normalsize", "large",
147   "Large", "" };
148
149 char const * font_sizes_gui[] =
150 { N_("Default"), N_("Tiny"), N_("Smallest"), N_("Smaller"), N_("Small"), N_("Normal"),
151   N_("Large"), N_("Larger"), "" };
152
153 char const * font_styles[] =
154 { "default", "rmfamily", "ttfamily", "sffamily", "" };
155
156 char const * font_styles_gui[] =
157 { N_("Default"), N_("Roman"), N_("Typewriter"), N_("Sans Serif"), "" };
158
159
160
161 GuiListings::GuiListings(GuiView & lv)
162         : GuiDialog(lv, "listings", qt_("Program Listing Settings"))
163 {
164         setupUi(this);
165
166         connect(okPB, SIGNAL(clicked()), this, SLOT(slotOK()));
167         connect(applyPB, SIGNAL(clicked()), this, SLOT(slotApply()));
168         connect(closePB, SIGNAL(clicked()), this, SLOT(slotClose()));
169
170         connect(languageCO, SIGNAL(currentIndexChanged(int)),
171                 this, SLOT(change_adaptor()));
172         connect(dialectCO, SIGNAL(currentIndexChanged(int)),
173                 this, SLOT(change_adaptor()));
174         connect(inlineCB, SIGNAL(clicked()),
175                 this, SLOT(change_adaptor()));
176         connect(floatCB, SIGNAL(clicked()),
177                 this, SLOT(change_adaptor()));
178         connect(placementLE, SIGNAL(textChanged(QString)),
179                 this, SLOT(change_adaptor()));
180         connect(numberSideCO, SIGNAL(currentIndexChanged(int)),
181                 this, SLOT(change_adaptor()));
182         connect(numberStepLE, SIGNAL(textChanged(QString)),
183                 this, SLOT(change_adaptor()));
184         connect(numberFontSizeCO, SIGNAL(currentIndexChanged(int)),
185                 this, SLOT(change_adaptor()));
186         connect(firstlineLE, SIGNAL(textChanged(QString)),
187                 this, SLOT(change_adaptor()));
188         connect(lastlineLE, SIGNAL(textChanged(QString)),
189                 this, SLOT(change_adaptor()));
190         connect(fontsizeCO, SIGNAL(currentIndexChanged(int)),
191                 this, SLOT(change_adaptor()));
192         connect(fontstyleCO, SIGNAL(currentIndexChanged(int)),
193                 this, SLOT(change_adaptor()));
194         connect(breaklinesCB, SIGNAL(clicked()),
195                 this, SLOT(change_adaptor()));
196         connect(spaceCB, SIGNAL(clicked()),
197                 this, SLOT(change_adaptor()));
198         connect(spaceInStringCB, SIGNAL(clicked()),
199                 this, SLOT(change_adaptor()));
200         connect(extendedcharsCB, SIGNAL(clicked()),
201                 this, SLOT(change_adaptor()));
202
203         connect(listingsED,  SIGNAL(textChanged()),
204                 this, SLOT(change_adaptor()));
205         connect(listingsED,  SIGNAL(textChanged()),
206                 this, SLOT(set_listings_msg()));
207         connect(bypassCB, SIGNAL(clicked()),
208                 this, SLOT(change_adaptor()));
209         connect(bypassCB, SIGNAL(clicked()),
210                 this, SLOT(set_listings_msg()));
211
212         for (int n = 0; languages[n][0]; ++n)
213                 languageCO->addItem(qt_(languages_gui[n]));
214
215         for (int n = 0; font_styles[n][0]; ++n)
216                 fontstyleCO->addItem(qt_(font_styles_gui[n]));
217
218         for (int n = 0; font_sizes[n][0]; ++n) {
219                 QString font = qt_(font_sizes_gui[n]);
220                 fontsizeCO->addItem(font);
221                 numberFontSizeCO->addItem(font);
222         }
223
224         // set validators
225         numberStepLE->setValidator(new QIntValidator(0, 1000000, this));
226         firstlineLE->setValidator(new QIntValidator(0, 1000000, this));
227         lastlineLE->setValidator(new QIntValidator(0, 1000000, this));
228         placementLE->setValidator(new QRegExpValidator(QRegExp("[\\*tbph]*"), this));
229
230         bc().setOK(okPB);
231         bc().setApply(applyPB);
232         bc().setCancel(closePB);
233         listingsTB->setPlainText(
234                 qt_("Input listing parameters on the right. Enter ? for a list of parameters."));
235
236         updateContents();
237
238 }
239
240
241 void GuiListings::change_adaptor()
242 {
243         changed();
244 }
245
246
247 string GuiListings::construct_params()
248 {
249         string language = languages[languageCO->currentIndex()];
250         string dialect;
251         string const dialect_gui = fromqstr(dialectCO->currentText());
252         if (dialectCO->currentIndex() > 0) {
253                 for (size_t i = 0; i != nr_dialects; ++i) {
254                         if (dialect_gui == dialects[i].gui
255                         && dialects[i].language == language
256                         && !dialects[i].is_default) {
257                                 dialect = dialects[i].dialect;
258                                 break;
259                         }
260                 }
261         }
262
263         bool float_ = floatCB->isChecked();
264         string placement;
265         if (placementLE->isEnabled())
266                 placement = fromqstr(placementLE->text());
267
268         string numberSide;
269         switch (numberSideCO->currentIndex()) {
270         case 0:
271                 numberSide = "none";
272                 break;
273         case 1:
274                 numberSide = "left";
275                 break;
276         case 2:
277                 numberSide = "right";
278                 break;
279         default:
280                 numberSide = "none";
281                 break;
282         }
283         string stepnumber = fromqstr(numberStepLE->text());
284         string numberfontsize = font_sizes[numberFontSizeCO->currentIndex()];
285         string firstline = fromqstr(firstlineLE->text());
286         string lastline = fromqstr(lastlineLE->text());
287
288         string fontsize = font_sizes[fontsizeCO->currentIndex()];
289         string fontstyle = font_styles[fontstyleCO->currentIndex()];
290         string basicstyle;
291         if (fontsize != "default")
292                 basicstyle = "\\" + fontsize;
293         if (fontstyle != "default")
294                 basicstyle += "\\" + fontstyle;
295         bool breakline = breaklinesCB->isChecked();
296         bool space = spaceCB->isChecked();
297         bool spaceInString = spaceInStringCB->isChecked();
298         bool extendedchars = extendedcharsCB->isChecked();
299         string extra = fromqstr(listingsED->toPlainText());
300
301         // compose a string
302         InsetListingsParams par;
303         if (language != "no language" && !contains(extra, "language=")) {
304                 if (dialect.empty())
305                         par.addParam("language", language);
306                 else
307                         par.addParam("language", "{[" + dialect + "]" + language + "}");
308         }
309         // this dialog uses float=placement instead of float,floatplacement=placement
310         // because float accepts *tbph and floatplacement accepts bph.
311         // our placement textedit is actually for the float parameter
312         if (float_)
313                 par.addParam("float", placement);
314         if (numberSide != "none")
315                 par.addParam("numbers", numberSide);
316         if (numberfontsize != "default" && numberSide != "none")
317                 par.addParam("numberstyle", "\\" + numberfontsize);
318         if (!stepnumber.empty() && numberSide != "none")
319                 par.addParam("stepnumber", stepnumber);
320         if (!firstline.empty())
321                 par.addParam("firstline", firstline);
322         if (!lastline.empty())
323                 par.addParam("lastline", lastline);
324         if (!basicstyle.empty())
325                 par.addParam("basicstyle", basicstyle);
326         if (breakline)
327                 par.addParam("breaklines", "true");
328         if (space)
329                 par.addParam("showspaces", "true");
330         if (!spaceInString)
331                 par.addParam("showstringspaces", "false");
332         if (extendedchars)
333                 par.addParam("extendedchars", "true");
334         par.addParams(extra);
335         return par.params();
336 }
337
338
339 docstring GuiListings::validate_listings_params()
340 {
341         // use a cache here to avoid repeated validation
342         // of the same parameters
343         static string param_cache;
344         static docstring msg_cache;
345         
346         if (bypassCB->isChecked())
347                 return docstring();
348
349         string params = construct_params();
350         if (params != param_cache) {
351                 param_cache = params;
352                 msg_cache = InsetListingsParams(params).validate();
353         }
354         return msg_cache;
355 }
356
357
358 void GuiListings::set_listings_msg()
359 {
360         static bool isOK = true;
361         docstring msg = validate_listings_params();
362         if (msg.empty()) {
363                 if (isOK)
364                         return;
365                 isOK = true;
366                 listingsTB->setPlainText(
367                         qt_("Input listing parameters on the right. Enter ? for a list of parameters."));
368         } else {
369                 isOK = false;
370                 listingsTB->setPlainText(toqstr(msg));
371         }
372 }
373
374
375 void GuiListings::on_floatCB_stateChanged(int state)
376 {
377         if (state == Qt::Checked) {
378                 inlineCB->setChecked(false);
379                 placementLE->setEnabled(true);
380         } else
381                 placementLE->setEnabled(false);
382 }
383
384
385 void GuiListings::on_inlineCB_stateChanged(int state)
386 {
387         if (state == Qt::Checked) {
388                 floatCB->setChecked(false);
389                 placementLE->setEnabled(false);
390         }
391 }
392
393
394 void GuiListings::on_numberSideCO_currentIndexChanged(int index)
395 {
396         numberStepLE->setEnabled(index > 0);
397         numberFontSizeCO->setEnabled(index > 0);
398 }
399
400
401 void GuiListings::on_languageCO_currentIndexChanged(int index)
402 {
403         dialectCO->clear();
404         // 0 is "no dialect"
405         int default_dialect = 0;
406         dialectCO->addItem(qt_("No dialect"));
407         string const language = languages[index];
408
409         for (size_t i = 0; i != nr_dialects; ++i) {
410                 if (language == dialects[i].language) {
411                         dialectCO->addItem(qt_(dialects[i].gui));
412                         if (dialects[i].is_default)
413                                 default_dialect =
414                                         dialectCO->findText(qt_(dialects[i].gui));
415                 }
416         }
417         dialectCO->setCurrentIndex(default_dialect);
418         dialectCO->setEnabled(dialectCO->count() > 1);
419 }
420
421
422 void GuiListings::applyView()
423 {
424         params_.setInline(inlineCB->isChecked());
425         params_.setParams(construct_params());
426 }
427
428
429 static string plainParam(string const & par)
430 {
431         // remove enclosing braces
432         if (prefixIs(par, "{") && suffixIs(par, "}"))
433                 return par.substr(1, par.size() - 2);
434         return par;
435 }
436
437
438 void GuiListings::updateContents()
439 {
440         // set default values
441         listingsTB->setPlainText(
442                 qt_("Input listing parameters on the right. Enter ? for a list of parameters."));
443         languageCO->setCurrentIndex(findToken(languages, "no language"));
444         dialectCO->setCurrentIndex(0);
445         floatCB->setChecked(false);
446         placementLE->clear();
447         numberSideCO->setCurrentIndex(0);
448         numberStepLE->clear();
449         numberFontSizeCO->setCurrentIndex(findToken(font_sizes, "default"));
450         firstlineLE->clear();
451         lastlineLE->clear();
452         fontstyleCO->setCurrentIndex(findToken(font_styles, "default"));
453         fontsizeCO->setCurrentIndex(findToken(font_sizes, "default"));
454         breaklinesCB->setChecked(false);
455         spaceCB->setChecked(false);
456         spaceInStringCB->setChecked(true);
457         extendedcharsCB->setChecked(false);
458
459         // set values from param string
460         inlineCB->setChecked(params_.isInline());
461         if (params_.isInline()) {
462                 floatCB->setChecked(false);
463                 placementLE->setEnabled(false);
464         }
465         // break other parameters and set values
466         vector<string> pars = getVectorFromString(params_.separatedParams(), "\n");
467         // process each of them
468         for (vector<string>::iterator it = pars.begin();
469             it != pars.end(); ++it) {
470                 if (prefixIs(*it, "language=")) {
471                         string arg = plainParam(it->substr(9));
472                         // has dialect?
473                         string language;
474                         string dialect;
475                         bool in_gui = false;
476                         if (prefixIs(arg, "[") && contains(arg, "]")) {
477                                 size_t end_dialect = arg.find("]");
478                                 dialect = arg.substr(1, end_dialect - 1);
479                                 language = arg.substr(end_dialect + 1);
480                         } else {
481                                 language = arg;
482                         }
483                         int n = findToken(languages, language);
484                         if (n >= 0) {
485                                 languageCO->setCurrentIndex(n);
486                                 in_gui = true;
487                         }
488                         // on_languageCO_currentIndexChanged should have set dialects
489                         if (!dialect.empty()) {
490                                 string dialect_gui;
491                                 for (size_t i = 0; i != nr_dialects; ++i) {
492                                         if (dialect == dialects[i].dialect
493                                             && dialects[i].language == language) {
494                                                 dialect_gui = dialects[i].gui;
495                                                 break;
496                                         }
497                                 }
498                                 n = dialectCO->findText(qt_(dialect_gui));
499                                 if (n >= 0)
500                                         dialectCO->setCurrentIndex(n);
501                                 else
502                                         in_gui = false;
503                         }
504                         if (in_gui)
505                                 *it = "";
506                         languageCO->setEnabled(in_gui);
507                         dialectCO->setEnabled(
508                                 in_gui && dialectCO->count() > 1);
509                 } else if (prefixIs(*it, "float")) {
510                         floatCB->setChecked(true);
511                         inlineCB->setChecked(false);
512                         placementLE->setEnabled(true);
513                         if (prefixIs(*it, "float="))
514                                 placementLE->setText(
515                                         toqstr(plainParam(it->substr(6))));
516                         *it = "";
517                 } else if (prefixIs(*it, "numbers=")) {
518                         string s = plainParam(it->substr(8));
519                         int n = 0;
520                         if (s == "left")
521                                 n = 1;
522                         else if (s == "right")
523                                 n = 2;
524                         numberSideCO->setCurrentIndex(n);
525                         *it = "";
526                 } else if (prefixIs(*it, "stepnumber=")) {
527                         numberStepLE->setText(
528                                 toqstr(plainParam(it->substr(11))));
529                         *it = "";
530                 } else if (prefixIs(*it, "numberstyle=")) {
531                         string par = plainParam(it->substr(12));
532                         int n = findToken(font_sizes, par.substr(1));
533                         if (n >= 0)
534                                 numberFontSizeCO->setCurrentIndex(n);
535                         *it = "";
536                 } else if (prefixIs(*it, "firstline=")) {
537                         firstlineLE->setText(
538                                 toqstr(plainParam(it->substr(10))));
539                         *it = "";
540                 } else if (prefixIs(*it, "lastline=")) {
541                         lastlineLE->setText(
542                                 toqstr(plainParam(it->substr(9))));
543                         *it = "";
544                 } else if (prefixIs(*it, "basicstyle=")) {
545                         string style;
546                         string size;
547                         for (int n = 0; font_styles[n][0]; ++n) {
548                                 string const s = font_styles[n];
549                                 if (contains(*it, "\\" + s)) {
550                                         style = "\\" + s;
551                                         break;
552                                 }
553                         }
554                         for (int n = 0; font_sizes[n][0]; ++n) {
555                                 string const s = font_sizes[n];
556                                 if (contains(*it, "\\" + s)) {
557                                         size = "\\" + s;
558                                         break;
559                                 }
560                         }
561                         if (plainParam(it->substr(11)) == style + size
562                             || plainParam(it->substr(11)) == size + style) {
563                                 if (!style.empty()) {
564                                         int n = findToken(font_styles, style.substr(1));
565                                         if (n >= 0)
566                                                 fontstyleCO->setCurrentIndex(n);
567                                 }
568                                 if (!size.empty()) {
569                                         int n = findToken(font_sizes, size.substr(1));
570                                         if (n >= 0)
571                                                 fontsizeCO->setCurrentIndex(n);
572                                 }
573                                 *it = "";
574                         }
575                 } else if (prefixIs(*it, "breaklines=")) {
576                         breaklinesCB->setChecked(contains(*it, "true"));
577                         *it = "";
578                 } else if (prefixIs(*it, "showspaces=")) {
579                         spaceCB->setChecked(contains(*it, "true"));
580                         *it = "";
581                 } else if (prefixIs(*it, "showstringspaces=")) {
582                         spaceInStringCB->setChecked(contains(*it, "true"));
583                         *it = "";
584                 } else if (prefixIs(*it, "extendedchars=")) {
585                         extendedcharsCB->setChecked(contains(*it, "true"));
586                         *it = "";
587                 }
588         }
589
590         numberStepLE->setEnabled(numberSideCO->currentIndex() > 0);
591         numberFontSizeCO->setEnabled(numberSideCO->currentIndex() > 0);
592         // parameters that can be handled by widgets are cleared
593         // the rest is put to the extra edit box.
594         string extra = getStringFromVector(pars);
595         listingsED->setPlainText(toqstr(InsetListingsParams(extra).separatedParams()));
596 }
597
598
599 bool GuiListings::isValid()
600 {
601         return validate_listings_params().empty();
602 }
603
604
605 bool GuiListings::initialiseParams(string const & data)
606 {
607         InsetListingsMailer::string2params(data, params_);
608         return true;
609 }
610
611
612 void GuiListings::clearParams()
613 {
614         params_.clear();
615 }
616
617
618 void GuiListings::dispatchParams()
619 {
620         string const lfun = InsetListingsMailer::params2string(params_);
621         dispatch(FuncRequest(getLfun(), lfun));
622 }
623
624
625 void GuiListings::setParams(InsetListingsParams const & params)
626 {
627         params_ = params;
628 }
629
630
631 Dialog * createGuiListings(GuiView & lv) { return new GuiListings(lv); }
632
633
634 } // namespace frontend
635 } // namespace lyx
636
637
638 #include "GuiListings_moc.cpp"