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(validate_listings_params()));
194 connect(bypassCB, SIGNAL(clicked()), this, SLOT(change_adaptor()));
196 for (int n = 0; languages[n][0]; ++n)
197 languageCO->addItem(qt_(languages_gui[n]));
199 for (int n = 0; font_styles[n][0]; ++n)
200 fontstyleCO->addItem(qt_(font_styles_gui[n]));
202 for (int n = 0; font_sizes[n][0]; ++n) {
203 QString font = qt_(font_sizes_gui[n]);
204 fontsizeCO->addItem(font);
205 numberFontSizeCO->addItem(font);
209 numberStepLE->setValidator(new QIntValidator(0, 1000000, this));
210 firstlineLE->setValidator(new QIntValidator(0, 1000000, this));
211 lastlineLE->setValidator(new QIntValidator(0, 1000000, this));
212 placementLE->setValidator(new QRegExpValidator(QRegExp("[\\*tbph]*"), this));
216 void QListingsDialog::closeEvent(QCloseEvent * e)
223 void QListingsDialog::change_adaptor()
229 string QListingsDialog::construct_params()
231 string language = languages[languageCO->currentIndex()];
233 string const dialect_gui = fromqstr(dialectCO->currentText());
234 if (dialectCO->currentIndex() > 0) {
235 for (size_t i = 0; i < nr_dialects; ++i) {
236 if (dialect_gui == dialects[i].gui
237 && dialects[i].language == language
238 && !dialects[i].is_default) {
239 dialect = dialects[i].dialect;
245 bool float_ = floatCB->isChecked();
247 if (placementLE->isEnabled())
248 placement = fromqstr(placementLE->text());
251 switch (numberSideCO->currentIndex()) {
259 numberSide = "right";
265 string stepnumber = fromqstr(numberStepLE->text());
266 string numberfontsize = font_sizes[numberFontSizeCO->currentIndex()];
267 string firstline = fromqstr(firstlineLE->text());
268 string lastline = fromqstr(lastlineLE->text());
270 string fontsize = font_sizes[fontsizeCO->currentIndex()];
271 string fontstyle = font_styles[fontstyleCO->currentIndex()];
273 if (fontsize != "default")
274 basicstyle = "\\" + fontsize;
275 if (fontstyle != "default")
276 basicstyle += "\\" + fontstyle;
277 bool breakline = breaklinesCB->isChecked();
278 bool space = spaceCB->isChecked();
279 bool spaceInString = spaceInStringCB->isChecked();
280 bool extendedchars = extendedcharsCB->isChecked();
281 string extra = fromqstr(listingsED->toPlainText());
284 InsetListingsParams par;
285 if (language != "no language" && !contains(extra, "language=")) {
287 par.addParam("language", language);
289 par.addParam("language", "{[" + dialect + "]" + language + "}");
291 // this dialog uses float=placement instead of float,floatplacement=placement
292 // because float accepts *tbph and floatplacement accepts bph.
293 // our placement textedit is actually for the float parameter
295 par.addParam("float", placement);
296 if (numberSide != "none")
297 par.addParam("numbers", numberSide);
298 if (numberfontsize != "default" && numberSide != "none")
299 par.addParam("numberstyle", "\\" + numberfontsize);
300 if (!stepnumber.empty() && numberSide != "none")
301 par.addParam("stepnumber", stepnumber);
302 if (!firstline.empty())
303 par.addParam("firstline", firstline);
304 if (!lastline.empty())
305 par.addParam("lastline", lastline);
306 if (!basicstyle.empty())
307 par.addParam("basicstyle", basicstyle);
309 par.addParam("breaklines", "true");
311 par.addParam("showspaces", "true");
313 par.addParam("showstringspaces", "false");
315 par.addParam("extendedchars", "true");
316 par.addParams(extra);
321 void QListingsDialog::validate_listings_params()
323 static bool isOK = true;
324 InsetListingsParams par(construct_params());
326 if (!bypassCB->isChecked())
327 msg = par.validate();
332 listingsTB->setPlainText(
333 qt_("Input listing parameters on the right. Enter ? for a list of parameters."));
334 okPB->setEnabled(true);
335 applyPB->setEnabled(true);
338 listingsTB->setPlainText(toqstr(msg));
339 okPB->setEnabled(false);
340 applyPB->setEnabled(false);
345 void QListingsDialog::on_floatCB_stateChanged(int state)
347 if (state == Qt::Checked) {
348 inlineCB->setChecked(false);
349 placementLE->setEnabled(true);
351 placementLE->setEnabled(false);
355 void QListingsDialog::on_inlineCB_stateChanged(int state)
357 if (state == Qt::Checked) {
358 floatCB->setChecked(false);
359 placementLE->setEnabled(false);
364 void QListingsDialog::on_numberSideCO_currentIndexChanged(int index)
366 numberStepLE->setEnabled(index > 0);
367 numberFontSizeCO->setEnabled(index > 0);
371 void QListingsDialog::on_languageCO_currentIndexChanged(int index)
375 int default_dialect = 0;
376 dialectCO->addItem(qt_("No dialect"));
377 string const language = languages[index];
379 for (size_t i = 0; i < nr_dialects; ++i) {
380 if (language == dialects[i].language) {
381 dialectCO->addItem(qt_(dialects[i].gui));
382 if (dialects[i].is_default)
384 dialectCO->findText(qt_(dialects[i].gui));
387 dialectCO->setCurrentIndex(default_dialect);
388 dialectCO->setEnabled(dialectCO->count() > 1);
392 /////////////////////////////////////////////////////////////////////
396 /////////////////////////////////////////////////////////////////////
398 typedef QController<ControlListings, QView<QListingsDialog> > listings_wrap_base_class;
400 QListings::QListings(Dialog & parent)
401 : listings_wrap_base_class(parent, _("Program Listing Settings"))
406 void QListings::build_dialog()
408 dialog_.reset(new QListingsDialog(this));
410 bcview().setOK(dialog_->okPB);
411 bcview().setApply(dialog_->applyPB);
412 bcview().setCancel(dialog_->closePB);
413 dialog_->listingsTB->setPlainText(
414 qt_("Input listing parameters on the right. Enter ? for a list of parameters."));
420 void QListings::apply()
422 InsetListingsParams & params = controller().params();
423 params.setInline(dialog_->inlineCB->isChecked());
424 params.setParams(dialog_->construct_params());
425 controller().setParams(params);
431 string plainParam(std::string const & par)
433 // remove enclosing braces
434 if (prefixIs(par, "{") && suffixIs(par, "}"))
435 return par.substr(1, par.size() - 2);
442 void QListings::update_contents()
444 // set default values
445 dialog_->listingsTB->setPlainText(
446 qt_("Input listing parameters on the right. Enter ? for a list of parameters."));
447 dialog_->languageCO->setCurrentIndex(findToken(languages, "no language"));
448 dialog_->dialectCO->setCurrentIndex(0);
449 dialog_->floatCB->setChecked(false);
450 dialog_->placementLE->clear();
451 dialog_->numberSideCO->setCurrentIndex(0);
452 dialog_->numberStepLE->clear();
453 dialog_->numberFontSizeCO->setCurrentIndex(findToken(font_sizes, "default"));
454 dialog_->firstlineLE->clear();
455 dialog_->lastlineLE->clear();
456 dialog_->fontstyleCO->setCurrentIndex(findToken(font_styles, "default"));
457 dialog_->fontsizeCO->setCurrentIndex(findToken(font_sizes, "default"));
458 dialog_->breaklinesCB->setChecked(false);
459 dialog_->spaceCB->setChecked(false);
460 dialog_->spaceInStringCB->setChecked(true);
461 dialog_->extendedcharsCB->setChecked(false);
463 // set values from param string
464 InsetListingsParams & params = controller().params();
465 dialog_->inlineCB->setChecked(params.isInline());
466 if (params.isInline()) {
467 dialog_->floatCB->setChecked(false);
468 dialog_->placementLE->setEnabled(false);
470 // break other parameters and set values
471 vector<string> pars = getVectorFromString(params.separatedParams(), "\n");
472 // process each of them
473 for (vector<string>::iterator it = pars.begin();
474 it != pars.end(); ++it) {
475 if (prefixIs(*it, "language=")) {
476 string arg = plainParam(it->substr(9));
481 if (prefixIs(arg, "[") && contains(arg, "]")) {
482 string::size_type end_dialect = arg.find("]");
483 dialect = arg.substr(1, end_dialect - 1);
484 language = arg.substr(end_dialect + 1);
487 int n = findToken(languages, language);
489 dialog_->languageCO->setCurrentIndex(n);
492 // on_languageCO_currentIndexChanged should have set dialects
493 if (!dialect.empty()) {
495 for (size_t i = 0; i < nr_dialects; ++i) {
496 if (dialect == dialects[i].dialect
497 && dialects[i].language == language) {
498 dialect_gui = dialects[i].gui;
502 n = dialog_->dialectCO->findText(qt_(dialect_gui));
504 dialog_->dialectCO->setCurrentIndex(n);
510 dialog_->languageCO->setEnabled(in_gui);
511 dialog_->dialectCO->setEnabled(
512 in_gui && dialog_->dialectCO->count() > 1);
513 } else if (prefixIs(*it, "float")) {
514 dialog_->floatCB->setChecked(true);
515 dialog_->inlineCB->setChecked(false);
516 dialog_->placementLE->setEnabled(true);
517 if (prefixIs(*it, "float="))
518 dialog_->placementLE->setText(
519 toqstr(plainParam(it->substr(6))));
521 } else if (prefixIs(*it, "numbers=")) {
522 string s = plainParam(it->substr(8));
526 else if (s == "right")
528 dialog_->numberSideCO->setCurrentIndex(n);
530 } else if (prefixIs(*it, "stepnumber=")) {
531 dialog_->numberStepLE->setText(
532 toqstr(plainParam(it->substr(11))));
534 } else if (prefixIs(*it, "numberstyle=")) {
535 string par = plainParam(it->substr(12));
536 int n = findToken(font_sizes, par.substr(1));
538 dialog_->numberFontSizeCO->setCurrentIndex(n);
540 } else if (prefixIs(*it, "firstline=")) {
541 dialog_->firstlineLE->setText(
542 toqstr(plainParam(it->substr(10))));
544 } else if (prefixIs(*it, "lastline=")) {
545 dialog_->lastlineLE->setText(
546 toqstr(plainParam(it->substr(9))));
548 } else if (prefixIs(*it, "basicstyle=")) {
551 for (int n = 0; font_styles[n][0]; ++n) {
552 string const s = font_styles[n];
553 if (contains(*it, "\\" + s)) {
558 for (int n = 0; font_sizes[n][0]; ++n) {
559 string const s = font_sizes[n];
560 if (contains(*it, "\\" + s)) {
565 if (plainParam(it->substr(11)) == style + size
566 || plainParam(it->substr(11)) == size + style) {
567 if (!style.empty()) {
568 int n = findToken(font_styles, style.substr(1));
570 dialog_->fontstyleCO->setCurrentIndex(n);
573 int n = findToken(font_sizes, size.substr(1));
575 dialog_->fontsizeCO->setCurrentIndex(n);
579 } else if (prefixIs(*it, "breaklines=")) {
580 dialog_->breaklinesCB->setChecked(contains(*it, "true"));
582 } else if (prefixIs(*it, "showspaces=")) {
583 dialog_->spaceCB->setChecked(contains(*it, "true"));
585 } else if (prefixIs(*it, "showstringspaces=")) {
586 dialog_->spaceInStringCB->setChecked(contains(*it, "true"));
588 } else if (prefixIs(*it, "extendedchars=")) {
589 dialog_->extendedcharsCB->setChecked(contains(*it, "true"));
594 dialog_->numberStepLE->setEnabled(dialog_->numberSideCO->currentIndex() > 0);
595 dialog_->numberFontSizeCO->setEnabled(dialog_->numberSideCO->currentIndex() > 0);
596 // parameters that can be handled by widgets are cleared
597 // the rest is put to the extra edit box.
598 string extra = getStringFromVector(pars);
599 dialog_->listingsED->setPlainText(toqstr(InsetListingsParams(extra).separatedParams()));
603 } // namespace frontend
607 #include "QListings_moc.cpp"