2 * \file GuiListings.cpp
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
7 * \author Jürgen Spitzmüller
9 * Full author contact details are available in file CREDITS.
14 #include "GuiListings.h"
16 #include "qt_helpers.h"
18 #include "FuncRequest.h"
20 #include "insets/InsetListings.h"
21 #include "insets/InsetListingsParams.h"
23 #include "support/convert.h"
24 #include "support/gettext.h"
25 #include "support/lstrings.h"
28 #include <QPushButton>
30 #include <QRegExpValidator>
33 using namespace lyx::support;
39 /////////////////////////////////////////////////////////////////////
43 /////////////////////////////////////////////////////////////////////
46 char const * languages_supported[] =
47 { "no language", "ABAP", "ACSL", "Ada", "ALGOL", "Assembler", "Awk", "bash", "Basic", "C",
48 "C++", "Caml", "Clean", "Cobol", "Comal 80", "command.com", "Comsol", "csh", "Delphi",
49 "Eiffel", "Elan", "erlang", "Euphoria", "Fortran", "Gnuplot", "Haskell", "HTML", "IDL", "inform",
50 "Java", "JVMIS", "ksh", "Lingo", "Lisp", "Logo", "make", "Mathematica", "Matlab", "Mercury",
51 "MetaPost", "Miranda", "ML", "Modula-2", "MuPAD", "NASTRAN", "Oberon-2", "OCL", "Octave",
52 "Oz", "Pascal", "Perl", "PHP", "PL/I", "Plasm", "PostScript", "POV", "Prolog", "Promela",
53 "PSTricks", "Python", "R", "Reduce", "Rexx", "RSL", "Ruby", "S", "SAS", "Scilab", "sh",
54 "SHELXL", "Simula", "tcl", "SPARQL", "SQL", "tcl", "TeX", "VBScript", "Verilog", "VHDL",
55 "VRML", "XML", "XSLT", "" };
58 char const * languages_gui[] =
59 { N_("No language"), "ABAP", "ACSL", "Ada", "ALGOL", "Assembler", "Awk", "bash", "Basic",
60 "C", "C++", "Caml", "Clean", "Cobol", "Comal 80", "command.com", "Comsol", "csh", "Delphi",
61 "Eiffel", "Elan", "Erlang", "Euphoria", "Fortran", "Gnuplot", "Haskell", "HTML", "IDL", "inform",
62 "Java", "JVMIS", "ksh", "Lingo", "Lisp", "Logo", "make", "Mathematica", "Matlab", "Mercury",
63 "MetaPost", "Miranda", "ML", "Modula-2", "MuPAD", "NASTRAN", "Oberon-2", "OCL", "Octave",
64 "Oz", "Pascal", "Perl", "PHP", "PL/I", "Plasm", "PostScript", "POV", "Prolog", "Promela",
65 "PSTricks", "Python", "R", "Reduce", "Rexx", "RSL", "Ruby", "S", "SAS", "Scilab", "sh",
66 "SHELXL", "Simula", "tcl", "SPARQL", "SQL", "tcl", "TeX", "VBScript", "Verilog", "VHDL",
67 "VRML", "XML", "XSLT", "" };
73 /// the associated language
74 char const * language;
75 /// representation of the dialect in the gui
77 /// is this the default dialect?
82 dialect_info const dialects[] = {
83 { "R/2 4.3", "ABAP", "R/2 4.3", false },
84 { "R/2 5.0", "ABAP", "R/2 5.0", false },
85 { "R/3 3.1", "ABAP", "R/3 3.1", false },
86 { "R/3 4.6C", "ABAP", "R/3 4.6C", false },
87 { "R/3 6.10", "ABAP", "R/3 6.10", true },
88 { "2005", "Ada", "2005", true },
89 { "83", "Ada", "83", false },
90 { "95", "Ada", "95", false },
91 { "60", "Algol", "60", false },
92 { "68", "Algol", "68", true },
93 { "Motorola68k", "Assembler", "Motorola 68xxx", false },
94 { "x86masm", "Assembler", "x86 (MASM)", false },
95 { "gnu", "Awk", "gnu", true },
96 { "POSIX", "Awk", "POSIX", false },
97 { "Visual", "Basic", "Visual", false },
98 { "ANSI", "C", "ANSI", true },
99 { "Handel", "C", "Handel", false },
100 { "Objective", "C", "Objective", false },
101 { "Sharp", "C", "Sharp", false },
102 { "ANSI", "C++", "ANSI", false },
103 { "GNU", "C++", "GNU", false },
104 { "ISO", "C++", "ISO", true },
105 { "Visual", "C++", "Visual", false },
106 { "light", "Caml", "light", true },
107 { "Objective", "Caml", "Objective", false },
108 { "1974", "Cobol", "1974", false },
109 { "1985", "Cobol", "1985", true },
110 { "ibm", "Cobol", "IBM", false },
111 { "WinXP", "command.com", "Windows XP", true },
112 { "77", "Fortran", "77", false },
113 { "90", "Fortran", "90", false },
114 { "95", "Fortran", "95", true },
115 { "CORBA", "IDL", "CORBA", false },
116 { "AspectJ", "Java", "Aspect J", false },
117 { "Auto", "Lisp", "Auto", false },
118 { "gnu", "make", "gnu", false },
119 { "1.0", "Mathematica", "1.0", false },
120 { "3.0", "Mathematica", "3.0", false },
121 { "5.2", "Mathematica", "5.2", true },
122 { "decorative", "OCL", "decorative", false },
123 { "OMG", "OCL", "OMG", true },
124 { "Borland6", "Pascal", "Borland 6", false },
125 { "Standard", "Pascal", "Standard", true },
126 { "XSC", "Pascal", "XSC", false },
127 { "PLUS", "S", "PLUS", false },
128 { "67", "Simula", "67", true },
129 { "CII", "Simula", "CII", false },
130 { "DEC", "Simula", "DEC", false },
131 { "IBM", "Simula", "IBM", false },
132 { "tk", "tcl", "tk", false },
133 { "AlLaTeX", "TeX", "AlLaTeX", false },
134 { "common", "TeX", "common", false },
135 { "LaTeX", "TeX", "LaTeX", false },
136 { "plain", "TeX", "plain", true },
137 { "primitive", "TeX", "primitive", false },
138 { "AMS", "VHDL", "AMS", false },
139 { "97", "VRML", "97", true }
143 size_t const nr_dialects = sizeof(dialects) / sizeof(dialect_info);
146 char const * font_sizes[] =
147 { "default", "tiny", "scriptsize", "footnotesize", "small", "normalsize", "large",
150 char const * font_sizes_gui[] =
151 { N_("Default"), N_("Tiny"), N_("Smallest"), N_("Smaller"), N_("Small"), N_("Normal"),
152 N_("Large"), N_("Larger"), "" };
154 char const * font_styles[] =
155 { "default", "rmfamily", "ttfamily", "sffamily", "" };
157 char const * font_styles_gui[] =
158 { N_("Default"), N_("Roman"), N_("Typewriter"), N_("Sans Serif"), "" };
162 GuiListings::GuiListings(GuiView & lv)
163 : GuiDialog(lv, "listings", qt_("Program Listing Settings"))
167 connect(okPB, SIGNAL(clicked()), this, SLOT(slotOK()));
168 connect(applyPB, SIGNAL(clicked()), this, SLOT(slotApply()));
169 connect(closePB, SIGNAL(clicked()), this, SLOT(slotClose()));
171 connect(languageCO, SIGNAL(currentIndexChanged(int)),
172 this, SLOT(change_adaptor()));
173 connect(dialectCO, SIGNAL(currentIndexChanged(int)),
174 this, SLOT(change_adaptor()));
175 connect(inlineCB, SIGNAL(clicked()),
176 this, SLOT(change_adaptor()));
177 connect(floatCB, SIGNAL(clicked()),
178 this, SLOT(change_adaptor()));
179 connect(placementLE, SIGNAL(textChanged(QString)),
180 this, SLOT(change_adaptor()));
181 connect(numberSideCO, SIGNAL(currentIndexChanged(int)),
182 this, SLOT(change_adaptor()));
183 connect(numberStepLE, SIGNAL(textChanged(QString)),
184 this, SLOT(change_adaptor()));
185 connect(numberFontSizeCO, SIGNAL(currentIndexChanged(int)),
186 this, SLOT(change_adaptor()));
187 connect(firstlineLE, SIGNAL(textChanged(QString)),
188 this, SLOT(change_adaptor()));
189 connect(lastlineLE, SIGNAL(textChanged(QString)),
190 this, SLOT(change_adaptor()));
191 connect(fontsizeCO, SIGNAL(currentIndexChanged(int)),
192 this, SLOT(change_adaptor()));
193 connect(fontstyleCO, SIGNAL(currentIndexChanged(int)),
194 this, SLOT(change_adaptor()));
195 connect(breaklinesCB, SIGNAL(clicked()),
196 this, SLOT(change_adaptor()));
197 connect(spaceCB, SIGNAL(clicked()),
198 this, SLOT(change_adaptor()));
199 connect(spaceInStringCB, SIGNAL(clicked()),
200 this, SLOT(change_adaptor()));
201 connect(tabsizeSB, SIGNAL(valueChanged(int)),
202 this, SLOT(change_adaptor()));
203 connect(extendedcharsCB, SIGNAL(clicked()),
204 this, SLOT(change_adaptor()));
206 connect(listingsED, SIGNAL(textChanged()),
207 this, SLOT(change_adaptor()));
208 connect(listingsED, SIGNAL(textChanged()),
209 this, SLOT(setListingsMsg()));
210 connect(bypassCB, SIGNAL(clicked()),
211 this, SLOT(change_adaptor()));
212 connect(bypassCB, SIGNAL(clicked()),
213 this, SLOT(setListingsMsg()));
215 for (int n = 0; languages_supported[n][0]; ++n)
216 languageCO->addItem(qt_(languages_gui[n]));
218 for (int n = 0; font_styles[n][0]; ++n)
219 fontstyleCO->addItem(qt_(font_styles_gui[n]));
221 for (int n = 0; font_sizes[n][0]; ++n) {
222 QString font = qt_(font_sizes_gui[n]);
223 fontsizeCO->addItem(font);
224 numberFontSizeCO->addItem(font);
228 numberStepLE->setValidator(new QIntValidator(0, 1000000, this));
229 firstlineLE->setValidator(new QIntValidator(0, 1000000, this));
230 lastlineLE->setValidator(new QIntValidator(0, 1000000, this));
231 placementLE->setValidator(new QRegExpValidator(QRegExp("[\\*tbph]*"), this));
233 bc().setPolicy(ButtonPolicy::NoRepeatedApplyReadOnlyPolicy);
235 bc().setApply(applyPB);
236 bc().setCancel(closePB);
237 listingsTB->setPlainText(
238 qt_("Input listing parameters on the right. Enter ? for a list of parameters."));
245 void GuiListings::change_adaptor()
251 string GuiListings::construct_params()
253 string language = languages_supported[qMax(0, languageCO->currentIndex())];
255 string const dialect_gui = fromqstr(dialectCO->currentText());
256 if (dialectCO->currentIndex() > 0) {
257 for (size_t i = 0; i != nr_dialects; ++i) {
258 if (dialect_gui == dialects[i].gui
259 && dialects[i].language == language
260 && !dialects[i].is_default) {
261 dialect = dialects[i].dialect;
267 bool float_ = floatCB->isChecked();
269 if (placementLE->isEnabled())
270 placement = fromqstr(placementLE->text());
273 switch (qMax(0, numberSideCO->currentIndex())) {
281 numberSide = "right";
287 string stepnumber = fromqstr(numberStepLE->text());
288 string numberfontsize = font_sizes[qMax(0, numberFontSizeCO->currentIndex())];
289 string firstline = fromqstr(firstlineLE->text());
290 string lastline = fromqstr(lastlineLE->text());
292 string fontsize = font_sizes[qMax(0, fontsizeCO->currentIndex())];
293 string fontstyle = font_styles[qMax(0, fontstyleCO->currentIndex())];
295 if (fontsize != "default")
296 basicstyle = "\\" + fontsize;
297 if (fontstyle != "default")
298 basicstyle += "\\" + fontstyle;
299 bool breakline = breaklinesCB->isChecked();
300 bool space = spaceCB->isChecked();
301 int tabsize = tabsizeSB->value();
302 bool spaceInString = spaceInStringCB->isChecked();
303 bool extendedchars = extendedcharsCB->isChecked();
304 string extra = fromqstr(listingsED->toPlainText());
307 InsetListingsParams par;
308 if (language != "no language" && !contains(extra, "language=")) {
310 par.addParam("language", language);
312 par.addParam("language", "{[" + dialect + "]" + language + "}");
314 // this dialog uses float=placement instead of float,floatplacement=placement
315 // because float accepts *tbph and floatplacement accepts bph.
316 // our placement textedit is actually for the float parameter
318 par.addParam("float", placement);
319 if (numberSide != "none")
320 par.addParam("numbers", numberSide);
321 if (numberfontsize != "default" && numberSide != "none")
322 par.addParam("numberstyle", "\\" + numberfontsize);
323 if (!stepnumber.empty() && numberSide != "none")
324 par.addParam("stepnumber", stepnumber);
325 if (!firstline.empty())
326 par.addParam("firstline", firstline);
327 if (!lastline.empty())
328 par.addParam("lastline", lastline);
329 if (!basicstyle.empty())
330 par.addParam("basicstyle", basicstyle);
332 par.addParam("breaklines", "true");
334 par.addParam("showspaces", "true");
336 par.addParam("showstringspaces", "false");
338 par.addParam("tabsize", convert<string>(tabsize));
340 par.addParam("extendedchars", "true");
341 par.addParams(extra);
346 docstring GuiListings::validate_listings_params()
348 // use a cache here to avoid repeated validation
349 // of the same parameters
350 static string param_cache;
351 static docstring msg_cache;
353 if (bypassCB->isChecked())
356 string params = construct_params();
357 if (params != param_cache) {
358 param_cache = params;
359 msg_cache = InsetListingsParams(params).validate();
365 void GuiListings::setListingsMsg()
367 static bool isOK = true;
368 docstring msg = validate_listings_params();
373 listingsTB->setPlainText(
374 qt_("Input listing parameters on the right. Enter ? for a list of parameters."));
377 listingsTB->setPlainText(toqstr(msg));
382 void GuiListings::on_floatCB_stateChanged(int state)
384 if (state == Qt::Checked) {
385 inlineCB->setChecked(false);
386 placementLE->setEnabled(true);
388 placementLE->setEnabled(false);
392 void GuiListings::on_inlineCB_stateChanged(int state)
394 if (state == Qt::Checked) {
395 floatCB->setChecked(false);
396 placementLE->setEnabled(false);
401 void GuiListings::on_numberSideCO_currentIndexChanged(int index)
403 numberStepLE->setEnabled(index > 0);
404 numberFontSizeCO->setEnabled(index > 0);
408 void GuiListings::on_languageCO_currentIndexChanged(int index)
412 int default_dialect = 0;
413 dialectCO->addItem(qt_("No dialect"));
414 string const language = languages_supported[index];
416 for (size_t i = 0; i != nr_dialects; ++i) {
417 if (language == dialects[i].language) {
418 dialectCO->addItem(qt_(dialects[i].gui));
419 if (dialects[i].is_default)
421 dialectCO->findText(qt_(dialects[i].gui));
424 dialectCO->setCurrentIndex(default_dialect);
425 dialectCO->setEnabled(dialectCO->count() > 1);
429 void GuiListings::applyView()
431 params_.setInline(inlineCB->isChecked());
432 params_.setParams(construct_params());
436 static string plainParam(string const & par)
438 // remove enclosing braces
439 if (prefixIs(par, "{") && suffixIs(par, "}"))
440 return par.substr(1, par.size() - 2);
445 void GuiListings::updateContents()
447 // set default values
448 listingsTB->setPlainText(
449 qt_("Input listing parameters on the right. Enter ? for a list of parameters."));
450 languageCO->setCurrentIndex(findToken(languages_supported, "no language"));
451 dialectCO->setCurrentIndex(0);
452 floatCB->setChecked(false);
453 placementLE->clear();
454 numberSideCO->setCurrentIndex(0);
455 numberStepLE->clear();
456 numberFontSizeCO->setCurrentIndex(findToken(font_sizes, "default"));
457 firstlineLE->clear();
459 fontstyleCO->setCurrentIndex(findToken(font_styles, "default"));
460 fontsizeCO->setCurrentIndex(findToken(font_sizes, "default"));
461 breaklinesCB->setChecked(false);
462 spaceCB->setChecked(false);
463 spaceInStringCB->setChecked(true);
464 tabsizeSB->setValue(8);
465 extendedcharsCB->setChecked(false);
467 // set values from param string
468 inlineCB->setChecked(params_.isInline());
469 if (params_.isInline()) {
470 floatCB->setChecked(false);
471 placementLE->setEnabled(false);
473 // break other parameters and set values
474 vector<string> pars = getVectorFromString(params_.separatedParams(), "\n");
475 // process each of them
476 for (vector<string>::iterator it = pars.begin();
477 it != pars.end(); ++it) {
478 if (prefixIs(*it, "language=")) {
479 string arg = plainParam(it->substr(9));
484 if (prefixIs(arg, "[") && contains(arg, "]")) {
485 size_t end_dialect = arg.find("]");
486 dialect = arg.substr(1, end_dialect - 1);
487 language = arg.substr(end_dialect + 1);
491 int n = findToken(languages_supported, language);
493 languageCO->setCurrentIndex(n);
496 // on_languageCO_currentIndexChanged should have set dialects
497 if (!dialect.empty()) {
499 for (size_t i = 0; i != nr_dialects; ++i) {
500 if (dialect == dialects[i].dialect
501 && dialects[i].language == language) {
502 dialect_gui = dialects[i].gui;
506 n = dialectCO->findText(qt_(dialect_gui));
508 dialectCO->setCurrentIndex(n);
514 languageCO->setEnabled(in_gui);
515 dialectCO->setEnabled(
516 in_gui && dialectCO->count() > 1);
517 } else if (prefixIs(*it, "float")) {
518 floatCB->setChecked(true);
519 inlineCB->setChecked(false);
520 placementLE->setEnabled(true);
521 if (prefixIs(*it, "float="))
522 placementLE->setText(
523 toqstr(plainParam(it->substr(6))));
525 } else if (prefixIs(*it, "numbers=")) {
526 string s = plainParam(it->substr(8));
530 else if (s == "right")
532 numberSideCO->setCurrentIndex(n);
534 } else if (prefixIs(*it, "stepnumber=")) {
535 numberStepLE->setText(
536 toqstr(plainParam(it->substr(11))));
538 } else if (prefixIs(*it, "numberstyle=")) {
539 string par = plainParam(it->substr(12));
540 int n = findToken(font_sizes, par.substr(1));
542 numberFontSizeCO->setCurrentIndex(n);
544 } else if (prefixIs(*it, "firstline=")) {
545 firstlineLE->setText(
546 toqstr(plainParam(it->substr(10))));
548 } else if (prefixIs(*it, "lastline=")) {
550 toqstr(plainParam(it->substr(9))));
552 } else if (prefixIs(*it, "basicstyle=")) {
555 for (int n = 0; font_styles[n][0]; ++n) {
556 string const s = font_styles[n];
557 if (contains(*it, "\\" + s)) {
562 for (int n = 0; font_sizes[n][0]; ++n) {
563 string const s = font_sizes[n];
564 if (contains(*it, "\\" + s)) {
569 if (plainParam(it->substr(11)) == style + size
570 || plainParam(it->substr(11)) == size + style) {
571 if (!style.empty()) {
572 int n = findToken(font_styles, style.substr(1));
574 fontstyleCO->setCurrentIndex(n);
577 int n = findToken(font_sizes, size.substr(1));
579 fontsizeCO->setCurrentIndex(n);
583 } else if (prefixIs(*it, "breaklines=")) {
584 breaklinesCB->setChecked(contains(*it, "true"));
586 } else if (prefixIs(*it, "showspaces=")) {
587 spaceCB->setChecked(contains(*it, "true"));
589 } else if (prefixIs(*it, "showstringspaces=")) {
590 spaceInStringCB->setChecked(contains(*it, "true"));
592 } else if (prefixIs(*it, "tabsize=")) {
593 tabsizeSB->setValue(convert<int>(plainParam(it->substr(8))));
595 } else if (prefixIs(*it, "extendedchars=")) {
596 extendedcharsCB->setChecked(contains(*it, "true"));
601 numberStepLE->setEnabled(numberSideCO->currentIndex() > 0);
602 numberFontSizeCO->setEnabled(numberSideCO->currentIndex() > 0);
603 // parameters that can be handled by widgets are cleared
604 // the rest is put to the extra edit box.
605 string extra = getStringFromVector(pars);
606 listingsED->setPlainText(toqstr(InsetListingsParams(extra).separatedParams()));
610 bool GuiListings::isValid()
612 return validate_listings_params().empty();
616 bool GuiListings::initialiseParams(string const & data)
618 InsetListings::string2params(data, params_);
623 void GuiListings::clearParams()
629 void GuiListings::dispatchParams()
631 string const lfun = InsetListings::params2string(params_);
632 dispatch(FuncRequest(getLfun(), lfun));
636 void GuiListings::setParams(InsetListingsParams const & params)
642 Dialog * createGuiListings(GuiView & lv) { return new GuiListings(lv); }
645 } // namespace frontend
649 #include "moc_GuiListings.cpp"