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