]> git.lyx.org Git - lyx.git/blob - src/insets/insetinclude.C
Look for mathed xpms. Doesn't do anything yet due to lack of workable XPMs
[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             noload == o.noload && 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         // Just to be safe...
134         string command;
135
136         switch (params_.flag) {
137                 case INCLUDE:
138                         command="include";
139                         break;
140                 case VERB:
141                         command="verbatiminput";
142                         break;
143                 case INPUT:
144                         command="input";
145                         break;
146                 case VERBAST:
147                         command="verbatiminput*";
148                         break;
149         }
150
151         params_.cparams.setCmdName(command);
152
153         if (preview_->monitoring())
154                 preview_->stopMonitoring();
155
156         if (grfx::PreviewedInset::activated() && params_.flag == INPUT)
157                 preview_->generatePreview();
158 }
159
160
161 Inset * InsetInclude::clone(Buffer const & buffer, bool) const
162 {
163         Params p(params_);
164         p.masterFilename_ = buffer.fileName();
165
166         return new InsetInclude(p);
167 }
168
169
170 void InsetInclude::edit(BufferView * bv, int, int, mouse_button::state)
171 {
172         bv->owner()->getDialogs().showInclude(this);
173 }
174
175
176 void InsetInclude::edit(BufferView * bv, bool)
177 {
178         edit(bv, 0, 0, mouse_button::none);
179 }
180
181
182 void InsetInclude::write(Buffer const *, ostream & os) const
183 {
184         os << "Include " << params_.cparams.getCommand() << '\n'
185            << "preview " << tostr(params_.cparams.preview()) << '\n';
186 }
187
188
189 void InsetInclude::read(Buffer const *, LyXLex & lex)
190 {
191         params_.cparams.read(lex);
192
193         if (params_.cparams.getCmdName() == "include")
194                 params_.flag = INCLUDE;
195         else if (params_.cparams.getCmdName() == "input")
196                 params_.flag = INPUT;
197         /* FIXME: is this logic necessary now ? */
198         else if (contains(params_.cparams.getCmdName(), "verbatim")) {
199                 params_.flag = VERB;
200                 if (params_.cparams.getCmdName() == "verbatiminput*")
201                         params_.flag = VERBAST;
202         }
203 }
204
205
206 bool InsetInclude::display() const
207 {
208         return !(params_.flag == INPUT);
209 }
210
211
212 string const InsetInclude::getScreenLabel(Buffer const *) const
213 {
214         string temp;
215
216         switch (params_.flag) {
217                 case INPUT: temp += _("Input"); break;
218                 case VERB: temp += _("Verbatim Input"); break;
219                 case VERBAST: temp += _("Verbatim Input*"); break;
220                 case INCLUDE: temp += _("Include"); break;
221         }
222
223         temp += ": ";
224
225         if (params_.cparams.getContents().empty())
226                 temp += "???";
227         else
228                 temp += params_.cparams.getContents();
229
230         return temp;
231 }
232
233
234 string const InsetInclude::getRelFileBaseName() const
235 {
236         return OnlyFilename(ChangeExtension(params_.cparams.getContents(), string()));
237 }
238
239
240 string const InsetInclude::getFileName() const
241 {
242         return MakeAbsPath(params_.cparams.getContents(),
243                            OnlyPath(getMasterFilename()));
244 }
245
246
247 string const InsetInclude::getMasterFilename() const
248 {
249         return params_.masterFilename_;
250 }
251
252
253 bool InsetInclude::loadIfNeeded() const
254 {
255         if (params_.noload || isVerbatim())
256                 return false;
257
258         if (!IsLyXFilename(getFileName()))
259                 return false;
260
261         if (bufferlist.exists(getFileName()))
262                 return true;
263
264         // the readonly flag can/will be wrong, not anymore I think.
265         FileInfo finfo(getFileName());
266         if (!finfo.isOK())
267                 return false;
268
269         return bufferlist.readFile(getFileName(), !finfo.writable()) != 0;
270 }
271
272
273 int InsetInclude::latex(Buffer const * buffer, ostream & os,
274                         bool /*fragile*/, bool /*fs*/) const
275 {
276         string incfile(params_.cparams.getContents());
277
278         // Do nothing if no file name has been specified
279         if (incfile.empty())
280                 return 0;
281
282         if (loadIfNeeded()) {
283                 Buffer * tmp = bufferlist.getBuffer(getFileName());
284
285                 // FIXME: this should be a GUI warning
286                 if (tmp->params.textclass != buffer->params.textclass) {
287                         lyxerr << "WARNING: Included file `"
288                                << MakeDisplayPath(getFileName())
289                                << "' has textclass `"
290                                << tmp->params.getLyXTextClass().name()
291                                << "' while parent file has textclass `"
292                                << buffer->params.getLyXTextClass().name()
293                                << "'." << endl;
294                         //return 0;
295                 }
296
297                 // write it to a file (so far the complete file)
298                 string writefile = ChangeExtension(getFileName(), ".tex");
299
300                 if (!buffer->tmppath.empty()
301                     && !buffer->niceFile) {
302                         incfile = subst(incfile, '/','@');
303 #ifdef __EMX__
304                         incfile = subst(incfile, ':', '$');
305 #endif
306                         writefile = AddName(buffer->tmppath, incfile);
307                 } else
308                         writefile = getFileName();
309                 writefile = ChangeExtension(writefile, ".tex");
310                 lyxerr[Debug::LATEX] << "incfile:" << incfile << endl;
311                 lyxerr[Debug::LATEX] << "writefile:" << writefile << endl;
312
313                 tmp->markDepClean(buffer->tmppath);
314
315                 tmp->makeLaTeXFile(writefile,
316                                    OnlyPath(getMasterFilename()),
317                                    buffer->niceFile, true);
318         }
319
320         if (isVerbatim()) {
321                 os << '\\' << params_.cparams.getCmdName() << '{' << incfile << '}';
322         } else if (params_.flag == INPUT) {
323                 // \input wants file with extension (default is .tex)
324                 if (!IsLyXFilename(getFileName())) {
325                         os << '\\' << params_.cparams.getCmdName() << '{' << incfile << '}';
326                 } else {
327                         os << '\\' << params_.cparams.getCmdName() << '{'
328                            << ChangeExtension(incfile, ".tex")
329                            <<  '}';
330                 }
331         } else {
332                 // \include don't want extension and demands that the
333                 // file really have .tex
334                 os << '\\' << params_.cparams.getCmdName() << '{'
335                    << ChangeExtension(incfile, string())
336                    << '}';
337         }
338
339         return 0;
340 }
341
342
343 int InsetInclude::ascii(Buffer const *, ostream & os, int) const
344 {
345         if (isVerbatim())
346                 os << GetFileContents(getFileName());
347         return 0;
348 }
349
350
351 int InsetInclude::linuxdoc(Buffer const * buffer, ostream & os) const
352 {
353         string incfile(params_.cparams.getContents());
354
355         // Do nothing if no file name has been specified
356         if (incfile.empty())
357                 return 0;
358
359         if (loadIfNeeded()) {
360                 Buffer * tmp = bufferlist.getBuffer(getFileName());
361
362                 // write it to a file (so far the complete file)
363                 string writefile = ChangeExtension(getFileName(), ".sgml");
364                 if (!buffer->tmppath.empty() && !buffer->niceFile) {
365                         incfile = subst(incfile, '/','@');
366                         writefile = AddName(buffer->tmppath, incfile);
367                 } else
368                         writefile = getFileName();
369
370                 if (IsLyXFilename(getFileName()))
371                         writefile = ChangeExtension(writefile, ".sgml");
372
373                 lyxerr[Debug::LATEX] << "incfile:" << incfile << endl;
374                 lyxerr[Debug::LATEX] << "writefile:" << writefile << endl;
375
376                 tmp->makeLinuxDocFile(writefile, buffer->niceFile, true);
377         }
378
379         if (isVerbatim()) {
380                 os << "<![CDATA["
381                    << GetFileContents(getFileName())
382                    << "]]>";
383         } else
384                 os << '&' << include_label << ';';
385
386         return 0;
387 }
388
389
390 int InsetInclude::docbook(Buffer const * buffer, ostream & os,
391                           bool /*mixcont*/) const
392 {
393         string incfile(params_.cparams.getContents());
394
395         // Do nothing if no file name has been specified
396         if (incfile.empty())
397                 return 0;
398
399         if (loadIfNeeded()) {
400                 Buffer * tmp = bufferlist.getBuffer(getFileName());
401
402                 // write it to a file (so far the complete file)
403                 string writefile = ChangeExtension(getFileName(), ".sgml");
404                 if (!buffer->tmppath.empty() && !buffer->niceFile) {
405                         incfile = subst(incfile, '/','@');
406                         writefile = AddName(buffer->tmppath, incfile);
407                 } else
408                         writefile = getFileName();
409                 if (IsLyXFilename(getFileName()))
410                         writefile = ChangeExtension(writefile, ".sgml");
411
412                 lyxerr[Debug::LATEX] << "incfile:" << incfile << endl;
413                 lyxerr[Debug::LATEX] << "writefile:" << writefile << endl;
414
415                 tmp->makeDocBookFile(writefile, buffer->niceFile, true);
416         }
417
418         if (isVerbatim()) {
419                 os << "<inlinegraphic fileref=\""
420                    << '&' << include_label << ';'
421                    << "\" format=\"linespecific\">";
422         } else
423                 os << '&' << include_label << ';';
424
425         return 0;
426 }
427
428
429 void InsetInclude::validate(LaTeXFeatures & features) const
430 {
431
432         string incfile(params_.cparams.getContents());
433         string writefile;
434
435         Buffer const * const b = bufferlist.getBuffer(getMasterFilename());
436
437         if (b && !b->tmppath.empty() && !b->niceFile && !isVerbatim()) {
438                 incfile = subst(incfile, '/','@');
439                 writefile = AddName(b->tmppath, incfile);
440         } else
441                 writefile = getFileName();
442
443         if (IsLyXFilename(getFileName()))
444                 writefile = ChangeExtension(writefile, ".sgml");
445
446         features.includeFile(include_label, writefile);
447
448         if (isVerbatim())
449                 features.require("verbatim");
450
451         // Here we must do the fun stuff...
452         // Load the file in the include if it needs
453         // to be loaded:
454         if (loadIfNeeded()) {
455                 // a file got loaded
456                 Buffer * const tmp = bufferlist.getBuffer(getFileName());
457                 if (tmp) {
458                         if (b)
459                                 tmp->niceFile = b->niceFile;
460                         tmp->validate(features);
461                 }
462         }
463 }
464
465
466 vector<string> const InsetInclude::getLabelList() const
467 {
468         vector<string> l;
469
470         if (loadIfNeeded()) {
471                 Buffer * tmp = bufferlist.getBuffer(getFileName());
472                 tmp->setParentName("");
473                 l = tmp->getLabelList();
474                 tmp->setParentName(getMasterFilename());
475         }
476
477         return l;
478 }
479
480
481 vector<pair<string,string> > const InsetInclude::getKeys() const
482 {
483         vector<pair<string,string> > keys;
484
485         if (loadIfNeeded()) {
486                 Buffer * tmp = bufferlist.getBuffer(getFileName());
487                 tmp->setParentName("");
488                 keys = tmp->getBibkeyList();
489                 tmp->setParentName(getMasterFilename());
490         }
491
492         return keys;
493 }
494
495
496 int InsetInclude::ascent(BufferView * bv, LyXFont const & font) const
497 {
498         return preview_->previewReady() ?
499                 preview_->pimage()->ascent() : InsetButton::ascent(bv, font);
500 }
501
502
503 int InsetInclude::descent(BufferView * bv, LyXFont const & font) const
504 {
505         return preview_->previewReady() ?
506                 preview_->pimage()->descent() : InsetButton::descent(bv, font);
507 }
508
509
510 int InsetInclude::width(BufferView * bv, LyXFont const & font) const
511 {
512         return preview_->previewReady() ?
513                 preview_->pimage()->width() : InsetButton::width(bv, font);
514 }
515
516
517 void InsetInclude::draw(BufferView * bv, LyXFont const & font, int y,
518                         float & xx, bool b) const
519 {
520         preview_->setView(bv);
521         if (!preview_->previewReady()) {
522                 InsetButton::draw(bv, font, y, xx, b);
523                 return;
524         }
525
526         if (!preview_->monitoring())
527                 preview_->startMonitoring();
528
529         int const x = int(xx);
530         int const w = width(bv, font);
531         int const d = descent(bv, font);
532         int const a = ascent(bv, font);
533         int const h = a + d;
534
535         bv->painter().image(x, y - a, w, h,
536                             *(preview_->pimage()->image(*this, *bv)));
537
538         xx += w;
539 }
540
541
542 //
543 // preview stuff
544 //
545
546 void InsetInclude::addPreview(grfx::PreviewLoader & ploader) const
547 {
548         preview_->addPreview(ploader);
549 }
550
551
552 bool InsetInclude::PreviewImpl::previewWanted() const
553 {
554         return parent().params_.flag == InsetInclude::INPUT &&
555                 parent().params_.cparams.preview() &&
556                 IsFileReadable(parent().getFileName());
557 }
558
559
560 string const InsetInclude::PreviewImpl::latexString() const
561 {
562         if (!view() || !view()->buffer())
563                 return string();
564
565         ostringstream os;
566         parent().latex(view()->buffer(), os, false, false);
567
568         return os.str().c_str();
569 }
570
571
572 void InsetInclude::PreviewImpl::startMonitoring()
573 {
574         monitor_.reset(new FileMonitor(parent().getFileName(), 2000));
575         monitor_->connect(boost::bind(&PreviewImpl::restartLoading, this));
576         monitor_->start();
577 }
578
579
580 void InsetInclude::PreviewImpl::restartLoading()
581 {
582         lyxerr << "restartLoading()" << std::endl;
583         removePreview();
584         if (view())
585                 view()->updateInset(&parent(), false);
586         generatePreview();
587 }