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"
19 #include "BufferParams.h"
20 #include "FuncRequest.h"
22 #include "insets/InsetListings.h"
23 #include "insets/InsetListingsParams.h"
25 #include "support/convert.h"
26 #include "support/debug.h"
27 #include "support/gettext.h"
28 #include "support/lstrings.h"
31 #include <QPushButton>
33 #include <QRegExpValidator>
36 using namespace lyx::support;
42 /////////////////////////////////////////////////////////////////////
46 /////////////////////////////////////////////////////////////////////
49 char const * languages_supported[] =
50 { "no language", "ABAP", "ACM", "ACMscript", "ACSL", "Ada", "ALGOL", "Ant", "Assembler", "Awk", "bash", "Basic", "C",
51 "C++", "Caml", "CIL", "Clean", "Cobol", "Comal 80", "command.com", "Comsol", "csh", "Delphi",
52 "Eiffel", "Elan", "elisp", "erlang", "Euphoria", "Fortran", "GAP", "GCL", "Gnuplot", "Go",
53 "hansl", "Haskell", "HTML", "IDL", "inform",
54 "Java", "JVMIS", "ksh", "Lingo", "Lisp", "LLVM", "Logo", "Lua", "make", "Mathematica", "Matlab", "Mercury",
55 "MetaPost", "Miranda", "Mizar", "ML", "Modula-2", "MuPAD", "NASTRAN", "Oberon-2", "OCL", "Octave", "OORexx",
56 "Oz", "Pascal", "Perl", "PHP", "PL/I", "Plasm", "PostScript", "POV", "Prolog", "Promela",
57 "PSTricks", "Python", "R", "Reduce", "Rexx", "RSL", "Ruby", "S", "SAS", "Scala", "Scilab", "sh",
58 "SHELXL", "Simula", "SPARQL", "SQL", "Swift", "tcl", "TeX", "VBScript", "Verilog", "VHDL",
59 "VRML", "XML", "XSLT", "" };
62 char const * languages_gui[] =
63 { N_("No language"), "ABAP", "ACM", "ACMscript", "ACSL", "Ada", "ALGOL", "Ant", "Assembler", "Awk", "bash", "Basic", "C",
64 "C++", "Caml", "CIL", "Clean", "Cobol", "Comal 80", "command.com", "Comsol", "csh", "Delphi",
65 "Eiffel", "Elan", "elisp", "erlang", "Euphoria", "Fortran", "GAP", "GCL", "Gnuplot", "Go",
66 "hansl", "Haskell", "HTML", "IDL", "inform",
67 "Java", "JVMIS", "ksh", "Lingo", "Lisp", "LLVM", "Logo", "Lua", "make", "Mathematica", "Matlab", "Mercury",
68 "MetaPost", "Miranda", "Mizar", "ML", "Modula-2", "MuPAD", "NASTRAN", "Oberon-2", "OCL", "Octave", "OORexx",
69 "Oz", "Pascal", "Perl", "PHP", "PL/I", "Plasm", "PostScript", "POV", "Prolog", "Promela",
70 "PSTricks", "Python", "R", "Reduce", "Rexx", "RSL", "Ruby", "S", "SAS", "Scala", "Scilab", "sh",
71 "SHELXL", "Simula", "SPARQL", "SQL", "Swift", "tcl", "TeX", "VBScript", "Verilog", "VHDL",
72 "VRML", "XML", "XSLT", "" };
78 /// the associated language
79 char const * language;
80 /// representation of the dialect in the gui
82 /// is this the default dialect?
87 dialect_info const dialects[] = {
88 { "R/2 4.3", "ABAP", "R/2 4.3", false },
89 { "R/2 5.0", "ABAP", "R/2 5.0", false },
90 { "R/3 3.1", "ABAP", "R/3 3.1", false },
91 { "R/3 4.6C", "ABAP", "R/3 4.6C", false },
92 { "R/3 6.10", "ABAP", "R/3 6.10", true },
93 { "2005", "Ada", "2005", true },
94 { "83", "Ada", "83", false },
95 { "95", "Ada", "95", false },
96 { "60", "Algol", "60", false },
97 { "68", "Algol", "68", true },
98 { "Motorola68k", "Assembler", "Motorola 68xxx", false },
99 { "x86masm", "Assembler", "x86 (MASM)", false },
100 { "gnu", "Awk", "gnu", true },
101 { "POSIX", "Awk", "POSIX", false },
102 { "Visual", "Basic", "Visual", false },
103 { "ANSI", "C", "ANSI", true },
104 { "Handel", "C", "Handel", false },
105 { "Objective", "C", "Objective", false },
106 { "Sharp", "C", "Sharp", false },
107 { "ANSI", "C++", "ANSI", false },
108 { "GNU", "C++", "GNU", false },
109 { "ISO", "C++", "ISO", true },
110 { "Visual", "C++", "Visual", false },
111 { "light", "Caml", "light", true },
112 { "Objective", "Caml", "Objective", false },
113 { "1974", "Cobol", "1974", false },
114 { "1985", "Cobol", "1985", true },
115 { "ibm", "Cobol", "IBM", false },
116 { "WinXP", "command.com", "Windows XP", true },
117 { "77", "Fortran", "77", false },
118 { "90", "Fortran", "90", false },
119 { "95", "Fortran", "95", true },
120 { "CORBA", "IDL", "CORBA", false },
121 { "AspectJ", "Java", "Aspect J", false },
122 { "Auto", "Lisp", "Auto", false },
123 { "gnu", "make", "gnu", false },
124 { "1.0", "Mathematica", "1.0", false },
125 { "3.0", "Mathematica", "3.0", false },
126 { "5.2", "Mathematica", "5.2", true },
127 { "decorative", "OCL", "decorative", false },
128 { "OMG", "OCL", "OMG", true },
129 { "Borland6", "Pascal", "Borland 6", false },
130 { "Standard", "Pascal", "Standard", true },
131 { "XSC", "Pascal", "XSC", false },
132 { "PLUS", "S", "PLUS", false },
133 { "67", "Simula", "67", true },
134 { "CII", "Simula", "CII", false },
135 { "DEC", "Simula", "DEC", false },
136 { "IBM", "Simula", "IBM", false },
137 { "tk", "tcl", "tk", false },
138 { "AlLaTeX", "TeX", "AlLaTeX", false },
139 { "common", "TeX", "common", false },
140 { "LaTeX", "TeX", "LaTeX", false },
141 { "plain", "TeX", "plain", true },
142 { "primitive", "TeX", "primitive", false },
143 { "AMS", "VHDL", "AMS", false },
144 { "97", "VRML", "97", true }
148 size_t const nr_dialects = sizeof(dialects) / sizeof(dialect_info);
151 char const * font_sizes[] =
152 { "default", "tiny", "scriptsize", "footnotesize", "small", "normalsize", "large",
155 char const * font_sizes_gui[] =
156 { N_("Default"), N_("Tiny"), N_("Smallest"), N_("Smaller"), N_("Small"), N_("Normal"),
157 N_("Large"), N_("Larger"), "" };
159 char const * font_styles[] =
160 { "default", "rmfamily", "ttfamily", "sffamily", "" };
162 char const * font_styles_gui[] =
163 { N_("Default"), N_("Roman"), N_("Typewriter"), N_("Sans Serif"), "" };
167 GuiListings::GuiListings(GuiView & lv)
168 : GuiDialog(lv, "listings", qt_("Program Listing Settings"))
172 connect(buttonBox, SIGNAL(clicked(QAbstractButton *)),
173 this, SLOT(slotButtonBox(QAbstractButton *)));
175 connect(languageCO, SIGNAL(currentIndexChanged(int)),
176 this, SLOT(change_adaptor()));
177 connect(dialectCO, SIGNAL(currentIndexChanged(int)),
178 this, SLOT(change_adaptor()));
179 connect(inlineCB, SIGNAL(clicked()),
180 this, SLOT(change_adaptor()));
181 connect(floatCB, SIGNAL(clicked()),
182 this, SLOT(change_adaptor()));
183 connect(placementLE, SIGNAL(textChanged(QString)),
184 this, SLOT(change_adaptor()));
185 connect(numberSideCO, SIGNAL(currentIndexChanged(int)),
186 this, SLOT(change_adaptor()));
187 connect(numberStepLE, SIGNAL(textChanged(QString)),
188 this, SLOT(change_adaptor()));
189 connect(numberFontSizeCO, SIGNAL(currentIndexChanged(int)),
190 this, SLOT(change_adaptor()));
191 connect(firstlineLE, SIGNAL(textChanged(QString)),
192 this, SLOT(change_adaptor()));
193 connect(lastlineLE, SIGNAL(textChanged(QString)),
194 this, SLOT(change_adaptor()));
195 connect(fontsizeCO, SIGNAL(currentIndexChanged(int)),
196 this, SLOT(change_adaptor()));
197 connect(fontstyleCO, SIGNAL(currentIndexChanged(int)),
198 this, SLOT(change_adaptor()));
199 connect(breaklinesCB, SIGNAL(clicked()),
200 this, SLOT(change_adaptor()));
201 connect(spaceCB, SIGNAL(clicked()),
202 this, SLOT(change_adaptor()));
203 connect(spaceInStringCB, SIGNAL(clicked()),
204 this, SLOT(change_adaptor()));
205 connect(tabsizeSB, SIGNAL(valueChanged(int)),
206 this, SLOT(change_adaptor()));
207 connect(extendedcharsCB, SIGNAL(clicked()),
208 this, SLOT(change_adaptor()));
210 connect(listingsED, SIGNAL(textChanged()),
211 this, SLOT(change_adaptor()));
212 connect(listingsED, SIGNAL(textChanged()),
213 this, SLOT(setListingsMsg()));
214 connect(bypassCB, SIGNAL(clicked()),
215 this, SLOT(change_adaptor()));
216 connect(bypassCB, SIGNAL(clicked()),
217 this, SLOT(setListingsMsg()));
219 for (int n = 0; languages_supported[n][0]; ++n)
220 languageCO->addItem(qt_(languages_gui[n]));
222 for (int n = 0; font_styles[n][0]; ++n)
223 fontstyleCO->addItem(qt_(font_styles_gui[n]));
225 for (int n = 0; font_sizes[n][0]; ++n) {
226 QString font = qt_(font_sizes_gui[n]);
227 fontsizeCO->addItem(font);
228 numberFontSizeCO->addItem(font);
232 numberStepLE->setValidator(new QIntValidator(0, 1000000, this));
233 firstlineLE->setValidator(new QIntValidator(0, 1000000, this));
234 lastlineLE->setValidator(new QIntValidator(0, 1000000, this));
235 placementLE->setValidator(new QRegExpValidator(QRegExp("[\\*tbph]*"), this));
237 bc().setPolicy(ButtonPolicy::NoRepeatedApplyReadOnlyPolicy);
238 bc().setOK(buttonBox->button(QDialogButtonBox::Ok));
239 bc().setApply(buttonBox->button(QDialogButtonBox::Apply));
240 bc().setCancel(buttonBox->button(QDialogButtonBox::Cancel));
241 listingsTB->setPlainText(
242 qt_("Input listing parameters on the right. Enter ? for a list of parameters."));
249 void GuiListings::change_adaptor()
255 string GuiListings::construct_params()
257 string language = languages_supported[qMax(0, languageCO->currentIndex())];
259 string const dialect_gui = fromqstr(dialectCO->currentText());
260 if (dialectCO->currentIndex() > 0) {
261 for (size_t i = 0; i != nr_dialects; ++i) {
262 if (dialect_gui == dialects[i].gui
263 && dialects[i].language == language
264 && !dialects[i].is_default) {
265 dialect = dialects[i].dialect;
271 bool float_ = floatCB->isChecked();
273 if (placementLE->isEnabled())
274 placement = fromqstr(placementLE->text());
277 switch (qMax(0, numberSideCO->currentIndex())) {
285 numberSide = "right";
291 string stepnumber = fromqstr(numberStepLE->text());
292 string numberfontsize = font_sizes[qMax(0, numberFontSizeCO->currentIndex())];
293 string firstline = fromqstr(firstlineLE->text());
294 string lastline = fromqstr(lastlineLE->text());
296 string fontsize = font_sizes[qMax(0, fontsizeCO->currentIndex())];
297 string fontstyle = font_styles[qMax(0, fontstyleCO->currentIndex())];
300 // FIXME: We should not compose listings- or minted-dependant string here
301 // This breaks if a users switches the backend without opening and
302 // re-applying all listings insets. Use a backend-abstract syntax!
303 bool const use_minted = buffer().params().use_minted;
304 if (fontsize != "default") {
306 mintedsize = "\\" + fontsize;
308 basicstyle = "\\" + fontsize;
310 if (fontstyle != "default") {
312 basicstyle = fontstyle.substr(0, 2);
314 basicstyle += "\\" + fontstyle;
316 bool breakline = breaklinesCB->isChecked();
317 bool space = spaceCB->isChecked();
318 int tabsize = tabsizeSB->value();
319 bool spaceInString = spaceInStringCB->isChecked();
320 bool extendedchars = extendedcharsCB->isChecked();
321 string extra = fromqstr(listingsED->toPlainText());
324 InsetListingsParams par;
325 par.setMinted(use_minted);
327 if (language == "no language" && !contains(extra, "language=")) {
328 string const & blp = buffer().params().listings_params;
329 size_t start = blp.find("language=");
330 if (start != string::npos) {
331 start += strlen("language=");
332 size_t len = blp.find(",", start);
333 if (len != string::npos)
335 par.addParam("language", blp.substr(start, len));
337 par.addParam("language", "TeX");
339 par.addParam("language", language);
340 } else if (language != "no language" && !contains(extra, "language=")) {
342 par.addParam("language", language);
344 par.addParam("language", "{[" + dialect + "]" + language + "}");
346 // this dialog uses float=placement instead of float,floatplacement=placement
347 // because float accepts *tbph and floatplacement accepts bph.
348 // our placement textedit is actually for the float parameter
350 par.addParam("float", placement);
351 if (numberSide != "none")
352 par.addParam("numbers", numberSide);
353 if (numberfontsize != "default" && numberSide != "none" && !use_minted)
354 par.addParam("numberstyle", "\\" + numberfontsize);
355 if (!stepnumber.empty() && numberSide != "none")
356 par.addParam("stepnumber", stepnumber);
357 if (!firstline.empty())
358 par.addParam("firstline", firstline);
359 if (!lastline.empty())
360 par.addParam("lastline", lastline);
361 if (!basicstyle.empty())
362 par.addParam(use_minted ? "fontfamily" : "basicstyle", basicstyle);
363 if (!mintedsize.empty())
364 par.addParam("fontsize", mintedsize);
366 par.addParam("breaklines", "true");
368 par.addParam("showspaces", "true");
369 if (!spaceInString && !use_minted)
370 par.addParam("showstringspaces", "false");
372 par.addParam("tabsize", convert<string>(tabsize));
373 if (extendedchars && !use_minted)
374 par.addParam("extendedchars", "true");
375 par.addParams(extra);
380 docstring GuiListings::validate_listings_params()
382 if (bypassCB->isChecked())
384 return InsetListingsParams(construct_params()).validate();
388 void GuiListings::setListingsMsg()
391 static bool isOK = true;
392 docstring msg = validate_listings_params();
397 listingsTB->setPlainText(
398 qt_("Input listing parameters on the right. Enter ? for a list of parameters."));
401 listingsTB->setPlainText(toqstr(msg));
406 void GuiListings::on_floatCB_stateChanged(int state)
408 if (state == Qt::Checked) {
409 inlineCB->setChecked(false);
410 placementLE->setEnabled(true);
412 placementLE->setEnabled(false);
416 void GuiListings::on_inlineCB_stateChanged(int state)
418 if (state == Qt::Checked) {
419 floatCB->setChecked(false);
420 placementLE->setEnabled(false);
425 void GuiListings::on_numberSideCO_currentIndexChanged(int index)
427 numberStepLE->setEnabled(index > 0);
428 numberFontSizeCO->setEnabled(index > 0);
432 void GuiListings::on_languageCO_currentIndexChanged(int index)
436 int default_dialect = 0;
437 dialectCO->addItem(qt_("No dialect"));
438 string const language = languages_supported[index];
440 for (size_t i = 0; i != nr_dialects; ++i) {
441 if (language == dialects[i].language) {
442 dialectCO->addItem(qt_(dialects[i].gui));
443 if (dialects[i].is_default)
445 dialectCO->findText(qt_(dialects[i].gui));
448 dialectCO->setCurrentIndex(default_dialect);
449 dialectCO->setEnabled(dialectCO->count() > 1
450 && !buffer().params().use_minted);
454 void GuiListings::applyView()
456 params_.setMinted(buffer().params().use_minted);
457 params_.setInline(inlineCB->isChecked());
458 params_.setParams(construct_params());
462 static string plainParam(string const & par)
464 // remove enclosing braces
465 if (prefixIs(par, "{") && suffixIs(par, "}"))
466 return par.substr(1, par.size() - 2);
471 void GuiListings::updateContents()
473 bool const use_minted = buffer().params().use_minted;
474 // set default values
475 listingsTB->setPlainText(
476 qt_("Input listing parameters on the right. Enter ? for a list of parameters."));
477 languageCO->setCurrentIndex(findToken(languages_supported, "no language"));
478 dialectCO->setCurrentIndex(0);
479 floatCB->setChecked(false);
480 placementLE->clear();
481 numberSideCO->setCurrentIndex(0);
482 numberStepLE->clear();
483 numberFontSizeCO->setCurrentIndex(findToken(font_sizes, "default"));
484 firstlineLE->clear();
486 fontstyleCO->setCurrentIndex(findToken(font_styles, "default"));
487 fontsizeCO->setCurrentIndex(findToken(font_sizes, "default"));
488 breaklinesCB->setChecked(false);
489 spaceCB->setChecked(false);
490 spaceInStringCB->setChecked(true);
491 tabsizeSB->setValue(8);
492 extendedcharsCB->setChecked(false);
494 // set values from param string
495 inlineCB->setChecked(params_.isInline());
496 if (params_.isInline()) {
497 floatCB->setChecked(false);
498 placementLE->setEnabled(false);
500 // break other parameters and set values
501 vector<string> pars = getVectorFromString(params_.separatedParams(), "\n");
502 // process each of them
503 for (vector<string>::iterator it = pars.begin();
504 it != pars.end(); ++it) {
505 if (prefixIs(*it, "language=")) {
506 string arg = plainParam(it->substr(9));
511 if (prefixIs(arg, "[") && contains(arg, "]")) {
512 size_t end_dialect = arg.find("]");
513 dialect = arg.substr(1, end_dialect - 1);
514 language = arg.substr(end_dialect + 1);
518 int n = findToken(languages_supported, language);
520 languageCO->setCurrentIndex(n);
523 // on_languageCO_currentIndexChanged should have set dialects
524 if (!dialect.empty()) {
526 for (size_t i = 0; i != nr_dialects; ++i) {
527 if (dialect == dialects[i].dialect
528 && dialects[i].language == language) {
529 dialect_gui = dialects[i].gui;
533 n = dialectCO->findText(qt_(dialect_gui));
535 dialectCO->setCurrentIndex(n);
541 languageCO->setEnabled(in_gui);
542 dialectCO->setEnabled(!use_minted &&
543 in_gui && dialectCO->count() > 1);
544 } else if (prefixIs(*it, "float")) {
545 floatCB->setChecked(true);
546 inlineCB->setChecked(false);
547 placementLE->setEnabled(true);
548 if (prefixIs(*it, "float="))
549 placementLE->setText(
550 toqstr(plainParam(it->substr(6))));
552 } else if (prefixIs(*it, "numbers=")) {
553 string s = plainParam(it->substr(8));
557 else if (s == "right")
559 numberSideCO->setCurrentIndex(n);
561 } else if (prefixIs(*it, "stepnumber=")) {
562 numberStepLE->setText(
563 toqstr(plainParam(it->substr(11))));
565 } else if (prefixIs(*it, "numberstyle=")) {
566 string par = plainParam(it->substr(12));
567 int n = findToken(font_sizes, par.substr(1));
569 numberFontSizeCO->setCurrentIndex(n);
571 } else if (prefixIs(*it, "firstline=")) {
572 firstlineLE->setText(
573 toqstr(plainParam(it->substr(10))));
575 } else if (prefixIs(*it, "lastline=")) {
577 toqstr(plainParam(it->substr(9))));
579 } else if (prefixIs(*it, "basicstyle=")) {
582 for (int n = 0; font_styles[n][0]; ++n) {
583 string const s = font_styles[n];
584 if (contains(*it, "\\" + s)) {
589 for (int n = 0; font_sizes[n][0]; ++n) {
590 string const s = font_sizes[n];
591 if (contains(*it, "\\" + s)) {
596 if (plainParam(it->substr(11)) == style + size
597 || plainParam(it->substr(11)) == size + style) {
598 if (!style.empty()) {
599 int n = findToken(font_styles, style.substr(1));
601 fontstyleCO->setCurrentIndex(n);
604 int n = findToken(font_sizes, size.substr(1));
606 fontsizeCO->setCurrentIndex(n);
610 } else if (prefixIs(*it, "fontsize=")) {
612 for (int n = 0; font_sizes[n][0]; ++n) {
613 string const s = font_sizes[n];
614 if (contains(*it, "\\" + s)) {
620 int n = findToken(font_sizes, size.substr(1));
622 fontsizeCO->setCurrentIndex(n);
625 } else if (prefixIs(*it, "fontfamily=")) {
627 for (int n = 0; font_styles[n][0]; ++n) {
628 string const s = font_styles[n];
629 if (contains(*it, "=" + s.substr(0,2))) {
634 if (!style.empty()) {
635 int n = findToken(font_styles, style.substr(1));
637 fontstyleCO->setCurrentIndex(n);
640 } else if (prefixIs(*it, "breaklines=")) {
641 breaklinesCB->setChecked(contains(*it, "true"));
643 } else if (prefixIs(*it, "showspaces=")) {
644 spaceCB->setChecked(contains(*it, "true"));
646 } else if (prefixIs(*it, "showstringspaces=")) {
647 spaceInStringCB->setChecked(contains(*it, "true"));
649 } else if (prefixIs(*it, "tabsize=")) {
650 tabsizeSB->setValue(convert<int>(plainParam(it->substr(8))));
652 } else if (prefixIs(*it, "extendedchars=")) {
653 extendedcharsCB->setChecked(contains(*it, "true"));
658 numberStepLE->setEnabled(numberSideCO->currentIndex() > 0);
659 numberFontSizeCO->setEnabled(numberSideCO->currentIndex() > 0
661 spaceInStringCB->setEnabled(!use_minted);
662 extendedcharsCB->setEnabled(!use_minted);
663 // parameters that can be handled by widgets are cleared
664 // the rest is put to the extra edit box.
665 string extra = getStringFromVector(pars);
666 listingsED->setPlainText(toqstr(InsetListingsParams(extra).separatedParams()));
667 params_.setMinted(use_minted);
671 bool GuiListings::isValid()
673 return validate_listings_params().empty();
677 bool GuiListings::initialiseParams(string const & sdata)
679 InsetListings::string2params(sdata, params_);
684 void GuiListings::clearParams()
687 params_.setMinted(buffer().params().use_minted);
691 void GuiListings::dispatchParams()
693 string const lfun = InsetListings::params2string(params_);
694 dispatch(FuncRequest(getLfun(), lfun));
698 void GuiListings::setParams(InsetListingsParams const & params)
701 params_.setMinted(buffer().params().use_minted);
705 Dialog * createGuiListings(GuiView & lv) { return new GuiListings(lv); }
708 } // namespace frontend
712 #include "moc_GuiListings.cpp"