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 "QListings.h"
16 #include "qt_helpers.h"
17 #include "controllers/ControlListings.h"
18 #include "insets/InsetListingsParams.h"
21 #include "support/convert.h"
22 #include "support/lstrings.h"
25 #include <QCloseEvent>
26 #include <QPushButton>
28 #include <QRegExpValidator>
33 using lyx::support::findToken;
34 using lyx::support::getVectorFromString;
35 using lyx::support::getStringFromVector;
36 using lyx::support::prefixIs;
37 using lyx::support::suffixIs;
38 using lyx::support::contains;
43 /////////////////////////////////////////////////////////////////////
47 /////////////////////////////////////////////////////////////////////
50 char const * languages[] =
51 { "no language", "ABAP", "ACSL", "Ada", "ALGOL", "Assembler", "Awk", "bash", "Basic", "C",
52 "C++", "Caml", "Clean", "Cobol", "Comal 80", "command.com", "Comsol", "csh", "Delphi",
53 "Eiffel", "Elan", "Euphoria", "Fortran", "Gnuplot", "Haskell", "HTML", "IDL", "inform",
54 "Java", "JVMIS", "ksh", "Lingo", "Lisp", "Logo", "make", "Mathematica", "Matlab", "Mercury",
55 "MetaPost", "Miranda", "ML", "Modula-2", "MuPAD", "NASTRAN", "Oberon-2", "OCL", "Octave",
56 "Oz", "Pascal", "Perl", "PHP", "PL/I", "Plasm", "PostScript", "POV", "Prolog", "Promela",
57 "PSTricks", "Python", "R", "Reduce", "Rexx", "RSL", "Ruby", "S", "SAS", "Scilab", "sh",
58 "SHELXL", "Simula", "tcl", "SPARQL", "SQL", "tcl", "TeX", "VBScript", "Verilog", "VHDL",
59 "VRML", "XML", "XSLT", "" };
62 char const * languages_gui[] =
63 { N_("No language"), "ABAP", "ACSL", "Ada", "ALGOL", "Assembler", "Awk", "bash", "Basic",
64 "C", "C++", "Caml", "Clean", "Cobol", "Comal 80", "command.com", "Comsol", "csh", "Delphi",
65 "Eiffel", "Elan", "Euphoria", "Fortran", "Gnuplot", "Haskell", "HTML", "IDL", "inform",
66 "Java", "JVMIS", "ksh", "Lingo", "Lisp", "Logo", "make", "Mathematica", "Matlab", "Mercury",
67 "MetaPost", "Miranda", "ML", "Modula-2", "MuPAD", "NASTRAN", "Oberon-2", "OCL", "Octave",
68 "Oz", "Pascal", "Perl", "PHP", "PL/I", "Plasm", "PostScript", "POV", "Prolog", "Promela",
69 "PSTricks", "Python", "R", "Reduce", "Rexx", "RSL", "Ruby", "S", "SAS", "Scilab", "sh",
70 "SHELXL", "Simula", "tcl", "SPARQL", "SQL", "tcl", "TeX", "VBScript", "Verilog", "VHDL",
71 "VRML", "XML", "XSLT", "" };
77 /// the associated language
78 char const * language;
79 /// representation of the dialect in the gui
81 /// is this the default dialect?
86 dialect_info const dialects[] = {
87 { "R/2 4.3", "ABAP", "R/2 4.3", false },
88 { "R/2 5.0", "ABAP", "R/2 5.0", false },
89 { "R/3 3.1", "ABAP", "R/3 3.1", false },
90 { "R/3 4.6C", "ABAP", "R/3 4.6C", false },
91 { "R/3 6.10", "ABAP", "R/3 6.10", true },
92 { "2005", "Ada", "2005", true },
93 { "83", "Ada", "83", false },
94 { "95", "Ada", "95", false },
95 { "60", "Algol", "60", false },
96 { "68", "Algol", "68", true },
97 { "Motorola68k", "Assembler", "Motorola 68xxx", false },
98 { "x86masm", "Assembler", "x86 (MASM)", false },
99 { "gnu", "Awk", "gnu", true },
100 { "POSIX", "Awk", "POSIX", false },
101 { "Visual", "Basic", "Visual", false },
102 { "ANSI", "C", "ANSI", true },
103 { "Handel", "C", "Handel", false },
104 { "Objective", "C", "Objective", false },
105 { "Sharp", "C", "Sharp", false },
106 { "ANSI", "C++", "ANSI", false },
107 { "GNU", "C++", "GNU", false },
108 { "ISO", "C++", "ISO", true },
109 { "Visual", "C++", "Visual", false },
110 { "light", "Caml", "light", true },
111 { "Objective", "Caml", "Objective", false },
112 { "1974", "Cobol", "1974", false },
113 { "1985", "Cobol", "1985", true },
114 { "ibm", "Cobol", "IBM", false },
115 { "WinXP", "command.com", "Windows XP", true },
116 { "77", "Fortran", "77", false },
117 { "90", "Fortran", "90", false },
118 { "95", "Fortran", "95", true },
119 { "CORBA", "IDL", "CORBA", false },
120 { "AspectJ", "Java", "Aspect J", false },
121 { "Auto", "Lisp", "Auto", false },
122 { "gnu", "make", "gnu", false },
123 { "1.0", "Mathematica", "1.0", false },
124 { "3.0", "Mathematica", "3.0", false },
125 { "5.2", "Mathematica", "5.2", true },
126 { "decorative", "OCL", "decorative", false },
127 { "OMG", "OCL", "OMG", true },
128 { "Borland6", "Pascal", "Borland 6", false },
129 { "Standard", "Pascal", "Standard", true },
130 { "XSC", "Pascal", "XSC", false },
131 { "PLUS", "S", "PLUS", false },
132 { "67", "Simula", "67", true },
133 { "CII", "Simula", "CII", false },
134 { "DEC", "Simula", "DEC", false },
135 { "IBM", "Simula", "IBM", false },
136 { "tk", "tcl", "tk", false },
137 { "AlLaTeX", "TeX", "AlLaTeX", false },
138 { "common", "TeX", "common", false },
139 { "LaTeX", "TeX", "LaTeX", false },
140 { "plain", "TeX", "plain", true },
141 { "primitive", "TeX", "primitive", false },
142 { "AMS", "VHDL", "AMS", false },
143 { "97", "VRML", "97", true }
147 size_t const nr_dialects = sizeof(dialects) / sizeof(dialect_info);
150 char const * font_sizes[] =
151 { "default", "tiny", "scriptsize", "footnotesize", "small", "normalsize", "large",
154 char const * font_sizes_gui[] =
155 { N_("Default"), N_("Tiny"), N_("Smallest"), N_("Smaller"), N_("Small"), N_("Normal"),
156 N_("Large"), N_("Larger"), "" };
158 char const * font_styles[] =
159 { "default", "rmfamily", "ttfamily", "sffamily", "" };
161 char const * font_styles_gui[] =
162 { N_("Default"), N_("Roman"), N_("Typewriter"), N_("Sans Serif"), "" };
166 QListingsDialog::QListingsDialog(QListings * form)
171 connect(okPB, SIGNAL(clicked()), form, SLOT(slotOK()));
172 connect(applyPB, SIGNAL(clicked()), form_, SLOT(slotApply()));
173 connect(closePB, SIGNAL(clicked()), form, SLOT(slotClose()));
175 connect(languageCO, SIGNAL(currentIndexChanged(int)), this, SLOT(change_adaptor()));
176 connect(dialectCO, SIGNAL(currentIndexChanged(int)), this, SLOT(change_adaptor()));
177 connect(inlineCB, SIGNAL(clicked()), this, SLOT(change_adaptor()));
178 connect(floatCB, SIGNAL(clicked()), this, SLOT(change_adaptor()));
179 connect(placementLE, SIGNAL(textChanged(const QString&)), this, SLOT(change_adaptor()));
180 connect(numberSideCO, SIGNAL(currentIndexChanged(int)), this, SLOT(change_adaptor()));
181 connect(numberStepLE, SIGNAL(textChanged(const QString&)), this, SLOT(change_adaptor()));
182 connect(numberFontSizeCO, SIGNAL(currentIndexChanged(int)), this, SLOT(change_adaptor()));
183 connect(firstlineLE, SIGNAL(textChanged(const QString&)), this, SLOT(change_adaptor()));
184 connect(lastlineLE, SIGNAL(textChanged(const QString&)), this, SLOT(change_adaptor()));
185 connect(fontsizeCO, SIGNAL(currentIndexChanged(int)), this, SLOT(change_adaptor()));
186 connect(fontstyleCO, SIGNAL(currentIndexChanged(int)), this, SLOT(change_adaptor()));
187 connect(breaklinesCB, SIGNAL(clicked()), this, SLOT(change_adaptor()));
188 connect(spaceCB, SIGNAL(clicked()), this, SLOT(change_adaptor()));
189 connect(spaceInStringCB, SIGNAL(clicked()), this, SLOT(change_adaptor()));
190 connect(extendedcharsCB, SIGNAL(clicked()), this, SLOT(change_adaptor()));
192 connect(listingsED, SIGNAL(textChanged()), this, SLOT(change_adaptor()));
193 connect(listingsED, SIGNAL(textChanged()), this, SLOT(set_listings_msg()));
194 connect(bypassCB, SIGNAL(clicked()), this, SLOT(change_adaptor()));
195 connect(bypassCB, SIGNAL(clicked()), this, SLOT(set_listings_msg()));
197 for (int n = 0; languages[n][0]; ++n)
198 languageCO->addItem(qt_(languages_gui[n]));
200 for (int n = 0; font_styles[n][0]; ++n)
201 fontstyleCO->addItem(qt_(font_styles_gui[n]));
203 for (int n = 0; font_sizes[n][0]; ++n) {
204 QString font = qt_(font_sizes_gui[n]);
205 fontsizeCO->addItem(font);
206 numberFontSizeCO->addItem(font);
210 numberStepLE->setValidator(new QIntValidator(0, 1000000, this));
211 firstlineLE->setValidator(new QIntValidator(0, 1000000, this));
212 lastlineLE->setValidator(new QIntValidator(0, 1000000, this));
213 placementLE->setValidator(new QRegExpValidator(QRegExp("[\\*tbph]*"), this));
217 void QListingsDialog::closeEvent(QCloseEvent * e)
224 void QListingsDialog::change_adaptor()
230 string QListingsDialog::construct_params()
232 string language = languages[languageCO->currentIndex()];
234 string const dialect_gui = fromqstr(dialectCO->currentText());
235 if (dialectCO->currentIndex() > 0) {
236 for (size_t i = 0; i < nr_dialects; ++i) {
237 if (dialect_gui == dialects[i].gui
238 && dialects[i].language == language
239 && !dialects[i].is_default) {
240 dialect = dialects[i].dialect;
246 bool float_ = floatCB->isChecked();
248 if (placementLE->isEnabled())
249 placement = fromqstr(placementLE->text());
252 switch (numberSideCO->currentIndex()) {
260 numberSide = "right";
266 string stepnumber = fromqstr(numberStepLE->text());
267 string numberfontsize = font_sizes[numberFontSizeCO->currentIndex()];
268 string firstline = fromqstr(firstlineLE->text());
269 string lastline = fromqstr(lastlineLE->text());
271 string fontsize = font_sizes[fontsizeCO->currentIndex()];
272 string fontstyle = font_styles[fontstyleCO->currentIndex()];
274 if (fontsize != "default")
275 basicstyle = "\\" + fontsize;
276 if (fontstyle != "default")
277 basicstyle += "\\" + fontstyle;
278 bool breakline = breaklinesCB->isChecked();
279 bool space = spaceCB->isChecked();
280 bool spaceInString = spaceInStringCB->isChecked();
281 bool extendedchars = extendedcharsCB->isChecked();
282 string extra = fromqstr(listingsED->toPlainText());
285 InsetListingsParams par;
286 if (language != "no language" && !contains(extra, "language=")) {
288 par.addParam("language", language);
290 par.addParam("language", "{[" + dialect + "]" + language + "}");
292 // this dialog uses float=placement instead of float,floatplacement=placement
293 // because float accepts *tbph and floatplacement accepts bph.
294 // our placement textedit is actually for the float parameter
296 par.addParam("float", placement);
297 if (numberSide != "none")
298 par.addParam("numbers", numberSide);
299 if (numberfontsize != "default" && numberSide != "none")
300 par.addParam("numberstyle", "\\" + numberfontsize);
301 if (!stepnumber.empty() && numberSide != "none")
302 par.addParam("stepnumber", stepnumber);
303 if (!firstline.empty())
304 par.addParam("firstline", firstline);
305 if (!lastline.empty())
306 par.addParam("lastline", lastline);
307 if (!basicstyle.empty())
308 par.addParam("basicstyle", basicstyle);
310 par.addParam("breaklines", "true");
312 par.addParam("showspaces", "true");
314 par.addParam("showstringspaces", "false");
316 par.addParam("extendedchars", "true");
317 par.addParams(extra);
322 docstring QListingsDialog::validate_listings_params()
324 // use a cache here to avoid repeated validation
325 // of the same parameters
326 static string param_cache = string();
327 static docstring msg_cache = docstring();
329 if (bypassCB->isChecked())
332 string params = construct_params();
333 if (params != param_cache) {
334 param_cache = params;
335 msg_cache = InsetListingsParams(params).validate();
341 void QListingsDialog::set_listings_msg()
343 static bool isOK = true;
344 docstring msg = validate_listings_params();
349 listingsTB->setPlainText(
350 qt_("Input listing parameters on the right. Enter ? for a list of parameters."));
353 listingsTB->setPlainText(toqstr(msg));
358 void QListingsDialog::on_floatCB_stateChanged(int state)
360 if (state == Qt::Checked) {
361 inlineCB->setChecked(false);
362 placementLE->setEnabled(true);
364 placementLE->setEnabled(false);
368 void QListingsDialog::on_inlineCB_stateChanged(int state)
370 if (state == Qt::Checked) {
371 floatCB->setChecked(false);
372 placementLE->setEnabled(false);
377 void QListingsDialog::on_numberSideCO_currentIndexChanged(int index)
379 numberStepLE->setEnabled(index > 0);
380 numberFontSizeCO->setEnabled(index > 0);
384 void QListingsDialog::on_languageCO_currentIndexChanged(int index)
388 int default_dialect = 0;
389 dialectCO->addItem(qt_("No dialect"));
390 string const language = languages[index];
392 for (size_t i = 0; i < nr_dialects; ++i) {
393 if (language == dialects[i].language) {
394 dialectCO->addItem(qt_(dialects[i].gui));
395 if (dialects[i].is_default)
397 dialectCO->findText(qt_(dialects[i].gui));
400 dialectCO->setCurrentIndex(default_dialect);
401 dialectCO->setEnabled(dialectCO->count() > 1);
405 /////////////////////////////////////////////////////////////////////
409 /////////////////////////////////////////////////////////////////////
411 typedef QController<ControlListings, QView<QListingsDialog> > listings_wrap_base_class;
413 QListings::QListings(Dialog & parent)
414 : listings_wrap_base_class(parent, _("Program Listing Settings"))
419 void QListings::build_dialog()
421 dialog_.reset(new QListingsDialog(this));
423 bcview().setOK(dialog_->okPB);
424 bcview().setApply(dialog_->applyPB);
425 bcview().setCancel(dialog_->closePB);
426 dialog_->listingsTB->setPlainText(
427 qt_("Input listing parameters on the right. Enter ? for a list of parameters."));
433 void QListings::apply()
435 InsetListingsParams & params = controller().params();
436 params.setInline(dialog_->inlineCB->isChecked());
437 params.setParams(dialog_->construct_params());
438 controller().setParams(params);
444 string plainParam(std::string const & par)
446 // remove enclosing braces
447 if (prefixIs(par, "{") && suffixIs(par, "}"))
448 return par.substr(1, par.size() - 2);
455 void QListings::update_contents()
457 // set default values
458 dialog_->listingsTB->setPlainText(
459 qt_("Input listing parameters on the right. Enter ? for a list of parameters."));
460 dialog_->languageCO->setCurrentIndex(findToken(languages, "no language"));
461 dialog_->dialectCO->setCurrentIndex(0);
462 dialog_->floatCB->setChecked(false);
463 dialog_->placementLE->clear();
464 dialog_->numberSideCO->setCurrentIndex(0);
465 dialog_->numberStepLE->clear();
466 dialog_->numberFontSizeCO->setCurrentIndex(findToken(font_sizes, "default"));
467 dialog_->firstlineLE->clear();
468 dialog_->lastlineLE->clear();
469 dialog_->fontstyleCO->setCurrentIndex(findToken(font_styles, "default"));
470 dialog_->fontsizeCO->setCurrentIndex(findToken(font_sizes, "default"));
471 dialog_->breaklinesCB->setChecked(false);
472 dialog_->spaceCB->setChecked(false);
473 dialog_->spaceInStringCB->setChecked(true);
474 dialog_->extendedcharsCB->setChecked(false);
476 // set values from param string
477 InsetListingsParams & params = controller().params();
478 dialog_->inlineCB->setChecked(params.isInline());
479 if (params.isInline()) {
480 dialog_->floatCB->setChecked(false);
481 dialog_->placementLE->setEnabled(false);
483 // break other parameters and set values
484 vector<string> pars = getVectorFromString(params.separatedParams(), "\n");
485 // process each of them
486 for (vector<string>::iterator it = pars.begin();
487 it != pars.end(); ++it) {
488 if (prefixIs(*it, "language=")) {
489 string arg = plainParam(it->substr(9));
494 if (prefixIs(arg, "[") && contains(arg, "]")) {
495 string::size_type end_dialect = arg.find("]");
496 dialect = arg.substr(1, end_dialect - 1);
497 language = arg.substr(end_dialect + 1);
500 int n = findToken(languages, language);
502 dialog_->languageCO->setCurrentIndex(n);
505 // on_languageCO_currentIndexChanged should have set dialects
506 if (!dialect.empty()) {
508 for (size_t i = 0; i < nr_dialects; ++i) {
509 if (dialect == dialects[i].dialect
510 && dialects[i].language == language) {
511 dialect_gui = dialects[i].gui;
515 n = dialog_->dialectCO->findText(qt_(dialect_gui));
517 dialog_->dialectCO->setCurrentIndex(n);
523 dialog_->languageCO->setEnabled(in_gui);
524 dialog_->dialectCO->setEnabled(
525 in_gui && dialog_->dialectCO->count() > 1);
526 } else if (prefixIs(*it, "float")) {
527 dialog_->floatCB->setChecked(true);
528 dialog_->inlineCB->setChecked(false);
529 dialog_->placementLE->setEnabled(true);
530 if (prefixIs(*it, "float="))
531 dialog_->placementLE->setText(
532 toqstr(plainParam(it->substr(6))));
534 } else if (prefixIs(*it, "numbers=")) {
535 string s = plainParam(it->substr(8));
539 else if (s == "right")
541 dialog_->numberSideCO->setCurrentIndex(n);
543 } else if (prefixIs(*it, "stepnumber=")) {
544 dialog_->numberStepLE->setText(
545 toqstr(plainParam(it->substr(11))));
547 } else if (prefixIs(*it, "numberstyle=")) {
548 string par = plainParam(it->substr(12));
549 int n = findToken(font_sizes, par.substr(1));
551 dialog_->numberFontSizeCO->setCurrentIndex(n);
553 } else if (prefixIs(*it, "firstline=")) {
554 dialog_->firstlineLE->setText(
555 toqstr(plainParam(it->substr(10))));
557 } else if (prefixIs(*it, "lastline=")) {
558 dialog_->lastlineLE->setText(
559 toqstr(plainParam(it->substr(9))));
561 } else if (prefixIs(*it, "basicstyle=")) {
564 for (int n = 0; font_styles[n][0]; ++n) {
565 string const s = font_styles[n];
566 if (contains(*it, "\\" + s)) {
571 for (int n = 0; font_sizes[n][0]; ++n) {
572 string const s = font_sizes[n];
573 if (contains(*it, "\\" + s)) {
578 if (plainParam(it->substr(11)) == style + size
579 || plainParam(it->substr(11)) == size + style) {
580 if (!style.empty()) {
581 int n = findToken(font_styles, style.substr(1));
583 dialog_->fontstyleCO->setCurrentIndex(n);
586 int n = findToken(font_sizes, size.substr(1));
588 dialog_->fontsizeCO->setCurrentIndex(n);
592 } else if (prefixIs(*it, "breaklines=")) {
593 dialog_->breaklinesCB->setChecked(contains(*it, "true"));
595 } else if (prefixIs(*it, "showspaces=")) {
596 dialog_->spaceCB->setChecked(contains(*it, "true"));
598 } else if (prefixIs(*it, "showstringspaces=")) {
599 dialog_->spaceInStringCB->setChecked(contains(*it, "true"));
601 } else if (prefixIs(*it, "extendedchars=")) {
602 dialog_->extendedcharsCB->setChecked(contains(*it, "true"));
607 dialog_->numberStepLE->setEnabled(dialog_->numberSideCO->currentIndex() > 0);
608 dialog_->numberFontSizeCO->setEnabled(dialog_->numberSideCO->currentIndex() > 0);
609 // parameters that can be handled by widgets are cleared
610 // the rest is put to the extra edit box.
611 string extra = getStringFromVector(pars);
612 dialog_->listingsED->setPlainText(toqstr(InsetListingsParams(extra).separatedParams()));
616 bool QListings::isValid()
618 return dialog_->validate_listings_params().empty();
622 } // namespace frontend
626 #include "QListings_moc.cpp"