]> git.lyx.org Git - lyx.git/blob - src/insets/InsetInclude.cpp
'using namespace std' instead of 'using std::xxx'
[lyx.git] / src / insets / InsetInclude.cpp
1 /**
2  * \file InsetInclude.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Lars Gullik Bjønnes
7  * \author Richard Heck (conversion to InsetCommand)
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #include "InsetInclude.h"
15
16 #include "Buffer.h"
17 #include "buffer_funcs.h"
18 #include "BufferList.h"
19 #include "BufferParams.h"
20 #include "BufferView.h"
21 #include "Cursor.h"
22 #include "support/debug.h"
23 #include "DispatchResult.h"
24 #include "Exporter.h"
25 #include "FuncRequest.h"
26 #include "FuncStatus.h"
27 #include "support/gettext.h"
28 #include "LaTeXFeatures.h"
29 #include "LyX.h"
30 #include "LyXRC.h"
31 #include "Lexer.h"
32 #include "MetricsInfo.h"
33 #include "OutputParams.h"
34 #include "TocBackend.h"
35 #include "TextClass.h"
36
37 #include "frontends/alert.h"
38 #include "frontends/Painter.h"
39
40 #include "graphics/PreviewImage.h"
41 #include "graphics/PreviewLoader.h"
42
43 #include "insets/RenderPreview.h"
44 #include "insets/InsetListingsParams.h"
45
46 #include "support/docstream.h"
47 #include "support/FileNameList.h"
48 #include "support/filetools.h"
49 #include "support/lstrings.h" // contains
50 #include "support/lyxalgo.h"
51 #include "support/lyxlib.h"
52 #include "support/convert.h"
53
54 #include <boost/bind.hpp>
55
56 using namespace std;
57
58 namespace lyx {
59
60 using support::addName;
61 using support::absolutePath;
62 using support::bformat;
63 using support::changeExtension;
64 using support::contains;
65 using support::copy;
66 using support::DocFileName;
67 using support::FileName;
68 using support::FileNameList;
69 using support::getVectorFromString;
70 using support::isLyXFilename;
71 using support::isValidLaTeXFilename;
72 using support::latex_path;
73 using support::makeAbsPath;
74 using support::makeRelPath;
75 using support::onlyFilename;
76 using support::onlyPath;
77 using support::prefixIs;
78 using support::subst;
79
80 namespace Alert = frontend::Alert;
81
82
83 namespace {
84
85 docstring const uniqueID()
86 {
87         static unsigned int seed = 1000;
88         return "file" + convert<docstring>(++seed);
89 }
90
91
92 /// the type of inclusion
93 enum Types {
94         INCLUDE, VERB, INPUT, VERBAST, LISTINGS, NONE
95 };
96
97
98 Types type(std::string const & s)
99 {
100         if (s == "input")
101                 return INPUT;
102         if (s == "verbatiminput")
103                 return VERB;
104         if (s == "verbatiminput*")
105                 return VERBAST;
106         if (s == "lstinputlisting")
107                 return LISTINGS;
108         if (s == "include")
109                 return INCLUDE;
110         return NONE;
111 }
112
113
114 Types type(InsetCommandParams const & params)
115 {
116         return type(params.getCmdName());
117 }
118
119
120 bool isListings(InsetCommandParams const & params)
121 {
122         return type(params) == LISTINGS;
123 }
124
125
126 bool isVerbatim(InsetCommandParams const & params)
127 {
128         Types const t = type(params);
129         return t == VERB || t == VERBAST;
130 }
131
132
133 bool isInputOrInclude(InsetCommandParams const & params)
134 {
135         Types const t = type(params);
136         return t == INPUT || t == INCLUDE;
137 }
138
139 } // namespace anon
140
141
142 InsetInclude::InsetInclude(InsetCommandParams const & p)
143         : InsetCommand(p, "include"), include_label(uniqueID()),
144           preview_(new RenderMonitoredPreview(this)), set_label_(false)
145 {
146         preview_->fileChanged(boost::bind(&InsetInclude::fileChanged, this));
147 }
148
149
150 InsetInclude::InsetInclude(InsetInclude const & other)
151         : InsetCommand(other), include_label(other.include_label),
152           preview_(new RenderMonitoredPreview(this)), set_label_(false)
153 {
154         preview_->fileChanged(boost::bind(&InsetInclude::fileChanged, this));
155 }
156
157
158 CommandInfo const * InsetInclude::findInfo(std::string const & /* cmdName */)
159 {
160         // FIXME
161         // This is only correct for the case of listings, but it'll do for now.
162         // In the other cases, this second parameter should just be empty.
163         static const char * const paramnames[] = {"filename", "lstparams", ""};
164         static const bool isoptional[] = {false, true};
165         static const CommandInfo info = {2, paramnames, isoptional};
166         return &info;
167 }
168
169
170 bool InsetInclude::isCompatibleCommand(std::string const & s)
171 {
172         return type(s) != NONE;
173 }
174
175
176 void InsetInclude::doDispatch(Cursor & cur, FuncRequest & cmd)
177 {
178         switch (cmd.action) {
179
180         case LFUN_INSET_MODIFY: {
181                 InsetCommandParams p(INCLUDE_CODE);
182                 InsetCommandMailer::string2params("include", to_utf8(cmd.argument()), p);
183                 if (!p.getCmdName().empty()) {
184                         if (isListings(p)){
185                                 InsetListingsParams par_old(to_utf8(params()["lstparams"]));
186                                 InsetListingsParams par_new(to_utf8(p["lstparams"]));
187                                 if (par_old.getParamValue("label") !=
188                                     par_new.getParamValue("label")
189                                     && !par_new.getParamValue("label").empty())
190                                         cur.bv().buffer().changeRefsIfUnique(
191                                                 from_utf8(par_old.getParamValue("label")),
192                                                 from_utf8(par_new.getParamValue("label")),
193                                                 REF_CODE);
194                         }
195                         set(p, cur.buffer());
196                         cur.buffer().updateBibfilesCache();
197                 } else
198                         cur.noUpdate();
199                 break;
200         }
201
202         //pass everything else up the chain
203         default:
204                 InsetCommand::doDispatch(cur, cmd);
205                 break;
206         }
207 }
208
209
210 namespace {
211
212 FileName const masterFileName(Buffer const & buffer)
213 {
214         return buffer.masterBuffer()->fileName();
215 }
216
217
218 string const parentFilename(Buffer const & buffer)
219 {
220         return buffer.absFileName();
221 }
222
223
224 FileName const includedFilename(Buffer const & buffer,
225                               InsetCommandParams const & params)
226 {
227         return makeAbsPath(to_utf8(params["filename"]),
228                onlyPath(parentFilename(buffer)));
229 }
230
231
232 void add_preview(RenderMonitoredPreview &, InsetInclude const &, Buffer const &);
233
234 } // namespace anon
235
236
237 void InsetInclude::set(InsetCommandParams const & p, Buffer const & buffer)
238 {
239         setParams(p);
240         set_label_ = false;
241
242         if (preview_->monitoring())
243                 preview_->stopMonitoring();
244
245         if (type(params()) == INPUT)
246                 add_preview(*preview_, *this, buffer);
247 }
248
249
250 Inset * InsetInclude::clone() const
251 {
252         return new InsetInclude(*this);
253 }
254
255
256 docstring const InsetInclude::getScreenLabel(Buffer const & buf) const
257 {
258         docstring temp;
259
260         switch (type(params())) {
261                 case INPUT:
262                         temp = buf.B_("Input");
263                         break;
264                 case VERB:
265                         temp = buf.B_("Verbatim Input");
266                         break;
267                 case VERBAST:
268                         temp = buf.B_("Verbatim Input*");
269                         break;
270                 case INCLUDE:
271                         temp = buf.B_("Include");
272                         break;
273                 case LISTINGS:
274                         temp = listings_label_;
275                         break;
276                 case NONE:
277                         BOOST_ASSERT(false);
278         }
279
280         temp += ": ";
281
282         if (params()["filename"].empty())
283                 temp += "???";
284         else
285                 temp += from_utf8(onlyFilename(to_utf8(params()["filename"])));
286
287         return temp;
288 }
289
290
291 namespace {
292
293 /// return the child buffer if the file is a LyX doc and is loaded
294 Buffer * getChildBuffer(Buffer const & buffer, InsetCommandParams const & params)
295 {
296         if (isVerbatim(params) || isListings(params))
297                 return 0;
298
299         string const included_file = includedFilename(buffer, params).absFilename();
300         if (!isLyXFilename(included_file))
301                 return 0;
302
303         Buffer * childBuffer = theBufferList().getBuffer(included_file);
304
305         //FIXME RECURSIVE INCLUDES
306         if (childBuffer == & buffer)
307                 return 0;
308         else
309                 return childBuffer;
310 }
311
312 } // namespace anon
313
314
315 /// return true if the file is or got loaded.
316 Buffer * loadIfNeeded(Buffer const & parent, InsetCommandParams const & params)
317 {
318         if (isVerbatim(params) || isListings(params))
319                 return 0;
320
321         string const parent_filename = parent.absFileName();
322         FileName const included_file = makeAbsPath(to_utf8(params["filename"]),
323                            onlyPath(parent_filename));
324
325         if (!isLyXFilename(included_file.absFilename()))
326                 return 0;
327
328         Buffer * child = theBufferList().getBuffer(included_file.absFilename());
329         if (!child) {
330                 // the readonly flag can/will be wrong, not anymore I think.
331                 if (!included_file.exists())
332                         return 0;
333
334                 child = theBufferList().newBuffer(included_file.absFilename());
335                 if (!child->loadLyXFile(included_file)) {
336                         //close the buffer we just opened
337                         theBufferList().release(child);
338                         return 0;
339                 }
340         }
341         child->setParent(&parent);
342         return child;
343 }
344
345
346 void resetParentBuffer(Buffer const * parent, InsetCommandParams const & params,
347         bool close_it)
348 {
349         if (isVerbatim(params) || isListings(params))
350                 return;
351
352         string const parent_filename = parent->absFileName();
353         FileName const included_file = makeAbsPath(to_utf8(params["filename"]),
354                            onlyPath(parent_filename));
355
356         if (!isLyXFilename(included_file.absFilename()))
357                 return;
358
359         Buffer * child = theBufferList().getBuffer(included_file.absFilename());
360         // File not opened, nothing to close.
361         if (!child)
362                 return;
363
364         // Child document has a different parent, don't close it.
365         if (child->parent() != parent)
366                 return;
367
368         //close the buffer.
369         child->setParent(0);
370         if (close_it)
371                 theBufferList().release(child);
372         else
373                 updateLabels(*child);
374 }
375
376
377 int InsetInclude::latex(Buffer const & buffer, odocstream & os,
378                         OutputParams const & runparams) const
379 {
380         string incfile(to_utf8(params()["filename"]));
381
382         // Do nothing if no file name has been specified
383         if (incfile.empty())
384                 return 0;
385
386         FileName const included_file = includedFilename(buffer, params());
387
388         //Check we're not trying to include ourselves.
389         //FIXME RECURSIVE INCLUDE
390         //This isn't sufficient, as the inclusion could be downstream.
391         //But it'll have to do for now.
392         if (isInputOrInclude(params()) &&
393                 buffer.absFileName() == included_file.absFilename())
394         {
395                 Alert::error(_("Recursive input"),
396                                bformat(_("Attempted to include file %1$s in itself! "
397                                "Ignoring inclusion."), from_utf8(incfile)));
398                 return 0;
399         }
400
401         Buffer const * const masterBuffer = buffer.masterBuffer();
402
403         // if incfile is relative, make it relative to the master
404         // buffer directory.
405         if (!absolutePath(incfile)) {
406                 // FIXME UNICODE
407                 incfile = to_utf8(makeRelPath(from_utf8(included_file.absFilename()),
408                                               from_utf8(masterBuffer->filePath())));
409         }
410
411         // write it to a file (so far the complete file)
412         string const exportfile = changeExtension(incfile, ".tex");
413         string const mangled =
414                 DocFileName(changeExtension(included_file.absFilename(),".tex")).
415                         mangledFilename();
416         FileName const writefile(makeAbsPath(mangled, masterBuffer->temppath()));
417
418         if (!runparams.nice)
419                 incfile = mangled;
420         else if (!isValidLaTeXFilename(incfile)) {
421                 frontend::Alert::warning(_("Invalid filename"),
422                                          _("The following filename is likely to cause trouble "
423                                            "when running the exported file through LaTeX: ") +
424                                             from_utf8(incfile));
425         }
426         LYXERR(Debug::LATEX, "incfile:" << incfile);
427         LYXERR(Debug::LATEX, "exportfile:" << exportfile);
428         LYXERR(Debug::LATEX, "writefile:" << writefile);
429
430         if (runparams.inComment || runparams.dryrun) {
431                 //Don't try to load or copy the file if we're
432                 //in a comment or doing a dryrun
433         } else if (isInputOrInclude(params()) &&
434                  isLyXFilename(included_file.absFilename())) {
435                 //if it's a LyX file and we're inputting or including,
436                 //try to load it so we can write the associated latex
437                 if (!loadIfNeeded(buffer, params()))
438                         return false;
439
440                 Buffer * tmp = theBufferList().getBuffer(included_file.absFilename());
441
442                 if (tmp->params().getBaseClass() != masterBuffer->params().getBaseClass()) {
443                         // FIXME UNICODE
444                         docstring text = bformat(_("Included file `%1$s'\n"
445                                                 "has textclass `%2$s'\n"
446                                                              "while parent file has textclass `%3$s'."),
447                                               included_file.displayName(),
448                                               from_utf8(tmp->params().getTextClass().name()),
449                                               from_utf8(masterBuffer->params().getTextClass().name()));
450                         Alert::warning(_("Different textclasses"), text);
451                         //return 0;
452                 }
453
454                 // Make sure modules used in child are all included in master
455                 //FIXME It might be worth loading the children's modules into the master
456                 //over in BufferParams rather than doing this check.
457                 vector<string> const masterModules = masterBuffer->params().getModules();
458                 vector<string> const childModules = tmp->params().getModules();
459                 vector<string>::const_iterator it = childModules.begin();
460                 vector<string>::const_iterator end = childModules.end();
461                 for (; it != end; ++it) {
462                         string const module = *it;
463                         vector<string>::const_iterator found =
464                                 find(masterModules.begin(), masterModules.end(), module);
465                         if (found != masterModules.end()) {
466                                 docstring text = bformat(_("Included file `%1$s'\n"
467                                                         "uses module `%2$s'\n"
468                                                         "which is not used in parent file."),
469                                        included_file.displayName(), from_utf8(module));
470                                 Alert::warning(_("Module not found"), text);
471                         }
472                 }
473
474                 tmp->markDepClean(masterBuffer->temppath());
475
476 // FIXME: handle non existing files
477 // FIXME: Second argument is irrelevant!
478 // since only_body is true, makeLaTeXFile will not look at second
479 // argument. Should we set it to string(), or should makeLaTeXFile
480 // make use of it somehow? (JMarc 20031002)
481                 // The included file might be written in a different encoding
482                 Encoding const * const oldEnc = runparams.encoding;
483                 runparams.encoding = &tmp->params().encoding();
484                 tmp->makeLaTeXFile(writefile,
485                                    masterFileName(buffer).onlyPath().absFilename(),
486                                    runparams, false);
487                 runparams.encoding = oldEnc;
488         } else {
489                 // In this case, it's not a LyX file, so we copy the file
490                 // to the temp dir, so that .aux files etc. are not created
491                 // in the original dir. Files included by this file will be
492                 // found via input@path, see ../Buffer.cpp.
493                 unsigned long const checksum_in  = included_file.checksum();
494                 unsigned long const checksum_out = writefile.checksum();
495
496                 if (checksum_in != checksum_out) {
497                         if (!copy(included_file, writefile)) {
498                                 // FIXME UNICODE
499                                 LYXERR(Debug::LATEX,
500                                         to_utf8(bformat(_("Could not copy the file\n%1$s\n"
501                                                                   "into the temporary directory."),
502                                                    from_utf8(included_file.absFilename()))));
503                                 return 0;
504                         }
505                 }
506         }
507
508         string const tex_format = (runparams.flavor == OutputParams::LATEX) ?
509                         "latex" : "pdflatex";
510         if (isVerbatim(params())) {
511                 incfile = latex_path(incfile);
512                 // FIXME UNICODE
513                 os << '\\' << from_ascii(params().getCmdName()) << '{'
514                    << from_utf8(incfile) << '}';
515         } else if (type(params()) == INPUT) {
516                 runparams.exportdata->addExternalFile(tex_format, writefile,
517                                                       exportfile);
518
519                 // \input wants file with extension (default is .tex)
520                 if (!isLyXFilename(included_file.absFilename())) {
521                         incfile = latex_path(incfile);
522                         // FIXME UNICODE
523                         os << '\\' << from_ascii(params().getCmdName())
524                            << '{' << from_utf8(incfile) << '}';
525                 } else {
526                 incfile = changeExtension(incfile, ".tex");
527                 incfile = latex_path(incfile);
528                         // FIXME UNICODE
529                         os << '\\' << from_ascii(params().getCmdName())
530                            << '{' << from_utf8(incfile) <<  '}';
531                 }
532         } else if (type(params()) == LISTINGS) {
533                 os << '\\' << from_ascii(params().getCmdName());
534                 string const opt = to_utf8(params()["lstparams"]);
535                 // opt is set in QInclude dialog and should have passed validation.
536                 InsetListingsParams params(opt);
537                 if (!params.params().empty())
538                         os << "[" << from_utf8(params.params()) << "]";
539                 os << '{'  << from_utf8(incfile) << '}';
540         } else {
541                 runparams.exportdata->addExternalFile(tex_format, writefile,
542                                                       exportfile);
543
544                 // \include don't want extension and demands that the
545                 // file really have .tex
546                 incfile = changeExtension(incfile, string());
547                 incfile = latex_path(incfile);
548                 // FIXME UNICODE
549                 os << '\\' << from_ascii(params().getCmdName()) << '{'
550                    << from_utf8(incfile) << '}';
551         }
552
553         return 0;
554 }
555
556
557 int InsetInclude::plaintext(Buffer const & buffer, odocstream & os,
558                             OutputParams const &) const
559 {
560         if (isVerbatim(params()) || isListings(params())) {
561                 os << '[' << getScreenLabel(buffer) << '\n';
562                 // FIXME: We don't know the encoding of the file, default to UTF-8.
563                 os << includedFilename(buffer, params()).fileContents("UTF-8");
564                 os << "\n]";
565                 return PLAINTEXT_NEWLINE + 1; // one char on a separate line
566         } else {
567                 docstring const str = '[' + getScreenLabel(buffer) + ']';
568                 os << str;
569                 return str.size();
570         }
571 }
572
573
574 int InsetInclude::docbook(Buffer const & buffer, odocstream & os,
575                           OutputParams const & runparams) const
576 {
577         string incfile = to_utf8(params()["filename"]);
578
579         // Do nothing if no file name has been specified
580         if (incfile.empty())
581                 return 0;
582
583         string const included_file = includedFilename(buffer, params()).absFilename();
584
585         //Check we're not trying to include ourselves.
586         //FIXME RECURSIVE INCLUDE
587         //This isn't sufficient, as the inclusion could be downstream.
588         //But it'll have to do for now.
589         if (buffer.absFileName() == included_file) {
590                 Alert::error(_("Recursive input"),
591                                bformat(_("Attempted to include file %1$s in itself! "
592                                "Ignoring inclusion."), from_utf8(incfile)));
593                 return 0;
594         }
595
596         // write it to a file (so far the complete file)
597         string const exportfile = changeExtension(incfile, ".sgml");
598         DocFileName writefile(changeExtension(included_file, ".sgml"));
599
600         if (loadIfNeeded(buffer, params())) {
601                 Buffer * tmp = theBufferList().getBuffer(included_file);
602
603                 string const mangled = writefile.mangledFilename();
604                 writefile = makeAbsPath(mangled,
605                                         buffer.masterBuffer()->temppath());
606                 if (!runparams.nice)
607                         incfile = mangled;
608
609                 LYXERR(Debug::LATEX, "incfile:" << incfile);
610                 LYXERR(Debug::LATEX, "exportfile:" << exportfile);
611                 LYXERR(Debug::LATEX, "writefile:" << writefile);
612
613                 tmp->makeDocBookFile(writefile, runparams, true);
614         }
615
616         runparams.exportdata->addExternalFile("docbook", writefile,
617                                               exportfile);
618         runparams.exportdata->addExternalFile("docbook-xml", writefile,
619                                               exportfile);
620
621         if (isVerbatim(params()) || isListings(params())) {
622                 os << "<inlinegraphic fileref=\""
623                    << '&' << include_label << ';'
624                    << "\" format=\"linespecific\">";
625         } else
626                 os << '&' << include_label << ';';
627
628         return 0;
629 }
630
631
632 void InsetInclude::validate(LaTeXFeatures & features) const
633 {
634         string incfile = to_utf8(params()["filename"]);
635         string writefile;
636
637         Buffer const & buffer = features.buffer();
638
639         string const included_file = includedFilename(buffer, params()).absFilename();
640
641         if (isLyXFilename(included_file))
642                 writefile = changeExtension(included_file, ".sgml");
643         else
644                 writefile = included_file;
645
646         if (!features.runparams().nice && !isVerbatim(params()) && !isListings(params())) {
647                 incfile = DocFileName(writefile).mangledFilename();
648                 writefile = makeAbsPath(incfile,
649                                         buffer.masterBuffer()->temppath()).absFilename();
650         }
651
652         features.includeFile(include_label, writefile);
653
654         if (isVerbatim(params()))
655                 features.require("verbatim");
656         else if (isListings(params()))
657                 features.require("listings");
658
659         // Here we must do the fun stuff...
660         // Load the file in the include if it needs
661         // to be loaded:
662         if (loadIfNeeded(buffer, params())) {
663                 // a file got loaded
664                 Buffer * const tmp = theBufferList().getBuffer(included_file);
665                 // make sure the buffer isn't us
666                 // FIXME RECURSIVE INCLUDES
667                 // This is not sufficient, as recursive includes could be
668                 // more than a file away. But it will do for now.
669                 if (tmp && tmp != & buffer) {
670                         // We must temporarily change features.buffer,
671                         // otherwise it would always be the master buffer,
672                         // and nested includes would not work.
673                         features.setBuffer(*tmp);
674                         tmp->validate(features);
675                         features.setBuffer(buffer);
676                 }
677         }
678 }
679
680
681 void InsetInclude::getLabelList(Buffer const & buffer,
682                                 std::vector<docstring> & list) const
683 {
684         if (isListings(params())) {
685                 InsetListingsParams p(to_utf8(params()["lstparams"]));
686                 string label = p.getParamValue("label");
687                 if (!label.empty())
688                         list.push_back(from_utf8(label));
689         }
690         else if (loadIfNeeded(buffer, params())) {
691                 string const included_file = includedFilename(buffer, params()).absFilename();
692                 Buffer * tmp = theBufferList().getBuffer(included_file);
693                 tmp->setParent(0);
694                 tmp->getLabelList(list);
695                 tmp->setParent(const_cast<Buffer *>(&buffer));
696         }
697 }
698
699
700 void InsetInclude::fillWithBibKeys(Buffer const & buffer,
701                 BiblioInfo & keys, InsetIterator const & /*di*/) const
702 {
703         if (loadIfNeeded(buffer, params())) {
704                 string const included_file = includedFilename(buffer, params()).absFilename();
705                 Buffer * tmp = theBufferList().getBuffer(included_file);
706                 //FIXME This is kind of a dirty hack and should be made reasonable.
707                 tmp->setParent(0);
708                 keys.fillWithBibKeys(tmp);
709                 tmp->setParent(&buffer);
710         }
711 }
712
713
714 void InsetInclude::updateBibfilesCache(Buffer const & buffer)
715 {
716         Buffer * const tmp = getChildBuffer(buffer, params());
717         if (tmp) {
718                 tmp->setParent(0);
719                 tmp->updateBibfilesCache();
720                 tmp->setParent(&buffer);
721         }
722 }
723
724
725 FileNameList const &
726 InsetInclude::getBibfilesCache(Buffer const & buffer) const
727 {
728         Buffer * const tmp = getChildBuffer(buffer, params());
729         if (tmp) {
730                 tmp->setParent(0);
731                 FileNameList const & cache = tmp->getBibfilesCache();
732                 tmp->setParent(&buffer);
733                 return cache;
734         }
735         static FileNameList const empty;
736         return empty;
737 }
738
739
740 void InsetInclude::metrics(MetricsInfo & mi, Dimension & dim) const
741 {
742         BOOST_ASSERT(mi.base.bv);
743
744         bool use_preview = false;
745         if (RenderPreview::status() != LyXRC::PREVIEW_OFF) {
746                 graphics::PreviewImage const * pimage =
747                         preview_->getPreviewImage(mi.base.bv->buffer());
748                 use_preview = pimage && pimage->image();
749         }
750
751         if (use_preview) {
752                 preview_->metrics(mi, dim);
753         } else {
754                 if (!set_label_) {
755                         set_label_ = true;
756                         button_.update(getScreenLabel(mi.base.bv->buffer()),
757                                        true);
758                 }
759                 button_.metrics(mi, dim);
760         }
761
762         Box b(0, dim.wid, -dim.asc, dim.des);
763         button_.setBox(b);
764 }
765
766
767 void InsetInclude::draw(PainterInfo & pi, int x, int y) const
768 {
769         BOOST_ASSERT(pi.base.bv);
770
771         bool use_preview = false;
772         if (RenderPreview::status() != LyXRC::PREVIEW_OFF) {
773                 graphics::PreviewImage const * pimage =
774                         preview_->getPreviewImage(pi.base.bv->buffer());
775                 use_preview = pimage && pimage->image();
776         }
777
778         if (use_preview)
779                 preview_->draw(pi, x, y);
780         else
781                 button_.draw(pi, x, y);
782 }
783
784
785 Inset::DisplayType InsetInclude::display() const
786 {
787         return type(params()) == INPUT ? Inline : AlignCenter;
788 }
789
790
791
792 //
793 // preview stuff
794 //
795
796 void InsetInclude::fileChanged() const
797 {
798         Buffer const * const buffer = updateFrontend();
799         if (!buffer)
800                 return;
801
802         preview_->removePreview(*buffer);
803         add_preview(*preview_.get(), *this, *buffer);
804         preview_->startLoading(*buffer);
805 }
806
807
808 namespace {
809
810 bool preview_wanted(InsetCommandParams const & params, Buffer const & buffer)
811 {
812         FileName const included_file = includedFilename(buffer, params);
813
814         return type(params) == INPUT && params.preview() &&
815                 included_file.isReadableFile();
816 }
817
818
819 docstring const latex_string(InsetInclude const & inset, Buffer const & buffer)
820 {
821         odocstringstream os;
822         // We don't need to set runparams.encoding since this will be done
823         // by latex() anyway.
824         OutputParams runparams(0);
825         runparams.flavor = OutputParams::LATEX;
826         inset.latex(buffer, os, runparams);
827
828         return os.str();
829 }
830
831
832 void add_preview(RenderMonitoredPreview & renderer, InsetInclude const & inset,
833                  Buffer const & buffer)
834 {
835         InsetCommandParams const & params = inset.params();
836         if (RenderPreview::status() != LyXRC::PREVIEW_OFF &&
837             preview_wanted(params, buffer)) {
838                 renderer.setAbsFile(includedFilename(buffer, params));
839                 docstring const snippet = latex_string(inset, buffer);
840                 renderer.addPreview(snippet, buffer);
841         }
842 }
843
844 } // namespace anon
845
846
847 void InsetInclude::addPreview(graphics::PreviewLoader & ploader) const
848 {
849         Buffer const & buffer = ploader.buffer();
850         if (preview_wanted(params(), buffer)) {
851                 preview_->setAbsFile(includedFilename(buffer, params()));
852                 docstring const snippet = latex_string(*this, buffer);
853                 preview_->addPreview(snippet, ploader);
854         }
855 }
856
857
858 void InsetInclude::addToToc(TocList & toclist, Buffer const & buffer,
859         ParConstIterator const & pit) const
860 {
861         if (isListings(params())) {
862                 InsetListingsParams p(to_utf8(params()["lstparams"]));
863                 string caption = p.getParamValue("caption");
864                 if (caption.empty())
865                         return;
866                 Toc & toc = toclist["listing"];
867                 docstring const str = convert<docstring>(toc.size() + 1)
868                         + ". " +  from_utf8(caption);
869                 // This inset does not have a valid ParConstIterator
870                 // so it has to use the iterator of its parent paragraph
871                 toc.push_back(TocItem(pit, 0, str));
872                 return;
873         }
874         Buffer const * const childbuffer = getChildBuffer(buffer, params());
875         if (!childbuffer)
876                 return;
877
878         TocList const & childtoclist = childbuffer->tocBackend().tocs();
879         TocList::const_iterator it = childtoclist.begin();
880         TocList::const_iterator const end = childtoclist.end();
881         for(; it != end; ++it)
882                 toclist[it->first].insert(toclist[it->first].end(),
883                                 it->second.begin(), it->second.end());
884 }
885
886
887 void InsetInclude::updateLabels(Buffer const & buffer, ParIterator const &)
888 {
889         Buffer const * const childbuffer = getChildBuffer(buffer, params());
890         if (childbuffer)
891                 lyx::updateLabels(*childbuffer, true);
892         else if (isListings(params())) {
893                 InsetListingsParams const par(to_utf8(params()["lstparams"]));
894                 if (par.getParamValue("caption").empty())
895                         listings_label_.clear();
896                 else {
897                         Counters & counters = buffer.params().getTextClass().counters();
898                         docstring const cnt = from_ascii("listing");
899                         if (counters.hasCounter(cnt)) {
900                                 counters.step(cnt);
901                                 listings_label_ = buffer.B_("Program Listing ")
902                                         + convert<docstring>(counters.value(cnt));
903                         } else
904                                 listings_label_ = buffer.B_("Program Listing");
905                 }
906         }
907 }
908
909
910 void InsetInclude::registerEmbeddedFiles(Buffer const & buffer,
911         EmbeddedFiles & files) const
912 {
913         // include and input are temprarily not considered.
914         if (isVerbatim(params()) || isListings(params()))
915                 files.registerFile(includedFilename(buffer, params()).absFilename(),
916                         false, this);
917 }
918
919 } // namespace lyx