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