]> git.lyx.org Git - features.git/blob - src/frontends/qt4/QListings.cpp
make InsetListings ready for dialects, part 1 (joint work with Bo Peng):
[features.git] / src / frontends / qt4 / QListings.cpp
1 /**
2  * \file QListings.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Bo Peng
7  * \author Jürgen Spitzmüller
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #include "QListings.h"
15 #include "Qt2BC.h"
16 #include "qt_helpers.h"
17 #include "controllers/ControlListings.h"
18 #include "insets/InsetListingsParams.h"
19 #include "debug.h"
20
21 #include "support/convert.h"
22 #include "support/lstrings.h"
23
24 #include <QLineEdit>
25 #include <QCloseEvent>
26 #include <QPushButton>
27 #include <QValidator>
28 #include <QRegExpValidator>
29
30
31 using std::string;
32 using std::vector;
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;
39
40 namespace lyx {
41 namespace frontend {
42
43 /////////////////////////////////////////////////////////////////////
44 //
45 // QListingsDialog
46 //
47 /////////////////////////////////////////////////////////////////////
48
49
50 char const * languages[] =
51 { "no language", "ABAP", "ACSL", "Ada", "ALGOL", "C", "C++", "Caml", "Clean", "Cobol",
52   "Comal 80", "csh", "Delphi", "Eiffel", "Elan", "Euphoria", "Fortran", "Haskell",
53   "HTML", "IDL", "Java", "Lisp", "Logo", "make", "Mathematica", "Matlab", "Mercury",
54   "Miranda", "ML", "Modula-2", "Oberon-2", "OCL", "Pascal", "Perl", "PHP", "PL/I", "POV",
55   "Prolog", "Python", "R", "S", "SAS", "SHELXL", "Simula", "tcl", "SQL", "TeX", "VBScript",
56   "VHDL", "XML", "" };
57
58 char const * languages_gui[] =
59 { N_("No language"), "ABAP", "ACSL", "Ada", "ALGOL", "C", "C++", "Caml", "Clean", "Cobol",
60   "Comal 80", "csh", "Delphi", "Eiffel", "Elan", "Euphoria", "Fortran", "Haskell",
61   "HTML", "IDL", "Java", "Lisp", "Logo", "make", "Mathematica", "Matlab", "Mercury",
62   "Miranda", "ML", "Modula-2", "Oberon-2", "OCL", "Pascal", "Perl", "PHP", "PL/I", "POV",
63   "Prolog", "Python", "R", "S", "SAS", "SHELXL", "Simula", "tcl", "SQL", "TeX", "VBScript",
64   "VHDL", "XML", "" };
65
66 char const * font_sizes[] =
67 { "default", "tiny", "scriptsize", "footnotesize", "small", "normalsize", "large",
68   "Large", "" };
69
70 char const * font_sizes_gui[] =
71 { N_("Default"), N_("Tiny"), N_("Smallest"), N_("Smaller"), N_("Small"), N_("Normal"),
72   N_("Large"), N_("Larger"), "" };
73
74 char const * font_styles[] =
75 { "default", "rmfamily", "ttfamily", "sffamily", "" };
76
77 char const * font_styles_gui[] =
78 { N_("Default"), N_("Roman"), N_("Typewriter"), N_("Sans Serif"), "" };
79
80
81
82 QListingsDialog::QListingsDialog(QListings * form)
83         : form_(form)
84 {
85         setupUi(this);
86         
87         connect(okPB, SIGNAL(clicked()), form, SLOT(slotOK()));
88         connect(applyPB, SIGNAL(clicked()), form_, SLOT(slotApply()));
89         connect(closePB, SIGNAL(clicked()), form, SLOT(slotClose()));
90         
91         connect(languageCO, SIGNAL(currentIndexChanged(int)), this, SLOT(change_adaptor()));
92         connect(inlineCB, SIGNAL(clicked()), this, SLOT(change_adaptor()));
93         connect(floatCB, SIGNAL(clicked()), this, SLOT(change_adaptor()));
94         connect(placementLE, SIGNAL(textChanged(const QString&)), this, SLOT(change_adaptor()));
95         connect(numberSideCO, SIGNAL(currentIndexChanged(int)), this, SLOT(change_adaptor()));
96         connect(numberStepLE, SIGNAL(textChanged(const QString&)), this, SLOT(change_adaptor()));
97         connect(numberFontSizeCO, SIGNAL(currentIndexChanged(int)), this, SLOT(change_adaptor()));
98         connect(firstlineLE, SIGNAL(textChanged(const QString&)), this, SLOT(change_adaptor()));
99         connect(lastlineLE, SIGNAL(textChanged(const QString&)), this, SLOT(change_adaptor()));
100         connect(fontsizeCO, SIGNAL(currentIndexChanged(int)), this, SLOT(change_adaptor()));
101         connect(fontstyleCO, SIGNAL(currentIndexChanged(int)), this, SLOT(change_adaptor()));
102         connect(breaklinesCB, SIGNAL(clicked()), this, SLOT(change_adaptor()));
103         connect(spaceCB, SIGNAL(clicked()), this, SLOT(change_adaptor()));
104         connect(extendedcharsCB, SIGNAL(clicked()), this, SLOT(change_adaptor()));
105         
106         connect(listingsED,  SIGNAL(textChanged()), this, SLOT(change_adaptor()));
107         connect(listingsED,  SIGNAL(textChanged()), this, SLOT(validate_listings_params()));
108
109         for (int n = 0; languages[n][0]; ++n)
110                 languageCO->addItem(languages_gui[n]);
111
112         for (int n = 0; font_styles[n][0]; ++n)
113                 fontstyleCO->addItem(font_styles_gui[n]);
114
115         for (int n = 0; font_sizes[n][0]; ++n) {
116                 QString font = toqstr(font_sizes_gui[n]);
117                 fontsizeCO->addItem(font);
118                 numberFontSizeCO->addItem(font);
119         }
120
121         // set validators
122         numberStepLE->setValidator(new QIntValidator(0, 1000000, this));
123         firstlineLE->setValidator(new QIntValidator(0, 1000000, this));
124         lastlineLE->setValidator(new QIntValidator(0, 1000000, this));
125         placementLE->setValidator(new QRegExpValidator(QRegExp("[tbph]*"), this));
126 }
127
128
129 void QListingsDialog::closeEvent(QCloseEvent * e)
130 {
131         form_->slotWMHide();
132         e->accept();
133 }
134
135
136 void QListingsDialog::change_adaptor()
137 {
138         form_->changed();
139 }
140
141
142 string QListingsDialog::construct_params()
143 {
144         string language = languages[languageCO->currentIndex()];
145         
146         bool float_ = floatCB->isChecked();
147         string placement;
148         if (placementLE->isEnabled())
149                 placement = fromqstr(placementLE->text());
150
151         string numberSide;
152         switch (numberSideCO->currentIndex()) {
153         case 0:
154                 numberSide = "none";
155                 break;
156         case 1:
157                 numberSide = "left";
158                 break;
159         case 2:
160                 numberSide = "right";
161                 break;
162         default:
163                 numberSide = "none";
164                 break;
165         }
166         string stepnumber = fromqstr(numberStepLE->text());
167         string numberfontsize = font_sizes[numberFontSizeCO->currentIndex()];
168         string firstline = fromqstr(firstlineLE->text());
169         string lastline = fromqstr(lastlineLE->text());
170         
171         string fontsize = font_sizes[fontsizeCO->currentIndex()];
172         string fontstyle = font_styles[fontstyleCO->currentIndex()];
173         string basicstyle;
174         if (fontsize != "default")
175                 basicstyle = "\\" + fontsize;
176         if (fontstyle != "default")
177                 basicstyle += "\\" + fontstyle;
178         bool breakline = breaklinesCB->isChecked();
179         bool space = spaceCB->isChecked();
180         bool extendedchars = extendedcharsCB->isChecked();
181         string extra = fromqstr(listingsED->toPlainText());
182
183         // compose a string
184         InsetListingsParams par;
185         if (language != "no language" && !contains(extra, "language="))
186                 par.addParam("language", language);
187         if (float_)
188                 par.addParam("float", "");
189         if (!placement.empty())
190                 par.addParam("floatplacement", placement);
191         if (numberSide != "none")
192                 par.addParam("numbers", numberSide);
193         if (numberfontsize != "default" && numberSide != "none")
194                 par.addParam("numberstyle", "\\" + numberfontsize);
195         if (!stepnumber.empty() && numberSide != "none")
196                 par.addParam("stepnumber", stepnumber);
197         if (!firstline.empty())
198                 par.addParam("firstline", firstline);
199         if (!lastline.empty())
200                 par.addParam("lastline", lastline);
201         if (!basicstyle.empty())
202                 par.addParam("basicstyle", basicstyle);
203         if (breakline)
204                 par.addParam("breaklines", "true");
205         if (space)
206                 par.addParam("showspaces", "true");
207         if (extendedchars)
208                 par.addParam("extendedchars", "true");
209         par.addParams(extra);
210         return par.params();
211 }
212
213
214 void QListingsDialog::validate_listings_params()
215 {
216         static bool isOK = true;
217         try {
218                 InsetListingsParams par(construct_params());
219                 if (!isOK) {
220                         isOK = true;
221                         listingsTB->setPlainText(
222                                 qt_("Input listings parameters on the right. Enter ? for a list of parameters."));
223                         okPB->setEnabled(true);
224                         applyPB->setEnabled(true);
225                 }
226         } catch (invalidParam & e) {
227                 isOK = false;
228                 listingsTB->setPlainText(e.what());
229                 okPB->setEnabled(false);
230                 applyPB->setEnabled(false);
231         }
232 }
233
234
235 void QListingsDialog::on_floatCB_stateChanged(int state)
236 {
237         if (state == Qt::Checked) {
238                 inlineCB->setChecked(false);
239                 placementLE->setEnabled(true);
240         } else
241                 placementLE->setEnabled(false);
242 }
243
244
245 void QListingsDialog::on_inlineCB_stateChanged(int state)
246 {
247         if (state == Qt::Checked) {
248                 floatCB->setChecked(false);
249                 placementLE->setEnabled(false);
250         }
251 }
252
253
254 void QListingsDialog::on_numberSideCO_currentIndexChanged(int index)
255 {
256         numberStepLE->setEnabled(index > 0);
257         numberFontSizeCO->setEnabled(index > 0);
258 }
259
260
261 /////////////////////////////////////////////////////////////////////
262 //
263 // QListings
264 //
265 /////////////////////////////////////////////////////////////////////
266
267 typedef QController<ControlListings, QView<QListingsDialog> > listings_wrap_base_class;
268
269 QListings::QListings(Dialog & parent)
270         : listings_wrap_base_class(parent, _("Program Listings Settings"))
271 {
272 }
273
274
275 void QListings::build_dialog()
276 {
277         dialog_.reset(new QListingsDialog(this));
278         
279         bcview().setOK(dialog_->okPB);
280         bcview().setApply(dialog_->applyPB);
281         bcview().setCancel(dialog_->closePB);
282         dialog_->listingsTB->setPlainText(
283                 qt_("Input listings parameters on the right. Enter ? for a list of parameters."));
284
285         update_contents();
286 }
287
288
289 void QListings::apply()
290 {
291         InsetListingsParams & params = controller().params();
292         params.setInline(dialog_->inlineCB->isChecked());
293         params.setParams(dialog_->construct_params());
294         controller().setParams(params);
295 }
296
297
298 namespace {
299
300 string plainParam(std::string const & par)
301 {
302         // remove enclosing braces
303         if (prefixIs(par, "{") && suffixIs(par, "}"))
304                 return par.substr(1, par.size() - 2);
305         return par;
306 }
307
308 } //namespace anon
309
310
311 void QListings::update_contents()
312 {
313         // set default values 
314         dialog_->listingsTB->setPlainText(
315                 qt_("Input listings parameters on the right. Enter ? for a list of parameters."));
316         dialog_->languageCO->setCurrentIndex(findToken(languages, "no language"));
317         dialog_->floatCB->setChecked(false);
318         dialog_->placementLE->clear();
319         dialog_->numberSideCO->setCurrentIndex(0);
320         dialog_->numberStepLE->clear();
321         dialog_->numberFontSizeCO->setCurrentIndex(findToken(font_sizes, "default"));
322         dialog_->firstlineLE->clear();
323         dialog_->lastlineLE->clear();
324         dialog_->fontstyleCO->setCurrentIndex(findToken(font_styles, "default"));
325         dialog_->fontsizeCO->setCurrentIndex(findToken(font_sizes, "default"));
326         dialog_->breaklinesCB->setChecked(false);
327         dialog_->spaceCB->setChecked(false);
328         dialog_->extendedcharsCB->setChecked(false);
329
330         // set values from param string
331         InsetListingsParams & params = controller().params();
332         dialog_->inlineCB->setChecked(params.isInline());
333         if (params.isInline()) {
334                 dialog_->floatCB->setChecked(false);
335                 dialog_->placementLE->setEnabled(false);
336         }
337         // break other parameters and set values
338         vector<string> pars = getVectorFromString(params.separatedParams(), "\n");
339         // process each of them
340         for (vector<string>::iterator it = pars.begin();
341             it != pars.end(); ++it) {
342                 if (prefixIs(*it, "language=")) {
343                         int n = findToken(languages, plainParam(it->substr(9)));
344                         if (n >= 0) {
345                                 dialog_->languageCO->setEnabled(true);
346                                 dialog_->languageCO->setCurrentIndex(n);
347                                 *it = "";
348                         }
349                         else
350                                 // a known language that is not in the gui
351                                 dialog_->languageCO->setEnabled(false);
352                 } else if (prefixIs(*it, "floatplacement=")) {
353                         dialog_->floatCB->setChecked(true);
354                         dialog_->placementLE->setEnabled(true);
355                         dialog_->placementLE->setText(
356                                 toqstr(plainParam(it->substr(15))));
357                         dialog_->inlineCB->setChecked(false);
358                         *it = "";
359                 } else if (prefixIs(*it, "float")) {
360                         dialog_->floatCB->setChecked(true);
361                         dialog_->inlineCB->setChecked(false);
362                         dialog_->placementLE->setEnabled(true);
363                         if (prefixIs(*it, "float="))
364                                 dialog_->placementLE->setText(
365                                         toqstr(plainParam(it->substr(6))));
366                         *it = "";
367                 } else if (prefixIs(*it, "numbers=")) {
368                         string s = plainParam(it->substr(8));
369                         int n = 0;
370                         if (s == "left")
371                                 n = 1;
372                         else if (s == "right")
373                                 n = 2;
374                         dialog_->numberSideCO->setCurrentIndex(n);
375                         *it = "";
376                 } else if (prefixIs(*it, "stepnumber=")) {
377                         dialog_->numberStepLE->setText(
378                                 toqstr(plainParam(it->substr(11))));
379                         *it = "";
380                 } else if (prefixIs(*it, "numberstyle=")) {
381                         string par = plainParam(it->substr(12));
382                         int n = findToken(font_sizes, par.substr(1));
383                         if (n >= 0)
384                                 dialog_->numberFontSizeCO->setCurrentIndex(n);
385                         *it = "";
386                 } else if (prefixIs(*it, "firstline=")) {
387                         dialog_->firstlineLE->setText(
388                                 toqstr(plainParam(it->substr(10))));
389                         *it = "";
390                 } else if (prefixIs(*it, "lastline=")) {
391                         dialog_->lastlineLE->setText(
392                                 toqstr(plainParam(it->substr(9))));
393                         *it = "";
394                 } else if (prefixIs(*it, "basicstyle=")) {
395                         string style;
396                         string size;
397                         for (int n = 0; font_styles[n][0]; ++n) {
398                                 string const s = font_styles[n];
399                                 if (contains(*it, "\\" + s)) {
400                                         style = "\\" + s;
401                                         break;
402                                 }
403                         }
404                         for (int n = 0; font_sizes[n][0]; ++n) {
405                                 string const s = font_sizes[n];
406                                 if (contains(*it, "\\" + s)) {
407                                         size = "\\" + s;
408                                         break;
409                                 }
410                         }
411                         if (plainParam(it->substr(11)) == style + size 
412                             || plainParam(it->substr(11)) == size + style) {
413                                 if (!style.empty()) {
414                                         int n = findToken(font_styles, style.substr(1));
415                                         if (n >= 0)
416                                                 dialog_->fontstyleCO->setCurrentIndex(n);
417                                 }
418                                 if (!size.empty()) {
419                                         int n = findToken(font_sizes, size.substr(1));
420                                         if (n >= 0)
421                                                 dialog_->fontsizeCO->setCurrentIndex(n);
422                                 }
423                                 *it = "";
424                         }
425                 } else if (prefixIs(*it, "breaklines=")) {
426                         dialog_->breaklinesCB->setChecked(contains(*it, "true"));
427                         *it = "";
428                 } else if (prefixIs(*it, "showspaces=")) {
429                         dialog_->spaceCB->setChecked(contains(*it, "true"));
430                         *it = "";
431                 } else if (prefixIs(*it, "extendedchars=")) {
432                         dialog_->extendedcharsCB->setChecked(contains(*it, "true"));
433                         *it = "";
434                 }
435         }
436
437         dialog_->numberStepLE->setEnabled(dialog_->numberSideCO->currentIndex() > 0);
438         dialog_->numberFontSizeCO->setEnabled(dialog_->numberSideCO->currentIndex() > 0);
439         // parameters that can be handled by widgets are cleared
440         // the rest is put to the extra edit box.
441         string extra = getStringFromVector(pars);
442         dialog_->listingsED->setPlainText(toqstr(InsetListingsParams(extra).separatedParams()));
443 }
444
445
446 } // namespace frontend
447 } // namespace lyx
448
449
450 #include "QListings_moc.cpp"