]> git.lyx.org Git - lyx.git/blob - src/insets/insetinclude.C
Cache the BufferView as a weak_ptr; get rid of those horrible current_views.
[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/lstrings.h"
23
24 #include "graphics/PreviewedInset.h"
25 #include "graphics/PreviewImage.h"
26
27 #include <cstdlib>
28
29
30 using std::ostream;
31 using std::endl;
32 using std::vector;
33 using std::pair;
34
35 extern BufferList bufferlist;
36
37
38 class InsetInclude::PreviewImpl : public grfx::PreviewedInset {
39 public:
40         ///
41         PreviewImpl(InsetInclude & p) : PreviewedInset(p) {}
42
43         ///
44         bool previewWanted() const;
45         ///
46         string const latexString() const;
47         ///
48         InsetInclude & parent() const {
49                 return *static_cast<InsetInclude*>(inset());
50         }
51 };
52
53
54 namespace {
55
56 string const uniqueID()
57 {
58         static unsigned int seed = 1000;
59
60         ostringstream ost;
61         ost << "file" << ++seed;
62
63         // Needed if we use lyxstring.
64         return ost.str().c_str();
65 }
66
67 } // namespace anon
68
69
70 InsetInclude::InsetInclude(Params const & p)
71         : params_(p), include_label(uniqueID()),
72           preview_(new PreviewImpl(*this))
73 {}
74
75
76 InsetInclude::InsetInclude(InsetCommandParams const & p, Buffer const & b)
77         : include_label(uniqueID()),
78           preview_(new PreviewImpl(*this))
79 {
80         params_.cparams = p;
81         params_.masterFilename_ = b.fileName();
82 }
83
84
85 InsetInclude::~InsetInclude()
86 {
87         hideDialog();
88 }
89
90
91 InsetInclude::Params const & InsetInclude::params() const
92 {
93         return params_;
94 }
95
96
97 bool InsetInclude::Params::operator==(Params const & o) const
98 {
99         if (cparams == o.cparams && flag == o.flag &&
100             noload == o.noload && masterFilename_ == o.masterFilename_)
101                 return true;
102
103         return false;
104 }
105
106
107 bool InsetInclude::Params::operator!=(Params const & o) const
108 {
109         return !(*this == o);
110 }
111
112
113 void InsetInclude::set(Params const & p)
114 {
115         params_ = p;
116
117         // Just to be safe...
118         string command;
119
120         switch (params_.flag) {
121                 case INCLUDE:
122                         command="include";
123                         break;
124                 case VERB:
125                         command="verbatiminput";
126                         break;
127                 case INPUT:
128                         command="input";
129                         break;
130                 case VERBAST:
131                         command="verbatiminput*";
132                         break;
133         }
134
135         params_.cparams.setCmdName(command);
136
137         if (grfx::PreviewedInset::activated() && params_.flag == INPUT)
138                 preview_->generatePreview();
139 }
140
141
142 Inset * InsetInclude::clone(Buffer const & buffer, bool) const
143 {
144         Params p(params_);
145         p.masterFilename_ = buffer.fileName();
146
147         return new InsetInclude(p);
148 }
149
150
151 void InsetInclude::edit(BufferView * bv, int, int, mouse_button::state)
152 {
153         bv->owner()->getDialogs()->showInclude(this);
154 }
155
156
157 void InsetInclude::edit(BufferView * bv, bool)
158 {
159         edit(bv, 0, 0, mouse_button::none);
160 }
161
162
163 void InsetInclude::write(Buffer const *, ostream & os) const
164 {
165         os << "Include " << params_.cparams.getCommand() << "\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 (params_.noload || 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         int const x = int(xx);
507         int const w = width(bv, font);
508         int const d = descent(bv, font);
509         int const a = ascent(bv, font);
510         int const h = a + d;
511
512         bv->painter().image(x, y - a, w, h,
513                             *(preview_->pimage()->image(*this, *bv)));
514
515         xx += w;
516 }
517
518
519 //
520 // preview stuff
521 //
522
523 void InsetInclude::addPreview(grfx::PreviewLoader & ploader) const
524 {
525         preview_->addPreview(ploader);
526 }
527
528
529 bool InsetInclude::PreviewImpl::previewWanted() const
530 {
531         return parent().params_.flag == InsetInclude::INPUT;
532 }
533
534
535 string const InsetInclude::PreviewImpl::latexString() const
536 {
537         if (!view() || !view()->buffer())
538                 return string();
539
540         ostringstream os;
541         parent().latex(view()->buffer(), os, false, false);
542
543         // This fails if the file has a relative path.
544         // return os.str().c_str();
545
546         // I would /really/ like not to do this...
547         // HELP!
548         string command;
549         string file = rtrim(split(os.str().c_str(), command, '{'), "}");
550
551         if (!AbsolutePath(file))
552                 file = MakeAbsPath(file, view()->buffer()->filePath());
553
554         ostringstream out;
555         out << command << '{' << file << '}' << endl;
556         
557         return out.str().c_str();
558 }