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", N_("common"), false },
139 { "LaTeX", "TeX", "LaTeX", false },
140 { "plain", "TeX", N_("plain"), true },
141 { "primitive", "TeX", N_("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()));
195 for (int n = 0; languages[n][0]; ++n)
196 languageCO->addItem(languages_gui[n]);
198 for (int n = 0; font_styles[n][0]; ++n)
199 fontstyleCO->addItem(font_styles_gui[n]);
201 for (int n = 0; font_sizes[n][0]; ++n) {
202 QString font = toqstr(font_sizes_gui[n]);
203 fontsizeCO->addItem(font);
204 numberFontSizeCO->addItem(font);
208 numberStepLE->setValidator(new QIntValidator(0, 1000000, this));
209 firstlineLE->setValidator(new QIntValidator(0, 1000000, this));
210 lastlineLE->setValidator(new QIntValidator(0, 1000000, this));
211 placementLE->setValidator(new QRegExpValidator(QRegExp("[\\*tbph]*"), this));
215 void QListingsDialog::closeEvent(QCloseEvent * e)
222 void QListingsDialog::change_adaptor()
228 string QListingsDialog::construct_params()
230 string language = languages[languageCO->currentIndex()];
232 string const dialect_gui = fromqstr(dialectCO->currentText());
233 if (dialectCO->currentIndex() > 0) {
234 for (size_t i = 0; i < nr_dialects; ++i) {
235 if (dialect_gui == dialects[i].gui
236 && dialects[i].language == language
237 && !dialects[i].is_default) {
238 dialect = dialects[i].dialect;
244 bool float_ = floatCB->isChecked();
246 if (placementLE->isEnabled())
247 placement = fromqstr(placementLE->text());
250 switch (numberSideCO->currentIndex()) {
258 numberSide = "right";
264 string stepnumber = fromqstr(numberStepLE->text());
265 string numberfontsize = font_sizes[numberFontSizeCO->currentIndex()];
266 string firstline = fromqstr(firstlineLE->text());
267 string lastline = fromqstr(lastlineLE->text());
269 string fontsize = font_sizes[fontsizeCO->currentIndex()];
270 string fontstyle = font_styles[fontstyleCO->currentIndex()];
272 if (fontsize != "default")
273 basicstyle = "\\" + fontsize;
274 if (fontstyle != "default")
275 basicstyle += "\\" + fontstyle;
276 bool breakline = breaklinesCB->isChecked();
277 bool space = spaceCB->isChecked();
278 bool spaceInString = spaceInStringCB->isChecked();
279 bool extendedchars = extendedcharsCB->isChecked();
280 string extra = fromqstr(listingsED->toPlainText());
283 InsetListingsParams par;
284 if (language != "no language" && !contains(extra, "language=")) {
286 par.addParam("language", language);
288 par.addParam("language", "{[" + dialect + "]" + language + "}");
290 // this dialog uses float=placement instead of float,floatplacement=placement
291 // because float accepts *tbph and floatplacement accepts bph.
292 // our placement textedit is actually for the float parameter
294 par.addParam("float", placement);
295 if (numberSide != "none")
296 par.addParam("numbers", numberSide);
297 if (numberfontsize != "default" && numberSide != "none")
298 par.addParam("numberstyle", "\\" + numberfontsize);
299 if (!stepnumber.empty() && numberSide != "none")
300 par.addParam("stepnumber", stepnumber);
301 if (!firstline.empty())
302 par.addParam("firstline", firstline);
303 if (!lastline.empty())
304 par.addParam("lastline", lastline);
305 if (!basicstyle.empty())
306 par.addParam("basicstyle", basicstyle);
308 par.addParam("breaklines", "true");
310 par.addParam("showspaces", "true");
312 par.addParam("showstringspaces", "false");
314 par.addParam("extendedchars", "true");
315 par.addParams(extra);
320 void QListingsDialog::validate_listings_params()
322 static bool isOK = true;
324 InsetListingsParams par(construct_params());
327 listingsTB->setPlainText(
328 qt_("Input listings parameters on the right. Enter ? for a list of parameters."));
329 okPB->setEnabled(true);
330 applyPB->setEnabled(true);
332 } catch (invalidParam & e) {
334 listingsTB->setPlainText(toqstr(e.what()));
335 okPB->setEnabled(false);
336 applyPB->setEnabled(false);
341 void QListingsDialog::on_floatCB_stateChanged(int state)
343 if (state == Qt::Checked) {
344 inlineCB->setChecked(false);
345 placementLE->setEnabled(true);
347 placementLE->setEnabled(false);
351 void QListingsDialog::on_inlineCB_stateChanged(int state)
353 if (state == Qt::Checked) {
354 floatCB->setChecked(false);
355 placementLE->setEnabled(false);
360 void QListingsDialog::on_numberSideCO_currentIndexChanged(int index)
362 numberStepLE->setEnabled(index > 0);
363 numberFontSizeCO->setEnabled(index > 0);
367 void QListingsDialog::on_languageCO_currentIndexChanged(int index)
371 int default_dialect = 0;
372 dialectCO->addItem(qt_("No dialect"));
373 string const language = languages[index];
375 for (size_t i = 0; i < nr_dialects; ++i) {
376 if (language == dialects[i].language) {
377 dialectCO->addItem(dialects[i].gui);
378 if (dialects[i].is_default)
380 dialectCO->findText(dialects[i].gui);
383 dialectCO->setCurrentIndex(default_dialect);
384 dialectCO->setEnabled(dialectCO->count() > 1);
388 /////////////////////////////////////////////////////////////////////
392 /////////////////////////////////////////////////////////////////////
394 typedef QController<ControlListings, QView<QListingsDialog> > listings_wrap_base_class;
396 QListings::QListings(Dialog & parent)
397 : listings_wrap_base_class(parent, _("Program Listings Settings"))
402 void QListings::build_dialog()
404 dialog_.reset(new QListingsDialog(this));
406 bcview().setOK(dialog_->okPB);
407 bcview().setApply(dialog_->applyPB);
408 bcview().setCancel(dialog_->closePB);
409 dialog_->listingsTB->setPlainText(
410 qt_("Input listings parameters on the right. Enter ? for a list of parameters."));
416 void QListings::apply()
418 InsetListingsParams & params = controller().params();
419 params.setInline(dialog_->inlineCB->isChecked());
420 params.setParams(dialog_->construct_params());
421 controller().setParams(params);
427 string plainParam(std::string const & par)
429 // remove enclosing braces
430 if (prefixIs(par, "{") && suffixIs(par, "}"))
431 return par.substr(1, par.size() - 2);
438 void QListings::update_contents()
440 // set default values
441 dialog_->listingsTB->setPlainText(
442 qt_("Input listings parameters on the right. Enter ? for a list of parameters."));
443 dialog_->languageCO->setCurrentIndex(findToken(languages, "no language"));
444 dialog_->dialectCO->setCurrentIndex(0);
445 dialog_->floatCB->setChecked(false);
446 dialog_->placementLE->clear();
447 dialog_->numberSideCO->setCurrentIndex(0);
448 dialog_->numberStepLE->clear();
449 dialog_->numberFontSizeCO->setCurrentIndex(findToken(font_sizes, "default"));
450 dialog_->firstlineLE->clear();
451 dialog_->lastlineLE->clear();
452 dialog_->fontstyleCO->setCurrentIndex(findToken(font_styles, "default"));
453 dialog_->fontsizeCO->setCurrentIndex(findToken(font_sizes, "default"));
454 dialog_->breaklinesCB->setChecked(false);
455 dialog_->spaceCB->setChecked(false);
456 dialog_->spaceInStringCB->setChecked(true);
457 dialog_->extendedcharsCB->setChecked(false);
459 // set values from param string
460 InsetListingsParams & params = controller().params();
461 dialog_->inlineCB->setChecked(params.isInline());
462 if (params.isInline()) {
463 dialog_->floatCB->setChecked(false);
464 dialog_->placementLE->setEnabled(false);
466 // break other parameters and set values
467 vector<string> pars = getVectorFromString(params.separatedParams(), "\n");
468 // process each of them
469 for (vector<string>::iterator it = pars.begin();
470 it != pars.end(); ++it) {
471 if (prefixIs(*it, "language=")) {
472 string arg = plainParam(it->substr(9));
477 if (prefixIs(arg, "[") && contains(arg, "]")) {
478 string::size_type end_dialect = arg.find("]");
479 dialect = arg.substr(1, end_dialect - 1);
480 language = arg.substr(end_dialect + 1);
483 int n = findToken(languages, language);
485 dialog_->languageCO->setCurrentIndex(n);
488 // on_languageCO_currentIndexChanged should have set dialects
489 if (!dialect.empty()) {
491 for (size_t i = 0; i < nr_dialects; ++i) {
492 if (dialect == dialects[i].dialect
493 && dialects[i].language == language) {
494 dialect_gui = dialects[i].gui;
498 n = dialog_->dialectCO->findText(toqstr(dialect_gui));
500 dialog_->dialectCO->setCurrentIndex(n);
506 dialog_->languageCO->setEnabled(in_gui);
507 dialog_->dialectCO->setEnabled(
508 in_gui && dialog_->dialectCO->count() > 1);
509 } else if (prefixIs(*it, "float")) {
510 dialog_->floatCB->setChecked(true);
511 dialog_->inlineCB->setChecked(false);
512 dialog_->placementLE->setEnabled(true);
513 if (prefixIs(*it, "float="))
514 dialog_->placementLE->setText(
515 toqstr(plainParam(it->substr(6))));
517 } else if (prefixIs(*it, "numbers=")) {
518 string s = plainParam(it->substr(8));
522 else if (s == "right")
524 dialog_->numberSideCO->setCurrentIndex(n);
526 } else if (prefixIs(*it, "stepnumber=")) {
527 dialog_->numberStepLE->setText(
528 toqstr(plainParam(it->substr(11))));
530 } else if (prefixIs(*it, "numberstyle=")) {
531 string par = plainParam(it->substr(12));
532 int n = findToken(font_sizes, par.substr(1));
534 dialog_->numberFontSizeCO->setCurrentIndex(n);
536 } else if (prefixIs(*it, "firstline=")) {
537 dialog_->firstlineLE->setText(
538 toqstr(plainParam(it->substr(10))));
540 } else if (prefixIs(*it, "lastline=")) {
541 dialog_->lastlineLE->setText(
542 toqstr(plainParam(it->substr(9))));
544 } else if (prefixIs(*it, "basicstyle=")) {
547 for (int n = 0; font_styles[n][0]; ++n) {
548 string const s = font_styles[n];
549 if (contains(*it, "\\" + s)) {
554 for (int n = 0; font_sizes[n][0]; ++n) {
555 string const s = font_sizes[n];
556 if (contains(*it, "\\" + s)) {
561 if (plainParam(it->substr(11)) == style + size
562 || plainParam(it->substr(11)) == size + style) {
563 if (!style.empty()) {
564 int n = findToken(font_styles, style.substr(1));
566 dialog_->fontstyleCO->setCurrentIndex(n);
569 int n = findToken(font_sizes, size.substr(1));
571 dialog_->fontsizeCO->setCurrentIndex(n);
575 } else if (prefixIs(*it, "breaklines=")) {
576 dialog_->breaklinesCB->setChecked(contains(*it, "true"));
578 } else if (prefixIs(*it, "showspaces=")) {
579 dialog_->spaceCB->setChecked(contains(*it, "true"));
581 } else if (prefixIs(*it, "showstringspaces=")) {
582 dialog_->spaceInStringCB->setChecked(contains(*it, "true"));
584 } else if (prefixIs(*it, "extendedchars=")) {
585 dialog_->extendedcharsCB->setChecked(contains(*it, "true"));
590 dialog_->numberStepLE->setEnabled(dialog_->numberSideCO->currentIndex() > 0);
591 dialog_->numberFontSizeCO->setEnabled(dialog_->numberSideCO->currentIndex() > 0);
592 // parameters that can be handled by widgets are cleared
593 // the rest is put to the extra edit box.
594 string extra = getStringFromVector(pars);
595 dialog_->listingsED->setPlainText(toqstr(InsetListingsParams(extra).separatedParams()));
599 } // namespace frontend
603 #include "QListings_moc.cpp"