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/debug.h"
25 #include "support/gettext.h"
26 #include "support/lstrings.h"
29 #include <QPushButton>
31 #include <QRegExpValidator>
34 using namespace lyx::support;
40 /////////////////////////////////////////////////////////////////////
44 /////////////////////////////////////////////////////////////////////
47 char const * languages_supported[] =
48 { "no language", "ABAP", "ACSL", "Ada", "ALGOL", "Assembler", "Awk", "bash", "Basic", "C",
49 "C++", "Caml", "Clean", "Cobol", "Comal 80", "command.com", "Comsol", "csh", "Delphi",
50 "Eiffel", "Elan", "erlang", "Euphoria", "Fortran", "Gnuplot", "Haskell", "HTML", "IDL", "inform",
51 "Java", "JVMIS", "ksh", "Lingo", "Lisp", "Logo", "make", "Mathematica", "Matlab", "Mercury",
52 "MetaPost", "Miranda", "ML", "Modula-2", "MuPAD", "NASTRAN", "Oberon-2", "OCL", "Octave",
53 "Oz", "Pascal", "Perl", "PHP", "PL/I", "Plasm", "PostScript", "POV", "Prolog", "Promela",
54 "PSTricks", "Python", "R", "Reduce", "Rexx", "RSL", "Ruby", "S", "SAS", "Scilab", "sh",
55 "SHELXL", "Simula", "tcl", "SPARQL", "SQL", "tcl", "TeX", "VBScript", "Verilog", "VHDL",
56 "VRML", "XML", "XSLT", "" };
59 char const * languages_gui[] =
60 { N_("No language"), "ABAP", "ACSL", "Ada", "ALGOL", "Assembler", "Awk", "bash", "Basic",
61 "C", "C++", "Caml", "Clean", "Cobol", "Comal 80", "command.com", "Comsol", "csh", "Delphi",
62 "Eiffel", "Elan", "Erlang", "Euphoria", "Fortran", "Gnuplot", "Haskell", "HTML", "IDL", "inform",
63 "Java", "JVMIS", "ksh", "Lingo", "Lisp", "Logo", "make", "Mathematica", "Matlab", "Mercury",
64 "MetaPost", "Miranda", "ML", "Modula-2", "MuPAD", "NASTRAN", "Oberon-2", "OCL", "Octave",
65 "Oz", "Pascal", "Perl", "PHP", "PL/I", "Plasm", "PostScript", "POV", "Prolog", "Promela",
66 "PSTricks", "Python", "R", "Reduce", "Rexx", "RSL", "Ruby", "S", "SAS", "Scilab", "sh",
67 "SHELXL", "Simula", "tcl", "SPARQL", "SQL", "tcl", "TeX", "VBScript", "Verilog", "VHDL",
68 "VRML", "XML", "XSLT", "" };
74 /// the associated language
75 char const * language;
76 /// representation of the dialect in the gui
78 /// is this the default dialect?
83 dialect_info const dialects[] = {
84 { "R/2 4.3", "ABAP", "R/2 4.3", false },
85 { "R/2 5.0", "ABAP", "R/2 5.0", false },
86 { "R/3 3.1", "ABAP", "R/3 3.1", false },
87 { "R/3 4.6C", "ABAP", "R/3 4.6C", false },
88 { "R/3 6.10", "ABAP", "R/3 6.10", true },
89 { "2005", "Ada", "2005", true },
90 { "83", "Ada", "83", false },
91 { "95", "Ada", "95", false },
92 { "60", "Algol", "60", false },
93 { "68", "Algol", "68", true },
94 { "Motorola68k", "Assembler", "Motorola 68xxx", false },
95 { "x86masm", "Assembler", "x86 (MASM)", false },
96 { "gnu", "Awk", "gnu", true },
97 { "POSIX", "Awk", "POSIX", false },
98 { "Visual", "Basic", "Visual", false },
99 { "ANSI", "C", "ANSI", true },
100 { "Handel", "C", "Handel", false },
101 { "Objective", "C", "Objective", false },
102 { "Sharp", "C", "Sharp", false },
103 { "ANSI", "C++", "ANSI", false },
104 { "GNU", "C++", "GNU", false },
105 { "ISO", "C++", "ISO", true },
106 { "Visual", "C++", "Visual", false },
107 { "light", "Caml", "light", true },
108 { "Objective", "Caml", "Objective", false },
109 { "1974", "Cobol", "1974", false },
110 { "1985", "Cobol", "1985", true },
111 { "ibm", "Cobol", "IBM", false },
112 { "WinXP", "command.com", "Windows XP", true },
113 { "77", "Fortran", "77", false },
114 { "90", "Fortran", "90", false },
115 { "95", "Fortran", "95", true },
116 { "CORBA", "IDL", "CORBA", false },
117 { "AspectJ", "Java", "Aspect J", false },
118 { "Auto", "Lisp", "Auto", false },
119 { "gnu", "make", "gnu", false },
120 { "1.0", "Mathematica", "1.0", false },
121 { "3.0", "Mathematica", "3.0", false },
122 { "5.2", "Mathematica", "5.2", true },
123 { "decorative", "OCL", "decorative", false },
124 { "OMG", "OCL", "OMG", true },
125 { "Borland6", "Pascal", "Borland 6", false },
126 { "Standard", "Pascal", "Standard", true },
127 { "XSC", "Pascal", "XSC", false },
128 { "PLUS", "S", "PLUS", false },
129 { "67", "Simula", "67", true },
130 { "CII", "Simula", "CII", false },
131 { "DEC", "Simula", "DEC", false },
132 { "IBM", "Simula", "IBM", false },
133 { "tk", "tcl", "tk", false },
134 { "AlLaTeX", "TeX", "AlLaTeX", false },
135 { "common", "TeX", "common", false },
136 { "LaTeX", "TeX", "LaTeX", false },
137 { "plain", "TeX", "plain", true },
138 { "primitive", "TeX", "primitive", false },
139 { "AMS", "VHDL", "AMS", false },
140 { "97", "VRML", "97", true }
144 size_t const nr_dialects = sizeof(dialects) / sizeof(dialect_info);
147 char const * font_sizes[] =
148 { "default", "tiny", "scriptsize", "footnotesize", "small", "normalsize", "large",
151 char const * font_sizes_gui[] =
152 { N_("Default"), N_("Tiny"), N_("Smallest"), N_("Smaller"), N_("Small"), N_("Normal"),
153 N_("Large"), N_("Larger"), "" };
155 char const * font_styles[] =
156 { "default", "rmfamily", "ttfamily", "sffamily", "" };
158 char const * font_styles_gui[] =
159 { N_("Default"), N_("Roman"), N_("Typewriter"), N_("Sans Serif"), "" };
163 GuiListings::GuiListings(GuiView & lv)
164 : GuiDialog(lv, "listings", qt_("Program Listing Settings"))
168 connect(okPB, SIGNAL(clicked()), this, SLOT(slotOK()));
169 connect(applyPB, SIGNAL(clicked()), this, SLOT(slotApply()));
170 connect(closePB, SIGNAL(clicked()), this, SLOT(slotClose()));
172 connect(languageCO, SIGNAL(currentIndexChanged(int)),
173 this, SLOT(change_adaptor()));
174 connect(dialectCO, SIGNAL(currentIndexChanged(int)),
175 this, SLOT(change_adaptor()));
176 connect(inlineCB, SIGNAL(clicked()),
177 this, SLOT(change_adaptor()));
178 connect(floatCB, SIGNAL(clicked()),
179 this, SLOT(change_adaptor()));
180 connect(placementLE, SIGNAL(textChanged(QString)),
181 this, SLOT(change_adaptor()));
182 connect(numberSideCO, SIGNAL(currentIndexChanged(int)),
183 this, SLOT(change_adaptor()));
184 connect(numberStepLE, SIGNAL(textChanged(QString)),
185 this, SLOT(change_adaptor()));
186 connect(numberFontSizeCO, SIGNAL(currentIndexChanged(int)),
187 this, SLOT(change_adaptor()));
188 connect(firstlineLE, SIGNAL(textChanged(QString)),
189 this, SLOT(change_adaptor()));
190 connect(lastlineLE, SIGNAL(textChanged(QString)),
191 this, SLOT(change_adaptor()));
192 connect(fontsizeCO, SIGNAL(currentIndexChanged(int)),
193 this, SLOT(change_adaptor()));
194 connect(fontstyleCO, SIGNAL(currentIndexChanged(int)),
195 this, SLOT(change_adaptor()));
196 connect(breaklinesCB, SIGNAL(clicked()),
197 this, SLOT(change_adaptor()));
198 connect(spaceCB, SIGNAL(clicked()),
199 this, SLOT(change_adaptor()));
200 connect(spaceInStringCB, SIGNAL(clicked()),
201 this, SLOT(change_adaptor()));
202 connect(tabsizeSB, SIGNAL(valueChanged(int)),
203 this, SLOT(change_adaptor()));
204 connect(extendedcharsCB, SIGNAL(clicked()),
205 this, SLOT(change_adaptor()));
207 connect(listingsED, SIGNAL(textChanged()),
208 this, SLOT(change_adaptor()));
209 connect(listingsED, SIGNAL(textChanged()),
210 this, SLOT(setListingsMsg()));
211 connect(bypassCB, SIGNAL(clicked()),
212 this, SLOT(change_adaptor()));
213 connect(bypassCB, SIGNAL(clicked()),
214 this, SLOT(setListingsMsg()));
216 for (int n = 0; languages_supported[n][0]; ++n)
217 languageCO->addItem(qt_(languages_gui[n]));
219 for (int n = 0; font_styles[n][0]; ++n)
220 fontstyleCO->addItem(qt_(font_styles_gui[n]));
222 for (int n = 0; font_sizes[n][0]; ++n) {
223 QString font = qt_(font_sizes_gui[n]);
224 fontsizeCO->addItem(font);
225 numberFontSizeCO->addItem(font);
229 numberStepLE->setValidator(new QIntValidator(0, 1000000, this));
230 firstlineLE->setValidator(new QIntValidator(0, 1000000, this));
231 lastlineLE->setValidator(new QIntValidator(0, 1000000, this));
232 placementLE->setValidator(new QRegExpValidator(QRegExp("[\\*tbph]*"), this));
234 bc().setPolicy(ButtonPolicy::NoRepeatedApplyReadOnlyPolicy);
236 bc().setApply(applyPB);
237 bc().setCancel(closePB);
238 listingsTB->setPlainText(
239 qt_("Input listing parameters on the right. Enter ? for a list of parameters."));
246 void GuiListings::change_adaptor()
252 string GuiListings::construct_params()
254 string language = languages_supported[qMax(0, languageCO->currentIndex())];
256 string const dialect_gui = fromqstr(dialectCO->currentText());
257 if (dialectCO->currentIndex() > 0) {
258 for (size_t i = 0; i != nr_dialects; ++i) {
259 if (dialect_gui == dialects[i].gui
260 && dialects[i].language == language
261 && !dialects[i].is_default) {
262 dialect = dialects[i].dialect;
268 bool float_ = floatCB->isChecked();
270 if (placementLE->isEnabled())
271 placement = fromqstr(placementLE->text());
274 switch (qMax(0, numberSideCO->currentIndex())) {
282 numberSide = "right";
288 string stepnumber = fromqstr(numberStepLE->text());
289 string numberfontsize = font_sizes[qMax(0, numberFontSizeCO->currentIndex())];
290 string firstline = fromqstr(firstlineLE->text());
291 string lastline = fromqstr(lastlineLE->text());
293 string fontsize = font_sizes[qMax(0, fontsizeCO->currentIndex())];
294 string fontstyle = font_styles[qMax(0, fontstyleCO->currentIndex())];
296 if (fontsize != "default")
297 basicstyle = "\\" + fontsize;
298 if (fontstyle != "default")
299 basicstyle += "\\" + fontstyle;
300 bool breakline = breaklinesCB->isChecked();
301 bool space = spaceCB->isChecked();
302 int tabsize = tabsizeSB->value();
303 bool spaceInString = spaceInStringCB->isChecked();
304 bool extendedchars = extendedcharsCB->isChecked();
305 string extra = fromqstr(listingsED->toPlainText());
308 InsetListingsParams par;
309 if (language != "no language" && !contains(extra, "language=")) {
311 par.addParam("language", language);
313 par.addParam("language", "{[" + dialect + "]" + language + "}");
315 // this dialog uses float=placement instead of float,floatplacement=placement
316 // because float accepts *tbph and floatplacement accepts bph.
317 // our placement textedit is actually for the float parameter
319 par.addParam("float", placement);
320 if (numberSide != "none")
321 par.addParam("numbers", numberSide);
322 if (numberfontsize != "default" && numberSide != "none")
323 par.addParam("numberstyle", "\\" + numberfontsize);
324 if (!stepnumber.empty() && numberSide != "none")
325 par.addParam("stepnumber", stepnumber);
326 if (!firstline.empty())
327 par.addParam("firstline", firstline);
328 if (!lastline.empty())
329 par.addParam("lastline", lastline);
330 if (!basicstyle.empty())
331 par.addParam("basicstyle", basicstyle);
333 par.addParam("breaklines", "true");
335 par.addParam("showspaces", "true");
337 par.addParam("showstringspaces", "false");
339 par.addParam("tabsize", convert<string>(tabsize));
341 par.addParam("extendedchars", "true");
342 par.addParams(extra);
347 docstring GuiListings::validate_listings_params()
349 // use a cache here to avoid repeated validation
350 // of the same parameters
352 static string param_cache;
353 static docstring msg_cache;
355 if (bypassCB->isChecked())
358 string params = construct_params();
359 if (params != param_cache) {
360 param_cache = params;
361 msg_cache = InsetListingsParams(params).validate();
367 void GuiListings::setListingsMsg()
370 static bool isOK = true;
371 docstring msg = validate_listings_params();
376 listingsTB->setPlainText(
377 qt_("Input listing parameters on the right. Enter ? for a list of parameters."));
380 listingsTB->setPlainText(toqstr(msg));
385 void GuiListings::on_floatCB_stateChanged(int state)
387 if (state == Qt::Checked) {
388 inlineCB->setChecked(false);
389 placementLE->setEnabled(true);
391 placementLE->setEnabled(false);
395 void GuiListings::on_inlineCB_stateChanged(int state)
397 if (state == Qt::Checked) {
398 floatCB->setChecked(false);
399 placementLE->setEnabled(false);
404 void GuiListings::on_numberSideCO_currentIndexChanged(int index)
406 numberStepLE->setEnabled(index > 0);
407 numberFontSizeCO->setEnabled(index > 0);
411 void GuiListings::on_languageCO_currentIndexChanged(int index)
415 int default_dialect = 0;
416 dialectCO->addItem(qt_("No dialect"));
417 string const language = languages_supported[index];
419 for (size_t i = 0; i != nr_dialects; ++i) {
420 if (language == dialects[i].language) {
421 dialectCO->addItem(qt_(dialects[i].gui));
422 if (dialects[i].is_default)
424 dialectCO->findText(qt_(dialects[i].gui));
427 dialectCO->setCurrentIndex(default_dialect);
428 dialectCO->setEnabled(dialectCO->count() > 1);
432 void GuiListings::applyView()
434 params_.setInline(inlineCB->isChecked());
435 params_.setParams(construct_params());
439 static string plainParam(string const & par)
441 // remove enclosing braces
442 if (prefixIs(par, "{") && suffixIs(par, "}"))
443 return par.substr(1, par.size() - 2);
448 void GuiListings::updateContents()
450 // set default values
451 listingsTB->setPlainText(
452 qt_("Input listing parameters on the right. Enter ? for a list of parameters."));
453 languageCO->setCurrentIndex(findToken(languages_supported, "no language"));
454 dialectCO->setCurrentIndex(0);
455 floatCB->setChecked(false);
456 placementLE->clear();
457 numberSideCO->setCurrentIndex(0);
458 numberStepLE->clear();
459 numberFontSizeCO->setCurrentIndex(findToken(font_sizes, "default"));
460 firstlineLE->clear();
462 fontstyleCO->setCurrentIndex(findToken(font_styles, "default"));
463 fontsizeCO->setCurrentIndex(findToken(font_sizes, "default"));
464 breaklinesCB->setChecked(false);
465 spaceCB->setChecked(false);
466 spaceInStringCB->setChecked(true);
467 tabsizeSB->setValue(8);
468 extendedcharsCB->setChecked(false);
470 // set values from param string
471 inlineCB->setChecked(params_.isInline());
472 if (params_.isInline()) {
473 floatCB->setChecked(false);
474 placementLE->setEnabled(false);
476 // break other parameters and set values
477 vector<string> pars = getVectorFromString(params_.separatedParams(), "\n");
478 // process each of them
479 for (vector<string>::iterator it = pars.begin();
480 it != pars.end(); ++it) {
481 if (prefixIs(*it, "language=")) {
482 string arg = plainParam(it->substr(9));
487 if (prefixIs(arg, "[") && contains(arg, "]")) {
488 size_t end_dialect = arg.find("]");
489 dialect = arg.substr(1, end_dialect - 1);
490 language = arg.substr(end_dialect + 1);
494 int n = findToken(languages_supported, language);
496 languageCO->setCurrentIndex(n);
499 // on_languageCO_currentIndexChanged should have set dialects
500 if (!dialect.empty()) {
502 for (size_t i = 0; i != nr_dialects; ++i) {
503 if (dialect == dialects[i].dialect
504 && dialects[i].language == language) {
505 dialect_gui = dialects[i].gui;
509 n = dialectCO->findText(qt_(dialect_gui));
511 dialectCO->setCurrentIndex(n);
517 languageCO->setEnabled(in_gui);
518 dialectCO->setEnabled(
519 in_gui && dialectCO->count() > 1);
520 } else if (prefixIs(*it, "float")) {
521 floatCB->setChecked(true);
522 inlineCB->setChecked(false);
523 placementLE->setEnabled(true);
524 if (prefixIs(*it, "float="))
525 placementLE->setText(
526 toqstr(plainParam(it->substr(6))));
528 } else if (prefixIs(*it, "numbers=")) {
529 string s = plainParam(it->substr(8));
533 else if (s == "right")
535 numberSideCO->setCurrentIndex(n);
537 } else if (prefixIs(*it, "stepnumber=")) {
538 numberStepLE->setText(
539 toqstr(plainParam(it->substr(11))));
541 } else if (prefixIs(*it, "numberstyle=")) {
542 string par = plainParam(it->substr(12));
543 int n = findToken(font_sizes, par.substr(1));
545 numberFontSizeCO->setCurrentIndex(n);
547 } else if (prefixIs(*it, "firstline=")) {
548 firstlineLE->setText(
549 toqstr(plainParam(it->substr(10))));
551 } else if (prefixIs(*it, "lastline=")) {
553 toqstr(plainParam(it->substr(9))));
555 } else if (prefixIs(*it, "basicstyle=")) {
558 for (int n = 0; font_styles[n][0]; ++n) {
559 string const s = font_styles[n];
560 if (contains(*it, "\\" + s)) {
565 for (int n = 0; font_sizes[n][0]; ++n) {
566 string const s = font_sizes[n];
567 if (contains(*it, "\\" + s)) {
572 if (plainParam(it->substr(11)) == style + size
573 || plainParam(it->substr(11)) == size + style) {
574 if (!style.empty()) {
575 int n = findToken(font_styles, style.substr(1));
577 fontstyleCO->setCurrentIndex(n);
580 int n = findToken(font_sizes, size.substr(1));
582 fontsizeCO->setCurrentIndex(n);
586 } else if (prefixIs(*it, "breaklines=")) {
587 breaklinesCB->setChecked(contains(*it, "true"));
589 } else if (prefixIs(*it, "showspaces=")) {
590 spaceCB->setChecked(contains(*it, "true"));
592 } else if (prefixIs(*it, "showstringspaces=")) {
593 spaceInStringCB->setChecked(contains(*it, "true"));
595 } else if (prefixIs(*it, "tabsize=")) {
596 tabsizeSB->setValue(convert<int>(plainParam(it->substr(8))));
598 } else if (prefixIs(*it, "extendedchars=")) {
599 extendedcharsCB->setChecked(contains(*it, "true"));
604 numberStepLE->setEnabled(numberSideCO->currentIndex() > 0);
605 numberFontSizeCO->setEnabled(numberSideCO->currentIndex() > 0);
606 // parameters that can be handled by widgets are cleared
607 // the rest is put to the extra edit box.
608 string extra = getStringFromVector(pars);
609 listingsED->setPlainText(toqstr(InsetListingsParams(extra).separatedParams()));
613 bool GuiListings::isValid()
615 return validate_listings_params().empty();
619 bool GuiListings::initialiseParams(string const & data)
621 InsetListings::string2params(data, params_);
626 void GuiListings::clearParams()
632 void GuiListings::dispatchParams()
634 string const lfun = InsetListings::params2string(params_);
635 dispatch(FuncRequest(getLfun(), lfun));
639 void GuiListings::setParams(InsetListingsParams const & params)
645 Dialog * createGuiListings(GuiView & lv) { return new GuiListings(lv); }
648 } // namespace frontend
652 #include "moc_GuiListings.cpp"