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", "ACSL", "Ada", "ALGOL", "Assembler", "Awk", "bash", "Basic", "C",
51 "C++", "Caml", "Clean", "Cobol", "Comal 80", "command.com", "Comsol", "csh", "Delphi",
52 "Eiffel", "Elan", "erlang", "Euphoria", "Fortran", "Gnuplot", "Haskell", "HTML", "IDL", "inform",
53 "Java", "JVMIS", "ksh", "Lingo", "Lisp", "Logo", "make", "Mathematica", "Matlab", "Mercury",
54 "MetaPost", "Miranda", "ML", "Modula-2", "MuPAD", "NASTRAN", "Oberon-2", "OCL", "Octave",
55 "Oz", "Pascal", "Perl", "PHP", "PL/I", "Plasm", "PostScript", "POV", "Prolog", "Promela",
56 "PSTricks", "Python", "R", "Reduce", "Rexx", "RSL", "Ruby", "S", "SAS", "Scilab", "sh",
57 "SHELXL", "Simula", "tcl", "SPARQL", "SQL", "tcl", "TeX", "VBScript", "Verilog", "VHDL",
58 "VRML", "XML", "XSLT", "" };
61 char const * languages_gui[] =
62 { N_("No language"), "ABAP", "ACSL", "Ada", "ALGOL", "Assembler", "Awk", "bash", "Basic",
63 "C", "C++", "Caml", "Clean", "Cobol", "Comal 80", "command.com", "Comsol", "csh", "Delphi",
64 "Eiffel", "Elan", "Erlang", "Euphoria", "Fortran", "Gnuplot", "Haskell", "HTML", "IDL", "inform",
65 "Java", "JVMIS", "ksh", "Lingo", "Lisp", "Logo", "make", "Mathematica", "Matlab", "Mercury",
66 "MetaPost", "Miranda", "ML", "Modula-2", "MuPAD", "NASTRAN", "Oberon-2", "OCL", "Octave",
67 "Oz", "Pascal", "Perl", "PHP", "PL/I", "Plasm", "PostScript", "POV", "Prolog", "Promela",
68 "PSTricks", "Python", "R", "Reduce", "Rexx", "RSL", "Ruby", "S", "SAS", "Scilab", "sh",
69 "SHELXL", "Simula", "tcl", "SPARQL", "SQL", "tcl", "TeX", "VBScript", "Verilog", "VHDL",
70 "VRML", "XML", "XSLT", "" };
76 /// the associated language
77 char const * language;
78 /// representation of the dialect in the gui
80 /// is this the default dialect?
85 dialect_info const dialects[] = {
86 { "R/2 4.3", "ABAP", "R/2 4.3", false },
87 { "R/2 5.0", "ABAP", "R/2 5.0", false },
88 { "R/3 3.1", "ABAP", "R/3 3.1", false },
89 { "R/3 4.6C", "ABAP", "R/3 4.6C", false },
90 { "R/3 6.10", "ABAP", "R/3 6.10", true },
91 { "2005", "Ada", "2005", true },
92 { "83", "Ada", "83", false },
93 { "95", "Ada", "95", false },
94 { "60", "Algol", "60", false },
95 { "68", "Algol", "68", true },
96 { "Motorola68k", "Assembler", "Motorola 68xxx", false },
97 { "x86masm", "Assembler", "x86 (MASM)", false },
98 { "gnu", "Awk", "gnu", true },
99 { "POSIX", "Awk", "POSIX", false },
100 { "Visual", "Basic", "Visual", false },
101 { "ANSI", "C", "ANSI", true },
102 { "Handel", "C", "Handel", false },
103 { "Objective", "C", "Objective", false },
104 { "Sharp", "C", "Sharp", false },
105 { "ANSI", "C++", "ANSI", false },
106 { "GNU", "C++", "GNU", false },
107 { "ISO", "C++", "ISO", true },
108 { "Visual", "C++", "Visual", false },
109 { "light", "Caml", "light", true },
110 { "Objective", "Caml", "Objective", false },
111 { "1974", "Cobol", "1974", false },
112 { "1985", "Cobol", "1985", true },
113 { "ibm", "Cobol", "IBM", false },
114 { "WinXP", "command.com", "Windows XP", true },
115 { "77", "Fortran", "77", false },
116 { "90", "Fortran", "90", false },
117 { "95", "Fortran", "95", true },
118 { "CORBA", "IDL", "CORBA", false },
119 { "AspectJ", "Java", "Aspect J", false },
120 { "Auto", "Lisp", "Auto", false },
121 { "gnu", "make", "gnu", false },
122 { "1.0", "Mathematica", "1.0", false },
123 { "3.0", "Mathematica", "3.0", false },
124 { "5.2", "Mathematica", "5.2", true },
125 { "decorative", "OCL", "decorative", false },
126 { "OMG", "OCL", "OMG", true },
127 { "Borland6", "Pascal", "Borland 6", false },
128 { "Standard", "Pascal", "Standard", true },
129 { "XSC", "Pascal", "XSC", false },
130 { "PLUS", "S", "PLUS", false },
131 { "67", "Simula", "67", true },
132 { "CII", "Simula", "CII", false },
133 { "DEC", "Simula", "DEC", false },
134 { "IBM", "Simula", "IBM", false },
135 { "tk", "tcl", "tk", false },
136 { "AlLaTeX", "TeX", "AlLaTeX", false },
137 { "common", "TeX", "common", false },
138 { "LaTeX", "TeX", "LaTeX", false },
139 { "plain", "TeX", "plain", true },
140 { "primitive", "TeX", "primitive", false },
141 { "AMS", "VHDL", "AMS", false },
142 { "97", "VRML", "97", true }
146 size_t const nr_dialects = sizeof(dialects) / sizeof(dialect_info);
149 char const * font_sizes[] =
150 { "default", "tiny", "scriptsize", "footnotesize", "small", "normalsize", "large",
153 char const * font_sizes_gui[] =
154 { N_("Default"), N_("Tiny"), N_("Smallest"), N_("Smaller"), N_("Small"), N_("Normal"),
155 N_("Large"), N_("Larger"), "" };
157 char const * font_styles[] =
158 { "default", "rmfamily", "ttfamily", "sffamily", "" };
160 char const * font_styles_gui[] =
161 { N_("Default"), N_("Roman"), N_("Typewriter"), N_("Sans Serif"), "" };
165 GuiListings::GuiListings(GuiView & lv)
166 : GuiDialog(lv, "listings", qt_("Program Listing Settings"))
170 connect(buttonBox, SIGNAL(clicked(QAbstractButton *)),
171 this, SLOT(slotButtonBox(QAbstractButton *)));
173 connect(languageCO, SIGNAL(currentIndexChanged(int)),
174 this, SLOT(change_adaptor()));
175 connect(dialectCO, SIGNAL(currentIndexChanged(int)),
176 this, SLOT(change_adaptor()));
177 connect(inlineCB, SIGNAL(clicked()),
178 this, SLOT(change_adaptor()));
179 connect(floatCB, SIGNAL(clicked()),
180 this, SLOT(change_adaptor()));
181 connect(placementLE, SIGNAL(textChanged(QString)),
182 this, SLOT(change_adaptor()));
183 connect(numberSideCO, SIGNAL(currentIndexChanged(int)),
184 this, SLOT(change_adaptor()));
185 connect(numberStepLE, SIGNAL(textChanged(QString)),
186 this, SLOT(change_adaptor()));
187 connect(numberFontSizeCO, SIGNAL(currentIndexChanged(int)),
188 this, SLOT(change_adaptor()));
189 connect(firstlineLE, SIGNAL(textChanged(QString)),
190 this, SLOT(change_adaptor()));
191 connect(lastlineLE, SIGNAL(textChanged(QString)),
192 this, SLOT(change_adaptor()));
193 connect(fontsizeCO, SIGNAL(currentIndexChanged(int)),
194 this, SLOT(change_adaptor()));
195 connect(fontstyleCO, SIGNAL(currentIndexChanged(int)),
196 this, SLOT(change_adaptor()));
197 connect(breaklinesCB, SIGNAL(clicked()),
198 this, SLOT(change_adaptor()));
199 connect(spaceCB, SIGNAL(clicked()),
200 this, SLOT(change_adaptor()));
201 connect(spaceInStringCB, SIGNAL(clicked()),
202 this, SLOT(change_adaptor()));
203 connect(tabsizeSB, SIGNAL(valueChanged(int)),
204 this, SLOT(change_adaptor()));
205 connect(extendedcharsCB, SIGNAL(clicked()),
206 this, SLOT(change_adaptor()));
208 connect(listingsED, SIGNAL(textChanged()),
209 this, SLOT(change_adaptor()));
210 connect(listingsED, SIGNAL(textChanged()),
211 this, SLOT(setListingsMsg()));
212 connect(bypassCB, SIGNAL(clicked()),
213 this, SLOT(change_adaptor()));
214 connect(bypassCB, SIGNAL(clicked()),
215 this, SLOT(setListingsMsg()));
217 for (int n = 0; languages_supported[n][0]; ++n)
218 languageCO->addItem(qt_(languages_gui[n]));
220 for (int n = 0; font_styles[n][0]; ++n)
221 fontstyleCO->addItem(qt_(font_styles_gui[n]));
223 for (int n = 0; font_sizes[n][0]; ++n) {
224 QString font = qt_(font_sizes_gui[n]);
225 fontsizeCO->addItem(font);
226 numberFontSizeCO->addItem(font);
230 numberStepLE->setValidator(new QIntValidator(0, 1000000, this));
231 firstlineLE->setValidator(new QIntValidator(0, 1000000, this));
232 lastlineLE->setValidator(new QIntValidator(0, 1000000, this));
233 placementLE->setValidator(new QRegExpValidator(QRegExp("[\\*tbph]*"), this));
235 bc().setPolicy(ButtonPolicy::NoRepeatedApplyReadOnlyPolicy);
236 bc().setOK(buttonBox->button(QDialogButtonBox::Ok));
237 bc().setApply(buttonBox->button(QDialogButtonBox::Apply));
238 bc().setCancel(buttonBox->button(QDialogButtonBox::Cancel));
239 listingsTB->setPlainText(
240 qt_("Input listing parameters on the right. Enter ? for a list of parameters."));
247 void GuiListings::change_adaptor()
253 string GuiListings::construct_params()
255 string language = languages_supported[qMax(0, languageCO->currentIndex())];
257 string const dialect_gui = fromqstr(dialectCO->currentText());
258 if (dialectCO->currentIndex() > 0) {
259 for (size_t i = 0; i != nr_dialects; ++i) {
260 if (dialect_gui == dialects[i].gui
261 && dialects[i].language == language
262 && !dialects[i].is_default) {
263 dialect = dialects[i].dialect;
269 bool float_ = floatCB->isChecked();
271 if (placementLE->isEnabled())
272 placement = fromqstr(placementLE->text());
275 switch (qMax(0, numberSideCO->currentIndex())) {
283 numberSide = "right";
289 string stepnumber = fromqstr(numberStepLE->text());
290 string numberfontsize = font_sizes[qMax(0, numberFontSizeCO->currentIndex())];
291 string firstline = fromqstr(firstlineLE->text());
292 string lastline = fromqstr(lastlineLE->text());
294 string fontsize = font_sizes[qMax(0, fontsizeCO->currentIndex())];
295 string fontstyle = font_styles[qMax(0, fontstyleCO->currentIndex())];
298 bool const use_minted = buffer().params().use_minted;
299 if (fontsize != "default") {
301 mintedsize = "\\" + fontsize;
303 basicstyle = "\\" + fontsize;
305 if (fontstyle != "default") {
307 basicstyle = fontstyle.substr(0, 2);
309 basicstyle += "\\" + fontstyle;
311 bool breakline = breaklinesCB->isChecked();
312 bool space = spaceCB->isChecked();
313 int tabsize = tabsizeSB->value();
314 bool spaceInString = spaceInStringCB->isChecked();
315 bool extendedchars = extendedcharsCB->isChecked();
316 string extra = fromqstr(listingsED->toPlainText());
319 InsetListingsParams par;
320 par.setMinted(use_minted);
322 if (language == "no language" && !contains(extra, "language=")) {
323 string const & blp = buffer().params().listings_params;
324 size_t start = blp.find("language=");
325 if (start != string::npos) {
326 start += strlen("language=");
327 size_t len = blp.find(",", start);
328 if (len != string::npos)
330 par.addParam("language", blp.substr(start, len));
332 par.addParam("language", "TeX");
334 par.addParam("language", language);
335 } else if (language != "no language" && !contains(extra, "language=")) {
337 par.addParam("language", language);
339 par.addParam("language", "{[" + dialect + "]" + language + "}");
341 // this dialog uses float=placement instead of float,floatplacement=placement
342 // because float accepts *tbph and floatplacement accepts bph.
343 // our placement textedit is actually for the float parameter
345 par.addParam("float", placement);
346 if (numberSide != "none")
347 par.addParam("numbers", numberSide);
348 if (numberfontsize != "default" && numberSide != "none" && !use_minted)
349 par.addParam("numberstyle", "\\" + numberfontsize);
350 if (!stepnumber.empty() && numberSide != "none")
351 par.addParam("stepnumber", stepnumber);
352 if (!firstline.empty())
353 par.addParam("firstline", firstline);
354 if (!lastline.empty())
355 par.addParam("lastline", lastline);
356 if (!basicstyle.empty())
357 par.addParam(use_minted ? "fontfamily" : "basicstyle", basicstyle);
358 if (!mintedsize.empty())
359 par.addParam("fontsize", mintedsize);
361 par.addParam("breaklines", "true");
363 par.addParam("showspaces", "true");
364 if (!spaceInString && !use_minted)
365 par.addParam("showstringspaces", "false");
367 par.addParam("tabsize", convert<string>(tabsize));
368 if (extendedchars && !use_minted)
369 par.addParam("extendedchars", "true");
370 par.addParams(extra);
375 docstring GuiListings::validate_listings_params()
377 if (bypassCB->isChecked())
379 return InsetListingsParams(construct_params()).validate();
383 void GuiListings::setListingsMsg()
386 static bool isOK = true;
387 docstring msg = validate_listings_params();
392 listingsTB->setPlainText(
393 qt_("Input listing parameters on the right. Enter ? for a list of parameters."));
396 listingsTB->setPlainText(toqstr(msg));
401 void GuiListings::on_floatCB_stateChanged(int state)
403 if (state == Qt::Checked) {
404 inlineCB->setChecked(false);
405 placementLE->setEnabled(true);
407 placementLE->setEnabled(false);
411 void GuiListings::on_inlineCB_stateChanged(int state)
413 if (state == Qt::Checked) {
414 floatCB->setChecked(false);
415 placementLE->setEnabled(false);
420 void GuiListings::on_numberSideCO_currentIndexChanged(int index)
422 numberStepLE->setEnabled(index > 0);
423 numberFontSizeCO->setEnabled(index > 0);
427 void GuiListings::on_languageCO_currentIndexChanged(int index)
431 int default_dialect = 0;
432 dialectCO->addItem(qt_("No dialect"));
433 string const language = languages_supported[index];
435 for (size_t i = 0; i != nr_dialects; ++i) {
436 if (language == dialects[i].language) {
437 dialectCO->addItem(qt_(dialects[i].gui));
438 if (dialects[i].is_default)
440 dialectCO->findText(qt_(dialects[i].gui));
443 dialectCO->setCurrentIndex(default_dialect);
444 dialectCO->setEnabled(dialectCO->count() > 1
445 && !buffer().params().use_minted);
449 void GuiListings::applyView()
451 params_.setMinted(buffer().params().use_minted);
452 params_.setInline(inlineCB->isChecked());
453 params_.setParams(construct_params());
457 static string plainParam(string const & par)
459 // remove enclosing braces
460 if (prefixIs(par, "{") && suffixIs(par, "}"))
461 return par.substr(1, par.size() - 2);
466 void GuiListings::updateContents()
468 bool const use_minted = buffer().params().use_minted;
469 // set default values
470 listingsTB->setPlainText(
471 qt_("Input listing parameters on the right. Enter ? for a list of parameters."));
472 languageCO->setCurrentIndex(findToken(languages_supported, "no language"));
473 dialectCO->setCurrentIndex(0);
474 floatCB->setChecked(false);
475 placementLE->clear();
476 numberSideCO->setCurrentIndex(0);
477 numberStepLE->clear();
478 numberFontSizeCO->setCurrentIndex(findToken(font_sizes, "default"));
479 firstlineLE->clear();
481 fontstyleCO->setCurrentIndex(findToken(font_styles, "default"));
482 fontsizeCO->setCurrentIndex(findToken(font_sizes, "default"));
483 breaklinesCB->setChecked(false);
484 spaceCB->setChecked(false);
485 spaceInStringCB->setChecked(true);
486 tabsizeSB->setValue(8);
487 extendedcharsCB->setChecked(false);
489 // set values from param string
490 inlineCB->setChecked(params_.isInline());
491 if (params_.isInline()) {
492 floatCB->setChecked(false);
493 placementLE->setEnabled(false);
495 // break other parameters and set values
496 vector<string> pars = getVectorFromString(params_.separatedParams(), "\n");
497 // process each of them
498 for (vector<string>::iterator it = pars.begin();
499 it != pars.end(); ++it) {
500 if (prefixIs(*it, "language=")) {
501 string arg = plainParam(it->substr(9));
506 if (prefixIs(arg, "[") && contains(arg, "]")) {
507 size_t end_dialect = arg.find("]");
508 dialect = arg.substr(1, end_dialect - 1);
509 language = arg.substr(end_dialect + 1);
513 int n = findToken(languages_supported, language);
515 languageCO->setCurrentIndex(n);
518 // on_languageCO_currentIndexChanged should have set dialects
519 if (!dialect.empty()) {
521 for (size_t i = 0; i != nr_dialects; ++i) {
522 if (dialect == dialects[i].dialect
523 && dialects[i].language == language) {
524 dialect_gui = dialects[i].gui;
528 n = dialectCO->findText(qt_(dialect_gui));
530 dialectCO->setCurrentIndex(n);
536 languageCO->setEnabled(in_gui);
537 dialectCO->setEnabled(!use_minted &&
538 in_gui && dialectCO->count() > 1);
539 } else if (prefixIs(*it, "float")) {
540 floatCB->setChecked(true);
541 inlineCB->setChecked(false);
542 placementLE->setEnabled(true);
543 if (prefixIs(*it, "float="))
544 placementLE->setText(
545 toqstr(plainParam(it->substr(6))));
547 } else if (prefixIs(*it, "numbers=")) {
548 string s = plainParam(it->substr(8));
552 else if (s == "right")
554 numberSideCO->setCurrentIndex(n);
556 } else if (prefixIs(*it, "stepnumber=")) {
557 numberStepLE->setText(
558 toqstr(plainParam(it->substr(11))));
560 } else if (prefixIs(*it, "numberstyle=")) {
561 string par = plainParam(it->substr(12));
562 int n = findToken(font_sizes, par.substr(1));
564 numberFontSizeCO->setCurrentIndex(n);
566 } else if (prefixIs(*it, "firstline=")) {
567 firstlineLE->setText(
568 toqstr(plainParam(it->substr(10))));
570 } else if (prefixIs(*it, "lastline=")) {
572 toqstr(plainParam(it->substr(9))));
574 } else if (prefixIs(*it, "basicstyle=")) {
577 for (int n = 0; font_styles[n][0]; ++n) {
578 string const s = font_styles[n];
579 if (contains(*it, "\\" + s)) {
584 for (int n = 0; font_sizes[n][0]; ++n) {
585 string const s = font_sizes[n];
586 if (contains(*it, "\\" + s)) {
591 if (plainParam(it->substr(11)) == style + size
592 || plainParam(it->substr(11)) == size + style) {
593 if (!style.empty()) {
594 int n = findToken(font_styles, style.substr(1));
596 fontstyleCO->setCurrentIndex(n);
599 int n = findToken(font_sizes, size.substr(1));
601 fontsizeCO->setCurrentIndex(n);
605 } else if (prefixIs(*it, "fontsize=")) {
607 for (int n = 0; font_sizes[n][0]; ++n) {
608 string const s = font_sizes[n];
609 if (contains(*it, "\\" + s)) {
615 int n = findToken(font_sizes, size.substr(1));
617 fontsizeCO->setCurrentIndex(n);
620 } else if (prefixIs(*it, "fontfamily=")) {
622 for (int n = 0; font_styles[n][0]; ++n) {
623 string const s = font_styles[n];
624 if (contains(*it, "=" + s.substr(0,2))) {
629 if (!style.empty()) {
630 int n = findToken(font_styles, style.substr(1));
632 fontstyleCO->setCurrentIndex(n);
635 } else if (prefixIs(*it, "breaklines=")) {
636 breaklinesCB->setChecked(contains(*it, "true"));
638 } else if (prefixIs(*it, "showspaces=")) {
639 spaceCB->setChecked(contains(*it, "true"));
641 } else if (prefixIs(*it, "showstringspaces=")) {
642 spaceInStringCB->setChecked(contains(*it, "true"));
644 } else if (prefixIs(*it, "tabsize=")) {
645 tabsizeSB->setValue(convert<int>(plainParam(it->substr(8))));
647 } else if (prefixIs(*it, "extendedchars=")) {
648 extendedcharsCB->setChecked(contains(*it, "true"));
653 numberStepLE->setEnabled(numberSideCO->currentIndex() > 0);
654 numberFontSizeCO->setEnabled(numberSideCO->currentIndex() > 0
656 spaceInStringCB->setEnabled(!use_minted);
657 extendedcharsCB->setEnabled(!use_minted);
658 // parameters that can be handled by widgets are cleared
659 // the rest is put to the extra edit box.
660 string extra = getStringFromVector(pars);
661 listingsED->setPlainText(toqstr(InsetListingsParams(extra).separatedParams()));
662 params_.setMinted(use_minted);
666 bool GuiListings::isValid()
668 return validate_listings_params().empty();
672 bool GuiListings::initialiseParams(string const & sdata)
674 InsetListings::string2params(sdata, params_);
679 void GuiListings::clearParams()
682 params_.setMinted(buffer().params().use_minted);
686 void GuiListings::dispatchParams()
688 string const lfun = InsetListings::params2string(params_);
689 dispatch(FuncRequest(getLfun(), lfun));
693 void GuiListings::setParams(InsetListingsParams const & params)
696 params_.setMinted(buffer().params().use_minted);
700 Dialog * createGuiListings(GuiView & lv) { return new GuiListings(lv); }
703 } // namespace frontend
707 #include "moc_GuiListings.cpp"