]> git.lyx.org Git - features.git/blob - src/frontends/qt/GuiInclude.cpp
Fix bug 4475.
[features.git] / src / frontends / qt / GuiInclude.cpp
1 /**
2  * \file GuiInclude.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Alejandro Aguilar Sierra
7  * \author John Levon
8  * \author Angus Leeming
9  *
10  * Full author contact details are available in file CREDITS.
11  */
12
13 #include <config.h>
14
15 #include "GuiInclude.h"
16
17 #include "Buffer.h"
18 #include "BufferParams.h"
19 #include "FuncRequest.h"
20 #include "LyXRC.h"
21
22 #include "qt_helpers.h"
23 #include "LyXRC.h"
24
25 #include "support/gettext.h"
26 #include "support/lstrings.h"
27 #include "support/os.h"
28 #include "support/FileName.h"
29 #include "support/filetools.h"
30
31 #include "insets/InsetListingsParams.h"
32 #include "insets/InsetInclude.h"
33
34 #include <QCheckBox>
35 #include <QFile>
36 #include <QLineEdit>
37 #include <QPushButton>
38
39 #include <utility>
40
41 using namespace std;
42 using namespace lyx::support;
43 using namespace lyx::support::os;
44
45 namespace lyx {
46 namespace frontend {
47
48
49 GuiInclude::GuiInclude(GuiView & lv)
50         : GuiDialog(lv, "include", qt_("Child Document")),
51           params_(insetCode("include"))
52 {
53         setupUi(this);
54
55         connect(buttonBox, SIGNAL(clicked(QAbstractButton *)),
56                 this, SLOT(slotButtonBox(QAbstractButton *)));
57
58         connect(visiblespaceCB, SIGNAL(clicked()), this, SLOT(change_adaptor()));
59         connect(filenameED, SIGNAL(textChanged(const QString &)),
60                 this, SLOT(change_adaptor()));
61         connect(editPB, SIGNAL(clicked()), this, SLOT(edit()));
62         connect(browsePB, SIGNAL(clicked()), this, SLOT(browse()));
63         connect(typeCO, SIGNAL(activated(int)), this, SLOT(change_adaptor()));
64         connect(typeCO, SIGNAL(activated(int)), this, SLOT(typeChanged(int)));
65         connect(previewCB, SIGNAL(clicked()), this, SLOT(change_adaptor()));
66         connect(captionLE, SIGNAL(textChanged(const QString&)), this, SLOT(change_adaptor()));
67         connect(labelLE, SIGNAL(textChanged(const QString&)), this, SLOT(change_adaptor()));
68         connect(literalCB, SIGNAL(clicked()), this, SLOT(change_adaptor()));
69         connect(listingsED, SIGNAL(textChanged()), this, SLOT(change_adaptor()));
70         connect(listingsED, SIGNAL(textChanged()), this, SLOT(setListingsMsg()));
71         connect(bypassCB, SIGNAL(clicked()), this, SLOT(change_adaptor()));
72         connect(bypassCB, SIGNAL(clicked()), this, SLOT(setListingsMsg()));
73
74         setFocusProxy(filenameED);
75
76         bc().setPolicy(ButtonPolicy::OkApplyCancelReadOnlyPolicy);
77         bc().setOK(buttonBox->button(QDialogButtonBox::Ok));
78         bc().setCancel(buttonBox->button(QDialogButtonBox::Cancel));
79         bc().addReadOnly(filenameED);
80         bc().addReadOnly(browsePB);
81         bc().addReadOnly(visiblespaceCB);
82         bc().addReadOnly(typeCO);
83         bc().addReadOnly(listingsED);
84
85         bc().addCheckedLineEdit(filenameED, filenameLA);
86 }
87
88
89 void GuiInclude::change_adaptor()
90 {
91         changed();
92 }
93
94
95 docstring GuiInclude::validate_listings_params()
96 {
97         if (typeCO->currentIndex() != 3 || bypassCB->isChecked())
98                 return docstring();
99         string params = fromqstr(listingsED->toPlainText());
100         InsetListingsParams lstparams(params);
101         lstparams.setMinted(buffer().params().use_minted);
102         return lstparams.validate();
103 }
104
105
106 void GuiInclude::setListingsMsg()
107 {
108         // FIXME THREAD
109         static bool isOK = true;
110         docstring msg = validate_listings_params();
111         if (msg.empty()) {
112                 if (isOK)
113                         return;
114                 isOK = true;
115                 listingsTB->setPlainText(
116                         qt_("Input listing parameters on the right. Enter ? for a list of parameters."));
117         } else {
118                 isOK = false;
119                 listingsTB->setPlainText(toqstr(msg));
120         }
121 }
122
123
124 void GuiInclude::typeChanged(int v)
125 {
126         switch (v) {
127                 //case Include
128                 case 0:
129                         visiblespaceCB->setEnabled(false);
130                         visiblespaceCB->setChecked(false);
131                         previewCB->setEnabled(false);
132                         previewCB->setChecked(false);
133                         listingsGB->setEnabled(false);
134                         break;
135                 //case Input
136                 case 1:
137                         visiblespaceCB->setEnabled(false);
138                         visiblespaceCB->setChecked(false);
139                         previewCB->setEnabled(true);
140                         listingsGB->setEnabled(false);
141                         break;
142                 //case listings
143                 case 3:
144                         visiblespaceCB->setEnabled(false);
145                         visiblespaceCB->setChecked(false);
146                         previewCB->setEnabled(false);
147                         previewCB->setChecked(false);
148                         listingsGB->setEnabled(true);
149                         break;
150                 //case Verbatim
151                 default:
152                         visiblespaceCB->setEnabled(true);
153                         previewCB->setEnabled(false);
154                         previewCB->setChecked(false);
155                         listingsGB->setEnabled(false);
156                         break;
157         }
158 }
159
160
161 void GuiInclude::paramsToDialog(InsetCommandParams const & icp)
162 {
163         filenameED->setText(toqstr(icp["filename"]));
164
165         visiblespaceCB->setChecked(false);
166         visiblespaceCB->setEnabled(false);
167         previewCB->setChecked(false);
168         previewCB->setEnabled(false);
169         listingsGB->setEnabled(false);
170         captionLE->clear();
171         labelLE->clear();
172         listingsED->clear();
173         listingsTB->setPlainText(
174                 qt_("Input listing parameters on the right. Enter ? for a list of parameters."));
175
176         string cmdname = icp.getCmdName();
177         if (cmdname != "include" &&
178             cmdname != "verbatiminput" &&
179             cmdname != "verbatiminput*" &&
180             cmdname != "lstinputlisting" &&
181             cmdname != "inputminted")
182                 cmdname = "input";
183
184         if (cmdname == "include") {
185                 typeCO->setCurrentIndex(0);
186
187         } else if (cmdname == "input") {
188                 typeCO->setCurrentIndex(1);
189                 previewCB->setEnabled(true);
190                 previewCB->setChecked(icp.preview());
191
192         } else if (cmdname == "verbatiminput*") {
193                 typeCO->setCurrentIndex(2);
194                 visiblespaceCB->setEnabled(true);
195                 visiblespaceCB->setChecked(true);
196
197         } else if (cmdname == "verbatiminput") {
198                 typeCO->setCurrentIndex(2);
199                 visiblespaceCB->setEnabled(true);
200
201         } else if (cmdname == "lstinputlisting" || cmdname == "inputminted") {
202                 typeCO->setCurrentIndex(3);
203                 listingsGB->setEnabled(true);
204                 listingsED->setEnabled(true);
205                 InsetListingsParams par(to_utf8(icp["lstparams"]));
206                 // extract caption and label and put them into their respective editboxes
207                 vector<string> pars = getVectorFromString(par.separatedParams(), "\n");
208                 for (vector<string>::iterator it = pars.begin();
209                         it != pars.end(); ++it) {
210                         if (prefixIs(*it, "caption=")) {
211                                 string cap = it->substr(8);
212                                 if (cap[0] == '{' && cap[cap.size() - 1] == '}') {
213                                         captionLE->setText(toqstr(cap.substr(1, cap.size() - 2)));
214                                         *it = "";
215                                 }
216                         } else if (prefixIs(*it, "label=")) {
217                                 string lbl = it->substr(6);
218                                 if (lbl[0] == '{' && lbl[lbl.size()-1] == '}') {
219                                         labelLE->setText(toqstr(lbl.substr(1, lbl.size() - 2)));
220                                         *it = "";
221                                 }
222                         }
223                 }
224                 // the rest is put to the extra edit box.
225                 string extra = getStringFromVector(pars);
226                 listingsED->setPlainText(toqstr(InsetListingsParams(extra).separatedParams()));
227         }
228         literalCB->setChecked(icp["literal"] == "true");
229
230         // Make sure that the bc is in the INITIAL state
231         if (bc().policy().buttonStatus(ButtonPolicy::OKAY))
232                 bc().restore();
233 }
234
235
236 void GuiInclude::applyView()
237 {
238         params_["filename"] = from_utf8(internal_path(fromqstr(filenameED->text())));
239         params_.preview(previewCB->isChecked());
240
241         int const item = typeCO->currentIndex();
242         if (item == 0) {
243                 params_.setCmdName("include");
244         } else if (item == 1) {
245                 params_.setCmdName("input");
246         } else if (item == 3) {
247                 if (buffer().params().use_minted)
248                         params_.setCmdName("inputminted");
249                 else
250                         params_.setCmdName("lstinputlisting");
251                 // the parameter string should have passed validation
252                 InsetListingsParams par(fromqstr(listingsED->toPlainText()));
253                 string caption = fromqstr(captionLE->text());
254                 string label = fromqstr(labelLE->text());
255                 if (!caption.empty())
256                         par.addParam("caption", "{" + caption + "}");
257                 if (!label.empty())
258                         par.addParam("label", "{" + label + "}");
259                 string const listparams = par.params();
260                 params_["lstparams"] = from_utf8(listparams);
261         } else {
262                 if (visiblespaceCB->isChecked())
263                         params_.setCmdName("verbatiminput*");
264                 else
265                         params_.setCmdName("verbatiminput");
266         }
267         params_["literal"] = literalCB->isChecked()
268                         ? from_ascii("true") : from_ascii("false");
269
270         // Do we need to create a LyX file?
271         if (item == 0 || item == 1) {
272                 QString fname = filenameED->text();
273                 string const mypath = buffer().absFileName();
274                 string const bpath = buffer().filePath();
275                 QString absfname = makeAbsPath(fname, toqstr(bpath));
276                 if (!QFile::exists(absfname)) {
277                         dispatch(FuncRequest(LFUN_BUFFER_NEW, fromqstr(absfname)));
278                         dispatch(FuncRequest(LFUN_BUFFER_WRITE));
279                         dispatch(FuncRequest(LFUN_BUFFER_SWITCH, mypath));
280                 }
281         }
282 }
283
284
285 void GuiInclude::edit()
286 {
287         if (!isValid())
288                 return;
289         if (bc().policy().buttonStatus(ButtonPolicy::OKAY)) {
290                 slotOK();
291                 applyView();
292         } else
293                 hideView();
294         dispatch(FuncRequest(LFUN_INSET_EDIT));
295 }
296
297
298 bool GuiInclude::isValid()
299 {
300         QString fname = filenameED->text();
301         bool fempty = fname.isEmpty();
302         if (fempty || !validate_listings_params().empty()) {
303                 editPB->setEnabled(false);
304                 return false;
305         }
306
307         QPushButton * okbutton = buttonBox->button(QDialogButtonBox::Ok);
308         int const item = typeCO->currentIndex();
309         // Are we inputting or including a LyX file?
310         if (item != 0 && item != 1) {
311                 okbutton->setText("OK");
312                 return true;
313         }
314         // Do we have a LyX filename?
315         if (!support::isLyXFileName(fromqstr(fname))) {
316                 okbutton->setText("OK");
317                 return false;
318         }
319         string const bpath = buffer().filePath();
320         QString absfname = makeAbsPath(fname, toqstr(bpath));
321         bool const fexists = QFile::exists(absfname);
322         okbutton->setText(fexists ? "OK" : "Create");
323         editPB->setEnabled(fexists);
324         return true;
325 }
326
327
328 void GuiInclude::browse()
329 {
330         Type type;
331
332         int const item = typeCO->currentIndex();
333         if (item == 0)
334                 type = INCLUDE;
335         else if (item == 1)
336                 type = INPUT;
337         else if (item == 2)
338                 type = VERBATIM;
339         else
340                 type = LISTINGS;
341
342         QString name = browse(filenameED->text(), type);
343         if (!name.isEmpty())
344                 filenameED->setText(name);
345 }
346
347
348 QString GuiInclude::browse(QString const & in_name, Type in_type) const
349 {
350         QString const title = qt_("Select document to include");
351
352         // input TeX, verbatim, or LyX file ?
353         QStringList filters;
354         switch (in_type) {
355         case INCLUDE:
356         case INPUT:
357                 filters = fileFilters(qt_("LaTeX/LyX Documents (*.tex *.lyx)"));
358                 break;
359         case VERBATIM:
360         case LISTINGS:
361                 filters = fileFilters(QString());
362                 break;
363         }
364
365         QString const docpath = toqstr(support::onlyPath(buffer().absFileName()));
366
367         return browseRelToParent(in_name, docpath, title, filters, false,
368                 qt_("D&ocuments"), toqstr(lyxrc.document_path));
369 }
370
371
372 bool GuiInclude::initialiseParams(std::string const & sdata)
373 {
374         InsetCommand::string2params(sdata, params_);
375         paramsToDialog(params_);
376         return true;
377 }
378
379
380 void GuiInclude::dispatchParams()
381 {
382         std::string const lfun = InsetCommand::params2string(params_);
383         dispatch(FuncRequest(getLfun(), lfun));
384 }
385
386
387 Dialog * createGuiInclude(GuiView & lv) { return new GuiInclude(lv); }
388
389
390 } // namespace frontend
391 } // namespace lyx
392
393 #include "moc_GuiInclude.cpp"