3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Lars Gullik Bjønnes
8 * Full author contact details are available in file CREDITS
13 #include "insetinclude.h"
15 #include "bufferlist.h"
16 #include "BufferView.h"
18 #include "funcrequest.h"
20 #include "LaTeXFeatures.h"
21 #include "latexrunparams.h"
25 #include "metricsinfo.h"
26 #include "dimension.h"
28 #include "frontends/Dialogs.h"
29 #include "frontends/LyXView.h"
30 #include "frontends/Painter.h"
32 #include "support/filetools.h"
33 #include "support/FileInfo.h"
34 #include "support/FileMonitor.h"
35 #include "support/lstrings.h" // contains
36 #include "support/tostr.h"
38 #include "graphics/PreviewedInset.h"
39 #include "graphics/PreviewImage.h"
41 #include <boost/bind.hpp>
50 extern BufferList bufferlist;
53 class InsetInclude::PreviewImpl : public grfx::PreviewedInset {
56 PreviewImpl(InsetInclude & p) : PreviewedInset(p) {}
59 bool previewWanted() const;
61 string const latexString() const;
63 InsetInclude & parent() const {
64 return *static_cast<InsetInclude*>(inset());
68 bool monitoring() const { return monitor_.get(); }
70 void startMonitoring();
72 void stopMonitoring() { monitor_.reset(); }
75 /// Invoked by monitor_ should the parent file change.
76 void restartLoading();
78 boost::scoped_ptr<FileMonitor> monitor_;
84 string const uniqueID()
86 static unsigned int seed = 1000;
87 return "file" + tostr(++seed);
93 InsetInclude::InsetInclude(Params const & p)
94 : params_(p), include_label(uniqueID()),
95 preview_(new PreviewImpl(*this))
99 InsetInclude::InsetInclude(InsetCommandParams const & p, Buffer const & b)
100 : include_label(uniqueID()),
101 preview_(new PreviewImpl(*this))
104 params_.masterFilename_ = b.fileName();
108 InsetInclude::~InsetInclude()
110 InsetIncludeMailer mailer(*this);
115 dispatch_result InsetInclude::localDispatch(FuncRequest const & cmd)
117 switch (cmd.action) {
119 case LFUN_INSET_MODIFY: {
120 InsetInclude::Params p;
121 InsetIncludeMailer::string2params(cmd.argument, p);
122 if (!p.cparams.getCmdName().empty()) {
124 params_.masterFilename_ = cmd.view()->buffer()->fileName();
125 cmd.view()->updateInset(this);
130 case LFUN_INSET_DIALOG_UPDATE:
131 InsetIncludeMailer(*this).updateDialog(cmd.view());
134 case LFUN_MOUSE_RELEASE:
135 case LFUN_INSET_EDIT:
136 InsetIncludeMailer(*this).showDialog(cmd.view());
140 return InsetButton::localDispatch(cmd);
145 InsetInclude::Params const & InsetInclude::params() const
151 bool InsetInclude::Params::operator==(Params const & o) const
153 return cparams == o.cparams && flag == o.flag &&
154 masterFilename_ == o.masterFilename_;
158 bool InsetInclude::Params::operator!=(Params const & o) const
160 return !(*this == o);
164 void InsetInclude::set(Params const & p)
170 switch (params_.flag) {
175 command="verbatiminput";
181 command="verbatiminput*";
185 params_.cparams.setCmdName(command);
187 if (preview_->monitoring())
188 preview_->stopMonitoring();
190 if (grfx::PreviewedInset::activated() && params_.flag == INPUT)
191 preview_->generatePreview();
195 Inset * InsetInclude::clone() const
198 //p.masterFilename_ = buffer.fileName();
199 #warning FIXME: broken cross-doc copy/paste - must fix
201 return new InsetInclude(params_);
205 void InsetInclude::write(Buffer const *, ostream & os) const
207 os << "Include " << params_.cparams.getCommand() << '\n'
208 << "preview " << tostr(params_.cparams.preview()) << '\n';
212 void InsetInclude::read(Buffer const *, LyXLex & lex)
214 params_.cparams.read(lex);
216 if (params_.cparams.getCmdName() == "include")
217 params_.flag = INCLUDE;
218 else if (params_.cparams.getCmdName() == "input")
219 params_.flag = INPUT;
220 /* FIXME: is this logic necessary now ? */
221 else if (contains(params_.cparams.getCmdName(), "verbatim")) {
223 if (params_.cparams.getCmdName() == "verbatiminput*")
224 params_.flag = VERBAST;
229 bool InsetInclude::display() const
231 return !(params_.flag == INPUT);
235 string const InsetInclude::getScreenLabel(Buffer const *) const
239 switch (params_.flag) {
240 case INPUT: temp += _("Input"); break;
241 case VERB: temp += _("Verbatim Input"); break;
242 case VERBAST: temp += _("Verbatim Input*"); break;
243 case INCLUDE: temp += _("Include"); break;
248 if (params_.cparams.getContents().empty())
251 temp += params_.cparams.getContents();
257 string const InsetInclude::getFileName() const
259 return MakeAbsPath(params_.cparams.getContents(),
260 OnlyPath(getMasterFilename()));
264 string const InsetInclude::getMasterFilename() const
266 return params_.masterFilename_;
270 bool InsetInclude::loadIfNeeded() const
275 if (!IsLyXFilename(getFileName()))
278 if (bufferlist.exists(getFileName()))
281 // the readonly flag can/will be wrong, not anymore I think.
282 FileInfo finfo(getFileName());
286 return bufferlist.loadLyXFile(getFileName(), false) != 0;
290 int InsetInclude::latex(Buffer const * buffer, ostream & os,
291 LatexRunParams const & runparams) const
293 string incfile(params_.cparams.getContents());
295 // Do nothing if no file name has been specified
299 if (loadIfNeeded()) {
300 Buffer * tmp = bufferlist.getBuffer(getFileName());
302 // FIXME: this should be a GUI warning
303 if (tmp->params.textclass != buffer->params.textclass) {
304 lyxerr << "WARNING: Included file `"
305 << MakeDisplayPath(getFileName())
306 << "' has textclass `"
307 << tmp->params.getLyXTextClass().name()
308 << "' while parent file has textclass `"
309 << buffer->params.getLyXTextClass().name()
314 // write it to a file (so far the complete file)
315 string writefile = ChangeExtension(getFileName(), ".tex");
317 if (!buffer->tmppath.empty() && !runparams.nice) {
318 incfile = subst(incfile, '/','@');
320 incfile = subst(incfile, ':', '$');
322 writefile = AddName(buffer->tmppath, incfile);
324 writefile = getFileName();
325 writefile = ChangeExtension(writefile, ".tex");
326 lyxerr[Debug::LATEX] << "incfile:" << incfile << endl;
327 lyxerr[Debug::LATEX] << "writefile:" << writefile << endl;
329 tmp->markDepClean(buffer->tmppath);
331 tmp->makeLaTeXFile(writefile, OnlyPath(getMasterFilename()),
336 os << '\\' << params_.cparams.getCmdName() << '{' << incfile << '}';
337 } else if (params_.flag == INPUT) {
338 // \input wants file with extension (default is .tex)
339 if (!IsLyXFilename(getFileName())) {
340 os << '\\' << params_.cparams.getCmdName() << '{' << incfile << '}';
342 os << '\\' << params_.cparams.getCmdName() << '{'
343 << ChangeExtension(incfile, ".tex")
347 // \include don't want extension and demands that the
348 // file really have .tex
349 os << '\\' << params_.cparams.getCmdName() << '{'
350 << ChangeExtension(incfile, string())
358 int InsetInclude::ascii(Buffer const *, ostream & os, int) const
361 os << GetFileContents(getFileName());
366 int InsetInclude::linuxdoc(Buffer const * buffer, ostream & os) const
368 string incfile(params_.cparams.getContents());
370 // Do nothing if no file name has been specified
374 if (loadIfNeeded()) {
375 Buffer * tmp = bufferlist.getBuffer(getFileName());
377 // write it to a file (so far the complete file)
378 string writefile = ChangeExtension(getFileName(), ".sgml");
379 if (!buffer->tmppath.empty() && !buffer->niceFile) {
380 incfile = subst(incfile, '/','@');
381 writefile = AddName(buffer->tmppath, incfile);
383 writefile = getFileName();
385 if (IsLyXFilename(getFileName()))
386 writefile = ChangeExtension(writefile, ".sgml");
388 lyxerr[Debug::LATEX] << "incfile:" << incfile << endl;
389 lyxerr[Debug::LATEX] << "writefile:" << writefile << endl;
391 tmp->makeLinuxDocFile(writefile, buffer->niceFile, true);
396 << GetFileContents(getFileName())
399 os << '&' << include_label << ';';
405 int InsetInclude::docbook(Buffer const * buffer, ostream & os,
406 bool /*mixcont*/) const
408 string incfile(params_.cparams.getContents());
410 // Do nothing if no file name has been specified
414 if (loadIfNeeded()) {
415 Buffer * tmp = bufferlist.getBuffer(getFileName());
417 // write it to a file (so far the complete file)
418 string writefile = ChangeExtension(getFileName(), ".sgml");
419 if (!buffer->tmppath.empty() && !buffer->niceFile) {
420 incfile = subst(incfile, '/','@');
421 writefile = AddName(buffer->tmppath, incfile);
423 writefile = getFileName();
424 if (IsLyXFilename(getFileName()))
425 writefile = ChangeExtension(writefile, ".sgml");
427 lyxerr[Debug::LATEX] << "incfile:" << incfile << endl;
428 lyxerr[Debug::LATEX] << "writefile:" << writefile << endl;
430 tmp->makeDocBookFile(writefile, buffer->niceFile, true);
434 os << "<inlinegraphic fileref=\""
435 << '&' << include_label << ';'
436 << "\" format=\"linespecific\">";
438 os << '&' << include_label << ';';
444 void InsetInclude::validate(LaTeXFeatures & features) const
447 string incfile(params_.cparams.getContents());
450 Buffer const * const b = bufferlist.getBuffer(getMasterFilename());
452 if (b && !b->tmppath.empty() && !b->niceFile && !isVerbatim()) {
453 incfile = subst(incfile, '/','@');
454 writefile = AddName(b->tmppath, incfile);
456 writefile = getFileName();
458 if (IsLyXFilename(getFileName()))
459 writefile = ChangeExtension(writefile, ".sgml");
461 features.includeFile(include_label, writefile);
464 features.require("verbatim");
466 // Here we must do the fun stuff...
467 // Load the file in the include if it needs
469 if (loadIfNeeded()) {
471 Buffer * const tmp = bufferlist.getBuffer(getFileName());
474 tmp->niceFile = b->niceFile;
475 tmp->validate(features);
481 vector<string> const InsetInclude::getLabelList() const
485 if (loadIfNeeded()) {
486 Buffer * tmp = bufferlist.getBuffer(getFileName());
487 tmp->setParentName("");
488 l = tmp->getLabelList();
489 tmp->setParentName(getMasterFilename());
496 void InsetInclude::fillWithBibKeys(vector<pair<string,string> > & keys) const
498 if (loadIfNeeded()) {
499 Buffer * tmp = bufferlist.getBuffer(getFileName());
500 tmp->setParentName("");
501 tmp->fillWithBibKeys(keys);
502 tmp->setParentName(getMasterFilename());
507 void InsetInclude::metrics(MetricsInfo & mi, Dimension & dim) const
509 if (preview_->previewReady()) {
510 dim.asc = preview_->pimage()->ascent();
511 dim.des = preview_->pimage()->descent();
512 dim.wid = preview_->pimage()->width();
514 InsetButton::metrics(mi, dim);
520 void InsetInclude::draw(PainterInfo & pi, int x, int y) const
523 if (!preview_->previewReady()) {
524 InsetButton::draw(pi, x, y);
528 if (!preview_->monitoring())
529 preview_->startMonitoring();
531 pi.pain.image(x, y - dim_.asc, dim_.wid, dim_.height(),
532 *(preview_->pimage()->image()));
540 void InsetInclude::addPreview(grfx::PreviewLoader & ploader) const
542 preview_->addPreview(ploader);
546 bool InsetInclude::PreviewImpl::previewWanted() const
548 return parent().params_.flag == InsetInclude::INPUT &&
549 parent().params_.cparams.preview() &&
550 IsFileReadable(parent().getFileName());
554 string const InsetInclude::PreviewImpl::latexString() const
556 if (!view() || !view()->buffer())
560 LatexRunParams runparams;
561 runparams.flavor = LatexRunParams::LATEX;
562 parent().latex(view()->buffer(), os, runparams);
564 return STRCONV(os.str());
568 void InsetInclude::PreviewImpl::startMonitoring()
570 monitor_.reset(new FileMonitor(parent().getFileName(), 2000));
571 monitor_->connect(boost::bind(&PreviewImpl::restartLoading, this));
576 void InsetInclude::PreviewImpl::restartLoading()
578 lyxerr << "restartLoading()" << std::endl;
581 view()->updateInset(&parent());
586 string const InsetIncludeMailer::name_("include");
588 InsetIncludeMailer::InsetIncludeMailer(InsetInclude & inset)
593 string const InsetIncludeMailer::inset2string() const
595 return params2string(inset_.params());
599 void InsetIncludeMailer::string2params(string const & in,
600 InsetInclude::Params & params)
602 params = InsetInclude::Params();
607 istringstream data(STRCONV(in));
613 string const token = lex.getString();
618 // This is part of the inset proper that is usually swallowed
619 // by Buffer::readInset
622 string const token = lex.getString();
623 if (token != "Include")
628 InsetInclude inset(params);
630 params = inset.params();
636 InsetIncludeMailer::params2string(InsetInclude::Params const & params)
638 InsetInclude inset(params);
641 data << name_ << ' ';
642 inset.write(0, data);
643 data << "\\end_inset\n";
644 return STRCONV(data.str());