]> git.lyx.org Git - lyx.git/blob - src/insets/insetinclude.C
remove noload/don't typeset
[lyx.git] / src / insets / insetinclude.C
1 #include <config.h>
2
3 #ifdef __GNUG__
4 #pragma implementation
5 #endif
6
7 #include "insetinclude.h"
8 #include "buffer.h"
9 #include "bufferlist.h"
10 #include "BufferView.h"
11 #include "debug.h"
12 #include "lyxrc.h"
13 #include "LaTeXFeatures.h"
14 #include "gettext.h"
15
16 #include "frontends/Dialogs.h"
17 #include "frontends/LyXView.h"
18 #include "frontends/Painter.h"
19
20 #include "support/filetools.h"
21 #include "support/FileInfo.h"
22 #include "support/FileMonitor.h"
23 #include "support/lstrings.h"
24
25 #include "graphics/PreviewedInset.h"
26 #include "graphics/PreviewImage.h"
27
28 #include <boost/bind.hpp>
29
30 #include <cstdlib>
31
32
33 using std::ostream;
34 using std::endl;
35 using std::vector;
36 using std::pair;
37
38 extern BufferList bufferlist;
39
40
41 class InsetInclude::PreviewImpl : public grfx::PreviewedInset {
42 public:
43         ///
44         PreviewImpl(InsetInclude & p) : PreviewedInset(p) {}
45
46         ///
47         bool previewWanted() const;
48         ///
49         string const latexString() const;
50         ///
51         InsetInclude & parent() const {
52                 return *static_cast<InsetInclude*>(inset());
53         }
54
55         ///
56         bool monitoring() const { return monitor_.get(); }
57         ///
58         void startMonitoring();
59         ///
60         void stopMonitoring() { monitor_.reset(); }
61
62 private:
63         /// Invoked by monitor_ should the parent file change.
64         void restartLoading();
65         ///
66         boost::scoped_ptr<FileMonitor> monitor_;
67 };
68
69
70 namespace {
71
72 string const uniqueID()
73 {
74         static unsigned int seed = 1000;
75
76         ostringstream ost;
77         ost << "file" << ++seed;
78
79         // Needed if we use lyxstring.
80         return ost.str().c_str();
81 }
82
83 } // namespace anon
84
85
86 InsetInclude::InsetInclude(Params const & p)
87         : params_(p), include_label(uniqueID()),
88           preview_(new PreviewImpl(*this))
89 {}
90
91
92 InsetInclude::InsetInclude(InsetCommandParams const & p, Buffer const & b)
93         : include_label(uniqueID()),
94           preview_(new PreviewImpl(*this))
95 {
96         params_.cparams = p;
97         params_.masterFilename_ = b.fileName();
98 }
99
100
101 InsetInclude::~InsetInclude()
102 {
103         hideDialog();
104 }
105
106
107 InsetInclude::Params const & InsetInclude::params() const
108 {
109         return params_;
110 }
111
112
113 bool InsetInclude::Params::operator==(Params const & o) const
114 {
115         if (cparams == o.cparams && flag == o.flag &&
116             masterFilename_ == o.masterFilename_)
117                 return true;
118
119         return false;
120 }
121
122
123 bool InsetInclude::Params::operator!=(Params const & o) const
124 {
125         return !(*this == o);
126 }
127
128
129 void InsetInclude::set(Params const & p)
130 {
131         params_ = p;
132
133         if (preview_->monitoring())
134                 preview_->stopMonitoring();
135
136         if (grfx::PreviewedInset::activated() && params_.flag == INPUT)
137                 preview_->generatePreview();
138 }
139
140
141 Inset * InsetInclude::clone(Buffer const & buffer, bool) const
142 {
143         Params p(params_);
144         p.masterFilename_ = buffer.fileName();
145
146         return new InsetInclude(p);
147 }
148
149
150 void InsetInclude::edit(BufferView * bv, int, int, mouse_button::state)
151 {
152         bv->owner()->getDialogs().showInclude(this);
153 }
154
155
156 void InsetInclude::edit(BufferView * bv, bool)
157 {
158         edit(bv, 0, 0, mouse_button::none);
159 }
160
161
162 void InsetInclude::write(Buffer const *, ostream & os) const
163 {
164         os << "Include " << params_.cparams.getCommand() << '\n'
165            << "preview " << tostr(params_.cparams.preview()) << '\n';
166 }
167
168
169 void InsetInclude::read(Buffer const *, LyXLex & lex)
170 {
171         params_.cparams.read(lex);
172
173         if (params_.cparams.getCmdName() == "include")
174                 params_.flag = INCLUDE;
175         else if (params_.cparams.getCmdName() == "input")
176                 params_.flag = INPUT;
177         /* FIXME: is this logic necessary now ? */
178         else if (contains(params_.cparams.getCmdName(), "verbatim")) {
179                 params_.flag = VERB;
180                 if (params_.cparams.getCmdName() == "verbatiminput*")
181                         params_.flag = VERBAST;
182         }
183 }
184
185
186 bool InsetInclude::display() const
187 {
188         return !(params_.flag == INPUT);
189 }
190
191
192 string const InsetInclude::getScreenLabel(Buffer const *) const
193 {
194         string temp;
195
196         switch (params_.flag) {
197                 case INPUT: temp += _("Input"); break;
198                 case VERB: temp += _("Verbatim Input"); break;
199                 case VERBAST: temp += _("Verbatim Input*"); break;
200                 case INCLUDE: temp += _("Include"); break;
201         }
202
203         temp += ": ";
204
205         if (params_.cparams.getContents().empty())
206                 temp += "???";
207         else
208                 temp += params_.cparams.getContents();
209
210         return temp;
211 }
212
213
214 string const InsetInclude::getRelFileBaseName() const
215 {
216         return OnlyFilename(ChangeExtension(params_.cparams.getContents(), string()));
217 }
218
219
220 string const InsetInclude::getFileName() const
221 {
222         return MakeAbsPath(params_.cparams.getContents(),
223                            OnlyPath(getMasterFilename()));
224 }
225
226
227 string const InsetInclude::getMasterFilename() const
228 {
229         return params_.masterFilename_;
230 }
231
232
233 bool InsetInclude::loadIfNeeded() const
234 {
235         if (isVerbatim())
236                 return false;
237
238         if (!IsLyXFilename(getFileName()))
239                 return false;
240
241         if (bufferlist.exists(getFileName()))
242                 return true;
243
244         // the readonly flag can/will be wrong, not anymore I think.
245         FileInfo finfo(getFileName());
246         if (!finfo.isOK())
247                 return false;
248
249         return bufferlist.readFile(getFileName(), !finfo.writable()) != 0;
250 }
251
252
253 int InsetInclude::latex(Buffer const * buffer, ostream & os,
254                         bool /*fragile*/, bool /*fs*/) const
255 {
256         string incfile(params_.cparams.getContents());
257
258         // Do nothing if no file name has been specified
259         if (incfile.empty())
260                 return 0;
261
262         if (loadIfNeeded()) {
263                 Buffer * tmp = bufferlist.getBuffer(getFileName());
264
265                 // FIXME: this should be a GUI warning
266                 if (tmp->params.textclass != buffer->params.textclass) {
267                         lyxerr << "WARNING: Included file `"
268                                << MakeDisplayPath(getFileName())
269                                << "' has textclass `"
270                                << tmp->params.getLyXTextClass().name()
271                                << "' while parent file has textclass `"
272                                << buffer->params.getLyXTextClass().name()
273                                << "'." << endl;
274                         //return 0;
275                 }
276
277                 // write it to a file (so far the complete file)
278                 string writefile = ChangeExtension(getFileName(), ".tex");
279
280                 if (!buffer->tmppath.empty()
281                     && !buffer->niceFile) {
282                         incfile = subst(incfile, '/','@');
283 #ifdef __EMX__
284                         incfile = subst(incfile, ':', '$');
285 #endif
286                         writefile = AddName(buffer->tmppath, incfile);
287                 } else
288                         writefile = getFileName();
289                 writefile = ChangeExtension(writefile, ".tex");
290                 lyxerr[Debug::LATEX] << "incfile:" << incfile << endl;
291                 lyxerr[Debug::LATEX] << "writefile:" << writefile << endl;
292
293                 tmp->markDepClean(buffer->tmppath);
294
295                 tmp->makeLaTeXFile(writefile,
296                                    OnlyPath(getMasterFilename()),
297                                    buffer->niceFile, true);
298         }
299
300         if (isVerbatim()) {
301                 os << '\\' << params_.cparams.getCmdName() << '{' << incfile << '}';
302         } else if (params_.flag == INPUT) {
303                 // \input wants file with extension (default is .tex)
304                 if (!IsLyXFilename(getFileName())) {
305                         os << '\\' << params_.cparams.getCmdName() << '{' << incfile << '}';
306                 } else {
307                         os << '\\' << params_.cparams.getCmdName() << '{'
308                            << ChangeExtension(incfile, ".tex")
309                            <<  '}';
310                 }
311         } else {
312                 // \include don't want extension and demands that the
313                 // file really have .tex
314                 os << '\\' << params_.cparams.getCmdName() << '{'
315                    << ChangeExtension(incfile, string())
316                    << '}';
317         }
318
319         return 0;
320 }
321
322
323 int InsetInclude::ascii(Buffer const *, ostream & os, int) const
324 {
325         if (isVerbatim())
326                 os << GetFileContents(getFileName());
327         return 0;
328 }
329
330
331 int InsetInclude::linuxdoc(Buffer const * buffer, ostream & os) const
332 {
333         string incfile(params_.cparams.getContents());
334
335         // Do nothing if no file name has been specified
336         if (incfile.empty())
337                 return 0;
338
339         if (loadIfNeeded()) {
340                 Buffer * tmp = bufferlist.getBuffer(getFileName());
341
342                 // write it to a file (so far the complete file)
343                 string writefile = ChangeExtension(getFileName(), ".sgml");
344                 if (!buffer->tmppath.empty() && !buffer->niceFile) {
345                         incfile = subst(incfile, '/','@');
346                         writefile = AddName(buffer->tmppath, incfile);
347                 } else
348                         writefile = getFileName();
349
350                 if (IsLyXFilename(getFileName()))
351                         writefile = ChangeExtension(writefile, ".sgml");
352
353                 lyxerr[Debug::LATEX] << "incfile:" << incfile << endl;
354                 lyxerr[Debug::LATEX] << "writefile:" << writefile << endl;
355
356                 tmp->makeLinuxDocFile(writefile, buffer->niceFile, true);
357         }
358
359         if (isVerbatim()) {
360                 os << "<![CDATA["
361                    << GetFileContents(getFileName())
362                    << "]]>";
363         } else
364                 os << '&' << include_label << ';';
365
366         return 0;
367 }
368
369
370 int InsetInclude::docbook(Buffer const * buffer, ostream & os,
371                           bool /*mixcont*/) const
372 {
373         string incfile(params_.cparams.getContents());
374
375         // Do nothing if no file name has been specified
376         if (incfile.empty())
377                 return 0;
378
379         if (loadIfNeeded()) {
380                 Buffer * tmp = bufferlist.getBuffer(getFileName());
381
382                 // write it to a file (so far the complete file)
383                 string writefile = ChangeExtension(getFileName(), ".sgml");
384                 if (!buffer->tmppath.empty() && !buffer->niceFile) {
385                         incfile = subst(incfile, '/','@');
386                         writefile = AddName(buffer->tmppath, incfile);
387                 } else
388                         writefile = getFileName();
389                 if (IsLyXFilename(getFileName()))
390                         writefile = ChangeExtension(writefile, ".sgml");
391
392                 lyxerr[Debug::LATEX] << "incfile:" << incfile << endl;
393                 lyxerr[Debug::LATEX] << "writefile:" << writefile << endl;
394
395                 tmp->makeDocBookFile(writefile, buffer->niceFile, true);
396         }
397
398         if (isVerbatim()) {
399                 os << "<inlinegraphic fileref=\""
400                    << '&' << include_label << ';'
401                    << "\" format=\"linespecific\">";
402         } else
403                 os << '&' << include_label << ';';
404
405         return 0;
406 }
407
408
409 void InsetInclude::validate(LaTeXFeatures & features) const
410 {
411
412         string incfile(params_.cparams.getContents());
413         string writefile;
414
415         Buffer const * const b = bufferlist.getBuffer(getMasterFilename());
416
417         if (b && !b->tmppath.empty() && !b->niceFile && !isVerbatim()) {
418                 incfile = subst(incfile, '/','@');
419                 writefile = AddName(b->tmppath, incfile);
420         } else
421                 writefile = getFileName();
422
423         if (IsLyXFilename(getFileName()))
424                 writefile = ChangeExtension(writefile, ".sgml");
425
426         features.includeFile(include_label, writefile);
427
428         if (isVerbatim())
429                 features.require("verbatim");
430
431         // Here we must do the fun stuff...
432         // Load the file in the include if it needs
433         // to be loaded:
434         if (loadIfNeeded()) {
435                 // a file got loaded
436                 Buffer * const tmp = bufferlist.getBuffer(getFileName());
437                 if (tmp) {
438                         if (b)
439                                 tmp->niceFile = b->niceFile;
440                         tmp->validate(features);
441                 }
442         }
443 }
444
445
446 vector<string> const InsetInclude::getLabelList() const
447 {
448         vector<string> l;
449
450         if (loadIfNeeded()) {
451                 Buffer * tmp = bufferlist.getBuffer(getFileName());
452                 tmp->setParentName("");
453                 l = tmp->getLabelList();
454                 tmp->setParentName(getMasterFilename());
455         }
456
457         return l;
458 }
459
460
461 vector<pair<string,string> > const InsetInclude::getKeys() const
462 {
463         vector<pair<string,string> > keys;
464
465         if (loadIfNeeded()) {
466                 Buffer * tmp = bufferlist.getBuffer(getFileName());
467                 tmp->setParentName("");
468                 keys = tmp->getBibkeyList();
469                 tmp->setParentName(getMasterFilename());
470         }
471
472         return keys;
473 }
474
475
476 int InsetInclude::ascent(BufferView * bv, LyXFont const & font) const
477 {
478         return preview_->previewReady() ?
479                 preview_->pimage()->ascent() : InsetButton::ascent(bv, font);
480 }
481
482
483 int InsetInclude::descent(BufferView * bv, LyXFont const & font) const
484 {
485         return preview_->previewReady() ?
486                 preview_->pimage()->descent() : InsetButton::descent(bv, font);
487 }
488
489
490 int InsetInclude::width(BufferView * bv, LyXFont const & font) const
491 {
492         return preview_->previewReady() ?
493                 preview_->pimage()->width() : InsetButton::width(bv, font);
494 }
495
496
497 void InsetInclude::draw(BufferView * bv, LyXFont const & font, int y,
498                         float & xx, bool b) const
499 {
500         preview_->setView(bv);
501         if (!preview_->previewReady()) {
502                 InsetButton::draw(bv, font, y, xx, b);
503                 return;
504         }
505
506         if (!preview_->monitoring())
507                 preview_->startMonitoring();
508
509         int const x = int(xx);
510         int const w = width(bv, font);
511         int const d = descent(bv, font);
512         int const a = ascent(bv, font);
513         int const h = a + d;
514
515         bv->painter().image(x, y - a, w, h,
516                             *(preview_->pimage()->image(*this, *bv)));
517
518         xx += w;
519 }
520
521
522 //
523 // preview stuff
524 //
525
526 void InsetInclude::addPreview(grfx::PreviewLoader & ploader) const
527 {
528         preview_->addPreview(ploader);
529 }
530
531
532 bool InsetInclude::PreviewImpl::previewWanted() const
533 {
534         return parent().params_.flag == InsetInclude::INPUT &&
535                 parent().params_.cparams.preview() &&
536                 IsFileReadable(parent().getFileName());
537 }
538
539
540 string const InsetInclude::PreviewImpl::latexString() const
541 {
542         if (!view() || !view()->buffer())
543                 return string();
544
545         ostringstream os;
546         parent().latex(view()->buffer(), os, false, false);
547
548         return os.str().c_str();
549 }
550
551
552 void InsetInclude::PreviewImpl::startMonitoring()
553 {
554         monitor_.reset(new FileMonitor(parent().getFileName(), 2000));
555         monitor_->connect(boost::bind(&PreviewImpl::restartLoading, this));
556         monitor_->start();
557 }
558
559
560 void InsetInclude::PreviewImpl::restartLoading()
561 {
562         lyxerr << "restartLoading()" << std::endl;
563         removePreview();
564         if (view())
565                 view()->updateInset(&parent(), false);
566         generatePreview();
567 }