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