]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/QListings.cpp
InsetListings: Enhanced listings dialog, more than 10 widgets are added to handle...
[lyx.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  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "QListings.h"
14 #include "Qt2BC.h"
15 #include "qt_helpers.h"
16 #include "controllers/ControlListings.h"
17 #include "insets/InsetListingsParams.h"
18 #include "debug.h"
19
20 #include "support/convert.h"
21 #include "support/lstrings.h"
22
23 #include <QLineEdit>
24 #include <QCloseEvent>
25 #include <QPushButton>
26 #include <QValidator>
27 #include <QRegExpValidator>
28
29
30 using std::string;
31 using std::vector;
32 using lyx::support::getVectorFromString;
33 using lyx::support::getStringFromVector;
34 using lyx::support::prefixIs;
35 using lyx::support::contains;
36
37 namespace lyx {
38 namespace frontend {
39
40 /////////////////////////////////////////////////////////////////////
41 //
42 // QListingsDialog
43 //
44 /////////////////////////////////////////////////////////////////////
45
46
47 string const allowed_languages = 
48         "no language\nBAP\nACSL\nAda\nALGOL\nC\nC++\nCaml\nClean\nCobol\n"
49         "Comal 80\ncsh\nDelphi\nEiffel\nElan\nEuphoria\nFortran\nHaskell\n"
50         "HTML\nIDL\nJava\nLisp\nLogo\nmake\nMathematica\nMatlab\nMercury\n"
51         "Miranda\nML\nModula-2\nOberon-2\nOCL\nPascal\nPerl\nPHP\nPL/I\nPOV\n"
52         "Python\nProlog\nR\nS\nSAS\nSHELXL\nSimula\ntcl\nSQL\nTeX\nVBScript\n"
53         "VHDL\nXML";
54 string const allowed_fontsizes = "default\ntiny\nscriptsize\nfootnotesize\nsmall\n"
55         "normalsize\nlarge\nLarge";
56 string const allowed_fontstyles = "default\nrmfamily\nttfamily\nsffamily";
57
58 QListingsDialog::QListingsDialog(QListings * form)
59         : form_(form)
60 {
61         setupUi(this);
62         
63         connect(okPB, SIGNAL(clicked()), form, SLOT(slotOK()));
64         connect(closePB, SIGNAL(clicked()), form, SLOT(slotClose()));
65         
66         connect(languageCO, SIGNAL(currentIndexChanged(int)), this, SLOT(change_adaptor()));
67         connect(inlineCB, SIGNAL(clicked()), this, SLOT(change_adaptor()));
68         connect(floatCB, SIGNAL(clicked()), this, SLOT(change_adaptor()));
69         connect(placementLE, SIGNAL(textChanged(const QString&)), this, SLOT(change_adaptor()));
70         connect(numberLeftCB, SIGNAL(clicked()), this, SLOT(change_adaptor()));
71         connect(numberRightCB, SIGNAL(clicked()), this, SLOT(change_adaptor()));
72         connect(numberStepLE, SIGNAL(textChanged(const QString&)), this, SLOT(change_adaptor()));
73         connect(numberFontSizeCO, SIGNAL(currentIndexChanged(int)), this, SLOT(change_adaptor()));
74         connect(firstlineLE, SIGNAL(textChanged(const QString&)), this, SLOT(change_adaptor()));
75         connect(lastlineLE, SIGNAL(textChanged(const QString&)), this, SLOT(change_adaptor()));
76         connect(fontsizeCO, SIGNAL(currentIndexChanged(int)), this, SLOT(change_adaptor()));
77         connect(fontstyleCO, SIGNAL(currentIndexChanged(int)), this, SLOT(change_adaptor()));
78         connect(breaklinesCB, SIGNAL(clicked()), this, SLOT(change_adaptor()));
79         connect(spaceCB, SIGNAL(clicked()), this, SLOT(change_adaptor()));
80         connect(extendedcharsCB, SIGNAL(clicked()), this, SLOT(change_adaptor()));
81         connect(captionLE, SIGNAL(textChanged(const QString&)), this, SLOT(change_adaptor()));
82         connect(labelLE, SIGNAL(textChanged(const QString&)), this, SLOT(change_adaptor()));
83         
84         connect(listingsED,  SIGNAL(textChanged()), this, SLOT(change_adaptor()));
85         connect(listingsED,  SIGNAL(textChanged()), this, SLOT(validate_listings_params()));
86 }
87
88
89 void QListingsDialog::closeEvent(QCloseEvent * e)
90 {
91         form_->slotWMHide();
92         e->accept();
93 }
94
95
96 void QListingsDialog::change_adaptor()
97 {
98         form_->changed();
99 }
100
101
102 string QListingsDialog::construct_params()
103 {
104         string language = fromqstr(languageCO->currentText());
105         
106         bool float_ = floatCB->checkState() == Qt::Checked;
107         string placement = fromqstr(placementLE->text());
108         
109         bool left = numberLeftCB->checkState() == Qt::Checked;
110         bool right = numberRightCB->checkState() == Qt::Checked;
111         string step = fromqstr(numberStepLE->text());
112         string numberfontsize = fromqstr(numberFontSizeCO->currentText());
113         string firstline = fromqstr(firstlineLE->text());
114         string lastline = fromqstr(lastlineLE->text());
115         
116         string fontsize = fromqstr(fontsizeCO->currentText());
117         string fontstyle = fromqstr(fontstyleCO->currentText());
118         string basicstyle;
119         if (fontsize != "default")
120                 basicstyle = "\\" + fontsize;
121         if (fontstyle != "default")
122                 basicstyle += "\\" + fontstyle;
123         bool breakline = breaklinesCB->checkState() == Qt::Checked;
124         bool space = spaceCB->checkState() == Qt::Checked;
125         bool extendedchar = extendedcharsCB->checkState() == Qt::Checked;
126         
127         string caption = fromqstr(captionLE->text());
128         string label = fromqstr(labelLE->text());
129         
130         string extra = fromqstr(listingsED->toPlainText());
131
132         // compose a string
133         InsetListingsParams par;
134         if (language != "no language")
135                 par.addParam("language", language);
136         if (float_)
137                 par.addParam("float", "");
138         if (!placement.empty())
139                 par.addParam("floatplacement", placement);
140         if (left)
141                 par.addParam("numbers", "left");
142         else if (right)
143                 par.addParam("numbers", "right");
144         if (numberfontsize != "default")
145                 par.addParam("numberstyle", "\\" + numberfontsize);
146         if (!firstline.empty())
147                 par.addParam("firstline", firstline);
148         if (!lastline.empty())
149                 par.addParam("lastline", lastline);
150         if (basicstyle != "")
151                 par.addParam("basicstyle", basicstyle);
152         if (breakline)
153                 par.addParam("breaklines", "true");
154         if (space)
155                 par.addParam("showspaces", "true");
156         if (extendedchar)
157                 par.addParam("extendedchars", "true");
158         if (!caption.empty())
159                 par.addParam("caption", "{" + caption + "}");
160         if (!label.empty())
161                 par.addParam("label", "{" + label + "}");
162         par.addParams(extra);
163         return par.params();
164 }
165
166
167 void QListingsDialog::validate_listings_params()
168 {
169         static bool isOK = true;
170         try {
171                 InsetListingsParams par(construct_params());
172                 if (!isOK) {
173                         isOK = true;
174                         // listingsTB->setTextColor("black");
175                         listingsTB->setPlainText("Input listings parameters below. Enter ? for a list of parameters.");
176                         okPB->setEnabled(true);
177                 }
178         } catch (invalidParam & e) {
179                 isOK = false;
180                 // listingsTB->setTextColor("red");
181                 listingsTB->setPlainText(e.what());
182                 okPB->setEnabled(false);
183         }
184 }
185
186 /////////////////////////////////////////////////////////////////////
187 //
188 // QListings
189 //
190 /////////////////////////////////////////////////////////////////////
191
192 typedef QController<ControlListings, QView<QListingsDialog> > listings_wrap_base_class;
193
194 QListings::QListings(Dialog & parent)
195         : listings_wrap_base_class(parent, _("Program Listings Settings"))
196 {
197 }
198
199
200 void QListings::build_dialog()
201 {
202         dialog_.reset(new QListingsDialog(this));
203         
204         bcview().setOK(dialog_->okPB);
205         bcview().setCancel(dialog_->closePB);
206         dialog_->listingsTB->setPlainText("Input listings parameters below. Enter ? for a list of parameters.");
207
208         update_contents();
209 }
210
211
212 /// not used right now.
213 void QListings::apply()
214 {
215         InsetListingsParams & params = controller().params();
216         params.setInline(dialog_->inlineCB->isChecked());
217         params.setParams(dialog_->construct_params());
218         controller().setParams(params);
219 }
220
221
222 void QListings::update_contents()
223 {
224         // first prepare all choices
225         vector<string> const languages = 
226                 getVectorFromString(allowed_languages, "\n");
227         vector<string> const fontstyles = 
228                 getVectorFromString(allowed_fontstyles, "\n");
229         vector<string> const fontsizes = 
230                 getVectorFromString(allowed_fontsizes, "\n");
231
232         dialog_->languageCO->clear();
233         for (vector<string>::const_iterator it = languages.begin();
234             it != languages.end(); ++it) {
235                 dialog_->languageCO->addItem(toqstr(*it));
236         }
237         dialog_->fontstyleCO->clear();
238         dialog_->fontstyleCO->setEditable(false);
239         for (vector<string>::const_iterator it = fontstyles.begin();
240             it != fontstyles.end(); ++it) {
241                 dialog_->fontstyleCO->addItem(toqstr(*it));
242         }
243         dialog_->fontsizeCO->clear();
244         dialog_->fontsizeCO->setEditable(false);
245         dialog_->numberFontSizeCO->clear();
246         dialog_->numberFontSizeCO->setEditable(false);
247         for (vector<string>::const_iterator it = fontsizes.begin();
248             it != fontsizes.end(); ++it) {
249                 dialog_->fontsizeCO->addItem(toqstr(*it));
250                 dialog_->numberFontSizeCO->addItem(toqstr(*it));
251         }
252
253         // set validators
254         dialog_->numberStepLE->setValidator(new QIntValidator(0, 1000000, this));
255         dialog_->firstlineLE->setValidator(new QIntValidator(0, 1000000, this));
256         dialog_->lastlineLE->setValidator(new QIntValidator(0, 1000000, this));
257         dialog_->placementLE->setValidator(new QRegExpValidator(QRegExp("[tbph]*"), this));
258
259         //
260         dialog_->listingsTB->setPlainText("Input listings parameters below. Enter ? for a list of parameters.");
261
262         // set values from param string
263         InsetListingsParams & params = controller().params();
264         if (params.isInline())
265                 dialog_->inlineCB->setChecked(true);
266         else
267                 dialog_->inlineCB->setChecked(false);
268         // break other parameters and set values
269         vector<string> pars = getVectorFromString(params.separatedParams(), "\n");
270         // process each of them
271         for (vector<string>::iterator it = pars.begin();
272             it != pars.end(); ++it) {
273                 if (prefixIs(*it, "language=")) {
274                         for (vector<string>::const_iterator st = languages.begin();
275                             st != languages.end(); ++st) {
276                                 if (*it == "language=" + *st) {
277                                         dialog_->languageCO->setCurrentIndex(
278                                                 dialog_->languageCO->findText(toqstr(*st)));
279                                         *it = "";
280                                 }                       
281                         }
282                 } else if (prefixIs(*it, "float")) {
283                         if (prefixIs(*it, "float="))
284                                 dialog_->placementLE->setText(toqstr(it->substr(6)));
285                         else
286                                 dialog_->floatCB->setChecked(true);
287                         *it = "";
288                 } else if (prefixIs(*it, "floatplacement=")) {
289                         dialog_->placementLE->setText(toqstr(it->substr(15)));
290                         *it = "";
291                 } else if (prefixIs(*it, "numbers=")) {
292                         if (contains(*it, "left") != string::npos)
293                                 dialog_->numberLeftCB->setChecked(true);
294                         else if (contains(*it, "right") != string::npos)
295                                 dialog_->numberRightCB->setChecked(true);
296                         *it = "";
297                 } else if (prefixIs(*it, "stepnumber=")) {
298                         dialog_->numberStepLE->setText(toqstr(it->substr(11)));
299                         *it = "";
300                 } else if (prefixIs(*it, "numberstyle=")) {
301                         for (vector<string>::const_iterator st = fontsizes.begin();
302                             st != fontsizes.end(); ++st) {
303                                 if (*it == "numberstyle=\\" + *st) {
304                                         dialog_->numberFontSizeCO->setCurrentIndex(
305                                                 dialog_->numberFontSizeCO->findText(toqstr(*st)));
306                                         *it = "";
307                                 }                       
308                         }
309                 } else if (prefixIs(*it, "firstline=")) {
310                         dialog_->firstlineLE->setText(toqstr(it->substr(10)));
311                         *it = "";
312                 } else if (prefixIs(*it, "lastline=")) {
313                         dialog_->lastlineLE->setText(toqstr(it->substr(9)));
314                         *it = "";
315                 } else if (prefixIs(*it, "basicstyle=")) {
316                         string style;
317                         string size;
318                         for (vector<string>::const_iterator st = fontstyles.begin();
319                             st != fontstyles.end(); ++st)
320                                 if (contains(*it, "\\" + *st)) {
321                                         style = "\\" + *st;
322                                         break;
323                                 }
324                         for (vector<string>::const_iterator st = fontsizes.begin();
325                             st != fontsizes.end(); ++st)
326                                 if (contains(*it, "\\" + *st)) {
327                                         size = "\\" + *st;
328                                         break;
329                                 }
330                         if (it->substr(11) == style + size || it->substr(11) == size + style) {
331                                 if (!style.empty())
332                                         dialog_->fontstyleCO->setCurrentIndex(
333                                                 dialog_->fontstyleCO->findText(toqstr(style.substr(1))));
334                                 if (!size.empty())
335                                         dialog_->fontsizeCO->setCurrentIndex(
336                                                 dialog_->fontsizeCO->findText(toqstr(size.substr(1))));
337                                 *it = "";
338                         }
339                 } else if (prefixIs(*it, "breaklines=")) {
340                         dialog_->breaklinesCB->setChecked(prefixIs(*it, "true") != string::npos);
341                         *it = "";
342                 } else if (prefixIs(*it, "showspaces=")) {
343                         dialog_->spaceCB->setChecked(prefixIs(*it, "true") != string::npos);
344                         *it = "";
345                 } else if (prefixIs(*it, "extendedchars=")) {
346                         dialog_->extendedcharsCB->setChecked(prefixIs(*it, "true") != string::npos);
347                         *it = "";
348                 } else if (prefixIs(*it, "caption=")) {
349                         string cap = it->substr(8);
350                         if ((cap[0] == '{' && cap[cap.size()-1] == '}') ||
351                                 (cap[0] == '"' && cap[cap.size()-1] == '"') )
352                                 dialog_->captionLE->setText(toqstr(cap.substr(1, cap.size()-2)));
353                         else
354                                 dialog_->captionLE->setText(toqstr(cap));               
355                         *it = "";
356                 } else if (prefixIs(*it, "label=")) {
357                         string lbl = it->substr(6);
358                         if ((lbl[0] == '{' && lbl[lbl.size()-1] == '}') ||
359                                 (lbl[0] == '"' && lbl[lbl.size()-1] == '"') )
360                                 dialog_->labelLE->setText(toqstr(lbl.substr(1, lbl.size()-2)));
361                         else
362                                 dialog_->labelLE->setText(toqstr(lbl));                 
363                         *it = "";
364                 }
365         }
366         // parameters that can be handled by widgets are cleared
367         // the rest is put to the extra edit box.
368         string extra = getStringFromVector(pars);
369         dialog_->listingsED->setPlainText(toqstr(InsetListingsParams(extra).separatedParams()));
370 }
371
372
373 } // namespace frontend
374 } // namespace lyx
375
376
377 #include "QListings_moc.cpp"